def submit_send_tx(self, tx: TransferTransaction) -> bool: if tx is None: raise ValueError("The transaction was empty") if tx.subtype == qrl_pb2.Transaction.LATTICE: self._p2pfactory.broadcast_lt(tx) elif tx.subtype in (qrl_pb2.Transaction.TRANSFER, qrl_pb2.Transaction.MESSAGE, qrl_pb2.Transaction.TOKEN, qrl_pb2.Transaction.TRANSFERTOKEN): tx.validate_or_raise() block_number = self._buffered_chain.height + 1 tx_state = self._buffered_chain.get_stxn_state(block_number, tx.txfrom) if not tx.validate_extended(tx_state=tx_state, transaction_pool=self._buffered_chain.tx_pool.transaction_pool): raise ValueError("The transaction failed validatation (blockchain state)") self._buffered_chain.tx_pool.add_tx_to_pool(tx) self._buffered_chain.wallet.save_wallet() # FIXME: Optimization Required subtype = 'TX' if tx.subtype == qrl_pb2.Transaction.MESSAGE: subtype = 'MT' elif tx.subtype == qrl_pb2.Transaction.TOKEN: subtype = 'TK' elif tx.subtype == qrl_pb2.Transaction.TRANSFERTOKEN: subtype = 'TT' self._p2pfactory.broadcast_tx(tx, subtype=subtype) return True
def test_create_negative_fee(self): with self.assertRaises(ValueError): TransferTransaction.create(addr_from=self.alice.address, addrs_to=[self.bob.address], amounts=[-100], fee=-1, xmss_pk=self.alice.pk)
def test_create_negative_amount(self): with self.assertRaises(ValueError): TransferTransaction.create( addr_from=self.alice.get_address().encode(), addr_to=self.bob.get_address().encode(), amount=-100, fee=1, xmss_pk=self.alice.pk(), xmss_ots_index=self.alice.get_index())
def transfer(destinations, fee, mixin, unlock_time): if len(destinations) > config.dev.transaction_multi_output_limit: raise Exception('Payment Failed: Amount exceeds the allowed limit') addrs_to = [] amounts = [] for tx in destinations: addrs_to.append(bytes(hstr2bin(tx['address'][1:]))) # Skipping 'Q' amounts.append(tx['amount']) stub = get_public_stub() xmss = get_unused_payment_xmss(stub) if not xmss: raise Exception('Payment Failed: No Unused Payment XMSS found') tx = TransferTransaction.create(addrs_to=addrs_to, amounts=amounts, fee=fee, xmss_pk=xmss.pk, master_addr=payment_slaves[0]) tx.sign(xmss) response = stub.PushTransaction(request=qrl_pb2.PushTransactionReq( transaction_signed=tx.pbdata)) if response.error_code != 3: raise Exception('Transaction Submission Failed, Response Code: %s', response.error_code) response = {'tx_hash': bin2hstr(tx.txhash)} return response
def test_create(self): # Alice sending coins to Bob tx = TransferTransaction.create(addrs_to=[self.bob.address], amounts=[100], fee=1, xmss_pk=self.alice.pk) self.assertTrue(tx)
def transfer(destinations, fee, mixin, unlock_time): if len(destinations) > config.dev.transaction_multi_output_limit: return None addrs_to = [] amounts = [] for tx in destinations: addrs_to.append(bytes(hstr2bin(tx['address'][1:]))) # Skipping 'Q' amounts.append(tx['amount']) stub = get_public_stub() xmss = get_unused_payment_xmss(stub) if not xmss: return None tx = TransferTransaction.create(addr_from=payment_slaves[0], addrs_to=addrs_to, amounts=amounts, fee=fee, xmss_pk=xmss.pk) tx.sign(xmss) response = stub.PushTransaction(request=qrl_pb2.PushTransactionReq( transaction_signed=tx.pbdata)) if response.error_code != 3: return None response = {'tx_hash': bin2hstr(tx.txhash)} return response
def test_prepare_address_list(self): with set_qrl_dir('no_data'): with State() as state: block = Block.create(block_number=10, prev_block_headerhash=b'', prev_block_timestamp=10, transactions=[], miner_address=b'addr1') # Test Case: without any transactions of block self.assertEqual(state.prepare_address_list(block), {config.dev.coinbase_address, b'addr1'}) alice_xmss = get_alice_xmss() block = Block.create(block_number=10, prev_block_headerhash=b'', prev_block_timestamp=10, transactions=[ TransferTransaction.create( addrs_to=[b'addr2', b'addr3'], amounts=[100, 100], fee=0, xmss_pk=alice_xmss.pk) ], miner_address=b'addr1') # Test Case, with one Transaction self.assertEqual( state.prepare_address_list(block), { config.dev.coinbase_address, b'addr1', b'addr2', b'addr3', alice_xmss.address })
def test_to_json(self): tx = TransferTransaction.create(addrs_to=[self.bob.address], amounts=[100], fee=1, xmss_pk=self.alice.pk) txjson = tx.to_json() self.assertEqual(json.loads(test_json_Simple), json.loads(txjson))
def create_tx(addrs_to, amounts, signing_xmss, nonce): tx = TransferTransaction.create(addrs_to=addrs_to, amounts=amounts, fee=0, xmss_pk=signing_xmss.pk) tx.sign(signing_xmss) tx._data.nonce = nonce return tx
def test_create(self): # Alice sending coins to Bob tx = TransferTransaction.create( addr_from=self.alice.get_address().encode(), addr_to=self.bob.get_address().encode(), amount=100, fee=1, xmss_pk=self.alice.pk(), xmss_ots_index=self.alice.get_index()) self.assertTrue(tx)
def test_to_json(self): tx = TransferTransaction.create( addr_from=self.alice.get_address().encode(), addr_to=self.bob.get_address().encode(), amount=100, fee=1, xmss_pk=self.alice.pk(), xmss_ots_index=self.alice.get_index()) txjson = tx.to_json() self.assertEqual(json.loads(test_json_Simple), json.loads(txjson))
def create_send_tx(self, addr_from: bytes, addrs_to: list, amounts: list, fee: int, xmss_pk: bytes) -> TransferTransaction: balance = self.db_state.balance(addr_from) if sum(amounts) + fee > balance: raise RuntimeError("Not enough funds in the source address") return TransferTransaction.create(addr_from=addr_from, addrs_to=addrs_to, amounts=amounts, fee=fee, xmss_pk=xmss_pk)
def test_validate_tx(self): # If we change amount, fee, addr_from, addr_to, (maybe include xmss stuff) txhash should change. tx = TransferTransaction.create(addrs_to=[self.bob.address], amounts=[100], fee=1, xmss_pk=self.alice.pk) # We must sign the tx before validation will work. tx.sign(self.alice) # We have not touched the tx: validation should pass. self.assertTrue(tx.validate_or_raise())
def create_send_tx(self, addr_from: bytes, addr_to: bytes, amount: int, fee: int, xmss_pk: bytes, xmss_ots_index: int) -> TransferTransaction: balance = self.db_state.balance(addr_from) if amount + fee > balance: raise RuntimeError("Not enough funds in the source address") return TransferTransaction.create(addr_from=addr_from, addr_to=addr_to, amount=amount, fee=fee, xmss_pk=xmss_pk, xmss_ots_index=xmss_ots_index)
def test_update_last_tx(self): with set_qrl_dir('no_data'): with State() as state: alice_xmss = get_alice_xmss() # Test Case: When there is no last txns self.assertEqual(state.get_last_txs(), []) block = Block() tx1 = TransferTransaction.create(addrs_to=[b'q1', b'q2'], amounts=[1, 2], fee=0, xmss_pk=alice_xmss.pk) block._data.transactions.extend([tx1.pbdata]) state.update_last_tx(block, None) last_txns = state.get_last_txs() # Test Case: When there is only 1 last txns self.assertEqual(len(last_txns), 1) self.assertEqual(last_txns[0].to_json(), tx1.to_json()) block = Block() tx2 = TransferTransaction.create(addrs_to=[b'q2', b'q3'], amounts=[1, 2], fee=0, xmss_pk=alice_xmss.pk) tx3 = TransferTransaction.create(addrs_to=[b'q4', b'q5'], amounts=[1, 2], fee=0, xmss_pk=alice_xmss.pk) block._data.transactions.extend([tx2.pbdata, tx3.pbdata]) state.update_last_tx(block, None) last_txns = state.get_last_txs() # Test Case: When there are 3 last txns self.assertEqual(len(last_txns), 3) self.assertEqual(last_txns[0].to_json(), tx3.to_json()) self.assertEqual(last_txns[1].to_json(), tx2.to_json()) self.assertEqual(last_txns[2].to_json(), tx1.to_json())
def create_send_tx(self, addrs_to: list, amounts: list, fee: int, xmss_pk: bytes, master_addr: bytes) -> TransferTransaction: addr_from = self.get_addr_from(xmss_pk, master_addr) balance = self.db_state.balance(addr_from) if sum(amounts) + fee > balance: raise ValueError("Not enough funds in the source address") return TransferTransaction.create(addrs_to=addrs_to, amounts=amounts, fee=fee, xmss_pk=xmss_pk, master_addr=master_addr)
def test_update_tx_metadata(self): with set_qrl_dir('no_data'): with State() as state: alice_xmss = get_alice_xmss() tx = TransferTransaction.create(addrs_to=[b'q1', b'q2'], amounts=[1, 2], fee=0, xmss_pk=alice_xmss.pk) block_number = 5 state.put_tx_metadata(tx, block_number, 10000, None) tx_metadata = state.get_tx_metadata(tx.txhash) self.assertEqual(tx_metadata[0].to_json(), tx.to_json()) self.assertEqual(tx_metadata[1], block_number)
def test_validate_tx(self): # If we change amount, fee, txfrom, txto, (maybe include xmss stuff) txhash should change. tx = TransferTransaction.create( addr_from=self.alice.get_address().encode(), addr_to=self.bob.get_address().encode(), amount=100, fee=1, xmss_pk=self.alice.pk(), xmss_ots_index=self.alice.get_index()) # We must sign the tx before validation will work. tx.sign(self.alice) # We have not touched the tx: validation should pass. self.assertTrue(tx.validate_or_raise())
def create_unsigned_tx(self, transaction): if transaction.type == qrl_pb2.Transaction.TRANSFER: return TransferTransaction.create(transaction.addr_from, transaction.Transfer.addr_to, transaction.Transfer.amount, transaction.Transfer.fee, transaction.xmss_pk, transaction.xmss_ots_index) elif transaction.type == qrl_pb2.Transaction.LATTICE: return LatticePublicKey.create(transaction.addr_from, transaction.LatticePublicKey.kyber_pk, transaction.LatticePublicKey.tesla_pk, transaction.xmss_pk, transaction.xmss_ots_index) elif transaction.type == qrl_pb2.Transaction.MESSAGE: return MessageTransaction.create(transaction.addr_from, transaction.Message.message_hash, transaction.Message.fee, transaction.xmss_pk, transaction.xmss_ots_index) elif transaction.type == qrl_pb2.Transaction.TOKEN: return TokenTransaction.create(transaction.addr_from, transaction.Token.symbol, transaction.Token.name, transaction.Token.owner, transaction.Token.decimals, transaction.Token.initial_balances, transaction.Token.fee, transaction.xmss_pk, transaction.xmss_ots_index) elif transaction.type == qrl_pb2.Transaction.TRANSFERTOKEN: return TransferTokenTransaction.create(transaction.addr_from, transaction.TransferToken.token_txhash, transaction.TransferToken.addr_to, transaction.TransferToken.amount, transaction.TransferToken.fee, transaction.xmss_pk, transaction.xmss_ots_index) else: return None
def broadcast_tx(self, tx: TransferTransaction): logger.info('<<<Transmitting TX: %s', tx.txhash) if tx.subtype == qrl_pb2.Transaction.MESSAGE: legacy_type = qrllegacy_pb2.LegacyMessage.MT elif tx.subtype == qrl_pb2.Transaction.TRANSFER: legacy_type = qrllegacy_pb2.LegacyMessage.TX elif tx.subtype == qrl_pb2.Transaction.TOKEN: legacy_type = qrllegacy_pb2.LegacyMessage.TK elif tx.subtype == qrl_pb2.Transaction.TRANSFERTOKEN: legacy_type = qrllegacy_pb2.LegacyMessage.TT elif tx.subtype == qrl_pb2.Transaction.LATTICE: legacy_type = qrllegacy_pb2.LegacyMessage.LT elif tx.subtype == qrl_pb2.Transaction.SLAVE: legacy_type = qrllegacy_pb2.LegacyMessage.SL else: raise ValueError('Invalid Transaction Type') self.register_and_broadcast(legacy_type, tx.get_message_hash(), tx.pbdata)
def broadcast_tx(self, tx: TransferTransaction): logger.info('<<<Transmitting TX: %s', bin2hstr(tx.txhash)) if isinstance(tx, MessageTransaction): legacy_type = qrllegacy_pb2.LegacyMessage.MT elif isinstance(tx, TransferTransaction): legacy_type = qrllegacy_pb2.LegacyMessage.TX elif isinstance(tx, TokenTransaction): legacy_type = qrllegacy_pb2.LegacyMessage.TK elif isinstance(tx, TransferTokenTransaction): legacy_type = qrllegacy_pb2.LegacyMessage.TT elif isinstance(tx, LatticePublicKey): legacy_type = qrllegacy_pb2.LegacyMessage.LT elif isinstance(tx, SlaveTransaction): legacy_type = qrllegacy_pb2.LegacyMessage.SL else: raise ValueError('Invalid Transaction Type') self.register_and_broadcast(legacy_type, tx.get_message_hash(), tx.pbdata)
def test_notification(self): source = Mock() source.factory = Mock() source.factory.master_mr = Mock() source.factory.master_mr.isRequested = Mock() source.factory.add_unprocessed_txn = Mock() channel = Observable(source) self.tx_manager = P2PTxManagement() self.tx_manager.new_channel(channel) tx = TransferTransaction.create([], [0], 10, xmss_pk=bytes(40)) event = qrllegacy_pb2.LegacyMessage(func_name=qrllegacy_pb2.LegacyMessage.TX, txData=tx.pbdata) channel.notify(event, force_delivery=True) source.factory.master_mr.isRequested.assert_called() source.factory.add_unprocessed_txn.assert_called()
def test_rollback_tx_metadata(self): with set_qrl_dir('no_data'): with State() as state: alice_xmss = get_alice_xmss() tx1 = TransferTransaction.create(addrs_to=[b'q1', b'q2'], amounts=[1, 2], fee=0, xmss_pk=alice_xmss.pk) block = Block.create(block_number=5, prevblock_headerhash=b'', transactions=[tx1], miner_address=b'') state.update_tx_metadata(block=block, batch=None) tx_metadata = state.get_tx_metadata(tx1.txhash) self.assertEqual(tx_metadata[0].to_json(), tx1.to_json()) state.rollback_tx_metadata(block, None) self.assertIsNone(state.get_tx_metadata(tx1.txhash))
def test_remove_last_tx(self): with set_qrl_dir('no_data'): with State() as state: # Test Case: When there is no last txns self.assertEqual(state.get_last_txs(), []) alice_xmss = get_alice_xmss() block = Block() tx1 = TransferTransaction.create(addrs_to=[b'q1', b'q2'], amounts=[1, 2], fee=0, xmss_pk=alice_xmss.pk) block._data.transactions.extend([tx1.pbdata]) state.update_last_tx(block, None) last_txns = state.get_last_txs() self.assertEqual(last_txns[0].to_json(), tx1.to_json()) state.remove_last_tx(block, None) last_txns = state.get_last_txs() self.assertEqual(last_txns, [])
def test_getLatestData(self): blocks = [] txs = [] for i in range(1, 4): for j in range(1, 3): txs.append( TransferTransaction.create(addr_from=qrladdress('source'), addr_to=qrladdress('dest'), amount=i * 100 + j, fee=j, xmss_pk=get_alice_xmss().pk(), xmss_ots_index=i)) blocks.append( Block.create(staking_address=qrladdress('staking_addr'), block_number=i, reveal_hash=sha256(b'reveal'), prevblock_headerhash=sha256(b'reveal'), transactions=txs, duplicate_transactions=OrderedDict(), vote=VoteMetadata(), signing_xmss=get_alice_xmss(), nonce=i)) txpool = [] for j in range(10, 15): txpool.append( TransferTransaction.create(addr_from=qrladdress('source'), addr_to=qrladdress('dest'), amount=1000 + j, fee=j, xmss_pk=get_alice_xmss().pk(), xmss_ots_index=j)) db_state = Mock(spec=State) p2p_factory = Mock(spec=P2PFactory) buffered_chain = Mock(spec=BufferedChain) buffered_chain.tx_pool = Mock() buffered_chain.tx_pool.transaction_pool = txpool buffered_chain.get_block = Mock() buffered_chain.get_block.side_effect = blocks buffered_chain.height = len(blocks) buffered_chain._chain = Mock() buffered_chain._chain.blockchain = blocks qrlnode = QRLNode(db_state) qrlnode.set_p2pfactory(p2p_factory) qrlnode.set_chain(buffered_chain) service = PublicAPIService(qrlnode) context = Mock(spec=ServicerContext) request = qrl_pb2.GetLatestDataReq(filter=qrl_pb2.GetLatestDataReq.ALL, offset=1, quantity=3) response = service.GetLatestData(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() # Verify blockheaders self.assertEqual(2, len(response.blockheaders)) self.assertEqual(1, response.blockheaders[0].header.block_number) self.assertEqual(2, response.blockheaders[1].header.block_number) # Verify transactions self.assertEqual(3, len(response.transactions)) self.assertEqual(1, response.transactions[0].transfer.fee) self.assertEqual(2, response.transactions[1].transfer.fee) self.assertEqual(1, response.transactions[2].transfer.fee) # 302 should have been skipped self.assertEqual(301, response.transactions[0].transfer.amount) self.assertEqual(202, response.transactions[1].transfer.amount) self.assertEqual(201, response.transactions[2].transfer.amount) # Verify transactions_unconfirmed self.assertEqual(3, len(response.transactions_unconfirmed)) self.assertEqual(1013, response.transactions_unconfirmed[0].transfer.amount) self.assertEqual(1012, response.transactions_unconfirmed[1].transfer.amount) self.assertEqual(1011, response.transactions_unconfirmed[2].transfer.amount)
def test_add_4(self): destroy_state() with State() as state: with set_wallet_dir("test_wallet"): chain = Chain(state) buffered_chain = BufferedChain(chain) alice_xmss = get_alice_xmss() slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed()) random_xmss1 = get_random_xmss() random_xmss2 = get_random_xmss() staking_address = bytes(alice_xmss.get_address().encode()) # FIXME: Replace this with a call to create a hash_chain h0 = sha256(b'hashchain_seed') h1 = sha256(h0) h2 = sha256(h1) h3 = sha256(h2) h4 = sha256(h3) with mocked_genesis() as custom_genesis: custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance( address=alice_xmss.get_address(), balance=700000000000000) ]) res = buffered_chain.add_block(block=GenesisBlock()) self.assertTrue(res) stake_transaction = StakeTransaction.create( activation_blocknumber=1, xmss=alice_xmss, slavePK=slave_xmss.pk(), hashchain_terminator=h4) stake_transaction._data.nonce = 1 # FIXME: The test needs private access.. This is an API issue stake_transaction.sign(alice_xmss) vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=0, headerhash=GenesisBlock().headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(0) chain.pstate.stake_validators_tracker.add_sv( balance=700000000000000, stake_txn=stake_transaction, blocknumber=1) sv = chain.pstate.stake_validators_tracker.sv_dict[ staking_address] self.assertEqual(0, sv.nonce) # Token Transaction to create a token for test token_transaction = get_token_transaction( random_xmss1, random_xmss2) token_transaction._data.nonce = 1 token_transaction.sign(random_xmss1) # Transfer Token Transaction transfer_token1 = TransferTokenTransaction.create( addr_from=random_xmss1.get_address().encode(), token_txhash=token_transaction.txhash, addr_to=alice_xmss.get_address().encode(), amount=100000000, fee=1, xmss_pk=random_xmss1.pk(), xmss_ots_index=random_xmss1.get_index()) transfer_token1._data.nonce = 2 transfer_token1.sign(random_xmss1) transfer_token2 = TransferTokenTransaction.create( addr_from=random_xmss2.get_address().encode(), token_txhash=token_transaction.txhash, addr_to=alice_xmss.get_address().encode(), amount=200000000, fee=1, xmss_pk=random_xmss2.pk(), xmss_ots_index=random_xmss2.get_index()) transfer_token2._data.nonce = 1 transfer_token2.sign(random_xmss2) # Transfer Coin Transaction transfer_transaction = TransferTransaction.create( addr_from=random_xmss1.get_address().encode(), addr_to=random_xmss2.get_address().encode(), amount=10, fee=1, xmss_pk=random_xmss1.pk(), xmss_ots_index=random_xmss1.get_index()) transfer_transaction._data.nonce = 3 transfer_transaction.sign(random_xmss1) tmp_block1 = Block.create( staking_address=staking_address, block_number=1, reveal_hash=h3, prevblock_headerhash=GenesisBlock().headerhash, transactions=[stake_transaction, token_transaction], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=1) res = buffered_chain.add_block(block=tmp_block1) self.assertTrue(res) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block1.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=1, headerhash=tmp_block1.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(1) tmp_block2 = Block.create( staking_address=staking_address, block_number=2, reveal_hash=h2, prevblock_headerhash=tmp_block1.headerhash, transactions=[ transfer_token1, transfer_token2, transfer_transaction ], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=2) res = buffered_chain.add_block(block=tmp_block2) self.assertTrue(res) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block2.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=2, headerhash=tmp_block2.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(2) tmp_block3 = Block.create( staking_address=staking_address, block_number=3, reveal_hash=h1, prevblock_headerhash=tmp_block2.headerhash, transactions=[], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=3) res = buffered_chain.add_block(block=tmp_block3) self.assertTrue(res) chain = buffered_chain._chain random_xmss1_state = chain.pstate._get_address_state( random_xmss1.get_address().encode()) random_xmss2_state = chain.pstate._get_address_state( random_xmss2.get_address().encode()) self.assertEqual( random_xmss1_state.tokens[bin2hstr( token_transaction.txhash).encode()], 400000000) self.assertEqual( random_xmss2_state.tokens[bin2hstr( token_transaction.txhash).encode()], 200000000) # Need to move forward the time to align with block times with mock.patch('qrl.core.ntp.getTime') as time_mock: time_mock.return_value = tmp_block3.timestamp + config.dev.minimum_minting_delay vote = Vote.create( addr_from=alice_xmss.get_address().encode(), blocknumber=3, headerhash=tmp_block3.headerhash, xmss=slave_xmss) vote.sign(slave_xmss) buffered_chain.add_vote(vote) vote_metadata = buffered_chain.get_consensus(3) tmp_block4 = Block.create( staking_address=staking_address, block_number=4, reveal_hash=h0, prevblock_headerhash=tmp_block3.headerhash, transactions=[], duplicate_transactions=OrderedDict(), vote=vote_metadata, signing_xmss=slave_xmss, nonce=4) res = buffered_chain.add_block(block=tmp_block4) self.assertTrue(res) token_metadata = buffered_chain.get_token_metadata( token_transaction.txhash) self.assertEqual(token_metadata.token_txhash, token_transaction.txhash) self.assertEqual( len(token_metadata.transfer_token_tx_hashes), 3) self.assertEqual( token_metadata.transfer_token_tx_hashes[0], token_transaction.txhash) random_xmss1_state = chain.pstate._get_address_state( random_xmss1.get_address().encode()) random_xmss2_state = chain.pstate._get_address_state( random_xmss2.get_address().encode()) alice_state = chain.pstate._get_address_state( alice_xmss.get_address().encode()) self.assertEqual( random_xmss1_state.tokens[bin2hstr( token_transaction.txhash).encode()], 300000000) self.assertEqual( random_xmss2_state.tokens[bin2hstr( token_transaction.txhash).encode()], 0) self.assertEqual( alice_state.tokens[bin2hstr( token_transaction.txhash).encode()], 300000000) self.assertEqual(random_xmss1_state.balance, config.dev.default_account_balance - 13) self.assertEqual(random_xmss2_state.balance, config.dev.default_account_balance + 9)
def test_getObject(self): SOME_ODD_HASH = sha256(b'this should not be found') SOME_ADDR1 = b'Q' + sha256(b'address1') SOME_ADDR2 = b'Q' + sha256(b'address2') db_state = Mock(spec=State) p2p_factory = Mock(spec=P2PFactory) buffered_chain = Mock(spec=BufferedChain) buffered_chain.tx_pool = Mock() buffered_chain.tx_pool.transaction_pool = [] qrlnode = QRLNode(db_state) qrlnode.set_p2pfactory(p2p_factory) qrlnode.set_chain(buffered_chain) qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertFalse(response.found) # Find an address db_state.get_address = MagicMock(return_value=AddressState.create( address=SOME_ADDR1, nonce=25, balance=10, pubhashes=[sha256(b'a'), sha256(b'b')], tokens=dict())) db_state.get_address_tx_hashes = MagicMock( return_value=[sha256(b'0'), sha256(b'1')]) context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = SOME_ODD_HASH response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertFalse(response.found) context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = SOME_ADDR1 response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.address_state) self.assertEqual(SOME_ADDR1, response.address_state.address) self.assertEqual(25, response.address_state.nonce) self.assertEqual(10, response.address_state.balance) self.assertEqual([sha256(b'a'), sha256(b'b')], response.address_state.pubhashes) self.assertEqual([sha256(b'0'), sha256(b'1')], response.address_state.transaction_hashes) # Find a transaction db_state.address_used = MagicMock(return_value=False) tx1 = TransferTransaction.create(addr_from=SOME_ADDR1, addr_to=SOME_ADDR2, amount=125, fee=19, xmss_pk=sha256(b'pk'), xmss_ots_index=13) buffered_chain.tx_pool.transaction_pool = [tx1] context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = tx1.txhash response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.transaction) self.assertEqual(qrl_pb2.Transaction.TRANSFER, response.transaction.type) self.assertEqual(SOME_ADDR1, response.transaction.addr_from) self.assertEqual(sha256(b'pk'), response.transaction.public_key) self.assertEqual(tx1.txhash, response.transaction.transaction_hash) self.assertEqual(13, response.transaction.ots_key) self.assertEqual(b'', response.transaction.signature) self.assertEqual(SOME_ADDR2, response.transaction.transfer.addr_to) self.assertEqual(125, response.transaction.transfer.amount) self.assertEqual(19, response.transaction.transfer.fee) # Find a block buffered_chain.get_block = MagicMock(return_value=Block.create( staking_address=qrladdress('staking_addr'), block_number=1, reveal_hash=sha256(b'reveal'), prevblock_headerhash=sha256(b'reveal'), transactions=[], duplicate_transactions=OrderedDict(), vote=VoteMetadata(), signing_xmss=get_alice_xmss(), nonce=1)) context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = bytes(str2bin('1')) response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.block) self.assertEqual(1, response.block.header.block_number)
def test_multi_output_transaction_add_block(self): with set_data_dir('no_data'): with State() as state: state.get_measurement = MagicMock(return_value=10000000) alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() random_xmss = get_random_xmss() transfer_transaction = TransferTransaction.create( addr_from=bob_xmss.address, addrs_to=[alice_xmss.address, random_xmss.address], amounts=[ 40 * int(config.dev.shor_per_quanta), 59 * int(config.dev.shor_per_quanta) ], fee=1 * config.dev.shor_per_quanta, xmss_pk=bob_xmss.pk) transfer_transaction._data.nonce = 1 transfer_transaction.sign(bob_xmss) genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_boundary = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock( return_value=(tmp_difficulty, tmp_boundary)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[transfer_transaction], signing_xmss=alice_xmss, master_address=alice_xmss.address, nonce=1) while not PoWValidator().validate_mining_nonce( state, block_1.blockheader, False): block_1.set_mining_nonce(block_1.mining_nonce + 1) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) bob_addr_state = state.get_address(bob_xmss.address) alice_addr_state = state.get_address(alice_xmss.address) random_addr_state = state.get_address(random_xmss.address) self.assertEqual(bob_addr_state.balance, 0) self.assertEqual( alice_addr_state.balance, 140 * int(config.dev.shor_per_quanta) + block_1.block_reward + block_1.fee_reward) self.assertEqual(random_addr_state.balance, 159 * int(config.dev.shor_per_quanta))
def test_getObject(self): SOME_ODD_HASH = sha256(b'this should not be found') db_state = Mock(spec=State) db_state.get_tx_metadata = MagicMock(return_value=None) db_state.get_block = MagicMock(return_value=None) p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) qrlnode = QRLNode(db_state, mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) # First try an empty request context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertFalse(response.found) # Some odd address context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = SOME_ODD_HASH response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertFalse(response.found) # Find an address addr1_state = AddressState.create(address=qrladdress('SOME_ADDR1'), nonce=25, balance=10, ots_bitfield=[b'\x00'] * config.dev.ots_bitfield_size, tokens=dict(), slave_pks_access_type=dict(), ots_counter=0) addr1_state.transaction_hashes.append(sha256(b'0')) addr1_state.transaction_hashes.append(sha256(b'1')) db_state.get_address_state = MagicMock(return_value=addr1_state) context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = qrladdress('SOME_ADDR1') response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.address_state) self.assertEqual(qrladdress('SOME_ADDR1'), response.address_state.address) self.assertEqual(25, response.address_state.nonce) self.assertEqual(10, response.address_state.balance) self.assertEqual([sha256(b'0'), sha256(b'1')], response.address_state.transaction_hashes) # Find a transaction db_state.address_used = MagicMock(return_value=False) tx1 = TransferTransaction.create(addrs_to=[qrladdress('SOME_ADDR2')], amounts=[125], fee=19, xmss_pk=sha256(b'pk'), master_addr=qrladdress('SOME_ADDR1')) chain_manager.tx_pool.transaction_pool = [(0, TransactionInfo(tx1, 0))] context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = tx1.txhash response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.transaction) self.assertEqual('transfer', response.transaction.tx.WhichOneof('transactionType')) self.assertEqual(qrladdress('SOME_ADDR1'), response.transaction.tx.master_addr) self.assertEqual(sha256(b'pk'), response.transaction.tx.public_key) self.assertEqual(tx1.txhash, response.transaction.tx.transaction_hash) self.assertEqual(b'', response.transaction.tx.signature) self.assertEqual(qrladdress('SOME_ADDR2'), response.transaction.tx.transfer.addrs_to[0]) self.assertEqual(125, response.transaction.tx.transfer.amounts[0]) self.assertEqual(19, response.transaction.tx.fee) alice_xmss = get_alice_xmss() # Find a block db_state.get_block_by_number = MagicMock( return_value=Block.create(block_number=1, prev_block_headerhash=sha256(b'reveal'), prev_block_timestamp=10, transactions=[], miner_address=alice_xmss.address)) context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = bytes(str2bin('1')) response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.block_extended) self.assertEqual(1, response.block_extended.header.block_number)
def test_getLatestData(self): blocks = [] txs = [] alice_xmss = get_alice_xmss() for i in range(1, 4): for j in range(1, 3): txs.append( TransferTransaction.create(addrs_to=[qrladdress('dest')], amounts=[i * 100 + j], fee=j, xmss_pk=alice_xmss.pk)) blocks.append( Block.create(block_number=i, prev_block_headerhash=sha256(b'reveal'), prev_block_timestamp=10, transactions=txs, miner_address=alice_xmss.address)) txpool = [] for j in range(10, 15): tx = TransferTransaction.create(addrs_to=[qrladdress('dest')], amounts=[1000 + j], fee=j, xmss_pk=get_alice_xmss().pk) txpool.append((tx.fee, TransactionInfo(tx, 0))) db_state = Mock(spec=State) db_state.get_tx_metadata = MagicMock(return_value=None) db_state.get_last_txs = MagicMock(return_value=txs) p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = Mock(spec=ChainManager) chain_manager.get_block_by_number = Mock() chain_manager.get_block_by_number.side_effect = blocks chain_manager.tx_pool = Mock() chain_manager.tx_pool.transactions = heapq.nlargest( len(txpool), txpool) chain_manager.tx_pool.transaction_pool = txpool chain_manager.height = len(blocks) qrlnode = QRLNode(db_state, mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode.get_block_from_index = MagicMock(return_value=None) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow service = PublicAPIService(qrlnode) context = Mock(spec=ServicerContext) request = qrl_pb2.GetLatestDataReq(filter=qrl_pb2.GetLatestDataReq.ALL, offset=1, quantity=3) response = service.GetLatestData(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() # Verify blockheaders self.assertEqual(3, len(response.blockheaders)) self.assertEqual(1, response.blockheaders[0].header.block_number) self.assertEqual(2, response.blockheaders[1].header.block_number) self.assertEqual(3, response.blockheaders[2].header.block_number) # Verify transactions_unconfirmed self.assertEqual(3, len(response.transactions_unconfirmed)) # TODO: Verify expected order self.assertEqual( 1013, response.transactions_unconfirmed[0].tx.transfer.amounts[0]) self.assertEqual( 1012, response.transactions_unconfirmed[1].tx.transfer.amounts[0]) self.assertEqual( 1011, response.transactions_unconfirmed[2].tx.transfer.amounts[0]) # Verify transactions self.assertEqual(3, len(response.transactions)) self.assertEqual(2, response.transactions[0].tx.fee) self.assertEqual(1, response.transactions[1].tx.fee) self.assertEqual(2, response.transactions[2].tx.fee) self.assertEqual(102, response.transactions[0].tx.transfer.amounts[0]) self.assertEqual(201, response.transactions[1].tx.transfer.amounts[0]) self.assertEqual(202, response.transactions[2].tx.transfer.amounts[0])
def test_multi_output_transaction_add_block(self): with set_data_dir('no_data'): with State() as state: state.get_measurement = MagicMock(return_value=10000000) alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() extended_seed = "010300cebc4e25553afa0aab899f7838e59e18a48852fa9dfd5" \ "ae78278c371902aa9e6e9c1fa8a196d2dba0cbfd2f2d212d16c" random_xmss = XMSS.from_extended_seed(hstr2bin(extended_seed)) transfer_transaction = TransferTransaction.create( addrs_to=[alice_xmss.address, random_xmss.address], amounts=[ 40 * int(config.dev.shor_per_quanta), 59 * int(config.dev.shor_per_quanta) ], fee=1 * config.dev.shor_per_quanta, xmss_pk=bob_xmss.pk) transfer_transaction._data.nonce = 1 transfer_transaction.sign(bob_xmss) genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_boundary = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock( return_value=(tmp_difficulty, tmp_boundary)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[transfer_transaction], miner_address=alice_xmss.address) block_1.set_nonces(274, 0) # Uncomment only to determine the correct mining_nonce of above blocks # from qrl.core.PoWValidator import PoWValidator # while not PoWValidator().validate_mining_nonce(state, block_1.blockheader, False): # block_1.set_nonces(block_1.mining_nonce + 1) # print(block_1.mining_nonce) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) bob_addr_state = state.get_address(bob_xmss.address) alice_addr_state = state.get_address(alice_xmss.address) random_addr_state = state.get_address(random_xmss.address) self.assertEqual(bob_addr_state.balance, 0) self.assertEqual( alice_addr_state.balance, 140 * int(config.dev.shor_per_quanta) + block_1.block_reward + block_1.fee_reward) self.assertEqual(random_addr_state.balance, 159 * int(config.dev.shor_per_quanta))