def test_apply_token_txn(self):
        """
        Alice creates a token. Obviously, she gives herself some of this token.
        But she also gives Bob some tokens too.
        """
        initial_balances = [qrl_pb2.AddressAmount(address=self.alice.address, amount=1000),
                            qrl_pb2.AddressAmount(address=self.bob.address, amount=2000)]
        self.params["initial_balances"] = initial_balances

        tx = TokenTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = dict(self.addresses_state)
        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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)

        # According to the State, Alice has 100 coins, and Bob has 0 coins.
        # After applying the Transaction, Alice and Bob should have 1000 tokens, and Alice's balance should be 99.
        # AddressState.transaction_hashes now also reference the TokenTransaction that created the Tokens.
        self.assertFalse(state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(self.alice.address, 0))
        tx.apply(self.state, state_container)
        self.assertTrue(state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(self.alice.address, 0))
        self.assertEqual(addresses_state[self.alice.address].balance, 99)
        self.assertEqual(addresses_state[self.bob.address].balance, 0)

        self.assertEqual(2, len(state_container.paginated_tx_hash.key_value))

        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([tx.txhash], state_container.paginated_tx_hash.key_value[storage_key])

        storage_key = state_container.paginated_tx_hash.generate_key(self.bob.address, 1)
        self.assertIn(storage_key, state_container.paginated_tx_hash.key_value)
        self.assertEqual([tx.txhash], state_container.paginated_tx_hash.key_value[storage_key])

        self.assertEqual(2, len(state_container.tokens.data))
        self.assertIn((self.alice.address, tx.txhash), state_container.tokens.data)
        self.assertEqual(1000, state_container.tokens.data[(self.alice.address, tx.txhash)].balance)
        self.assertIn((self.bob.address, tx.txhash), state_container.tokens.data)
        self.assertEqual(2000, state_container.tokens.data[(self.bob.address, tx.txhash)].balance)
    def test_revert_token_txn_owner_not_in_address_state(self):
        """
        In this case, Alice didn't give herself any tokens. How generous! She gave them all to Bob.
        But we want to revert this.
        """
        initial_balances = [qrl_pb2.AddressAmount(address=self.bob.address, amount=1000)]
        self.params["initial_balances"] = initial_balances

        tx = TokenTransaction.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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)

        state_container.paginated_bitfield.set_ots_key(addresses_state, self.alice.address, 0)

        self.assertTrue(state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(self.alice.address, 0))
        tx.apply(self.state, state_container)
        tx.revert(self.state, state_container)
        self.assertFalse(state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(self.alice.address, 0))

        self.assertEqual(addresses_state[self.alice.address].balance, 100)
        self.assertEqual(addresses_state[self.bob.address].balance, 0)

        self.assertEqual(2, len(state_container.paginated_tx_hash.key_value))

        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])

        storage_key = state_container.paginated_tx_hash.generate_key(self.bob.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.assertEqual(1, len(state_container.tokens.data))
        self.assertIn((self.bob.address, tx.txhash), state_container.tokens.data)
        self.assertEqual(0, state_container.tokens.data[(self.bob.address, tx.txhash)].balance)
Example #3
0
 def mock_new_state_container(self):
     addresses_state = {alice.address: self.alice_address_state}
     self.chain_manager.new_state_container.return_value = 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=5,
         total_coin_supply=0,
         current_dev_config=config.dev,
         write_access=False,
         my_db=None,
         batch=None)
Example #4
0
    def test_revert_transfer_txn_tx_sends_to_self(self, m_logger):
        """
        Alice sent coins to herself, but she still lost the Transaction fee. Undo this.
        """
        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
            self.bob.address:
            OptimizedAddressState.get_default(self.bob.address)
        }
        addresses_state[self.alice.address].pbdata.balance = 200

        tx = TransferTransaction.create(addrs_to=[self.alice.address],
                                        amounts=[100],
                                        message_data=None,
                                        fee=1,
                                        xmss_pk=self.alice.pk)
        tx.sign(self.alice)
        ots_key = self.alice.ots_index - 1
        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)
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.alice.address,
                                                       ots_key)
        state_container.paginated_bitfield.put_addresses_bitfield(None)

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
        tx.apply(self.state, state_container)
        tx.revert(self.state, state_container)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))

        self.assertEqual(200, addresses_state[self.alice.address].balance)
        self.assertEqual(0, addresses_state[self.bob.address].balance)
Example #5
0
    def test_validate_extended(self, m_logger):
        """
        validate_extended() handles these parts of the validation:
        1. Master/slave
        2. balance, amount + fee from AddressState
        3. OTS key reuse from AddressState
        :return:
        """
        alice_address_state = OptimizedAddressState.get_default(
            self.alice.address)
        addresses_state = {self.alice.address: alice_address_state}
        alice_address_state.pbdata.balance = 200

        self.tx.validate_slave = Mock(autospec=Transaction.validate_slave,
                                      return_value=True)

        self.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 = self.tx.validate_all(state_container)
        self.assertTrue(result)

        # Suppose there was ots key reuse. The function should then return false.
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.tx.addr_from,
                                                       self.tx.ots_key)
        result = self.tx.validate_all(state_container)
        self.assertFalse(result)

        # Suppose the address doesn't have enough coins.
        alice_address_state.pbdata.balance = 99
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.tx.addr_from,
                                                       self.tx.ots_key)
        result = self.tx.validate_all(state_container)
        self.assertFalse(result)
