URI:
       ttest_transactionmonitor.py - electrum-personal-server - Maximally lightweight electrum server for a single user
  HTML git clone https://git.parazyd.org/electrum-personal-server
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       ttest_transactionmonitor.py (29287B)
       ---
            1 
            2 import pytest
            3 import logging
            4 
            5 from electrumpersonalserver.server import (
            6     DeterministicWallet,
            7     TransactionMonitor,
            8     JsonRpcError,
            9     script_to_scripthash
           10 )
           11 
           12 logger = logging.getLogger('ELECTRUMPERSONALSERVER-TEST')
           13 logger.setLevel(logging.DEBUG)
           14 
           15 class DummyJsonRpc(object):
           16     """
           17     Electrum Personal Server gets all its information about the bitcoin network
           18     from the json-rpc interface. This dummy interface is used for simulating
           19     events in bitcoin
           20     """
           21     def __init__(self, txlist, utxoset, block_heights):
           22         self.txlist = txlist
           23         self.utxoset = utxoset
           24         self.block_heights = block_heights
           25         self.imported_addresses = []
           26 
           27     def call(self, method, params):
           28         if method == "listtransactions":
           29             count = int(params[1])
           30             skip = int(params[2])
           31             return self.txlist[skip:skip + count][::-1]
           32         elif method == "gettransaction":
           33             for t in self.txlist:
           34                 if t["txid"] == params[0]:
           35                     return t
           36             raise JsonRpcError()
           37         elif method == "decoderawtransaction":
           38             for t in self.txlist:
           39                 if t["hex"] == params[0]:
           40                     return t
           41             logger.debug(params[0])
           42             assert 0
           43         elif method == "gettxout":
           44             for u in self.utxoset:
           45                 if u["txid"] == params[0] and u["vout"] == params[1]:
           46                     return u
           47             logger.debug("txid = " + params[0] + " vout = " + str(params[1]))
           48             assert 0
           49         elif method == "getblockheader":
           50             if params[0] in self.block_heights:
           51                 return {"height": self.block_heights[params[0]]}
           52             logger.debug(params[0])
           53             assert 0
           54         elif method == "decodescript":
           55             return {"addresses": [dummy_spk_to_address(params[0])]}
           56         elif method == "importaddress":
           57             self.imported_addresses.append(params[0])
           58         elif method == "getmempoolentry":
           59             for t in self.txlist:
           60                 if t["txid"] == params[0]:
           61                     return {"fees": {"base": 0},
           62                         "ancestorcount":
           63                             1 if t["vin"][0]["confirmations"] > 0 else 2}
           64             logger.debug(params[0])
           65             assert 0
           66         else:
           67             raise ValueError("unknown method in dummy jsonrpc " + method)
           68 
           69     def add_transaction(self, tx):
           70         self.txlist = [tx] + self.txlist
           71 
           72     def get_imported_addresses(self):
           73         return self.imported_addresses
           74 
           75 
           76 class DummyDeterministicWallet(DeterministicWallet):
           77     """Empty deterministic wallets"""
           78     def __init__(self):
           79         pass
           80 
           81     def have_scriptpubkeys_overrun_gaplimit(self, scriptpubkeys):
           82         return None #not overrun
           83 
           84     def get_new_scriptpubkeys(self, change, count):
           85         pass
           86 
           87 
           88 def dummy_spk_to_address(spk):
           89     ##spk is short for scriptPubKey
           90     return spk + "-address"
           91 
           92 deterministic_wallets = [DummyDeterministicWallet()]
           93 dummy_id_g = [1000]
           94 
           95 def create_dummy_spk(): #script pub key
           96     dummy_id = dummy_id_g[0]
           97     dummy_id_g[0] += 1
           98     return "deadbeef" + str(dummy_id)
           99 
          100 def create_dummy_funding_tx(confirmations=1, output_spk=None,
          101         input_txid="placeholder-unknown-input-txid", coinbase=False,
          102         input_confirmations=1):
          103     dummy_id = dummy_id_g[0]
          104     dummy_id_g[0] += 1
          105 
          106     if output_spk == None:
          107         dummy_spk = "deadbeef" + str(dummy_id) #scriptpubkey
          108     else:
          109         dummy_spk = output_spk
          110     dummy_containing_block = "blockhash-placeholder" + str(dummy_id)
          111     containing_block_height = dummy_id
          112     category = "receive"
          113     vin = [{"txid": input_txid, "vout": 0, "value": 1,
          114             "confirmations": input_confirmations}]
          115     if coinbase:
          116         vin = [{"coinbase": "nonce"}]
          117         if confirmations < 1:
          118             category = "orphan"
          119         elif confirmations <= 100:
          120             category = "immature"
          121         else:
          122             category = "generate"
          123     dummy_tx = {
          124         "txid": "placeholder-test-txid" + str(dummy_id),
          125         "vin": vin,
          126         "vout": [{"value": 1, "scriptPubKey": {"hex": dummy_spk}}],
          127         "address": dummy_spk_to_address(dummy_spk),
          128         "category": category,
          129         "confirmations": confirmations,
          130         "blockhash": dummy_containing_block,
          131         "hex": "placeholder-test-txhex" + str(dummy_id)
          132     }
          133     logger.debug("created dummy tx: " + str(dummy_tx))
          134     return dummy_spk, containing_block_height, dummy_tx
          135 
          136 def assert_address_history_tx(address_history, spk, height, txid, subscribed):
          137     history_element = address_history[script_to_scripthash(spk)]
          138     assert history_element["history"][0]["height"] == height
          139     assert history_element["history"][0]["tx_hash"] == txid
          140     #fee always zero, its easier to test because otherwise you have
          141     # to use Decimal to stop float weirdness
          142     if height == 0:
          143         assert history_element["history"][0]["fee"] == 0
          144     assert history_element["subscribed"] == subscribed
          145 
          146 def test_single_tx():
          147     ###single confirmed tx in wallet belonging to us, address history built
          148     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx()
          149 
          150     rpc = DummyJsonRpc([dummy_tx], [],
          151         {dummy_tx["blockhash"]: containing_block_height})
          152     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          153     assert txmonitor.build_address_history([dummy_spk])
          154     assert len(txmonitor.address_history) == 1
          155     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk,
          156         height=containing_block_height, txid=dummy_tx["txid"], subscribed=False)
          157 
          158 def test_two_txes():
          159     ###two confirmed txes in wallet belonging to us, addr history built
          160     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          161     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx()
          162 
          163     rpc = DummyJsonRpc([dummy_tx1, dummy_tx2], [],
          164         {dummy_tx1["blockhash"]: containing_block_height1,
          165         dummy_tx2["blockhash"]: containing_block_height2})
          166     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          167     assert txmonitor.build_address_history([dummy_spk1, dummy_spk2])
          168     assert len(txmonitor.address_history) == 2
          169     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          170         height=containing_block_height1, txid=dummy_tx1["txid"],
          171         subscribed=False)
          172     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk2,
          173         height=containing_block_height2, txid=dummy_tx2["txid"],
          174         subscribed=False)
          175 
          176 def test_coinbase_txs():
          177     ###two coinbase txs (mature and immature) in wallet, addr history built
          178     ## two more coinbase txs added, addr history updated
          179     ## orphaned coinbase txs not added to addr history
          180     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx(
          181         coinbase=True, confirmations=1)
          182     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx(
          183         coinbase=True, confirmations=101)
          184     dummy_spk3, containing_block_height3, dummy_tx3 = create_dummy_funding_tx(
          185         coinbase=True, confirmations=0)
          186     dummy_spk4, containing_block_height4, dummy_tx4 = create_dummy_funding_tx(
          187         coinbase=True, confirmations=1)
          188     dummy_spk5, containing_block_height5, dummy_tx5 = create_dummy_funding_tx(
          189         coinbase=True, confirmations=101)
          190     dummy_spk6, containing_block_height6, dummy_tx6 = create_dummy_funding_tx(
          191         coinbase=True, confirmations=0)
          192 
          193     rpc = DummyJsonRpc([dummy_tx1, dummy_tx2, dummy_tx3], [],
          194                        {dummy_tx1["blockhash"]: containing_block_height1,
          195                         dummy_tx2["blockhash"]: containing_block_height2,
          196                         dummy_tx3["blockhash"]: containing_block_height3,
          197                         dummy_tx4["blockhash"]: containing_block_height4,
          198                         dummy_tx5["blockhash"]: containing_block_height5,
          199                         dummy_tx6["blockhash"]: containing_block_height6})
          200     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          201     assert txmonitor.build_address_history([dummy_spk1, dummy_spk2, dummy_spk3,
          202                                             dummy_spk4, dummy_spk5, dummy_spk6])
          203     assert len(txmonitor.address_history) == 6
          204     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          205         height=containing_block_height1, txid=dummy_tx1["txid"],
          206         subscribed=False)
          207     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk2,
          208         height=containing_block_height2, txid=dummy_tx2["txid"],
          209         subscribed=False)
          210     sh3 = script_to_scripthash(dummy_spk3)
          211     assert len(txmonitor.get_electrum_history(sh3)) == 0
          212 
          213     rpc.add_transaction(dummy_tx4)
          214     rpc.add_transaction(dummy_tx5)
          215     rpc.add_transaction(dummy_tx6)
          216     assert len(list(txmonitor.check_for_updated_txes())) == 0
          217     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk4,
          218         height=containing_block_height4, txid=dummy_tx4["txid"],
          219         subscribed=False)
          220     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk5,
          221         height=containing_block_height5, txid=dummy_tx5["txid"],
          222         subscribed=False)
          223     sh6 = script_to_scripthash(dummy_spk6)
          224     assert len(txmonitor.get_electrum_history(sh6)) == 0
          225 
          226     #test orphan tx is removed from history
          227     dummy_tx1["confirmations"] = 0
          228     dummy_tx1["category"] = "orphan"
          229     assert len(list(txmonitor.check_for_updated_txes())) == 0
          230     sh1 = script_to_scripthash(dummy_spk1)
          231     assert len(txmonitor.get_electrum_history(sh1)) == 0
          232 
          233 def test_many_txes():
          234     ##many txes in wallet and many more added,, intended to test the loop
          235     ## in build_addr_history and check_for_new_txes()
          236     input_spk, input_block_height1, input_tx = create_dummy_funding_tx()
          237     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx(
          238         confirmations=0, input_txid=input_tx["vin"][0])
          239     sh = script_to_scripthash(dummy_spk)
          240 
          241     #batch size is 1000
          242     INITIAL_TX_COUNT = 1100
          243     txes = [dummy_tx]
          244     #0confirm to avoid having to obtain block hash
          245     txes.extend( (create_dummy_funding_tx(output_spk=dummy_spk,
          246         input_txid=input_tx["vin"][0], confirmations=0)[2]
          247         for i in range(INITIAL_TX_COUNT-1)) )
          248     assert len(txes) == INITIAL_TX_COUNT
          249 
          250     rpc = DummyJsonRpc(txes, [dummy_tx["vin"][0]], {})
          251     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          252     assert txmonitor.build_address_history([dummy_spk])
          253     assert len(txmonitor.address_history) == 1
          254     assert len(list(txmonitor.check_for_updated_txes())) == 0
          255     assert len(txmonitor.address_history[sh]["history"]) == INITIAL_TX_COUNT
          256 
          257     ADDED_TX_COUNT = 130
          258     new_txes = []
          259     new_txes.extend( (create_dummy_funding_tx(output_spk=dummy_spk,
          260         input_txid=input_tx["vin"][0], confirmations=0)[2]
          261         for i in range(ADDED_TX_COUNT)) )
          262 
          263     for tx in new_txes:
          264         rpc.add_transaction(tx)
          265     assert len(list(txmonitor.check_for_updated_txes())) == 0
          266     assert len(txmonitor.address_history[sh]["history"]) == (INITIAL_TX_COUNT
          267         + ADDED_TX_COUNT)
          268 
          269 def test_non_subscribed_confirmation():
          270     ###one unconfirmed tx in wallet belonging to us, with confirmed inputs,
          271     ### addr history built, then tx confirms, not subscribed to address
          272     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx(
          273         confirmations=0)
          274 
          275     rpc = DummyJsonRpc([dummy_tx], [dummy_tx["vin"][0]],
          276         {dummy_tx["blockhash"]: containing_block_height})
          277     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          278     assert txmonitor.build_address_history([dummy_spk])
          279     assert len(txmonitor.address_history) == 1
          280     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk,
          281         height=0, txid=dummy_tx["txid"], subscribed=False)
          282     assert len(list(txmonitor.check_for_updated_txes())) == 0
          283     dummy_tx["confirmations"] = 1 #tx confirms
          284     #not subscribed so still only returns an empty list
          285     assert len(list(txmonitor.check_for_updated_txes())) == 0
          286     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk,
          287         height=containing_block_height, txid=dummy_tx["txid"], subscribed=False)
          288 
          289 def test_tx_arrival_then_confirmation():
          290     ###build empty address history, subscribe one address
          291     ### an unconfirmed tx appears, then confirms
          292     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx(
          293         confirmations=0)
          294 
          295     rpc = DummyJsonRpc([], [dummy_tx["vin"][0]], {dummy_tx["blockhash"]:
          296         containing_block_height})
          297     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          298     assert txmonitor.build_address_history([dummy_spk])
          299     assert len(txmonitor.address_history) == 1
          300     sh = script_to_scripthash(dummy_spk)
          301     assert len(txmonitor.get_electrum_history(sh)) == 0
          302     txmonitor.subscribe_address(sh)
          303     # unconfirm transaction appears
          304     assert len(list(txmonitor.check_for_updated_txes())) == 0
          305     rpc.add_transaction(dummy_tx)
          306     assert len(list(txmonitor.check_for_updated_txes())) == 1
          307     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk,
          308         height=0, txid=dummy_tx["txid"], subscribed=True)
          309     # transaction confirms
          310     dummy_tx["confirmations"] = 1
          311     assert len(list(txmonitor.check_for_updated_txes())) == 1
          312     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk,
          313         height=containing_block_height, txid=dummy_tx["txid"], subscribed=True)
          314 
          315 def test_unrelated_tx():
          316     ###transaction that has nothing to do with our wallet
          317     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx(
          318         confirmations=0)
          319     our_dummy_spk = create_dummy_spk()
          320 
          321     rpc = DummyJsonRpc([dummy_tx], [], {dummy_tx["blockhash"]:
          322         containing_block_height})
          323     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          324     assert txmonitor.build_address_history([our_dummy_spk])
          325     assert len(txmonitor.address_history) == 1
          326     assert len(txmonitor.get_electrum_history(script_to_scripthash(
          327         our_dummy_spk))) == 0
          328 
          329 def test_duplicate_txid():
          330     ###two txes with the same txid, built history
          331     dummy_spk, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          332     dummy_spk, containing_block_height2, dummy_tx2 = create_dummy_funding_tx(
          333         output_spk=dummy_spk)
          334     dummy_spk, containing_block_height3, dummy_tx3 = create_dummy_funding_tx(
          335         output_spk=dummy_spk)
          336     dummy_tx2["txid"] = dummy_tx1["txid"]
          337     dummy_tx3["txid"] = dummy_tx1["txid"]
          338     sh = script_to_scripthash(dummy_spk)
          339     rpc = DummyJsonRpc([dummy_tx1, dummy_tx2], [], {dummy_tx1["blockhash"]:
          340         containing_block_height1, dummy_tx2["blockhash"]:
          341         containing_block_height2, dummy_tx3["blockhash"]:
          342         containing_block_height3})
          343     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          344     assert txmonitor.build_address_history([dummy_spk])
          345     assert len(txmonitor.get_electrum_history(sh)) == 1
          346     txmonitor.subscribe_address(sh)
          347     assert txmonitor.get_electrum_history(sh)[0]["tx_hash"] == dummy_tx1["txid"]
          348     rpc.add_transaction(dummy_tx3)
          349     assert len(list(txmonitor.check_for_updated_txes())) == 1
          350     assert len(txmonitor.get_electrum_history(sh)) == 1
          351     assert txmonitor.get_electrum_history(sh)[0]["tx_hash"] == dummy_tx1["txid"]
          352 
          353 def test_address_reuse():
          354     ###transaction which arrives to an address which already has a tx on it
          355     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          356     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx(
          357         output_spk=dummy_spk1)
          358 
          359     rpc = DummyJsonRpc([dummy_tx1], [], {dummy_tx1["blockhash"]:
          360         containing_block_height1, dummy_tx2["blockhash"]:
          361         containing_block_height2})
          362     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          363     assert txmonitor.build_address_history([dummy_spk1])
          364     sh = script_to_scripthash(dummy_spk1)
          365     assert len(txmonitor.get_electrum_history(sh)) == 1
          366     rpc.add_transaction(dummy_tx2)
          367     assert len(txmonitor.get_electrum_history(sh)) == 1
          368     txmonitor.check_for_updated_txes()
          369     assert len(txmonitor.get_electrum_history(sh)) == 2
          370 
          371 def test_from_address():
          372     ###transaction spending FROM one of our addresses
          373     dummy_spk1, containing_block_height1, input_tx = create_dummy_funding_tx()
          374     dummy_spk2, containing_block_height2, spending_tx = create_dummy_funding_tx(
          375         input_txid=input_tx["txid"])
          376 
          377     rpc = DummyJsonRpc([input_tx, spending_tx], [],
          378         {input_tx["blockhash"]: containing_block_height1,
          379         spending_tx["blockhash"]: containing_block_height2})
          380     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          381     assert txmonitor.build_address_history([dummy_spk1])
          382     sh = script_to_scripthash(dummy_spk1)
          383     assert len(txmonitor.get_electrum_history(sh)) == 2
          384 
          385 def test_tx_within_wallet():
          386     ###transaction from one address to the other, both addresses in wallet
          387     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          388     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx(
          389         input_txid=dummy_tx1["txid"])
          390 
          391     rpc = DummyJsonRpc([dummy_tx1, dummy_tx2], [],
          392         {dummy_tx1["blockhash"]: containing_block_height1,
          393         dummy_tx2["blockhash"]: containing_block_height2})
          394     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          395     assert txmonitor.build_address_history([dummy_spk1, dummy_spk2])
          396     assert len(txmonitor.get_electrum_history(script_to_scripthash(
          397         dummy_spk1))) == 2
          398     assert len(txmonitor.get_electrum_history(script_to_scripthash(
          399         dummy_spk2))) == 1
          400 
          401 def test_tx_with_unconfirmed_input():
          402     ###unconfirmed tx arrives with unconfirmed input, which then both confirm
          403 
          404     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx(
          405         confirmations=0)
          406     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx(
          407         confirmations=0, input_txid=dummy_tx1["txid"], input_confirmations=0)
          408 
          409     rpc = DummyJsonRpc([], [dummy_tx1["vin"][0], dummy_tx2["vin"][0]],
          410         {dummy_tx1["blockhash"]: containing_block_height1,
          411         dummy_tx2["blockhash"]: containing_block_height2})
          412     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          413 
          414     assert txmonitor.build_address_history([dummy_spk1, dummy_spk2])
          415     assert len(txmonitor.address_history) == 2
          416 
          417     sh1 = script_to_scripthash(dummy_spk1)
          418     sh2 = script_to_scripthash(dummy_spk2)
          419     assert len(txmonitor.get_electrum_history(sh1)) == 0
          420     assert len(txmonitor.get_electrum_history(sh2)) == 0
          421     txmonitor.subscribe_address(sh1)
          422     txmonitor.subscribe_address(sh2)
          423 
          424     #the unconfirmed transactions appear
          425     assert len(list(txmonitor.check_for_updated_txes())) == 0
          426     rpc.add_transaction(dummy_tx1)
          427     rpc.add_transaction(dummy_tx2)
          428     assert len(list(txmonitor.check_for_updated_txes())) == 2
          429     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          430         height=0, txid=dummy_tx1["txid"], subscribed=True)
          431     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk2,
          432         height=-1, txid=dummy_tx2["txid"], subscribed=True)
          433 
          434     #the transactions confirm
          435     dummy_tx1["confirmations"] = 1
          436     dummy_tx2["confirmations"] = 1
          437 
          438     assert len(list(txmonitor.check_for_updated_txes())) == 2
          439     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          440         height=containing_block_height1, txid=dummy_tx1["txid"],
          441         subscribed=True)
          442     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk2,
          443         height=containing_block_height2, txid=dummy_tx2["txid"],
          444         subscribed=True)
          445 
          446 def test_overrun_gap_limit():
          447     ###overrun gap limit so import address is needed
          448     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx()
          449     dummy_spk_imported = create_dummy_spk()
          450 
          451     class DummyImportDeterministicWallet(DeterministicWallet):
          452         def __init__(self):
          453             pass
          454 
          455         def have_scriptpubkeys_overrun_gaplimit(self, scriptpubkeys):
          456             return {0: 1} #overrun by one
          457 
          458         def get_new_scriptpubkeys(self, change, count):
          459             return [dummy_spk_imported]
          460 
          461     rpc = DummyJsonRpc([], [], {dummy_tx["blockhash"]: containing_block_height})
          462     txmonitor = TransactionMonitor(rpc, [DummyImportDeterministicWallet()],
          463                                    logger)
          464     assert txmonitor.build_address_history([dummy_spk])
          465     assert len(txmonitor.address_history) == 1
          466     assert len(list(txmonitor.check_for_updated_txes())) == 0
          467     assert len(txmonitor.get_electrum_history(script_to_scripthash(
          468         dummy_spk))) == 0
          469     rpc.add_transaction(dummy_tx)
          470     assert len(list(txmonitor.check_for_updated_txes())) == 0
          471     assert len(txmonitor.get_electrum_history(script_to_scripthash(
          472         dummy_spk))) == 1
          473     assert len(txmonitor.get_electrum_history(script_to_scripthash(
          474         dummy_spk_imported))) == 0
          475     assert len(rpc.get_imported_addresses()) == 1
          476     assert rpc.get_imported_addresses()[0] == dummy_spk_to_address(
          477         dummy_spk_imported)
          478 
          479 def test_conflicted_tx():
          480     ###conflicted transaction should get rejected
          481     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx(
          482         confirmations=-1)
          483     rpc = DummyJsonRpc([dummy_tx], [], {})
          484     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          485     sh = script_to_scripthash(dummy_spk)
          486 
          487     assert txmonitor.build_address_history([dummy_spk])
          488     assert len(txmonitor.address_history) == 1
          489     #shouldnt show up after build history because conflicted
          490     assert len(txmonitor.get_electrum_history(sh)) == 0
          491 
          492     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx(
          493         confirmations=-1, output_spk=dummy_spk)
          494     rpc.add_transaction(dummy_tx)
          495     assert len(list(txmonitor.check_for_updated_txes())) == 0
          496     #incoming tx is not added either
          497     assert len(txmonitor.get_electrum_history(sh)) == 0
          498 
          499 def test_reorg_finney_attack():
          500     ###an unconfirmed tx being broadcast, another conflicting tx being
          501     ### confirmed, the first tx gets conflicted status
          502 
          503     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx(
          504         confirmations=0)
          505     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx(
          506         confirmations=0, input_txid=dummy_tx1["vin"][0])
          507     #two unconfirmed txes spending the same input, so they are in conflict
          508 
          509     rpc = DummyJsonRpc([dummy_tx1], [dummy_tx1["vin"][0]],
          510         {dummy_tx1["blockhash"]: containing_block_height1,
          511         dummy_tx2["blockhash"]: containing_block_height2})
          512     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          513     assert txmonitor.build_address_history([dummy_spk1, dummy_spk2])
          514     assert len(txmonitor.address_history) == 2
          515     sh1 = script_to_scripthash(dummy_spk1)
          516     sh2 = script_to_scripthash(dummy_spk2)
          517     assert len(txmonitor.get_electrum_history(sh1)) == 1
          518     assert len(txmonitor.get_electrum_history(sh2)) == 0
          519     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          520         height=0, txid=dummy_tx1["txid"], subscribed=False)
          521     # a conflicting transaction confirms
          522     rpc.add_transaction(dummy_tx2)
          523     dummy_tx1["confirmations"] = -1
          524     dummy_tx2["confirmations"] = 1
          525     assert len(list(txmonitor.check_for_updated_txes())) == 0
          526     assert len(txmonitor.get_electrum_history(sh1)) == 0
          527     assert len(txmonitor.get_electrum_history(sh2)) == 1
          528     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk2,
          529         height=containing_block_height2, txid=dummy_tx2["txid"],
          530         subscribed=False)
          531 
          532 def test_reorg_race_attack():
          533     #a tx is confirmed, a chain reorganization happens and that tx is replaced
          534     # by another tx spending the same input, the original tx is now conflicted
          535     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          536     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx(
          537         input_txid=dummy_tx1["vin"][0])
          538 
          539     rpc = DummyJsonRpc([dummy_tx1], [],
          540         {dummy_tx1["blockhash"]: containing_block_height1,
          541         dummy_tx2["blockhash"]: containing_block_height2})
          542     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          543     assert txmonitor.build_address_history([dummy_spk1, dummy_spk2])
          544     assert len(txmonitor.address_history) == 2
          545     sh1 = script_to_scripthash(dummy_spk1)
          546     sh2 = script_to_scripthash(dummy_spk2)
          547     assert len(txmonitor.get_electrum_history(sh1)) == 1
          548     assert len(txmonitor.get_electrum_history(sh2)) == 0
          549     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          550         height=containing_block_height1, txid=dummy_tx1["txid"],
          551         subscribed=False)
          552     #race attack happens
          553     #dummy_tx1 goes to -1 confirmations, dummy_tx2 gets confirmed
          554     rpc.add_transaction(dummy_tx2)
          555     dummy_tx1["confirmations"] = -1
          556     dummy_tx2["confirmations"] = 1
          557     assert len(list(txmonitor.check_for_updated_txes())) == 0
          558     assert len(txmonitor.get_electrum_history(sh1)) == 0
          559     assert len(txmonitor.get_electrum_history(sh2)) == 1
          560     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk2,
          561         height=containing_block_height2, txid=dummy_tx2["txid"],
          562         subscribed=False)
          563 
          564 def test_reorg_censor_tx():
          565     #confirmed tx gets reorgd out and becomes unconfirmed
          566     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          567 
          568     rpc = DummyJsonRpc([dummy_tx1], [dummy_tx1["vin"][0]],
          569         {dummy_tx1["blockhash"]: containing_block_height1})
          570     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          571     assert txmonitor.build_address_history([dummy_spk1])
          572     assert len(txmonitor.address_history) == 1
          573     sh = script_to_scripthash(dummy_spk1)
          574     assert len(txmonitor.get_electrum_history(sh)) == 1
          575     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          576         height=containing_block_height1, txid=dummy_tx1["txid"],
          577         subscribed=False)
          578     #blocks appear which reorg out the tx, making it unconfirmed
          579     dummy_tx1["confirmations"] = 0
          580     assert len(list(txmonitor.check_for_updated_txes())) == 0
          581     assert len(txmonitor.get_electrum_history(sh)) == 1
          582     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          583         height=0, txid=dummy_tx1["txid"], subscribed=False)
          584 
          585 def test_reorg_different_block():
          586     #confirmed tx gets reorged into another block with a different height
          587     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          588     dummy_spk2, containing_block_height2, dummy_tx2 = create_dummy_funding_tx()
          589 
          590     rpc = DummyJsonRpc([dummy_tx1], [],
          591         {dummy_tx1["blockhash"]: containing_block_height1,
          592         dummy_tx2["blockhash"]: containing_block_height2})
          593     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          594     assert txmonitor.build_address_history([dummy_spk1])
          595     assert len(txmonitor.address_history) == 1
          596     sh = script_to_scripthash(dummy_spk1)
          597     assert len(txmonitor.get_electrum_history(sh)) == 1
          598     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          599         height=containing_block_height1, txid=dummy_tx1["txid"],
          600         subscribed=False)
          601 
          602     #tx gets reorged into another block (so still confirmed)
          603     dummy_tx1["blockhash"] = dummy_tx2["blockhash"]
          604     assert len(list(txmonitor.check_for_updated_txes())) == 0
          605     assert len(txmonitor.get_electrum_history(sh)) == 1
          606     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk1,
          607         height=containing_block_height2, txid=dummy_tx1["txid"],
          608         subscribed=False)
          609 
          610 def test_tx_safe_from_reorg():
          611     ##tx confirmed with 1 confirmation, then confirmations goes to 100
          612     ## test that the reorganizable_txes list length goes down
          613     dummy_spk1, containing_block_height1, dummy_tx1 = create_dummy_funding_tx()
          614     rpc = DummyJsonRpc([dummy_tx1], [],
          615         {dummy_tx1["blockhash"]: containing_block_height1})
          616     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          617     assert txmonitor.build_address_history([dummy_spk1])
          618     assert len(list(txmonitor.check_for_updated_txes())) == 0
          619     assert len(txmonitor.reorganizable_txes) == 1
          620     dummy_tx1["confirmations"] = 2000
          621     assert len(list(txmonitor.check_for_updated_txes())) == 0
          622     assert len(txmonitor.reorganizable_txes) == 0
          623 
          624 #other possible stuff to test:
          625 #finding confirmed and unconfirmed tx, in that order, then both confirm
          626 #finding unconfirmed and confirmed tx, in that order, then both confirm
          627 
          628 def test_single_tx_no_address_key():
          629     ### same as test_single_tx() but the result of listtransactions has no
          630     ### address field, see the github issue #31
          631     dummy_spk, containing_block_height, dummy_tx = create_dummy_funding_tx()
          632     del dummy_tx["address"]
          633     logger.info("dummy_tx with no address = " + str(dummy_tx))
          634     print("pdummy_tx with no address = " + str(dummy_tx))
          635 
          636     rpc = DummyJsonRpc([dummy_tx], [],
          637         {dummy_tx["blockhash"]: containing_block_height})
          638     txmonitor = TransactionMonitor(rpc, deterministic_wallets, logger)
          639     assert txmonitor.build_address_history([dummy_spk])
          640     assert len(txmonitor.address_history) == 1
          641     assert_address_history_tx(txmonitor.address_history, spk=dummy_spk,
          642         height=containing_block_height, txid=dummy_tx["txid"], subscribed=False)
          643