def create_peer(self, network, unlock_wallet=True): wallet = HDWallet(gap_limit=2) wallet._manually_initialize() manager = super().create_peer(network, wallet=wallet) manager.test_mode = TestMode.TEST_ALL_WEIGHT manager.avg_time_between_blocks = 64 # Don't use it anywhere else. It is unsafe to generate mnemonic words like this. # It should be used only for testing purposes. m = Mnemonic('english') words = m.to_mnemonic(bytes(random.randint(0, 255) for _ in range(32))) wallet.unlock(words=words, tx_storage=manager.tx_storage) return manager
def get_address(self, index: int) -> Optional[str]: """ Generate a fixed HD Wallet and return an address """ from hathor.wallet import HDWallet words = ( 'bind daring above film health blush during tiny neck slight clown salmon ' 'wine brown good setup later omit jaguar tourist rescue flip pet salute' ) hd = HDWallet(words=words) hd._manually_initialize() if index >= hd.gap_limit: return None return list(hd.keys.keys())[index]
def create_peer(self, network: Optional[str] = None, peer_id: Optional[PeerId] = None, enable_sync_v1: bool = True, enable_sync_v2: bool = True, soft_voided_tx_ids: Optional[Set[bytes]] = None) -> HathorManager: assert self._started if network is None: network = self._network wallet = HDWallet(gap_limit=2) wallet._manually_initialize() assert peer_id is not None # XXX: temporary, for checking that tests are using the peer_id if peer_id is None: peer_id = PeerId() tx_storage = TransactionMemoryStorage() manager = HathorManager( self._clock, peer_id=peer_id, network=network, wallet=wallet, enable_sync_v1=enable_sync_v1, enable_sync_v2=enable_sync_v2, tx_storage=tx_storage, rng=Random(self.rng.getrandbits(64)), soft_voided_tx_ids=soft_voided_tx_ids, ) manager.reactor = self._clock manager._full_verification = True manager.start() self.run_to_completion() # Don't use it anywhere else. It is unsafe to generate mnemonic words like this. # It should be used only for testing purposes. m = Mnemonic('english') words = m.to_mnemonic(self.rng.randbytes(32)) self.log.debug('randomized step: generate wallet', words=words) wallet.unlock(words=words, tx_storage=manager.tx_storage) return manager
class BaseWalletHDTest(unittest.TestCase): __test__ = False def setUp(self): super().setUp() self.wallet = HDWallet(gap_limit=2) self.wallet._manually_initialize() self.manager = self.create_peer('testnet', wallet=self.wallet, unlock_wallet=False) self.tx_storage = self.manager.tx_storage self.wallet.unlock(tx_storage=self.tx_storage) self.BLOCK_TOKENS = self.manager.get_tokens_issued_per_block(1) self.TOKENS = self.BLOCK_TOKENS def test_transaction_and_balance(self): # generate a new block and check if we increase balance new_address = self.wallet.get_unused_address() out = WalletOutputInfo(decode_address(new_address), self.TOKENS, timelock=None) block = add_new_block(self.manager) block.verify() utxo = self.wallet.unspent_txs[settings.HATHOR_TOKEN_UID].get( (block.hash, 0)) self.assertIsNotNone(utxo) self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.BLOCK_TOKENS)) # create transaction spending this value, but sending to same wallet add_blocks_unlock_reward(self.manager) new_address2 = self.wallet.get_unused_address() out = WalletOutputInfo(decode_address(new_address2), self.TOKENS, timelock=None) tx1 = self.wallet.prepare_transaction_compute_inputs( Transaction, [out], self.tx_storage) tx1.update_hash() tx1.verify_script(tx1.inputs[0], block) tx1.storage = self.tx_storage self.wallet.on_new_tx(tx1) self.tx_storage.save_transaction(tx1) self.assertEqual(len(self.wallet.spent_txs), 1) utxo = self.wallet.unspent_txs[settings.HATHOR_TOKEN_UID].get( (tx1.hash, 0)) self.assertIsNotNone(utxo) self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.TOKENS)) # pass inputs and outputs to prepare_transaction, but not the input keys # spend output last transaction input_info = WalletInputInfo(tx1.hash, 0, None) new_address3 = self.wallet.get_unused_address() out = WalletOutputInfo(decode_address(new_address3), self.TOKENS, timelock=None) tx2 = self.wallet.prepare_transaction_incomplete_inputs( Transaction, inputs=[input_info], outputs=[out], tx_storage=self.tx_storage) tx2.storage = self.tx_storage tx2.update_hash() tx2.storage = self.tx_storage tx2.verify_script(tx2.inputs[0], tx1) self.tx_storage.save_transaction(tx2) self.wallet.on_new_tx(tx2) self.assertEqual(len(self.wallet.spent_txs), 2) self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.TOKENS)) # Test getting more unused addresses than the gap limit for i in range(3): kwargs = {'mark_as_used': True} if i == 2: # Last one we dont mark as used kwargs['mark_as_used'] = False self.wallet.get_unused_address(**kwargs) def test_insuficient_funds(self): add_blocks_unlock_reward(self.manager) # create transaction spending some value new_address = self.wallet.get_unused_address() out = WalletOutputInfo(decode_address(new_address), self.TOKENS, timelock=None) with self.assertRaises(InsufficientFunds): self.wallet.prepare_transaction_compute_inputs( Transaction, [out], self.tx_storage) def test_lock(self): # Test locking and unlocking wallet # Initially is unlocked self.assertFalse(self.wallet.is_locked()) words = self.wallet.words address = self.wallet.get_unused_address() # We lock self.wallet.lock() # Now it's locked self.assertTrue(self.wallet.is_locked()) # We unlock self.wallet.unlock(tx_storage=self.tx_storage, words=words) self.assertFalse(self.wallet.is_locked()) self.assertEqual(address, self.wallet.get_unused_address()) def test_exceptions(self): with self.assertRaises(ValueError): HDWallet(word_count=3)
def test_checkmultisig(self): with self.assertRaises(MissingStackItems): op_checkmultisig([], log=[], extras=None) block = self.genesis_blocks[0] from hathor.transaction import Transaction, TxInput, TxOutput txin = TxInput(tx_id=block.hash, index=0, data=b'') txout = TxOutput(value=block.outputs[0].value, script=b'') tx = Transaction(inputs=[txin], outputs=[txout]) data_to_sign = tx.get_sighash_all() extras = ScriptExtras(tx=tx, txin=None, spent_tx=None) wallet = HDWallet() wallet._manually_initialize() wallet.words = wallet.mnemonic.generate() wallet._manually_initialize() keys_count = 3 keys = [] for i in range(keys_count): privkey = list(wallet.keys.values())[i] keys.append({ 'privkey': privkey, 'pubkey': privkey.sec(), 'signature': wallet.get_input_aux_data(data_to_sign, privkey)[1] }) wrong_privkey = list(wallet.keys.values())[3] wrong_key = { 'privkey': wrong_privkey, 'pubkey': wrong_privkey.sec(), 'signature': wallet.get_input_aux_data(data_to_sign, wrong_privkey)[1] } # All signatures match stack = [ keys[0]['signature'], keys[2]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] op_checkmultisig(stack, log=[], extras=extras) self.assertEqual(1, stack.pop()) # New set of valid signatures stack = [ keys[0]['signature'], keys[1]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] op_checkmultisig(stack, log=[], extras=extras) self.assertEqual(1, stack.pop()) # Changing the signatures but they match stack = [ keys[1]['signature'], keys[2]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] op_checkmultisig(stack, log=[], extras=extras) self.assertEqual(1, stack.pop()) # Signatures are valid but in wrong order stack = [ keys[1]['signature'], keys[0]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] op_checkmultisig(stack, log=[], extras=extras) self.assertEqual(0, stack.pop()) # Adding wrong signature, so we get error stack = [ keys[0]['signature'], wrong_key['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] op_checkmultisig(stack, log=[], extras=extras) self.assertEqual(0, stack.pop()) # Adding same signature twice, so we get error stack = [ keys[0]['signature'], keys[0]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] op_checkmultisig(stack, log=[], extras=extras) self.assertEqual(0, stack.pop()) # Adding less signatures than required, so we get error stack = [ keys[0]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] with self.assertRaises(MissingStackItems): op_checkmultisig(stack, log=[], extras=extras) # Quantity of signatures is more than it should stack = [ keys[0]['signature'], keys[1]['signature'], 3, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3 ] with self.assertRaises(MissingStackItems): op_checkmultisig(stack, log=[], extras=extras) # Quantity of pubkeys is more than it should stack = [ keys[0]['signature'], keys[1]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 4 ] with self.assertRaises(InvalidStackData): op_checkmultisig(stack, log=[], extras=extras) # Exception pubkey_count should be integer stack = [ keys[0]['signature'], keys[1]['signature'], 2, keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], '3' ] with self.assertRaises(InvalidStackData): op_checkmultisig(stack, log=[], extras=extras) # Exception not enough pub keys stack = [keys[0]['pubkey'], keys[1]['pubkey'], 3] with self.assertRaises(MissingStackItems): op_checkmultisig(stack, log=[], extras=extras) # Exception stack empty after pubkeys stack = [keys[0]['pubkey'], keys[1]['pubkey'], keys[2]['pubkey'], 3] with self.assertRaises(MissingStackItems): op_checkmultisig(stack, log=[], extras=extras)