Example #6
0
    def test_apply_transfer_txn_tx_sends_to_self(self, m_logger):
        """
        If you send coins to yourself, you should only lose the fee for the Transaction.
        """
        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
            self.bob.address:
            OptimizedAddressState.get_default(self.bob.address),
            self.slave.address:
            OptimizedAddressState.get_default(self.slave.address)
        }
        addresses_state[self.alice.address].pbdata.balance = 200

        tx = TransferTransaction.create(addrs_to=[self.alice.address],
                                        amounts=[100],
                                        message_data=None,
                                        fee=1,
                                        xmss_pk=self.alice.pk)
        tx.sign(self.alice)
        ots_key = self.alice.ots_index - 1
        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)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
        tx.apply(self.state, state_container)
        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))

        self.assertEqual(199, addresses_state[self.alice.address].balance)
        storage_key = state_container.paginated_tx_hash.generate_key(
            self.alice.address, 1)
        self.assertIn(tx.txhash,
                      state_container.paginated_tx_hash.key_value[storage_key])
Example #7
0
    def test_apply_coinbase_txn(self, m_logger):
        """
        Alice earned some coins.
        """
        addresses_state = {
            config.dev.coinbase_address:
            OptimizedAddressState.get_default(config.dev.coinbase_address),
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
        }
        addresses_state[
            config.dev.coinbase_address].pbdata.balance = 1000000000000000
        tx = CoinBase.create(config.dev, self.amount, self.alice.address,
                             self.mock_blockheader.block_number)
        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=self.mock_blockheader.block_number,
            total_coin_supply=100,
            current_dev_config=config.dev,
            write_access=True,
            my_db=self.state._db,
            batch=None)
        # self.state.apply(tx, addresses_state)
        tx.apply(self.state, state_container)
        reward = int(
            block_reward(self.mock_blockheader.block_number, config.dev))
        self.assertEqual(1000000000000000 - reward,
                         addresses_state[config.dev.coinbase_address].balance)

        storage_key = state_container.paginated_tx_hash.generate_key(
            config.dev.coinbase_address, 1)
        self.assertEqual(
            [tx.txhash],
            state_container.paginated_tx_hash.key_value[storage_key])
        self.assertEqual(tx.amount,
                         addresses_state[self.alice.address].balance)

        storage_key = state_container.paginated_tx_hash.generate_key(
            self.alice.address, 1)
        self.assertEqual(
            [tx.txhash],
            state_container.paginated_tx_hash.key_value[storage_key])
Example #8
0
    def test_apply_transfer_txn_multi_send(self, m_logger):
        """
        Test that apply_state_changes() also works with multiple recipients.
        """
        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
            self.bob.address:
            OptimizedAddressState.get_default(self.bob.address),
            self.slave.address:
            OptimizedAddressState.get_default(self.slave.address)
        }
        addresses_state[self.alice.address].pbdata.balance = 200

        tx_multisend = TransferTransaction.create(
            addrs_to=[self.bob.address, self.slave.address],
            amounts=[20, 20],
            message_data=None,
            fee=1,
            xmss_pk=self.alice.pk)
        tx_multisend.sign(self.alice)
        ots_key = self.alice.ots_index - 1
        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)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
        tx_multisend.apply(self.state, state_container)
        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))

        self.assertEqual(159, addresses_state[self.alice.address].balance)
        self.assertEqual(20, addresses_state[self.bob.address].balance)
        self.assertEqual(20, addresses_state[self.slave.address].balance)
    def test_revert_transfer_token_txn(self):
        """
        Alice has 1000 tokens and 100 QRL, Bob has none. Alice sends some tokens to Bob.
        Let's undo this.
        """
        tx = TransferTokenTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = dict(self.addresses_state)
        addresses_state[self.alice.address].pbdata.balance = 100
        addresses_state[self.bob.address].pbdata.balance = 0
        tokens = Indexer(b'token', None)
        tokens.data[(self.alice.address,
                     tx.token_txhash)] = TokenBalance(balance=1000)
        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=tokens,
                                         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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.alice.address, 0)

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))
        tx.apply(self.state, state_container)
        tx.revert(self.state, state_container)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))

        self.assertEqual(addresses_state[self.alice.address].balance, 100)
        self.assertEqual(addresses_state[self.bob.address].balance, 0)

        self.assertEqual(
            tokens.data[(self.alice.address, tx.token_txhash)].balance, 1000)
        self.assertEqual(
            tokens.data[(self.bob.address, tx.token_txhash)].balance, 0)
Example #10
0
    def test_validate_extended(self, m_logger):
        """
        CoinBase validate_extended() checks for
        1. valid coinbase address (the coinbase address must be config.dev.coinbase_address)
        2. valid addr_to
        then calls _validate_custom()
        """
        tx = CoinBase.create(config.dev, self.amount, self.alice.address,
                             self.mock_blockheader.block_number)
        tx._data.master_addr = self.alice.address

        addresses_state = {
            config.dev.coinbase_address:
            OptimizedAddressState.get_default(config.dev.coinbase_address),
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
        }
        addresses_state[config.dev.coinbase_address].pbdata.balance = 1000000

        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=self.mock_blockheader.block_number,
            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.assertFalse(result)

        tx._data.master_addr = config.dev.coinbase_address
        with patch('qrl.core.txs.CoinBase.CoinBase.addr_to',
                   new_callable=PropertyMock) as m_addr_to:
            m_addr_to.return_value = b'Fake Address'
            result = tx._validate_extended(state_container)
            self.assertFalse(result)

        result = tx._validate_extended(state_container)
        self.assertTrue(result)
