def test_simulation_xcp(): # fund server for i in range(2): address = lib.get_funding_addresses([ASSET])[ASSET] rawtx = api.create_send(**{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) api.sendrawtransaction(tx_hex=rawtx) # connect clients clients = [] for i in range(2): bob_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=bob_wif)) txid = client.connect(1000000, 65535, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) # server funds deposits cron.run_all() for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made
def connect(asset, quantity, expire_time=1024, delay_time=2): """ Create micropayment connection with hub. Args: asset (str): Asset to exchange in connection. quantity (str): Quantity to be bound in the deposit, this determins the maximum amount that can bet transferred. expire_time (int, default=1024): Time in blocks after which the deposit expires and can be recovered. delay_time (int, default=2): Blocks hub must wait before payout, protects against publish revoked commits. Returns: { "send_deposit_txid": "published bitcoin transaction id", "handle": "handle for created connection" } """ # connect to hub client = Mph(_hub_api()) send_deposit_txid = client.connect(quantity, expire_time=expire_time, asset=asset, delay_time=delay_time) # save to data data = _load_data() data["connections"][client.handle] = client.serialize() _save_data(data) return {"send_deposit_txid": send_deposit_txid, "handle": client.handle}
def test_hub_lacks_funds(server_db): try: auth_wif = util.gen_funded_wif("XCP", 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=auth_wif)) client.connect(1000000, 65535, asset="XCP") cron.fund_deposits() assert False except err.InsufficientFunds: assert True
def test_serialization(): auth_wif = util.gen_funded_wif("XCP", 1000000, 1000000) hub_api = util.MockAPI(auth_wif=auth_wif) client_alpha = Mph(hub_api) serialized_alpha = client_alpha.serialize() client_beta = Mph.deserialize(api=hub_api, data=serialized_alpha) serialized_beta = client_beta.serialize() assert serialized_alpha == serialized_beta
def sync(handle=None): """ Sync payments and recover funds from closed connections. This WILL cost a fee per channnel synced as defined in the hub terms. * Synchronize open connections to send/receive payments. * Recover funds of closed connections. Args: handle (str, default=None): Optionally limit to given handle. Returns: { "connection handle": { "rawtxs": ["of transactions publish while recovering funds"], "received_payments": [ { "payer_handle": "sender handle", "amount": 1337, "token": "provided by sender" } ] } } """ result = {} hub_api = _hub_api() data = _load_data() for _handle, connection_data in copy.deepcopy(data)["connections"].items(): if handle is not None and _handle != handle: continue client = Mph.deserialize(hub_api, connection_data) if client.can_cull(): continue # dont sync closed inactive status = client.get_status() # sync open connections if status["status"] == "open": result[_handle] = { "rawtxs": [], "received_payments": client.sync() } # update closed connections elif status["status"] == "closed": result[_handle] = { "rawtxs": client.update(), "received_payments": [] } data["connections"][client.handle] = client.serialize() _save_data(data) return result
def status(handle=None, verbose=False): """ Get status of connections and wallet. Args: handle (str, default=None): Optionally limit to given handle. verbose (bool, default=False): Optionally show additional information. Returns: { "connections": { "a0b206d1f68edb1aa24084752b5693a9022349dc547fb9952aa510003e93": { "asset": "XCP", "balance": 31337, "status": "open", "ttl": 404 } }, "wallet": { "address": "n2WQGAvnDS1vf7uXToLou6kLxJXRGFHo2b", "balances": { "BTC": 926109330, "XCP": 140982404156 } } } """ data = _load_data() hub_api = _hub_api() result = { "connections": {}, "wallet": { "address": keys.address_from_wif(load_wif()), "balances": balances() } } for _handle, connection_data in data["connections"].items(): if handle is not None and _handle != handle: continue client = Mph.deserialize(hub_api, connection_data) status = client.get_status() if verbose: status["data"] = connection_data result["connections"][_handle] = status else: result["connections"][_handle] = { "asset": status["asset"], "balance": status["balance"], "ttl": status["ttl"], "status": status["status"], "payments_queued": connection_data["payments_queued"] } return result
def connect(asset, quantity, expire_time=1024, delay_time=2): """ Create micropayment connection with hub. Args: asset (str): Asset to exchange in connection. quantity (str): Quantity to be bound in the deposit, this determins the maximum amount that can bet transferred. expire_time (int, default=1024): Time in blocks after which the deposit expires and can be recovered. delay_time (int, default=2): Blocks hub must wait before payout, protects against publish revoked commits. Returns: { "send_deposit_txid": "published bitcoin transaction id", "handle": "handle for created connection" } """ # check if funds available _status = status() _quantity = _status["wallet"]["balances"].get(asset, 0) err_msg = "Insufficient {0}: {1} required, {2} available!" assert _quantity > quantity, err_msg.format(asset, quantity, _quantity) # connect to hub client = Mph(_hub_api()) send_deposit_txid = client.connect(quantity, expire_time=expire_time, asset=asset, delay_time=delay_time) # save to data data = _load_data() data["connections"][client.handle] = client.serialize() _save_data(data) return { "send_deposit_txid": send_deposit_txid, "handle": client.handle }
def connected_clients(): # create asset unsigned_rawtx = api.create_issuance( source=FUNDING_ADDRESS, asset="A7736697071037023001", quantity=100000000 ) signed_rawtx = scripts.sign_deposit( get_txs, FUNDING_WIF, unsigned_rawtx ) api.sendrawtransaction(tx_hex=signed_rawtx) # fund server for i in range(3): address = lib.get_funding_address() for asset in ["XCP", "A7736697071037023001"]: unsigned_rawtx = api.create_send(**{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': asset, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit( get_txs, FUNDING_WIF, unsigned_rawtx ) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients clients = [] # fund XCP clients for i in range(3): wif = util.gen_funded_wif("XCP", 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=wif)) client.connect(1000000, expire_time=42, asset="XCP") clients.append(client) # fund A7736697071037023001 clients for i in range(3): wif = util.gen_funded_wif("A7736697071037023001", 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=wif)) client.connect(1000000, expire_time=42, asset="A7736697071037023001") clients.append(client) cron.fund_deposits() return clients
def test_simulation_xcp(): # fund server for i in range(2): address = lib.get_funding_address() unsigned_rawtx = api.create_send(**{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit( get_txs, FUNDING_WIF, unsigned_rawtx) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients clients = [] for i in range(2): bob_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=bob_wif)) txid = client.connect(1000000, 65535, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) # server funds deposits cron.run_all() for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made
def close(handle): """ Close open connection and settle to blockchain. Args: handle (str): Handle of connection to close. Returns: Commit txid or None if no assets received from hub. """ hub_api = _hub_api() data = _load_data() client = Mph.deserialize(hub_api, data["connections"][handle]) commit_txid = client.close() # FIXME recover now if possible data["connections"][handle] = client.serialize() _save_data(data) return commit_txid
def connected_clients(): # create asset rawtx = api.create_issuance(source=FUNDING_ADDRESS, asset="A7736697071037023001", quantity=100000000) api.sendrawtransaction(tx_hex=rawtx) # fund server for i in range(3): addresses = lib.get_funding_addresses(["XCP", "A7736697071037023001"]) for asset, address in addresses.items(): rawtx = api.create_send( **{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': asset, 'quantity': 1000000, 'regular_dust_size': 1000000 }) api.sendrawtransaction(tx_hex=rawtx) # connect clients clients = [] # fund XCP clients for i in range(3): bob_wif = util.gen_funded_wif("XCP", 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=bob_wif)) client.connect(1000000, 42, asset="XCP") clients.append(client) # fund A7736697071037023001 clients for i in range(3): bob_wif = util.gen_funded_wif("A7736697071037023001", 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=bob_wif)) client.connect(1000000, 42, asset="A7736697071037023001") clients.append(client) cron.fund_deposits() return clients
def queuepayment(source, destination, quantity, token=None): """ Queue micropayment channel send (sent on sync). Args: source (str): Handle of connection to send funds from. destination (str): Handle of connection to receive funds. quantity (int): Quantity of channel asset to transfer. token (str, default=None): Optional token payee will receive with the payment. Returns: Provided token or generated token if None given. """ hub_api = _hub_api() data = _load_data() client = Mph.deserialize(hub_api, data["connections"][source]) # FIXME check dest can receive payment result = client.micro_send(destination, quantity, token=token) data["connections"][source] = client.serialize() _save_data(data) return result
def cull(handle=None): """ Removes closed channels if all funds have been recovered. Args: handle (str): Optional handle of specific connection to be cull. Returns: List of with handles of culled connections. """ data = _load_data() hub_api = _hub_api() culled = [] for _handle, connection_data in copy.deepcopy(data)["connections"].items(): if handle is not None and _handle != handle: continue client = Mph.deserialize(hub_api, connection_data) if client.can_cull(): culled.append(_handle) del data["connections"][_handle] _save_data(data) return culled
def test_standard_usage(server_db): # fund server for i in range(4): address = lib.get_funding_address() unsigned_rawtx = api.create_send(**{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit( get_txs, FUNDING_WIF, unsigned_rawtx ) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients status = api.mph_status() assert len(status["connections"]) == 0 clients = [] for i in range(4): auth_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=auth_wif)) txid = client.connect(1000000, 42, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) assert len(api.mph_status()["connections"]) == 4 # server funds deposits assert len(cron.fund_deposits()) == 4 assert len(cron.fund_deposits()) == 0 for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made # before status alpha, beta, gamma, delta = clients alpha_before_status = alpha.get_status() beta_before_status = beta.get_status() gamma_before_status = gamma.get_status() # can send multiple payments alpha.micro_send(beta.handle, 5, "0000") alpha.micro_send(gamma.handle, 6, "0001") assert alpha.sync() == [] assert beta.sync() == [{ "payer_handle": alpha.handle, "amount": 5, "token": "0000" }] assert gamma.sync(), [{ "payer_handle": alpha.handle, "amount": 6, "token": "0001" }] # send more back, commits are revoked to maximize liquidity beta.micro_send(alpha.handle, 42, "0003") assert beta.sync() == [] assert alpha.sync() == [{ "payer_handle": beta.handle, "amount": 42, "token": "0003" }] # multiple syncs/commtis from single client alpha.micro_send(beta.handle, 1, "0004") assert alpha.sync() == [] # get after status alpha_after_status = alpha.get_status() beta_after_status = beta.get_status() gamma_after_status = gamma.get_status() # compare statuses alpha_after_status["send_balance"] == alpha_before_status[ "send_balance"] + 27 beta_after_status["send_balance"] == beta_before_status[ "send_balance"] - 40 gamma_after_status["send_balance"] == gamma_before_status[ "send_balance"] + 5 # client | c2h active | h2c active # -------+------------+----------- # alpha | 1 commit | 1 commit # beta | 1 commit | 0 commit # gamma | 0 commit | 1 commit # delta | 0 commit | 0 commit assert len(alpha.c2h_state["commits_active"]) == 1 assert len(alpha.h2c_state["commits_active"]) == 1 assert len(beta.c2h_state["commits_active"]) == 1 assert len(beta.h2c_state["commits_active"]) == 0 assert len(gamma.c2h_state["commits_active"]) == 0 assert len(gamma.h2c_state["commits_active"]) == 1 assert len(delta.c2h_state["commits_active"]) == 0 assert len(delta.h2c_state["commits_active"]) == 0 # close alpha payment channel # | h2c | c2h | # -------+-----+-----+ # commit | X | X | # payout | X | X | # change | X | X | assert len(api.mph_status()["connections"]) == 4 assert alpha.close() is not None # H2C COMMIT TX assert len(api.mph_status()["connections"]) == 3 assert _check_rawtxs(alpha.update()) # h2c payout delay not yet passed util_test.create_next_block(server_db) # let payout delay pass assert _check_rawtxs(alpha.update(), payout=1) # H2C PAYOUT TX # H2C CHANGE TX, C2H COMMIT TX assert _check_rawtxs(cron.run_all(), change=1, commit=1) util_test.create_next_block(server_db) # let c2h payout delay pass assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX assert _check_rawtxs(alpha.update(), change=1) # C2H CHANGE TX # close beta payment channel # recover | h2c | c2h | # --------+-----+-----+ # commit | - | X | # payout | - | X | # change | X | X | assert len(api.mph_status()["connections"]) == 3 assert beta.close() is None assert len(api.mph_status()["connections"]) == 2 # H2C CHANGE TX, C2H COMMIT TX assert _check_rawtxs(cron.run_all(), change=1, commit=1) util_test.create_next_block(server_db) # let payout delay pass assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX assert _check_rawtxs(beta.update(), change=1) # C2H CHANGE TX # close gamma payment channel # recover | h2c | c2h | # --------+-----+-----+ # commit | X | - | # payout | X | - | # change | X | X | assert len(api.mph_status()["connections"]) == 2 assert gamma.close() is not None # H2C COMMIT TX assert len(api.mph_status()["connections"]) == 1 assert _check_rawtxs(gamma.update(), change=1) # C2H CHANGE TX assert _check_rawtxs(gamma.update(), payout=1) # H2C PAYOUT TX assert _check_rawtxs(cron.run_all(), change=1) # H2C CHANGE TX # close delta payment channel # recover | h2c | c2h | # --------+-----+-----+ # commit | - | - | # payout | - | - | # change | X | X | assert len(api.mph_status()["connections"]) == 1 assert delta.close() is None assert len(api.mph_status()["connections"]) == 0 assert _check_rawtxs(delta.update(), change=1) # C2H CHANGE TX assert _check_rawtxs(cron.run_all(), change=1) # H2C CHANGE TX _assert_states_synced(alpha.handle, alpha.c2h_state, alpha.h2c_state) _assert_states_synced(beta.handle, beta.c2h_state, beta.h2c_state) _assert_states_synced(gamma.handle, gamma.c2h_state, gamma.h2c_state) _assert_states_synced(delta.handle, delta.c2h_state, delta.h2c_state)
def test_user_doesnt_publish_commit(server_db): # fund server for i in range(2): address = lib.get_funding_address() unsigned_rawtx = api.create_send(**{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit(get_txs, FUNDING_WIF, unsigned_rawtx) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients assert len(api.mph_status()["connections"]) == 0 clients = [] for i in range(2): auth_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=auth_wif)) txid = client.connect(1000000, 42, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) assert len(api.mph_status()["connections"]) == 2 # server funds deposits assert len(cron.fund_deposits()) == 2 assert len(cron.fund_deposits()) == 0 for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made # before status alpha, beta = clients # send funds to beta alpha.micro_send(beta.handle, 42) alpha.sync() alpha_status = alpha.get_status() assert alpha_status["send_balance"] == 1000000 - 42 - 1 # beta received funds beta.sync() beta_status = beta.get_status() assert beta_status["send_balance"] == 1000000 + 42 - 1 # return some funds to alpha beta.micro_send(alpha.handle, 13) beta.sync() beta_status = beta.get_status() assert beta_status["send_balance"] == 1000000 + 42 - 1 - 13 - 1 # alpha received funds alpha.sync() alpha_status = alpha.get_status() assert alpha_status["send_balance"] == 1000000 - 42 - 1 + 13 - 1 # beta settles assert len(api.mph_status()["connections"]) == 2 assert beta.close() is not None # H2C COMMIT TX assert len(api.mph_status()["connections"]) == 1 assert _check_rawtxs(beta.update()) # h2c payout delay not yet passed util_test.create_next_block(server_db) # let payout delay pass assert _check_rawtxs(beta.update(), payout=1) # H2C PAYOUT TX # H2C CHANGE TX, C2H COMMIT TX assert _check_rawtxs(cron.run_all(), change=1, commit=1) util_test.create_next_block(server_db) # let c2h payout delay pass assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX assert _check_rawtxs(beta.update(), change=1) # C2H CHANGE TX # let channel expire for i in range(50): util_test.create_next_block(server_db) # hub closes alice channel # | h2c | c2h | # -------+-----+-----+ # commit | - | X | # payout | - | X | # change | - | - | # expire | X | - | # C2H COMMIT TX, H2C EXPIRE TX assert _check_rawtxs(cron.run_all(), commit=1, expire=1) assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX
def test_user_doesnt_publish_commit(server_db): # fund server for i in range(2): address = lib.get_funding_addresses([ASSET])[ASSET] unsigned_rawtx = api.create_send( **{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit(get_tx, FUNDING_WIF, unsigned_rawtx) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients assert len(api.mph_status()["connections"]) == 0 clients = [] for i in range(2): auth_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=auth_wif)) txid = client.connect(1000000, 42, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) assert len(api.mph_status()["connections"]) == 2 # server funds deposits assert len(cron.fund_deposits()) == 2 assert len(cron.fund_deposits()) == 0 for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made # before status alpha, beta = clients # send funds to beta alpha.micro_send(beta.handle, 42) alpha.sync() alpha_status = alpha.get_status() assert alpha_status["send_balance"] == 1000000 - 42 - 1 # beta received funds beta.sync() beta_status = beta.get_status() assert beta_status["send_balance"] == 1000000 + 42 - 1 # return some funds to alpha beta.micro_send(alpha.handle, 13) beta.sync() beta_status = beta.get_status() assert beta_status["send_balance"] == 1000000 + 42 - 1 - 13 - 1 # alpha received funds alpha.sync() alpha_status = alpha.get_status() assert alpha_status["send_balance"] == 1000000 - 42 - 1 + 13 - 1 # beta settles assert len(api.mph_status()["connections"]) == 2 assert beta.close() is not None # H2C COMMIT TX assert len(api.mph_status()["connections"]) == 1 assert _check_rawtxs(beta.update()) # h2c payout delay not yet passed util_test.create_next_block(server_db) # let payout delay pass assert _check_rawtxs(beta.update(), payout=1) # H2C PAYOUT TX # H2C CHANGE TX, C2H COMMIT TX assert _check_rawtxs(cron.run_all(), change=1, commit=1) util_test.create_next_block(server_db) # let c2h payout delay pass assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX assert _check_rawtxs(beta.update(), change=1) # C2H CHANGE TX # let channel expire for i in range(50): util_test.create_next_block(server_db) # hub closes alice channel # | h2c | c2h | # -------+-----+-----+ # commit | - | X | # payout | - | X | # change | - | - | # expire | X | - | # C2H COMMIT TX, H2C EXPIRE TX assert _check_rawtxs(cron.run_all(), commit=1, expire=1) assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX
def test_standard_usage(server_db): # fund server for i in range(4): address = lib.get_funding_addresses([ASSET])[ASSET] unsigned_rawtx = api.create_send( **{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit(get_tx, FUNDING_WIF, unsigned_rawtx) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients assert len(api.mph_status()["connections"]) == 0 clients = [] for i in range(4): auth_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=auth_wif)) txid = client.connect(1000000, 42, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) assert len(api.mph_status()["connections"]) == 4 # server funds deposits assert len(cron.fund_deposits()) == 4 assert len(cron.fund_deposits()) == 0 for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made # before status alpha, beta, gamma, delta = clients alpha_before_status = alpha.get_status() beta_before_status = beta.get_status() gamma_before_status = gamma.get_status() # can send multiple payments alpha.micro_send(beta.handle, 5, "0000") alpha.micro_send(gamma.handle, 6, "0001") assert alpha.sync() == [] assert beta.sync() == [{ "payer_handle": alpha.handle, "amount": 5, "token": "0000" }] assert gamma.sync(), [{ "payer_handle": alpha.handle, "amount": 6, "token": "0001" }] # send more back, commits are revoked to maximize liquidity beta.micro_send(alpha.handle, 42, "0003") assert beta.sync() == [] assert alpha.sync() == [{ "payer_handle": beta.handle, "amount": 42, "token": "0003" }] # multiple syncs/commtis from single client alpha.micro_send(beta.handle, 1, "0004") assert alpha.sync() == [] # get after status alpha_after_status = alpha.get_status() beta_after_status = beta.get_status() gamma_after_status = gamma.get_status() # compare statuses alpha_after_status[ "send_balance"] == alpha_before_status["send_balance"] + 27 beta_after_status[ "send_balance"] == beta_before_status["send_balance"] - 40 gamma_after_status[ "send_balance"] == gamma_before_status["send_balance"] + 5 # client | c2h active | h2c active # -------+------------+----------- # alpha | 1 commit | 1 commit # beta | 1 commit | 0 commit # gamma | 0 commit | 1 commit # delta | 0 commit | 0 commit assert len(alpha.c2h_state["commits_active"]) == 1 assert len(alpha.h2c_state["commits_active"]) == 1 assert len(beta.c2h_state["commits_active"]) == 1 assert len(beta.h2c_state["commits_active"]) == 0 assert len(gamma.c2h_state["commits_active"]) == 0 assert len(gamma.h2c_state["commits_active"]) == 1 assert len(delta.c2h_state["commits_active"]) == 0 assert len(delta.h2c_state["commits_active"]) == 0 # close alpha payment channel # | h2c | c2h | # -------+-----+-----+ # commit | X | X | # payout | X | X | # change | X | X | assert len(api.mph_status()["connections"]) == 4 assert alpha.close() is not None # H2C COMMIT TX assert len(api.mph_status()["connections"]) == 3 assert _check_rawtxs(alpha.update()) # h2c payout delay not yet passed util_test.create_next_block(server_db) # let payout delay pass assert _check_rawtxs(alpha.update(), payout=1) # H2C PAYOUT TX # H2C CHANGE TX, C2H COMMIT TX assert _check_rawtxs(cron.run_all(), change=1, commit=1) util_test.create_next_block(server_db) # let c2h payout delay pass assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX assert _check_rawtxs(alpha.update(), change=1) # C2H CHANGE TX # close beta payment channel # recover | h2c | c2h | # --------+-----+-----+ # commit | - | X | # payout | - | X | # change | X | X | assert len(api.mph_status()["connections"]) == 3 assert beta.close() is None assert len(api.mph_status()["connections"]) == 2 # H2C CHANGE TX, C2H COMMIT TX assert _check_rawtxs(cron.run_all(), change=1, commit=1) util_test.create_next_block(server_db) # let payout delay pass assert _check_rawtxs(cron.run_all(), payout=1) # C2H PAYOUT TX assert _check_rawtxs(beta.update(), change=1) # C2H CHANGE TX # close gamma payment channel # recover | h2c | c2h | # --------+-----+-----+ # commit | X | - | # payout | X | - | # change | X | X | assert len(api.mph_status()["connections"]) == 2 assert gamma.close() is not None # H2C COMMIT TX assert len(api.mph_status()["connections"]) == 1 assert _check_rawtxs(gamma.update(), change=1) # C2H CHANGE TX assert _check_rawtxs(gamma.update(), payout=1) # H2C PAYOUT TX assert _check_rawtxs(cron.run_all(), change=1) # H2C CHANGE TX # close delta payment channel # recover | h2c | c2h | # --------+-----+-----+ # commit | - | - | # payout | - | - | # change | X | X | assert len(api.mph_status()["connections"]) == 1 assert delta.close() is None assert len(api.mph_status()["connections"]) == 0 assert _check_rawtxs(delta.update(), change=1) # C2H CHANGE TX assert _check_rawtxs(cron.run_all(), change=1) # H2C CHANGE TX _assert_states_synced(alpha.handle, alpha.c2h_state, alpha.h2c_state) _assert_states_synced(beta.handle, beta.c2h_state, beta.h2c_state) _assert_states_synced(gamma.handle, gamma.c2h_state, gamma.h2c_state) _assert_states_synced(delta.handle, delta.c2h_state, delta.h2c_state)
def test_standard_usage(server_db): # fund server for i in range(4): address = lib.get_funding_address() unsigned_rawtx = api.create_send( **{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit(get_txs, FUNDING_WIF, unsigned_rawtx) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients assert len(api.mph_status()["connections"]) == 0 clients = [] for i in range(4): auth_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=auth_wif)) txid = client.connect(1000000, 42, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) assert len(api.mph_status()["connections"]) == 4 # server funds deposits assert len(cron.fund_deposits()) == 4 assert len(cron.fund_deposits()) == 0 for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made # before status alpha, beta, gamma, delta = clients alpha_before_status = alpha.get_status() beta_before_status = beta.get_status() gamma_before_status = gamma.get_status() # can send multiple payments alpha.micro_send(beta.handle, 5, "0000") alpha.micro_send(gamma.handle, 6, "0001") assert alpha.sync() == [] assert beta.sync() == [{ "payer_handle": alpha.handle, "amount": 5, "token": "0000" }] assert gamma.sync(), [{ "payer_handle": alpha.handle, "amount": 6, "token": "0001" }] # send more back, commits are revoked to maximize liquidity beta.micro_send(alpha.handle, 42, "0003") assert beta.sync() == [] assert alpha.sync() == [{ "payer_handle": beta.handle, "amount": 42, "token": "0003" }] # multiple syncs/commtis from single client alpha.micro_send(beta.handle, 1, "0004") assert alpha.sync() == [] # get after status alpha_after_status = alpha.get_status() beta_after_status = beta.get_status() gamma_after_status = gamma.get_status() # compare statuses alpha_after_status[ "send_balance"] == alpha_before_status["send_balance"] + 27 beta_after_status[ "send_balance"] == beta_before_status["send_balance"] - 40 gamma_after_status[ "send_balance"] == gamma_before_status["send_balance"] + 5 # client | c2h active | h2c active # -------+------------+----------- # alpha | 1 commit | 1 commit # beta | 1 commit | 0 commit # gamma | 0 commit | 1 commit # delta | 0 commit | 0 commit assert len(alpha.c2h_state["commits_active"]) == 1 assert len(alpha.h2c_state["commits_active"]) == 1 assert len(beta.c2h_state["commits_active"]) == 1 assert len(beta.h2c_state["commits_active"]) == 0 assert len(gamma.c2h_state["commits_active"]) == 0 assert len(gamma.h2c_state["commits_active"]) == 1 assert len(delta.c2h_state["commits_active"]) == 0 assert len(delta.h2c_state["commits_active"]) == 0
def test_standard_usage(server_db): # fund server for i in range(4): address = lib.get_funding_address() unsigned_rawtx = api.create_send(**{ 'source': FUNDING_ADDRESS, 'destination': address, 'asset': ASSET, 'quantity': 1000000, 'regular_dust_size': 1000000 }) signed_rawtx = scripts.sign_deposit( get_txs, FUNDING_WIF, unsigned_rawtx ) api.sendrawtransaction(tx_hex=signed_rawtx) # connect clients assert len(api.mph_status()["connections"]) == 0 clients = [] for i in range(4): auth_wif = util.gen_funded_wif(ASSET, 1000000, 1000000) client = Mph(util.MockAPI(auth_wif=auth_wif)) txid = client.connect(1000000, 42, asset=ASSET) assert txid is not None status = client.get_status() assert status["send_balance"] == 1000000 assert status["send_deposit_ttl"] is not None assert status["recv_deposit_ttl"] is None # hub deposit not yet made clients.append(client) assert len(api.mph_status()["connections"]) == 4 # server funds deposits assert len(cron.fund_deposits()) == 4 assert len(cron.fund_deposits()) == 0 for client in clients: status = client.get_status() assert status["recv_deposit_ttl"] is not None # hub deposit now made # before status alpha, beta, gamma, delta = clients alpha_before_status = alpha.get_status() beta_before_status = beta.get_status() gamma_before_status = gamma.get_status() # can send multiple payments alpha.micro_send(beta.handle, 5, "0000") alpha.micro_send(gamma.handle, 6, "0001") assert alpha.sync() == [] assert beta.sync() == [{ "payer_handle": alpha.handle, "amount": 5, "token": "0000" }] assert gamma.sync(), [{ "payer_handle": alpha.handle, "amount": 6, "token": "0001" }] # send more back, commits are revoked to maximize liquidity beta.micro_send(alpha.handle, 42, "0003") assert beta.sync() == [] assert alpha.sync() == [{ "payer_handle": beta.handle, "amount": 42, "token": "0003" }] # multiple syncs/commtis from single client alpha.micro_send(beta.handle, 1, "0004") assert alpha.sync() == [] # get after status alpha_after_status = alpha.get_status() beta_after_status = beta.get_status() gamma_after_status = gamma.get_status() # compare statuses alpha_after_status["send_balance"] == alpha_before_status[ "send_balance"] + 27 beta_after_status["send_balance"] == beta_before_status[ "send_balance"] - 40 gamma_after_status["send_balance"] == gamma_before_status[ "send_balance"] + 5 # client | c2h active | h2c active # -------+------------+----------- # alpha | 1 commit | 1 commit # beta | 1 commit | 0 commit # gamma | 0 commit | 1 commit # delta | 0 commit | 0 commit assert len(alpha.c2h_state["commits_active"]) == 1 assert len(alpha.h2c_state["commits_active"]) == 1 assert len(beta.c2h_state["commits_active"]) == 1 assert len(beta.h2c_state["commits_active"]) == 0 assert len(gamma.c2h_state["commits_active"]) == 0 assert len(gamma.h2c_state["commits_active"]) == 1 assert len(delta.c2h_state["commits_active"]) == 0 assert len(delta.h2c_state["commits_active"]) == 0