def test_validate_extended(self, m_validate_slave, m_logger): """ Message._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. addr_from ots_key reuse """ m_addr_from_state = Mock(autospec=OptimizedAddressState, name='addr_from State', balance=100) m_addr_from_pk_state = Mock(autospec=OptimizedAddressState, name='addr_from_pk State') m_addr_from_pk_state.ots_key_reuse.return_value = False addresses_state = {self.alice.address: m_addr_from_state} tx = MessageTransaction.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=None, batch=None) result = tx._validate_extended(state_container) self.assertTrue(result) # fee = -1 with patch('qrl.core.txs.MessageTransaction.MessageTransaction.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 m_addr_from_state.balance = 0 result = tx._validate_extended(state_container) self.assertFalse(result) m_addr_from_state.balance = 100 self.params["message_hash"] = b'T' * 81 # Validation should fail, as we have entered a message of more than 80 lengths tx = MessageTransaction.create(**self.params) self.assertFalse(tx._validate_extended(state_container))
def test_validate_slave_master_addr_same_as_signing_addr(self, m_logger): self.params["master_addr"] = self.alice.address tx = MessageTransaction.create(**self.params) tx.sign(self.alice) result = tx.validate_slave(self.m_addr_state, self.m_addr_from_pk_state) self.assertFalse(result)
def test_revert_message_txn(self): tx = MessageTransaction.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=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])
def create_message_txn(message_hash: bytes, addr_to: bytes, fee: int, xmss_pk: bytes, master_addr: bytes): return MessageTransaction.create(message_hash=message_hash, addr_to=addr_to, fee=fee, xmss_pk=xmss_pk, master_addr=master_addr)
def test_validate_slave_has_insufficient_permissions(self, m_logger): """ Master's AddressState says the Slave has permission 0. But Slave's AddressState says the Slave is good for permission 2. Therefore the Slave does not have enough permissions. """ 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 tx = MessageTransaction.create(**self.params) tx.sign(self.alice) # The master's state says the slave can have these permissions. self.m_addr_state.slave_pks_access_type = {str(tx.PK): 0} # The signing slave's state can be 0 (full permissions) or 1 (mining only) but only 0 is used for now. # Let's give an invalid number. self.m_addr_from_pk_state.slave_pks_access_type = {str(tx.PK): 2} result = tx.validate_slave(self.m_addr_state, self.m_addr_from_pk_state) self.assertFalse(result) # Let's give a valid number, that matches what the master's state says (0) self.m_addr_from_pk_state.slave_pks_access_type = {str(tx.PK): 0} result = tx.validate_slave(self.m_addr_state, self.m_addr_from_pk_state) self.assertTrue(result)
def test_to_json(self, m_logger): tx = MessageTransaction.create(message_hash=b'Test Message', fee=1, xmss_pk=self.alice.pk) txjson = tx.to_json() self.assertEqual(json.loads(test_json_MessageTransaction), json.loads(txjson))
def test_revert_state_changes_empty_addresses_state(self, m_logger, m_apply_state_PK, m_revert_state_PK): tx = MessageTransaction.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()
def test_apply_state_changes(self, m_logger, m_apply_state_PK, m_revert_state_PK): tx = MessageTransaction.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) m_apply_state_PK.assert_called_once()
def test_validate_tx(self, m_logger, m_apply_state_PK, m_revert_state_PK): tx = MessageTransaction.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()
def test_revert_state_changes(self, m_logger, m_apply_state_PK, m_revert_state_PK): tx = MessageTransaction.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) m_revert_state_PK.assert_called_once()
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. self.m_addr_state.slave_pks_access_type = {} tx = MessageTransaction.create(**self.params) tx.sign(self.alice) result = tx.validate_slave(self.m_addr_state, self.m_addr_from_pk_state) self.assertFalse(result)
def relay_message_txn(self, message: str, fee: int, master_qaddress, signer_address: str, ots_index: int): self.authenticate() index, xmss = self._get_wallet_index_xmss(signer_address, ots_index) tx = MessageTransaction.create( message_hash=message.encode(), 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)
def tx_message(ctx, src, master, addr_to, message, fee, ots_key_index): """ Message Transaction """ try: _, src_xmss = _select_wallet(ctx, src) if not src_xmss: click.echo("A local wallet is required to sign the transaction") quit(1) address_src_pk = src_xmss.pk ots_key_index = validate_ots_index(ots_key_index, src_xmss) src_xmss.set_ots_index(ots_key_index) message = message.encode() if addr_to: addr_to = parse_qaddress(addr_to, False) else: addr_to = None 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) try: stub = ctx.obj.get_stub_public_api() tx = MessageTransaction.create(message_hash=message, addr_to=addr_to, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) tx.sign(src_xmss) push_transaction_req = qrl_pb2.PushTransactionReq( transaction_signed=tx.pbdata) push_transaction_resp = stub.PushTransaction( push_transaction_req, timeout=CONNECTION_TIMEOUT) print(push_transaction_resp) except Exception as e: print("Error {}".format(str(e)))
def relay_message_txn_by_slave(self, message: str, 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 = MessageTransaction.create( message_hash=message.encode(), 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_validate_extended(self, m_validate_slave, m_logger): """ Message.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. 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 = MessageTransaction.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.MessageTransaction.MessageTransaction.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)
def test_create(self, m_logger): tx = MessageTransaction.create(message_hash=b'Test Message', fee=1, xmss_pk=self.alice.pk) self.assertTrue(tx)
def test_set_affected_address(self, m_logger): result = set() tx = MessageTransaction.create(**self.params) tx.set_affected_address(result) self.assertEqual(1, len(result))