Example #11
0
    def test_revert_state_changes_for_PK(self, m_logger):
        """
        This is just an undo function.
        :return:
        """
        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address)
        }
        addresses_state[self.alice.address].pbdata.balance = 101
        addresses_state[self.alice.address].pbdata.nonce = 1

        tx = TransferTransaction.create(addrs_to=[self.bob.address],
                                        amounts=[100],
                                        message_data=None,
                                        fee=1,
                                        xmss_pk=self.alice.pk)
        tx.sign(self.alice)
        ots_key = self.alice.ots_index - 1
        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)
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.alice.address,
                                                       ots_key)
        state_container.paginated_bitfield.put_addresses_bitfield(None)

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
        tx._apply_state_changes_for_PK(state_container)
        tx._revert_state_changes_for_PK(state_container)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
Example #12
0
    def test_validate_extended(self):
        """
        CoinBase validate_extended() checks for
        1. valid coinbase address (the coinbase address must be config.dev.coinbase_address)
        2. valid addr_to
        then calls _validate_custom()
        """
        tx = MultiSigCreate.create(signatories=self.signatories,
                                   weights=self.weights,
                                   threshold=self.threshold,
                                   fee=5,
                                   xmss_pk=self.alice.pk)
        tx.sign(self.alice)
        alice_address_state = OptimizedAddressState.get_default(
            address=self.alice.address)
        alice_address_state.pbdata.balance = 5

        addresses_state = {
            self.alice.address: alice_address_state,
        }
        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=10,
                                         total_coin_supply=100,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=None,
                                         batch=None)

        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        alice_address_state.pbdata.balance = 4
        result = tx._validate_extended(state_container)
        self.assertFalse(
            result)  # False due to insufficient balance to pay the txn fee

        alice_address_state.pbdata.balance = 6
        result = tx._validate_extended(state_container)
        self.assertTrue(result)
Example #13
0
    def test_validate_all(self):
        tx = MultiSigCreate.create(signatories=self.signatories,
                                   weights=self.weights,
                                   threshold=self.threshold,
                                   fee=5,
                                   xmss_pk=self.random.pk,
                                   master_addr=self.alice.address)
        tx.sign(self.random)
        tx.pbdata.nonce = 1

        alice_address_state = OptimizedAddressState.get_default(
            address=self.alice.address)
        alice_address_state.pbdata.balance = 5
        random_address_state = OptimizedAddressState.get_default(
            address=self.random.address)

        addresses_state = {
            self.alice.address: alice_address_state,
            self.random.address: random_address_state,
        }
        slaves = Indexer(b'slave', None)
        slaves.data[(self.alice.address,
                     self.random.pk)] = SlaveMetadata(access_type=0)
        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=Indexer(b'token', None),
                                         slaves=slaves,
                                         lattice_pk=Indexer(
                                             b'lattice_pk', None),
                                         multi_sig_spend_txs=dict(),
                                         votes_stats=dict(),
                                         block_number=10,
                                         total_coin_supply=100,
                                         current_dev_config=config.dev,
                                         write_access=False,
                                         my_db=self.state._db,
                                         batch=None)

        result = tx.validate_all(state_container)
        self.assertTrue(result)

        tx.pbdata.nonce = 2
        result = tx.validate_all(state_container)
        self.assertFalse(result)  # False as nonce is invalid
