def test_validate_custom(self): """ MultiSigCreate _validate_custom() only checks if fee == 0 """ multi_sig_address = MultiSigAddressState.generate_multi_sig_address( b'') 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.random_signer.pk) del tx._data.multi_sig_spend.addrs_to[-1] result = tx._validate_custom() self.assertFalse(result) tx._data.multi_sig_spend.addrs_to.extend([self.alice.address]) result = tx._validate_custom() self.assertTrue(result) del tx._data.multi_sig_spend.amounts[-1] result = tx._validate_custom() self.assertFalse(result) tx._data.multi_sig_spend.amounts.extend([100]) result = tx._validate_custom() self.assertTrue(result) tx._data.multi_sig_spend.multi_sig_address = self.bob.address result = tx._validate_custom() self.assertFalse(result)
def test_apply(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 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) 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)
def test_validate_all(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.random.pk, master_addr=self.alice.address) tx.sign(self.random) tx._data.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) 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, self.random.address: random_address_state, multi_sig_address: multi_sig_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._data.nonce = 2 result = tx.validate_all(state_container) self.assertFalse(result) # False as nonce is invalid
def test_create(self): 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=0, xmss_pk=self.alice.pk) self.assertIsInstance(tx, MultiSigSpend)
def create_multi_sig_spend_txn(multi_sig_address: bytes, addrs_to: list, amounts: list, expiry_block_number: int, fee: int, xmss_pk: bytes, master_addr: bytes): return MultiSigSpend.create(multi_sig_address=multi_sig_address, addrs_to=addrs_to, amounts=amounts, expiry_block_number=expiry_block_number, fee=fee, xmss_pk=xmss_pk, master_addr=master_addr)
def test_to_json(self): 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=0, xmss_pk=self.alice.pk) txjson = tx.to_json() self.assertEqual(json.loads(test_json_MultiSigSpend), json.loads(txjson))
def test_affected_address(self): # This transaction can only involve 2 addresses. affected_addresses = set() 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.set_affected_address(affected_addresses) self.assertEqual(3, len(affected_addresses)) self.assertIn(self.alice.address, affected_addresses) self.assertIn(multi_sig_address, affected_addresses)
def test_create(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=0, xmss_pk=self.alice.pk) tx.sign(self.alice) self.assertIsInstance(tx, MultiSigVote)
def test_to_json(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=0, xmss_pk=self.alice.pk) txjson = tx.to_json() self.assertEqual(json.loads(test_json_MultiSigVote), json.loads(txjson))
def test_validate_custom(self): """ MultiSigCreate _validate_custom() only checks if fee == 0 """ 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=0, xmss_pk=self.alice.pk) tx.sign(self.alice) result = tx._validate_custom() self.assertTrue(result)
def test_affected_address(self): # This transaction can only involve 2 addresses. affected_addresses = set() 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) tx.set_affected_address(affected_addresses) self.assertEqual(1, len(affected_addresses)) self.assertIn(self.alice.address, affected_addresses)
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 tx_multi_sig_spend(ctx, src, master, multi_sig_address, dsts, amounts, expiry_block_number, fee, ots_key_index): """ Transfer coins from src to dsts """ address_src_pk = None master_addr = None addresses_dst = [] shor_amounts = [] fee_shor = [] signing_object = None try: # Retrieve signing object selected_wallet = _select_wallet(ctx, src) if selected_wallet is None or len(selected_wallet) != 2: click.echo("A wallet was not found") quit(1) _, src_xmss = selected_wallet 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) signing_object = src_xmss # Get and validate other inputs if master: master_addr = parse_qaddress(master) addresses_dst, shor_amounts = _parse_dsts_amounts( dsts, amounts, check_multi_sig_address=True) fee_shor = _quanta_to_shor(fee) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) multi_sig_address = bytes(hstr2bin(multi_sig_address[1:])) try: # MultiSigSpend transaction tx = MultiSigSpend.create(multi_sig_address=multi_sig_address, addrs_to=addresses_dst, amounts=shor_amounts, expiry_block_number=expiry_block_number, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) # Sign transaction tx.sign(signing_object) if not tx.validate(): print("It was not possible to validate the signature") quit(1) print("\nTransaction Blob (signed): \n") txblob = tx.pbdata.SerializeToString() txblobhex = hexlify(txblob).decode() print(txblobhex) # Push transaction print() print("Sending to a QRL Node...") stub = ctx.obj.get_stub_public_api() push_transaction_req = qrl_pb2.PushTransactionReq( transaction_signed=tx.pbdata) push_transaction_resp = stub.PushTransaction( push_transaction_req, timeout=CONNECTION_TIMEOUT) # Print result print(push_transaction_resp) except Exception as e: print("Error {}".format(str(e)))
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)
def test_validate_all(self): """ Test for Validate Extended when transaction has been signed by slave. :return: """ 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.random.pk, master_addr=self.alice.address) tx.sign(self.random) tx._data.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) 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, self.random.address: random_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, } 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=multi_sig_spend_txs, votes_stats=vote_stats, 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._data.nonce = 2 result = tx.validate_all(state_container) self.assertFalse(result) # False as nonce is invalid