async def asyncSetUp(self): self.ledger = ledger_class({ 'db': ledger_class.database_class(':memory:'), 'headers': ledger_class.headers_class(':memory:'), }) await self.ledger.db.open() self.account = self.ledger.account_class.generate(self.ledger, Wallet(), "torba")
def setUp(self): self.ledger = ledger_class({ 'db': ledger_class.database_class(':memory:'), 'headers': ledger_class.headers_class(':memory:'), })
async def asyncSetUp(self): self.ledger = ledger_class({ 'db': ledger_class.database_class(':memory:'), 'headers': ledger_class.headers_class(':memory:'), }) self.wallet = Wallet() await self.ledger.db.open()
async def test_private_key_validation(self): with self.assertRaisesRegex(TypeError, 'private key must be raw bytes'): PrivateKey(None, None, b'abcd' * 8, 0, 255) with self.assertRaisesRegex(ValueError, 'private key must be 32 bytes'): PrivateKey(None, b'abcd', b'abcd' * 8, 0, 255) private_key = PrivateKey( ledger_class({ 'db': ledger_class.database_class(':memory:'), 'headers': ledger_class.headers_class(':memory:'), }), unhexlify( '2423f3dc6087d9683f73a684935abc0ccd8bc26370588f56653128c6a6f0bf7c' ), b'abcd' * 8, 0, 1) ec_point = private_key.ec_point() self.assertEqual( ec_point[0], 30487144161998778625547553412379759661411261804838752332906558028921886299019 ) self.assertEqual( ec_point[1], 86198965946979720220333266272536217633917099472454294641561154971209433250106 ) self.assertEqual(private_key.address(), '1GVM5dEhThbiyCZ9gqBZBv6p9whga7MTXo') with self.assertRaisesRegex(ValueError, 'invalid BIP32 private key child number'): private_key.child(-1) self.assertIsInstance(private_key.child(PrivateKey.HARDENED), PrivateKey)
async def asyncSetUp(self): self.ledger = MainNetLedger({ 'db': MainNetLedger.database_class(':memory:'), 'headers': MainNetLedger.headers_class(':memory:') }) await self.ledger.db.open()
async def test_reset_on_version_change(self): self.ledger = ledger_class({ 'db': ledger_class.database_class(self.path), 'headers': ledger_class.headers_class(':memory:'), }) # initial open, pre-version enabled db self.ledger.db.SCHEMA_VERSION = None self.assertListEqual(self.get_tables(), []) await self.ledger.db.open() self.assertEqual( self.get_tables(), ['account_address', 'pubkey_address', 'tx', 'txi', 'txo']) self.assertListEqual(self.get_addresses(), []) self.add_address('address1') await self.ledger.db.close() # initial open after version enabled self.ledger.db.SCHEMA_VERSION = '1.0' await self.ledger.db.open() self.assertEqual(self.get_version(), '1.0') self.assertListEqual(self.get_tables(), [ 'account_address', 'pubkey_address', 'tx', 'txi', 'txo', 'version' ]) self.assertListEqual(self.get_addresses(), []) # address1 deleted during version upgrade self.add_address('address2') await self.ledger.db.close() # nothing changes self.assertEqual(self.get_version(), '1.0') self.assertListEqual(self.get_tables(), [ 'account_address', 'pubkey_address', 'tx', 'txi', 'txo', 'version' ]) await self.ledger.db.open() self.assertEqual(self.get_version(), '1.0') self.assertListEqual(self.get_tables(), [ 'account_address', 'pubkey_address', 'tx', 'txi', 'txo', 'version' ]) self.assertListEqual(self.get_addresses(), ['address2']) await self.ledger.db.close() # upgrade version, database reset self.ledger.db.SCHEMA_VERSION = '1.1' self.ledger.db.CREATE_TABLES_QUERY += """ create table if not exists foo (bar text); """ await self.ledger.db.open() self.assertEqual(self.get_version(), '1.1') self.assertListEqual(self.get_tables(), [ 'account_address', 'foo', 'pubkey_address', 'tx', 'txi', 'txo', 'version' ]) self.assertListEqual(self.get_addresses(), []) # all tables got reset await self.ledger.db.close()
async def create_tx_from_nothing(self, my_account, height): to_address = await my_account.receiving.get_or_create_usable_address() to_hash = ledger_class.address_to_hash160(to_address) tx = ledger_class.transaction_class(height=height, is_verified=True) \ .add_inputs([self.txi(self.txo(1, sha256(str(height).encode())))]) \ .add_outputs([self.txo(1, to_hash)]) await self.ledger.db.insert_transaction(tx) await self.ledger.db.save_transaction_io(tx, to_address, to_hash, '') return tx
def setUp(self): super().setUp() self.ledger = MainNetLedger({ 'db': MainNetLedger.database_class(':memory:'), 'headers': MainNetLedger.headers_class(':memory:') }) return self.ledger.db.open()
async def create_tx_from_txo(self, txo, to_account, height): from_hash = txo.script.values['pubkey_hash'] from_address = self.ledger.hash160_to_address(from_hash) to_address = await to_account.receiving.get_or_create_usable_address() to_hash = ledger_class.address_to_hash160(to_address) tx = ledger_class.transaction_class(height=height, is_verified=True) \ .add_inputs([self.txi(txo)]) \ .add_outputs([self.txo(1, to_hash)]) await self.ledger.db.insert_transaction(tx) await self.ledger.db.save_transaction_io(tx, from_address, from_hash, '') await self.ledger.db.save_transaction_io(tx, to_address, to_hash, '') return tx
async def asyncSetUp(self): self.manager = BaseWalletManager() config = {'data_path': '/tmp/wallet'} self.btc_ledger = self.manager.get_or_create_ledger( BTCLedger.get_id(), config) self.bch_ledger = self.manager.get_or_create_ledger( BCHLedger.get_id(), config)
def test_genesis_transaction(self): raw = unhexlify( '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04' 'ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e20' '6272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01' '000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4c' 'ef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000') tx = ledger_class.transaction_class(raw) self.assertEqual(tx.version, 1) self.assertEqual(tx.locktime, 0) self.assertEqual(len(tx.inputs), 1) self.assertEqual(len(tx.outputs), 1) coinbase = tx.inputs[0] self.assertEqual(coinbase.output_txhash, NULL_HASH) self.assertEqual(coinbase.output_index, 0xFFFFFFFF) self.assertEqual(coinbase.sequence, 4294967295) self.assertTrue(coinbase.is_coinbase) self.assertEqual(coinbase.script, None) self.assertEqual( coinbase.coinbase[8:], b'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks' ) out = tx.outputs[0] self.assertEqual(out.amount, 5000000000) self.assertEqual(out.index, 0) self.assertTrue(out.script.is_pay_pubkey) self.assertFalse(out.script.is_pay_pubkey_hash) self.assertFalse(out.script.is_pay_script_hash) tx._reset() self.assertEqual(tx.raw, raw)
def setUp(self): self.manager = WalletManager() config = {'wallet_path': '/tmp/wallet'} self.btc_ledger = self.manager.get_or_create_ledger( BTCLedger.get_id(), config) self.bch_ledger = self.manager.get_or_create_ledger( BCHLedger.get_id(), config)
def test_paying_from_my_account_to_my_account(self): tx = ledger_class.transaction_class() \ .add_inputs([get_input(300*CENT)]) \ .add_outputs([get_output(190*CENT, NULL_HASH), get_output(100*CENT, NULL_HASH)]) tx.inputs[0].txo_ref.txo.is_my_account = True tx.outputs[0].is_my_account = True tx.outputs[1].is_my_account = True self.assertEqual(tx.net_account_balance, -10 * CENT) # lost to fee
async def test_from_extended_keys(self): ledger = ledger_class({ 'db': ledger_class.database_class(':memory:'), 'headers': ledger_class.headers_class(':memory:'), }) self.assertIsInstance( from_extended_key_string( ledger, 'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P' '6yz3jMbycrLrRMpeAJxR8qDg8', ), PrivateKey) self.assertIsInstance( from_extended_key_string( ledger, 'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f' 'iW44g14WF52fYC5J483wqQ5ZP', ), PubKey)
async def create_tx_to_nowhere(self, txo, height): from_hash = txo.script.values['pubkey_hash'] from_address = self.ledger.hash160_to_address(from_hash) to_hash = NULL_HASH tx = ledger_class.transaction_class(height=height, is_verified=True) \ .add_inputs([self.txi(txo)]) \ .add_outputs([self.txo(1, to_hash)]) await self.ledger.db.save_transaction_io('insert', tx, from_address, from_hash, '') return tx
def setUp(self): self.ledger = ledger_class({ 'db': ledger_class.database_class(':memory:'), 'headers': ledger_class.headers_class(':memory:'), }) yield self.ledger.db.open() self.account = self.ledger.account_class.from_dict( self.ledger, Wallet(), { "seed": "carbon smart garage balance margin twelve chest sword " "toast envelope bottom stomach absent" }) addresses = yield self.account.ensure_address_gap() self.pubkey_hash = [ self.ledger.address_to_hash160(a) for a in addresses ] self.hash_cycler = cycle(self.pubkey_hash)
async def test_private_key_derivation(self): private_key = PrivateKey( ledger_class({ 'db': ledger_class.database_class(':memory:'), 'headers': ledger_class.headers_class(':memory:'), }), unhexlify( '2423f3dc6087d9683f73a684935abc0ccd8bc26370588f56653128c6a6f0bf7c' ), b'abcd' * 8, 0, 1) for i in range(20): new_privkey = private_key.child(i) self.assertIsInstance(new_privkey, PrivateKey) self.assertEqual(hexlify(new_privkey.private_key_bytes), expected_privkeys[i]) for i in range(PrivateKey.HARDENED + 1, private_key.HARDENED + 20): new_privkey = private_key.child(i) self.assertIsInstance(new_privkey, PrivateKey) self.assertEqual( hexlify(new_privkey.private_key_bytes), expected_hardened_privkeys[i - 1 - PrivateKey.HARDENED])
async def create_utxos(self, amounts): utxos = [self.txo(amount) for amount in amounts] self.funding_tx = ledger_class.transaction_class(is_verified=True) \ .add_inputs([self.txi(self.txo(sum(amounts)+0.1))]) \ .add_outputs(utxos) await self.ledger.db.insert_transaction(self.funding_tx) for utxo in utxos: await self.ledger.db.save_transaction_io( self.funding_tx, self.ledger.hash160_to_address( utxo.script.values['pubkey_hash']), utxo.script.values['pubkey_hash'], '') return utxos
def create_utxos(self, amounts): utxos = [self.txo(amount) for amount in amounts] self.funding_tx = ledger_class.transaction_class() \ .add_inputs([self.txi(self.txo(sum(amounts)+0.1))]) \ .add_outputs(utxos) save_tx = 'insert' for utxo in utxos: yield self.ledger.db.save_transaction_io( save_tx, self.funding_tx, 1, True, self.ledger.hash160_to_address( utxo.script.values['pubkey_hash']), utxo.script.values['pubkey_hash'], '') save_tx = 'update' defer.returnValue(utxos)
def test_coinbase_transaction(self): raw = unhexlify( '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4e03' '1f5a070473319e592f4254432e434f4d2f4e59412ffabe6d6dcceb2a9d0444c51cabc4ee97a1a000036ca0' 'cb48d25b94b78c8367d8b868454b0100000000000000c0309b21000008c5f8f80000ffffffff0291920b5d' '0000000017a914e083685a1097ce1ea9e91987ab9e94eae33d8a13870000000000000000266a24aa21a9ed' 'e6c99265a6b9e1d36c962fda0516b35709c49dc3b8176fa7e5d5f1f6197884b400000000' ) tx = ledger_class.transaction_class(raw) self.assertEqual(tx.version, 1) self.assertEqual(tx.locktime, 0) self.assertEqual(len(tx.inputs), 1) self.assertEqual(len(tx.outputs), 2) coinbase = tx.inputs[0] self.assertEqual(coinbase.output_txhash, NULL_HASH) self.assertEqual(coinbase.output_index, 0xFFFFFFFF) self.assertEqual(coinbase.sequence, 4294967295) self.assertTrue(coinbase.is_coinbase) self.assertEqual(coinbase.script, None) self.assertEqual(coinbase.coinbase[9:22], b'/BTC.COM/NYA/') out = tx.outputs[0] self.assertEqual(out.amount, 1561039505) self.assertEqual(out.index, 0) self.assertFalse(out.script.is_pay_pubkey) self.assertFalse(out.script.is_pay_pubkey_hash) self.assertTrue(out.script.is_pay_script_hash) self.assertFalse(out.script.is_return_data) out1 = tx.outputs[1] self.assertEqual(out1.amount, 0) self.assertEqual(out1.index, 1) self.assertEqual( hexlify(out1.script.values['data']), b'aa21a9ede6c99265a6b9e1d36c962fda0516b35709c49dc3b8176fa7e5d5f1f6197884b4' ) self.assertTrue(out1.script.is_return_data) self.assertFalse(out1.script.is_pay_pubkey) self.assertFalse(out1.script.is_pay_pubkey_hash) self.assertFalse(out1.script.is_pay_script_hash) tx._reset() self.assertEqual(tx.raw, raw)
def test_read_write(self): manager = BaseWalletManager() config = {'data_path': '/tmp/wallet'} ledger = manager.get_or_create_ledger(BTCLedger.get_id(), config) with tempfile.NamedTemporaryFile(suffix='.json') as wallet_file: wallet_file.write(b'{"version": 1}') wallet_file.seek(0) # create and write wallet to a file wallet = manager.import_wallet(wallet_file.name) account = wallet.generate_account(ledger) wallet.save() # read wallet from file wallet_storage = WalletStorage(wallet_file.name) wallet = Wallet.from_storage(wallet_storage, manager) self.assertEqual(account.public_key.address, wallet.default_account.public_key.address)
def test_sign(self): account = self.ledger.account_class.from_seed( self.ledger, u"carbon smart garage balance margin twelve chest sword toast envelope bottom stomach ab" u"sent", u"torba") yield account.ensure_address_gap() address1 = (yield account.receiving.get_addresses())[0] address2 = (yield account.receiving.get_addresses())[0] pubkey_hash1 = self.ledger.address_to_hash160(address1) pubkey_hash2 = self.ledger.address_to_hash160(address2) tx = ledger_class.transaction_class() \ .add_inputs([ledger_class.transaction_class.input_class.spend(get_output(2*COIN, pubkey_hash1))]) \ .add_outputs([ledger_class.transaction_class.output_class.pay_pubkey_hash(int(1.9*COIN), pubkey_hash2)]) \ yield tx.sign([account]) self.assertEqual( hexlify(tx.inputs[0].script.values['signature']), b'3044022064cd6b95c9e0084253c10dd56bcec2bfd816c29aad05fbea490511d79540462b02201aa9d6f73' b'48bb0c76b28d1ad87cf4ffd51cf4de0b299af8bf0ecad70e3369ef201')
def setUp(self): self.ledger = MainNetLedger( db=MainNetLedger.database_class(':memory:')) return self.ledger.db.start()
class TestSynchronization(unittest.TestCase): def setUp(self): self.ledger = MainNetLedger( db=MainNetLedger.database_class(':memory:'), headers_class=MockHeaders) return self.ledger.db.start() @defer.inlineCallbacks def test_update_history(self): account = self.ledger.account_class.generate(self.ledger, u"torba") address = yield account.receiving.get_or_create_usable_address() address_details = yield self.ledger.db.get_address(address) self.assertEqual(address_details['history'], None) self.ledger.headers.height = 3 self.ledger.network = MockNetwork( [ { 'tx_hash': b'abcd01', 'height': 1 }, { 'tx_hash': b'abcd02', 'height': 2 }, { 'tx_hash': b'abcd03', 'height': 3 }, ], { 'abcd01': hexlify(get_transaction(get_output(1)).raw), 'abcd02': hexlify(get_transaction(get_output(2)).raw), 'abcd03': hexlify(get_transaction(get_output(3)).raw), }) yield self.ledger.update_history(address) self.assertEqual(self.ledger.network.get_history_called, [address]) self.assertEqual(self.ledger.network.get_transaction_called, [b'abcd01', b'abcd02', b'abcd03']) address_details = yield self.ledger.db.get_address(address) self.assertEqual(address_details['history'], 'abcd01:1:abcd02:2:abcd03:3:') self.ledger.network.get_history_called = [] self.ledger.network.get_transaction_called = [] yield self.ledger.update_history(address) self.assertEqual(self.ledger.network.get_history_called, [address]) self.assertEqual(self.ledger.network.get_transaction_called, []) self.ledger.network.history.append({'tx_hash': b'abcd04', 'height': 4}) self.ledger.network.transaction['abcd04'] = hexlify( get_transaction(get_output(4)).raw) self.ledger.network.get_history_called = [] self.ledger.network.get_transaction_called = [] yield self.ledger.update_history(address) self.assertEqual(self.ledger.network.get_history_called, [address]) self.assertEqual(self.ledger.network.get_transaction_called, [b'abcd04']) address_details = yield self.ledger.db.get_address(address) self.assertEqual(address_details['history'], 'abcd01:1:abcd02:2:abcd03:3:abcd04:4:')
class TestAccount(unittest.TestCase): def setUp(self): self.ledger = MainNetLedger( db=MainNetLedger.database_class(':memory:')) return self.ledger.db.start() @defer.inlineCallbacks def test_generate_account(self): account = self.ledger.account_class.generate(self.ledger, u"torba") self.assertEqual(account.ledger, self.ledger) self.assertIsNotNone(account.seed) self.assertEqual(account.public_key.ledger, self.ledger) self.assertEqual(account.private_key.public_key, account.public_key) addresses = yield account.receiving.get_addresses() self.assertEqual(len(addresses), 0) addresses = yield account.change.get_addresses() self.assertEqual(len(addresses), 0) yield account.ensure_address_gap() addresses = yield account.receiving.get_addresses() self.assertEqual(len(addresses), 20) addresses = yield account.change.get_addresses() self.assertEqual(len(addresses), 6) @defer.inlineCallbacks def test_generate_account_from_seed(self): account = self.ledger.account_class.from_seed( self.ledger, u"carbon smart garage balance margin twelve chest sword toast envelope bottom stomach ab" u"sent", u"torba") self.assertEqual( account.private_key.extended_key_string(), b'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P' b'6yz3jMbycrLrRMpeAJxR8qDg8') self.assertEqual( account.public_key.extended_key_string(), b'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f' b'iW44g14WF52fYC5J483wqQ5ZP') address = yield account.receiving.ensure_address_gap() self.assertEqual(address[0], b'1PmX9T3sCiDysNtWszJa44SkKcpGc2NaXP') self.maxDiff = None private_key = yield self.ledger.get_private_key_for_address( b'1PmX9T3sCiDysNtWszJa44SkKcpGc2NaXP') self.assertEqual( private_key.extended_key_string(), b'xprv9xNEfQ296VTRaEUDZ8oKq74xw2U6kpj486vFUB4K1wT9U25GX4UwuzFgJN1YuRrqkQ5TTwCpkYnjNpSoH' b'SBaEigNHPkoeYbuPMRo6mRUjxg') invalid_key = yield self.ledger.get_private_key_for_address( b'BcQjRlhDOIrQez1WHfz3whnB33Bp34sUgX') self.assertIsNone(invalid_key) self.assertEqual( hexlify(private_key.wif()), b'1cc27be89ad47ef932562af80e95085eb0ab2ae3e5c019b1369b8b05ff2e94512f01' ) @defer.inlineCallbacks def test_load_and_save_account(self): account_data = { 'seed': "carbon smart garage balance margin twelve chest sword toast envelope bottom stomac" "h absent", 'encrypted': False, 'private_key': 'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P' '6yz3jMbycrLrRMpeAJxR8qDg8', 'public_key': 'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f' 'iW44g14WF52fYC5J483wqQ5ZP', 'receiving_gap': 10, 'receiving_maximum_use_per_address': 2, 'change_gap': 10, 'change_maximum_use_per_address': 2 } account = self.ledger.account_class.from_dict(self.ledger, account_data) yield account.ensure_address_gap() addresses = yield account.receiving.get_addresses() self.assertEqual(len(addresses), 10) addresses = yield account.change.get_addresses() self.assertEqual(len(addresses), 10) self.maxDiff = None account_data['ledger'] = 'btc_mainnet' self.assertDictEqual(account_data, account.to_dict())
def setUp(self): self.ledger = MainNetLedger( db=MainNetLedger.database_class(':memory:'), headers_class=MockHeaders) return self.ledger.db.start()
def setUp(self): self.ledger = ledger_class(db=ledger_class.database_class(':memory:')) return self.ledger.db.start()
def get_transaction(txo=None): return ledger_class.transaction_class() \ .add_inputs([get_input()]) \ .add_outputs([txo or ledger_class.transaction_class.output_class.pay_pubkey_hash(CENT, NULL_HASH)])
def get_output(amount=CENT, pubkey_hash=NULL_HASH): return ledger_class.transaction_class() \ .add_outputs([ledger_class.transaction_class.output_class.pay_pubkey_hash(amount, pubkey_hash)]) \ .outputs[0]