Example #14
0
    def test_apply_transfer_txn(self, m_logger):
        """
        apply_state_changes() is the part that actually updates everybody's balances.
        Then it forwards the addresses_state to _apply_state_changes_for_PK(), which updates everybody's addresses's
        nonce, OTS key index, and associated TX hashes
        If there is no AddressState for a particular Address, nothing is done.
        """
        self.tx.sign(self.alice)
        ots_key = self.alice.ots_index - 1
        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
            self.bob.address:
            OptimizedAddressState.get_default(self.bob.address),
            self.slave.address:
            OptimizedAddressState.get_default(self.slave.address)
        }
        addresses_state[self.alice.address].pbdata.balance = 200
        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)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
        self.tx.apply(self.state, state_container)
        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))

        # Now Alice should have 99 coins left (200 - 100 - 1) and Bob should have 100 coins.
        self.assertEqual(99, addresses_state[self.alice.address].balance)
        self.assertEqual(100, addresses_state[self.bob.address].balance)
    def test_revert_transfer_token_txn_send_tokens_to_self(self):
        """
        Alice has 1000 tokens and 100 QRL. She sends some tokens to herself.
        Can we undo this?
        """
        self.params["addrs_to"] = [self.alice.address]
        tx = TransferTokenTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = dict(self.addresses_state)
        addresses_state[self.alice.address].pbdata.balance = 100
        tokens = Indexer(b'token', None)
        tokens.data[(self.alice.address,
                     tx.token_txhash)] = TokenBalance(balance=100)
        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=tokens,
                                         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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.alice.address, 0)

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))
        tx.apply(self.state, state_container)
        tx.revert(self.state, state_container)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))

        self.assertEqual(addresses_state[self.alice.address].balance, 100)
        # Unfortunately importing mock.call results in some sort of ValueError so I can't check the arguments.
        self.assertEqual(
            tokens.data[(self.alice.address, tx.token_txhash)].balance, 100)
    def test_apply_state_changes_owner_not_in_address_state(self):
        """
        In this case, Alice didn't give herself any tokens. How generous! She gave them all to Bob.
        """
        initial_balances = [qrl_pb2.AddressAmount(address=self.bob.address, amount=1000)]
        self.params["initial_balances"] = initial_balances

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

        # Signing the TX also generates the txhash, which we need to generate the AddressState properly.
        addresses_state = dict(self.addresses_state)
        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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        tx.apply(self.state, state_container)

        self.assertEqual(addresses_state[self.alice.address].balance, 99)
        self.assertEqual(addresses_state[self.bob.address].balance, 0)

        self.assertEqual(2, len(state_container.paginated_tx_hash.key_value))

        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([tx.txhash], state_container.paginated_tx_hash.key_value[storage_key])

        storage_key = state_container.paginated_tx_hash.generate_key(self.bob.address, 1)
        self.assertIn(storage_key, state_container.paginated_tx_hash.key_value)
        self.assertEqual([tx.txhash], state_container.paginated_tx_hash.key_value[storage_key])

        self.assertEqual(1, len(state_container.tokens.data))
        self.assertIn((self.bob.address, tx.txhash), state_container.tokens.data)
        self.assertEqual(1000, state_container.tokens.data[(self.bob.address, tx.txhash)].balance)
    def test_revert_transfer_token_txn_empty_addresses_state(self):
        """
        If we didn't have any AddressStates for the addresses involved in this test, do nothing
        """
        tx = TransferTokenTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = dict(self.addresses_state)
        tokens = Indexer(b'token', None)
        tokens.data[(self.alice.address,
                     tx.token_txhash)] = TokenBalance(balance=100)
        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=tokens,
                                         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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.alice.address, 0)

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))
        tx.apply(self.state, state_container)
        tx.revert(self.state, state_container)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))

        self.assertEqual(
            100, tokens.data[(self.alice.address, tx.token_txhash)].balance)
        self.assertEqual(
            0, tokens.data[(self.bob.address, tx.token_txhash)].balance)
    def test_validate_slave_signing_xmss_state_has_no_slave_permissions_in_state(self, m_logger):
        bob = get_bob_xmss()
        # Let's say Alice is Bob's master.
        self.params["master_addr"] = self.alice.address
        self.params["xmss_pk"] = bob.pk

        # We need to add extra data to the mock AddressState.
        tx = MessageTransaction.create(**self.params)
        tx.sign(self.alice)
        state_container = StateContainer(addresses_state=dict(),
                                         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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        result = tx.validate_slave(state_container)
        self.assertFalse(result)
Example #19
0
    def test_apply_state_changes_for_PK(self, m_logger):
        """
        This updates the node's AddressState database with which OTS index a particular address should be on, and what
        tx hashes is this address associated with.
        Curiously enough, if the TX was signed by a master XMSS tree, it doesn't add this tx's txhash to the list of
        txs that address is associated with.
        :return:
        """
        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address)
        }
        self.tx.sign(self.alice)
        ots_key = self.alice.ots_index - 1
        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)

        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
        self.tx._apply_state_changes_for_PK(state_container)
        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))

        self.assertEqual(1, addresses_state[self.alice.address].nonce)
    def test_apply_transfer_token_txn_send_tokens_to_self(self):
        """
        Alice has 1000 tokens and 100 QRL. She sends some tokens to herself. What happens next?
        """
        self.params["addrs_to"] = [self.alice.address]
        tx = TransferTokenTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = dict(self.addresses_state)
        tokens = Indexer(b'token', None)
        tokens.data[(self.alice.address,
                     tx.token_txhash)] = TokenBalance(balance=100)
        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=tokens,
                                         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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)

        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))
        tx.apply(self.state, state_container)
        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, 0))

        self.assertEqual(addresses_state[self.alice.address].balance, 99)
        self.assertEqual(
            tokens.data[(self.alice.address, tx.token_txhash)].balance, 100)
Example #21
0
    def test_validate_extended(self):
        multi_sig_address = MultiSigAddressState.generate_multi_sig_address(
            b'')
        spend_tx = MultiSigSpend.create(multi_sig_address=multi_sig_address,
                                        addrs_to=[self.alice.address],
                                        amounts=[100],
                                        expiry_block_number=15000,
                                        fee=0,
                                        xmss_pk=self.alice.pk)
        spend_tx.sign(self.alice)
        tx = MultiSigVote.create(shared_key=spend_tx.txhash,
                                 unvote=False,
                                 fee=5,
                                 xmss_pk=self.alice.pk)
        tx.sign(self.alice)

        alice_address_state = OptimizedAddressState.get_default(
            address=self.alice.address)
        alice_address_state.pbdata.balance = 5
        multi_sig_address_state = MultiSigAddressState.create(
            creation_tx_hash=b'',
            balance=100,
            signatories=[self.alice.address, self.bob.address],
            weights=[4, 6],
            threshold=5,
            transaction_hash_count=0)
        addresses_state = {
            self.alice.address: alice_address_state,
            multi_sig_address: multi_sig_address_state,
        }
        vote_stats = {
            spend_tx.txhash:
            VoteStats.create(multi_sig_address=multi_sig_address,
                             shared_key=spend_tx.txhash,
                             signatories=multi_sig_address_state.signatories,
                             expiry_block_number=spend_tx.expiry_block_number),
        }
        multi_sig_spend_txs = {
            spend_tx.txhash: spend_tx,
        }
        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=multi_sig_spend_txs,
            votes_stats=vote_stats,
            block_number=10,
            total_coin_supply=100,
            current_dev_config=config.dev,
            write_access=True,
            my_db=None,
            batch=None)

        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        tx._data.multi_sig_vote.unvote = True
        result = tx._validate_extended(state_container)
        self.assertFalse(result)

        tx._data.multi_sig_vote.unvote = False
        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        alice_address_state.pbdata.balance = 0
        result = tx._validate_extended(state_container)
        self.assertFalse(result)

        alice_address_state.pbdata.balance = 5
        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        state_container.block_number = 15000
        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        state_container.block_number = 15001
        result = tx._validate_extended(state_container)
        self.assertFalse(result)
