def test_update_or_add(self): cache = TxCache(self.store) # Add. bytedata_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(bytedata_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) metadata_1 = TxData() cache.update_or_add([(tx_id_1, metadata_1, bytedata_1, TxFlags.StateCleared)]) self.assertTrue(cache.is_cached(tx_id_1)) entry = cache.get_entry(tx_id_1) self.assertEqual(TxFlags.HasByteData | TxFlags.StateCleared, entry.flags) self.assertIsNotNone(entry.bytedata) # Update. metadata_2 = TxData(position=22) cache.update_or_add([(tx_id_1, metadata_2, None, TxFlags.HasPosition | TxFlags.StateDispatched)]) entry = cache.get_entry(tx_id_1) store_flags = self.store.get_flags(tx_id_1) # State flags if present get set in an update otherwise they remain the same. expected_flags = TxFlags.HasPosition | TxFlags.HasByteData | TxFlags.StateDispatched self.assertEqual( expected_flags, store_flags, f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(store_flags)}" ) self.assertEqual( expected_flags, entry.flags, f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(entry.flags)}" ) self.assertEqual(bytedata_1, entry.bytedata) self.assertEqual(metadata_2.position, entry.metadata.position)
def test_add_then_update(self): cache = TxCache(self.store) bytedata_1 = bytes.fromhex(tx_hex_1) tx_id_1 = bitcoinx.hash_to_hex_str(bitcoinx.double_sha256(bytedata_1)) metadata_1 = TxData(position=11) cache.add([(tx_id_1, metadata_1, bytedata_1, TxFlags.StateDispatched)]) self.assertTrue(cache.is_cached(tx_id_1)) entry = cache.get_entry(tx_id_1) self.assertEqual( TxFlags.HasByteData | TxFlags.HasPosition | TxFlags.StateDispatched, entry.flags) self.assertIsNotNone(entry.bytedata) metadata_2 = TxData(fee=10, height=88) propagate_flags = TxFlags.HasFee | TxFlags.HasHeight cache.update([(tx_id_1, metadata_2, None, propagate_flags | TxFlags.HasPosition)]) entry = cache.get_entry(tx_id_1) expected_flags = propagate_flags | TxFlags.StateDispatched | TxFlags.HasByteData self.assertEqual( expected_flags, entry.flags, f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(entry.flags)}" ) self.assertIsNotNone(entry.bytedata)
def test_update_flags(self): cache = TxCache(self.store) tx_bytes_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(tx_bytes_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) data = TxData(position=11) cache.add([(tx_id_1, data, tx_bytes_1, TxFlags.StateDispatched)]) self.assertTrue(cache.is_cached(tx_id_1)) entry = cache.get_entry(tx_id_1) self.assertEqual( TxFlags.HasByteData | TxFlags.HasPosition | TxFlags.StateDispatched, entry.flags) self.assertIsNotNone(entry.bytedata) cache.update_flags(tx_id_1, TxFlags.StateCleared, TxFlags.HasByteData | TxFlags.HasProofData) entry = cache.get_entry(tx_id_1) store_flags = self.store.get_flags(tx_id_1) expected_flags = TxFlags.HasByteData | TxFlags.HasPosition | TxFlags.StateCleared self.assertEqual( expected_flags, store_flags, f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(store_flags)}" ) self.assertEqual( expected_flags, entry.flags, f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(entry.flags)}" ) self.assertIsNotNone(entry.bytedata)
def test_get_transaction(self): bytedata = bytes.fromhex(tx_hex_1) tx_hash_bytes = bitcoinx.double_sha256(bytedata) tx_id = bitcoinx.hash_to_hex_str(tx_hash_bytes) metadata = TxData(height=1, fee=2, position=None, timestamp=None) self.store.add(tx_id, metadata, bytedata) cache = TxCache(self.store) tx = cache.get_transaction(tx_id) self.assertIsNotNone(tx) self.assertEqual(tx_id, tx.txid())
def test_get_unverified_entries_too_high(self): cache = TxCache(self.store) tx_bytes_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(tx_bytes_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) data = TxData(height=11, position=22) cache.add([(tx_id_1, data, tx_bytes_1, TxFlags.StateCleared)]) results = cache.get_unverified_entries(100) self.assertEqual(0, len(results))
def test_get_transactions(self): tx_ids = [] for tx_hex in (tx_hex_1, tx_hex_2): tx_bytes = bytes.fromhex(tx_hex) tx_hash_bytes = bitcoinx.double_sha256(tx_bytes) tx_id = bitcoinx.hash_to_hex_str(tx_hash_bytes) data = TxData(height=1, fee=2, position=None, timestamp=None) self.store.add(tx_id, data, tx_bytes) tx_ids.append(tx_id) cache = TxCache(self.store) for (tx_id, tx) in cache.get_transactions(tx_ids=tx_ids): self.assertIsNotNone(tx) self.assertIn(tx.txid(), tx_ids)
def test_entry_visible(self): cache = TxCache(self.store) combos = [ (TxFlags.Unset, None, None, True), (TxFlags.Unset, None, TxFlags.HasHeight, False), (TxFlags.HasHeight, None, TxFlags.HasHeight, True), (TxFlags.HasHeight, TxFlags.HasHeight, None, True), (TxFlags.HasHeight, TxFlags.HasHeight, TxFlags.HasFee, False), (TxFlags.HasHeight, TxFlags.HasHeight, TxFlags.HasHeight, True), (TxFlags.HasFee, TxFlags.HasHeight, TxFlags.HasHeight, False), ] for i, (flag_bits, flags, mask, result) in enumerate(combos): actual_result = cache._entry_visible(flag_bits, flags, mask) self.assertEqual(result, actual_result, str(combos[i]))
def test_get_metadata(self): # Verify that getting a non-cached stored entry's metadata will only load the metadata. bytedata_set = os.urandom(10) tx_id = bitcoinx.hash_to_hex_str(bitcoinx.double_sha256(bytedata_set)) metadata_set = TxData(height=1, fee=2, position=None, timestamp=None) self.store.add(tx_id, metadata_set, bytedata_set) cache = TxCache(self.store) metadata_get = cache.get_metadata(tx_id) self.assertEqual(metadata_set.height, metadata_get.height) self.assertEqual(metadata_set.fee, metadata_get.fee) self.assertEqual(metadata_set.position, metadata_get.position) self.assertEqual(metadata_set.timestamp, metadata_get.timestamp) entry = cache.get_cached_entry(tx_id) self.assertTrue(entry.is_metadata_cached()) self.assertFalse(entry.is_bytedata_cached())
def test_delete(self): cache = TxCache(self.store) tx_bytes_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(tx_bytes_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) data = TxData(position=11) cache.add([(tx_id_1, data, tx_bytes_1, TxFlags.StateDispatched)]) self.assertTrue(self.store.has(tx_id_1)) self.assertTrue(cache.is_cached(tx_id_1)) cache.delete(tx_id_1) self.assertFalse(self.store.has(tx_id_1)) self.assertFalse(cache.is_cached(tx_id_1))
def test_get_unsynced_ids(self): cache = TxCache(self.store) bytedata_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(bytedata_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) metadata_1 = TxData(height=11) cache.add([(tx_id_1, metadata_1, None, TxFlags.StateCleared)]) results = cache.get_unsynced_ids() self.assertEqual(1, len(results)) metadata_2 = TxData() cache.update([(tx_id_1, metadata_2, bytedata_1, TxFlags.HasByteData)]) results = cache.get_unsynced_ids() self.assertEqual(0, len(results))
def test_add_missing_transaction(self): cache = TxCache(self.store) tx_bytes_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(tx_bytes_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) cache.add_missing_transaction(tx_id_1, 100, 94) self.assertTrue(cache.is_cached(tx_id_1)) entry = cache.get_entry(tx_id_1) self.assertEqual(TxFlags.HasFee | TxFlags.HasHeight, entry.flags & TxFlags.METADATA_FIELD_MASK) self.assertIsNone(entry.bytedata) tx_bytes_2 = bytes.fromhex(tx_hex_2) tx_hash_bytes_2 = bitcoinx.double_sha256(tx_bytes_2) tx_id_2 = bitcoinx.hash_to_hex_str(tx_hash_bytes_2) cache.add_missing_transaction(tx_id_2, 200) self.assertTrue(cache.is_cached(tx_id_2)) entry = cache.get_entry(tx_id_2) self.assertEqual(TxFlags.HasHeight, entry.flags & TxFlags.METADATA_FIELD_MASK) self.assertIsNone(entry.bytedata)
def test_add_transaction(self): cache = TxCache(self.store) tx = Transaction.from_hex(tx_hex_1) cache.add_transaction(tx) self.assertTrue(cache.is_cached(tx.txid())) entry = cache.get_entry(tx.txid()) self.assertEqual(TxFlags.HasByteData, entry.flags & TxFlags.HasByteData) self.assertIsNotNone(entry.bytedata)
def test_get_flags(self): cache = TxCache(self.store) self.assertIsNone(cache.get_flags(os.urandom(10).hex())) tx_bytes_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(tx_bytes_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) data = TxData(position=11) cache.add([(tx_id_1, data, tx_bytes_1, TxFlags.StateDispatched)]) self.assertTrue(cache.is_cached(tx_id_1)) self.assertEqual( TxFlags.StateDispatched | TxFlags.HasByteData | TxFlags.HasPosition, cache.get_flags(tx_id_1))
def test_get_entry(self): cache = TxCache(self.store) bytedata_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(bytedata_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) data = TxData(position=11) cache.add([(tx_id_1, data, bytedata_1, TxFlags.StateCleared)]) entry = cache.get_entry(tx_id_1, TxFlags.StateDispatched) self.assertIsNone(entry) entry = cache.get_entry(tx_id_1, TxFlags.StateCleared) self.assertIsNotNone(entry)
def test_add_transaction_update(self): cache = TxCache(self.store) tx = Transaction.from_hex(tx_hex_1) data = [ tx.txid(), TxData(height=1295924, timestamp=1555296290, position=4, fee=None), None, TxFlags.StateCleared ] cache.add([data]) entry = cache.get_entry(tx.txid()) self.assertIsNotNone(entry) self.assertEqual(TxFlags.StateCleared, entry.flags & TxFlags.StateCleared) cache.add_transaction(tx, TxFlags.StateSettled) entry = cache.get_entry(tx.txid()) self.assertIsNotNone(entry) self.assertIsNotNone(entry.bytedata) self.assertEqual(TxFlags.StateSettled, entry.flags & TxFlags.StateSettled)
def test_get_transaction_after_metadata(self): bytedata_set = os.urandom(10) tx_id = bitcoinx.hash_to_hex_str(bitcoinx.double_sha256(bytedata_set)) metadata_set = TxData(height=1, fee=2, position=None, timestamp=None) self.store.add(tx_id, metadata_set, bytedata_set) cache = TxCache(self.store) metadata_get = cache.get_metadata(tx_id) self.assertIsNotNone(metadata_get) cached_entry_1 = cache.get_cached_entry(tx_id) self.assertTrue(cached_entry_1.is_metadata_cached()) self.assertFalse(cached_entry_1.is_bytedata_cached()) entry = cache.get_entry(tx_id) self.assertTrue(entry.is_metadata_cached()) self.assertTrue(entry.is_bytedata_cached()) cached_entry_2 = cache.get_cached_entry(tx_id) self.assertEqual(entry, cached_entry_2)
def test_get_height(self): cache = TxCache(self.store) bytedata_1 = bytes.fromhex(tx_hex_1) tx_hash_bytes_1 = bitcoinx.double_sha256(bytedata_1) tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1) metadata_1 = TxData(height=11) cache.add([(tx_id_1, metadata_1, bytedata_1, TxFlags.StateCleared)]) self.assertEqual(11, cache.get_height(tx_id_1)) cache.update_flags(tx_id_1, TxFlags.StateSettled) self.assertEqual(11, cache.get_height(tx_id_1)) cache.update_flags(tx_id_1, TxFlags.StateReceived) self.assertIsNone(cache.get_height(tx_id_1))