Example #22
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))
Example #23
0
    def test_revert_multi_sig_create_txn(self):
        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
            self.bob.address:
            OptimizedAddressState.get_default(self.bob.address),
            self.random.address:
            OptimizedAddressState.get_default(self.random.address),
            self.random_signer.address:
            OptimizedAddressState.get_default(self.random_signer.address),
        }
        addresses_state[self.random_signer.address].pbdata.balance = 200
        tx = MultiSigCreate.create(self.signatories, self.weights,
                                   self.threshold, 1, self.random_signer.pk)
        tx.sign(self.random_signer)

        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)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.random_signer.address, tx.ots_key))

        tx.apply(self.state, state_container)

        self.assertEqual(200 - tx.fee,
                         addresses_state[self.random_signer.address].balance)

        storage_key = state_container.paginated_tx_hash.generate_key(
            self.random_signer.address, 1)
        self.assertEqual(
            [tx.txhash],
            state_container.paginated_tx_hash.key_value[storage_key])
        for signatory_address in self.signatories:
            storage_key = state_container.paginated_tx_hash.generate_key(
                signatory_address, 1)
            self.assertEqual(
                [tx.txhash],
                state_container.paginated_tx_hash.key_value[storage_key])

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.random_signer.address, tx.ots_key))
        AddressState.put_addresses_state(self.state, addresses_state)
        state_container.paginated_multisig_address.put_paginated_data(None)
        multi_sig_addresses_state = MultiSigAddressState.get_multi_sig_address_state_by_address(
            self.state._db,
            MultiSigAddressState.generate_multi_sig_address(tx.txhash))

        self.assertEqual(self.signatories,
                         multi_sig_addresses_state.signatories)
        self.assertEqual(self.weights, multi_sig_addresses_state.weights)
        self.assertEqual(self.threshold, multi_sig_addresses_state.threshold)

        for signatory_address in self.signatories:
            multi_sig_addresses = state_container.paginated_multisig_address.get_paginated_data(
                signatory_address, 1)
            self.assertEqual(len(multi_sig_addresses), 1)

        tx.revert(self.state, state_container)
        state_container.paginated_multisig_address.put_paginated_data(None)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.random_signer.address, tx.ots_key))
        self.assertIsNone(
            MultiSigAddressState.get_multi_sig_address_state_by_address(
                self.state._db,
                MultiSigAddressState.generate_multi_sig_address(tx.txhash)))

        for signatory_address in self.signatories:
            multi_sig_addresses = state_container.paginated_multisig_address.get_paginated_data(
                signatory_address, 1)
            self.assertEqual(len(multi_sig_addresses), 0)
Example #24
0
    def test_revert(self):
        multi_sig_address = MultiSigAddressState.generate_multi_sig_address(
            b'')
        spend_tx = MultiSigSpend.create(multi_sig_address=multi_sig_address,
                                        addrs_to=[self.alice.address],
                                        amounts=[100],
                                        expiry_block_number=15000,
                                        fee=0,
                                        xmss_pk=self.alice.pk)
        spend_tx.sign(self.alice)
        tx = MultiSigVote.create(shared_key=spend_tx.txhash,
                                 unvote=False,
                                 fee=5,
                                 xmss_pk=self.alice.pk)
        tx.sign(self.alice)

        alice_address_state = OptimizedAddressState.get_default(
            address=self.alice.address)
        alice_address_state.pbdata.balance = 5
        multi_sig_address_state = MultiSigAddressState.create(
            creation_tx_hash=b'',
            balance=100,
            signatories=[self.alice.address, self.bob.address],
            weights=[4, 6],
            threshold=5,
            transaction_hash_count=0)
        addresses_state = {
            self.alice.address: alice_address_state,
            multi_sig_address: multi_sig_address_state,
        }
        vote_stats = {
            spend_tx.txhash:
            VoteStats.create(multi_sig_address=multi_sig_address,
                             shared_key=spend_tx.txhash,
                             signatories=multi_sig_address_state.signatories,
                             expiry_block_number=spend_tx.expiry_block_number),
        }
        multi_sig_spend_txs = {
            spend_tx.txhash: spend_tx,
        }
        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=multi_sig_spend_txs,
            votes_stats=vote_stats,
            block_number=10,
            total_coin_supply=100,
            current_dev_config=config.dev,
            write_access=True,
            my_db=self.state._db,
            batch=None)

        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, tx.ots_key))

        tx.apply(self.state, state_container)

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, tx.ots_key))
        self.assertIn(spend_tx.txhash, state_container.votes_stats)
        vote_stats = state_container.votes_stats[spend_tx.txhash]
        unvote, index = vote_stats.get_unvote_by_address(tx.addr_from)
        self.assertNotEqual(index, -1)
        self.assertFalse(unvote)
        self.assertEqual(vote_stats.shared_key, spend_tx.txhash)
        self.assertEqual(vote_stats.total_weight, 4)
        self.assertEqual(vote_stats.signatories,
                         multi_sig_address_state.signatories)

        tx.revert(self.state, state_container)
        self.assertIn(spend_tx.txhash, state_container.votes_stats)
        vote_stats = state_container.votes_stats[spend_tx.txhash]
        unvote, index = vote_stats.get_unvote_by_address(tx.addr_from)
        self.assertNotEqual(index, -1)
        self.assertTrue(unvote)
        self.assertEqual(vote_stats.shared_key, spend_tx.txhash)
        self.assertEqual(vote_stats.total_weight, 0)
        self.assertEqual(vote_stats.signatories,
                         multi_sig_address_state.signatories)

        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, tx.ots_key))
Example #25
0
    def test_validate(self):
        # 1. Set up all the mocking so that Block.validate() should pass
        m_chain_manager = Mock(name='Mock ChainManager')
        attrs_all_pass = {
            'get_block_is_duplicate.return_value': False,
            'validate_mining_nonce.return_value': True,
            'get_config_by_block_number.return_value': config.dev,
            'new_state_container.return_value': StateContainer(None, None, None, None, None, None, 5,
                                                               None, config.dev, False, None, None)
        }
        m_chain_manager.configure_mock(**attrs_all_pass)
        self.block._validate_parent_child_relation = Mock(return_value=True)

        result = self.block.validate(m_chain_manager, OrderedDict())
        self.assertTrue(result)

        # 2. Switch the mock checks one by one to invalid, and make sure that validate() returns False
        # The Block is already in the State (a duplicate)
        m_chain_manager.get_block_is_duplicate.return_value = True
        result = self.block.validate(m_chain_manager, OrderedDict())
        self.assertFalse(result)
        m_chain_manager.get_block_is_duplicate.return_value = False

        # The mining nonce is invalid
        m_chain_manager.validate_mining_nonce.return_value = False
        result = self.block.validate(m_chain_manager, OrderedDict())
        self.assertFalse(result)
        m_chain_manager.validate_mining_nonce.return_value = True

        # No parent block found, and it's not in future_blocks either
        m_chain_manager.get_block.return_value = None
        result = self.block.validate(m_chain_manager, OrderedDict())
        self.assertFalse(result)
        m_chain_manager.get_block.return_value = Mock(name='mock Block')

        # The parent_block is not actually Block's parent
        self.block._validate_parent_child_relation.return_value = False
        result = self.block.validate(m_chain_manager, OrderedDict())
        self.assertFalse(result)
        self.block._validate_parent_child_relation.return_value = True

        # Block.transactions is [] (it should at least have the CoinBase TX in there)
        with patch('qrl.core.Block.Block.transactions', new_callable=PropertyMock) as m_transactions:
            m_transactions.return_value = []
            result = self.block.validate(m_chain_manager, OrderedDict())
            self.assertFalse(result)

        # There was a problem with the CoinBase TX
        with patch('qrl.core.txs.CoinBase.CoinBase._validate_extended') as m_validate_extended:
            m_validate_extended.return_value = False
            result = self.block.validate(m_chain_manager, OrderedDict())
            self.assertFalse(result)
            m_validate_extended.return_value = None

            m_validate_extended.side_effect = Exception
            result = self.block.validate(m_chain_manager, OrderedDict())
            self.assertFalse(result)

        # The BlockHeader doesn't fit with this Block
        self.blockheader.validate.return_value = False
        result = self.block.validate(m_chain_manager, OrderedDict())
        self.assertFalse(result)
Example #26
0
    def test_validate_extended(self, m_validate_slave, m_logger):
        """
        TokenTransaction._validate_extended checks for:
        1. valid master/slave
        2. from address is valid
        3. owner address is valid
        4. addresses that own the initial balances are valid
        5. that the AddressState has enough coins to pay the Transaction fee (because no coins are being transferred)
        6. OTS key reuse
        """
        alice_address_state = OptimizedAddressState.get_default(
            self.alice.address)
        alice_address_state.pbdata.balance = 100

        tx = TokenTransaction.create(**self.params)
        tx.sign(self.alice)
        addresses_state = {alice_address_state.address: alice_address_state}
        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=1000,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=self.state._db,
                                         batch=None)
        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        m_validate_slave.return_value = False
        result = tx.validate_all(state_container)
        self.assertFalse(result)
        m_validate_slave.return_value = True

        with patch('qrl.core.txs.TokenTransaction.TokenTransaction.addr_from',
                   new_callable=PropertyMock) as m_addr_from:
            m_addr_from.return_value = b'Invalid Address'
            result = tx._validate_extended(state_container)
            self.assertFalse(result)

        with patch('qrl.core.txs.TokenTransaction.TokenTransaction.owner',
                   new_callable=PropertyMock) as m_owner:
            m_owner.return_value = b'Invalid Address'
            result = tx._validate_extended(state_container)
            self.assertFalse(result)

        with patch(
                'qrl.core.txs.TokenTransaction.TokenTransaction.initial_balances',
                new_callable=PropertyMock) as m_address_balance:
            m_address_balance.return_value = [
                qrl_pb2.AddressAmount(address=b'Invalid Address 1',
                                      amount=1000),
                qrl_pb2.AddressAmount(address=b'Invalid Address 2',
                                      amount=1000)
            ]
            result = tx._validate_extended(state_container)
            self.assertFalse(result)

        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)

        # Token symbol too long
        tx = self.make_tx(symbol=b'QRLSQRLSQRL')
        tx.sign(self.alice)
        self.assertFalse(tx._validate_extended(state_container))

        # Token name too long
        tx = self.make_tx(name=b'Quantum Resistant LedgerQuantum')
        tx.sign(self.alice)
        self.assertFalse(tx._validate_extended(state_container))

        # Token symbol missing
        with self.assertRaises(ValueError):
            tx = self.make_tx(symbol=b'')
            tx.sign(self.alice)
            self.assertFalse(tx._validate_extended(state_container))

        # Token name missing
        with self.assertRaises(ValueError):
            tx = self.make_tx(name=b'')
            tx.sign(self.alice)
            tx._validate_extended(state_container)

        # Empty initial_balances
        with self.assertRaises(ValueError):
            tx = self.make_tx(initial_balances=[])
            tx.sign(self.alice)
            self.assertFalse(tx._validate_extended(state_container))

        # Invalid initial balances... 0!
        with self.assertRaises(ValueError):
            initial_balances_0_0 = [
                qrl_pb2.AddressAmount(address=self.alice.address, amount=0),
                qrl_pb2.AddressAmount(address=self.bob.address, amount=0)
            ]
            tx = self.make_tx(initial_balances=initial_balances_0_0)
            tx.sign(self.alice)
            self.assertFalse(tx._validate_extended(state_container))

        # Fee is -1
        with patch('qrl.core.txs.TokenTransaction.TokenTransaction.fee',
                   new_callable=PropertyMock) as m_fee:
            m_fee.return_value = -1
            with self.assertRaises(ValueError):
                tx = self.make_tx()
                tx.sign(self.alice)
Example #27
0
    def test_revert_transfer_txn_multi_send(self, m_logger):
        """
        Alice has sent 20 coins to Bob and Slave each, using 1 as Transaction fee. Now we need to undo this.
        """
        tx_multisend = TransferTransaction.create(
            addrs_to=[self.bob.address, self.slave.address],
            amounts=[20, 20],
            message_data=None,
            fee=1,
            xmss_pk=self.alice.pk)
        tx_multisend.sign(self.alice)
        ots_key = self.alice.ots_index - 1

        addresses_state = {
            self.alice.address:
            OptimizedAddressState.get_default(self.alice.address),
            self.bob.address:
            OptimizedAddressState.get_default(self.bob.address),
            self.slave.address:
            OptimizedAddressState.get_default(self.slave.address)
        }
        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)
        state_container.paginated_bitfield.set_ots_key(addresses_state,
                                                       self.alice.address,
                                                       ots_key)
        state_container.paginated_bitfield.put_addresses_bitfield(None)
        addresses_state[self.alice.address].pbdata.balance = 200
        addresses_state[self.bob.address].pbdata.balance = 0
        addresses_state[self.slave.address].pbdata.balance = 0

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))
        tx_multisend.apply(self.state, state_container)
        tx_multisend.revert(self.state, state_container)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, ots_key))

        self.assertEqual(200, addresses_state[self.alice.address].balance)
        self.assertEqual(0, addresses_state[self.bob.address].balance)
        self.assertEqual(0, addresses_state[self.slave.address].balance)

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

        storage_key = state_container.paginated_tx_hash.generate_key(
            self.bob.address, 1)
        self.assertEqual(
            [], state_container.paginated_tx_hash.key_value[storage_key])

        storage_key = state_container.paginated_tx_hash.generate_key(
            self.slave.address, 1)
        self.assertEqual(
            [], state_container.paginated_tx_hash.key_value[storage_key])
Example #28
0
    def test_revert(self):
        multi_sig_address = MultiSigAddressState.generate_multi_sig_address(
            b'')
        multi_sig_address_state = MultiSigAddressState.create(
            creation_tx_hash=b'',
            balance=100,
            signatories=[self.alice.address, self.bob.address],
            weights=[4, 6],
            threshold=5,
            transaction_hash_count=0)
        alice_address_state = OptimizedAddressState.get_default(
            self.alice.address)
        alice_address_state.pbdata.balance = 5
        alice_address_state.update_ots_bitfield_used_page()
        alice_address_state.used_ots_key_count += 1
        alice_address_state.update_multi_sig_address_count()
        bob_address_state = OptimizedAddressState.get_default(self.bob.address)
        addresses_state = {
            self.alice.address: alice_address_state,
            self.bob.address: bob_address_state,
            multi_sig_address: multi_sig_address_state,
        }

        tx = MultiSigSpend.create(multi_sig_address=multi_sig_address,
                                  addrs_to=[self.bob.address],
                                  amounts=[100],
                                  expiry_block_number=15000,
                                  fee=5,
                                  xmss_pk=self.alice.pk)
        tx.sign(self.alice)
        tx._data.nonce = 1

        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)

        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, tx.ots_key))

        tx.apply(self.state, state_container)

        self.assertTrue(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, tx.ots_key))
        self.assertIn(tx.txhash, state_container.votes_stats)
        vote_stats = state_container.votes_stats[tx.txhash]
        self.assertEqual(vote_stats.shared_key, tx.txhash)
        self.assertEqual(vote_stats.total_weight, 0)
        self.assertEqual(vote_stats.signatories,
                         multi_sig_address_state.signatories)

        tx.revert(self.state, state_container)
        self.assertNotIn(tx.txhash, state_container.votes_stats)
        self.assertFalse(
            state_container.paginated_bitfield.load_bitfield_and_ots_key_reuse(
                self.alice.address, tx.ots_key))
Example #29
0
    def test_validate_extended(self):
        """
        TODO: Check by signing txn from a non signatory address
        """
        multi_sig_address = MultiSigAddressState.generate_multi_sig_address(
            b'')
        tx = MultiSigSpend.create(multi_sig_address=multi_sig_address,
                                  addrs_to=[self.bob.address],
                                  amounts=[100],
                                  expiry_block_number=15000,
                                  fee=5,
                                  xmss_pk=self.alice.pk)
        tx.sign(self.alice)

        alice_address_state = OptimizedAddressState.get_default(
            address=self.alice.address)
        alice_address_state.pbdata.balance = 5
        multi_sig_address_state = MultiSigAddressState.create(
            creation_tx_hash=b'',
            balance=100,
            signatories=[self.alice.address, self.bob.address],
            weights=[4, 6],
            threshold=5,
            transaction_hash_count=0)
        addresses_state = {
            self.alice.address: alice_address_state,
            multi_sig_address: multi_sig_address_state,
        }
        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=10,
                                         total_coin_supply=100,
                                         current_dev_config=config.dev,
                                         write_access=True,
                                         my_db=None,
                                         batch=None)

        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        alice_address_state.pbdata.balance = 0
        result = tx._validate_extended(state_container)
        self.assertFalse(result)

        alice_address_state.pbdata.balance = 5
        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        multi_sig_address_state.pbdata.balance = 99
        result = tx._validate_extended(state_container)
        self.assertFalse(result)

        multi_sig_address_state.pbdata.balance = 100
        result = tx._validate_extended(state_container)
        self.assertTrue(result)

        tx.pbdata.multi_sig_spend.expiry_block_number = 10
        result = tx._validate_extended(state_container)
        self.assertFalse(result)

        tx.pbdata.multi_sig_spend.expiry_block_number = 15000
        result = tx._validate_extended(state_container)
        self.assertTrue(result)
    def test_validate_extended(self, m_validate_slave, m_logger):
        """
        TransferTokenTransaction._validate_extended checks for:
        1. valid master/slave
        2. negative fee, negative total token amounts transferred
        3. addr_from has enough funds for the fee
        4. if addr_from owns any tokens to begin with
        5. if addr_from has enough tokens
        6. addr_from ots_key reuse
        """
        alice_address_state = OptimizedAddressState.get_default(self.alice.address)
        alice_address_state.pbdata.balance = 100

        params = self.default_params()
        tx = TransferTokenTransaction.create(**params)
        tx.sign(self.alice)

        addresses_state = {
            alice_address_state.address: alice_address_state
        }
        tokens = Indexer(b'token', None)
        tokens.data[(self.alice.address, tx.token_txhash)] = qrl_pb2.TokenBalance(balance=1000,
                                                                                  decimals=0,
                                                                                  delete=False)

        state_container = StateContainer(addresses_state=addresses_state,
                                         tokens=tokens,
                                         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=1000,
                                         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
        state_container.tokens = Indexer(b'token', None)
        state_container.tokens.data[(self.alice.address, tx.token_txhash)] = qrl_pb2.TokenBalance(balance=1000,
                                                                                                  decimals=0,
                                                                                                  delete=False)
        result = tx.validate_all(state_container)
        self.assertFalse(result)
        m_validate_slave.return_value = True

        # fee = -1
        with patch('qrl.core.txs.TransferTokenTransaction.TransferTokenTransaction.fee',
                   new_callable=PropertyMock) as m_fee:
            m_fee.return_value = -1
            tokens = Indexer(b'token', None)
            tokens.data[(self.alice.address, tx.token_txhash)] = qrl_pb2.TokenBalance(balance=1000,
                                                                                      decimals=0,
                                                                                      delete=False)
            state_container.tokens = tokens
            result = tx._validate_extended(state_container)
            self.assertFalse(result)

        # total_amount = -1
        with patch('qrl.core.txs.TransferTokenTransaction.TransferTokenTransaction.total_amount',
                   new_callable=PropertyMock) as m_total_amount:
            m_total_amount.return_value = -100
            tokens = Indexer(b'token', None)
            tokens.data[(self.alice.address, tx.token_txhash)] = qrl_pb2.TokenBalance(balance=1000,
                                                                                      decimals=0,
                                                                                      delete=False)
            state_container.tokens = tokens
            result = tx._validate_extended(state_container)
            self.assertFalse(result)

        # balance = 0, cannot pay the Transaction fee
        alice_address_state.pbdata.balance = 0
        tokens = Indexer(b'token', None)
        tokens.data[(self.alice.address, tx.token_txhash)] = qrl_pb2.TokenBalance(balance=1000,
                                                                                  decimals=0,
                                                                                  delete=False)
        state_container.tokens = tokens
        result = tx._validate_extended(state_container)
        self.assertFalse(result)
        alice_address_state.pbdata.balance = 100

        # addr_from doesn't have these tokens
        state_container.tokens = Indexer(b'token', None)
        result = tx._validate_extended(state_container)
        self.assertFalse(result)

        # addr_from doesn't have enough tokens
        tokens = Indexer(b'token', None)
        tokens.data[(self.alice.address, tx.token_txhash)] = qrl_pb2.TokenBalance(balance=99,
                                                                                  decimals=0,
                                                                                  delete=False)
        state_container.tokens = tokens
        result = tx._validate_extended(state_container)
        self.assertFalse(result)

        # addr_from_pk has used this OTS key before
        addresses_state = {
            self.alice.address: alice_address_state
        }
        state_container.addresses_state = addresses_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)

        slave = get_slave_xmss()
        params = self.default_params()
        params["addrs_to"] = [self.bob.address, slave.address, self.alice.address]
        params["amounts"] = [2, 3, 5]
        tx = TransferTokenTransaction.create(**params)
        tx.sign(self.alice)
        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 = 1
            state_container.current_dev_config = m_config.dev
            self.assertFalse(tx._validate_extended(state_container=state_container))