def test_saves_state_revoked(connected_clients): alice, bob, charlie, david, eric, fred = connected_clients alice.micro_send(bob.handle, 5) alice.sync() # load alice c2h_state connection = db.hub_connection(handle=alice.handle) c2h_state = db.load_channel_state( connection["c2h_channel_id"], connection["asset"] ) # revoke c2h commit revoke_hashes = api.mpc_revoke_hashes_until(state=c2h_state, quantity=0) secrets = [lib.get_secret(h) for h in revoke_hashes] updated_c2h_state = api.mpc_revoke_all(state=c2h_state, secrets=secrets) assert len(updated_c2h_state["commits_active"]) == 0 assert len(updated_c2h_state["commits_revoked"]) == 1 # save updated c2h state db.save_channel_state( connection["c2h_channel_id"], updated_c2h_state, unnotified_revoke_secrets=secrets ) # load updated c2h state connection = db.hub_connection(handle=alice.handle) saved_c2h_state = db.load_channel_state( connection["c2h_channel_id"], connection["asset"] ) assert len(saved_c2h_state["commits_active"]) == 0 assert len(saved_c2h_state["commits_revoked"]) == 1 assert updated_c2h_state == saved_c2h_state
def close_connection(handle, h2c_spend_secret=None): cursor = sql.get_cursor() hub_connection = db.hub_connection(handle=handle, cursor=cursor) # save secret if given and not already known if h2c_spend_secret is not None: secret_hash = util.hash160hex(h2c_spend_secret) if not get_secret(secret_hash): db.add_secret(secret_value=h2c_spend_secret, secret_hash=secret_hash, cursor=cursor) # close connection if not already done if not hub_connection["closed"]: db.set_connection_closed(handle=handle, cursor=cursor) # get c2h spend secret if no commits for channel c2h_spend_secret = None c2h_state = db.load_channel_state(hub_connection["c2h_channel_id"], hub_connection["asset"], cursor=cursor) if len(c2h_state["commits_active"]) == 0: c2h_spend_secret_hash = scripts.get_deposit_spend_secret_hash( c2h_state["deposit_script"] ) c2h_spend_secret = get_secret(c2h_spend_secret_hash) hub_wif = load_wif() return ({"spend_secret": c2h_spend_secret}, hub_wif)
def sync_hub_connection(handle, next_revoke_secret_hash, payments, commit, revokes): cursor = sql.get_cursor() hub_connection = db.hub_connection(handle=handle, cursor=cursor) _update_channel_state(hub_connection, commit, revokes, cursor) _process_payments(handle, payments, hub_connection, cursor) _balance_channel(handle, cursor) next_revoke_secret = create_secret() # create next spend secret # load unnotified c2h_id = hub_connection["c2h_channel_id"] h2c_id = hub_connection["h2c_channel_id"] h2c_commit = db.unnotified_commit(channel_id=h2c_id) c2h_revokes = db.unnotified_revokes(channel_id=c2h_id) receive_payments = db.unnotified_payments(payee_handle=handle) # save sync data h2c_commit_id = None if h2c_commit: h2c_commit_id = h2c_commit.pop("id") _save_sync_data(cursor, handle, next_revoke_secret_hash, receive_payments, h2c_commit_id, c2h_revokes, c2h_id, next_revoke_secret) hub_key = db.channel_payer_key(id=h2c_id) return ({ "receive": receive_payments, "commit": h2c_commit, "revokes": [r["revoke_secret"] for r in c2h_revokes], "next_revoke_secret_hash": next_revoke_secret["secret_hash"] }, hub_key["wif"])
def close_connection(handle, h2c_spend_secret=None): cursor = sql.get_cursor() hub_connection = db.hub_connection(handle=handle, cursor=cursor) # save secret if given and not already known if h2c_spend_secret is not None: secret_hash = util.hash160hex(h2c_spend_secret) if not get_secret(secret_hash): db.add_secret(secret_value=h2c_spend_secret, secret_hash=secret_hash, cursor=cursor) # close connection if not already done if not hub_connection["closed"]: db.set_connection_closed(handle=handle, cursor=cursor) # get c2h spend secret if no commits for channel c2h_spend_secret = None c2h_state = db.load_channel_state(hub_connection["c2h_channel_id"], hub_connection["asset"], cursor=cursor) if len(c2h_state["commits_active"]) == 0: c2h_spend_secret_hash = scripts.get_deposit_spend_secret_hash( c2h_state["deposit_script"]) c2h_spend_secret = get_secret(c2h_spend_secret_hash) hub_key = db.channel_payer_key(id=hub_connection["h2c_channel_id"]) return ({"spend_secret": c2h_spend_secret}, hub_key["wif"])
def _assert_states_synced(handle, c2h_state, h2c_state): connection = db.hub_connection(handle=handle) db_h2c_state = db.load_channel_state(connection["h2c_channel_id"], connection["asset"]) db_c2h_state = db.load_channel_state(connection["c2h_channel_id"], connection["asset"]) assert c2h_state["asset"] == db_c2h_state["asset"] assert h2c_state["asset"] == db_h2c_state["asset"] assert c2h_state["deposit_script"] == db_c2h_state["deposit_script"] assert h2c_state["deposit_script"] == db_h2c_state["deposit_script"] c2h_scripts = [x["script"] for x in c2h_state["commits_active"]] db_c2h_scripts = [x["script"] for x in db_c2h_state["commits_active"]] assert c2h_scripts == db_c2h_scripts h2c_scripts = [x["script"] for x in h2c_state["commits_active"]] db_h2c_scripts = [x["script"] for x in db_h2c_state["commits_active"]] assert h2c_scripts == db_h2c_scripts
def _load_incomplete_connection(handle, c2h_deposit_script_hex): client_pubkey = scripts.get_deposit_payer_pubkey(c2h_deposit_script_hex) hub_pubkey = scripts.get_deposit_payee_pubkey(c2h_deposit_script_hex) expire_time = scripts.get_deposit_expire_time(c2h_deposit_script_hex) hub_conn = db.hub_connection(handle=handle) assert(hub_conn is not None) assert(not hub_conn["complete"]) h2c = db.micropayment_channel(id=hub_conn["h2c_channel_id"]) assert(h2c["payer_pubkey"] == hub_pubkey) assert(h2c["payee_pubkey"] == client_pubkey) c2h = db.micropayment_channel(id=hub_conn["c2h_channel_id"]) assert(c2h["payer_pubkey"] == client_pubkey) assert(c2h["payee_pubkey"] == hub_pubkey) hub_wif = get_wif(hub_pubkey) return hub_conn, h2c, expire_time, hub_wif
def _load_incomplete_connection(handle, c2h_deposit_script_hex): client_pubkey = scripts.get_deposit_payer_pubkey(c2h_deposit_script_hex) hub_pubkey = scripts.get_deposit_payee_pubkey(c2h_deposit_script_hex) expire_time = scripts.get_deposit_expire_time(c2h_deposit_script_hex) hub_conn = db.hub_connection(handle=handle) assert (hub_conn is not None) assert (not hub_conn["complete"]) h2c = db.micropayment_channel(id=hub_conn["h2c_channel_id"]) assert (h2c["payer_pubkey"] == hub_pubkey) assert (h2c["payee_pubkey"] == client_pubkey) c2h = db.micropayment_channel(id=hub_conn["c2h_channel_id"]) assert (c2h["payer_pubkey"] == client_pubkey) assert (c2h["payee_pubkey"] == hub_pubkey) hub_key = db.key(pubkey=hub_pubkey) return hub_conn, h2c, expire_time, hub_key
def sync_hub_connection(handle, next_revoke_secret_hash, payments, commit, revokes): cursor = sql.get_cursor() hub_connection = db.hub_connection(handle=handle, cursor=cursor) _update_channel_state(hub_connection, commit, revokes, cursor) _process_payments(handle, payments, hub_connection, cursor) _balance_channel(handle, cursor) next_revoke_secret = create_secret() # create next spend secret # load unnotified c2h_id = hub_connection["c2h_channel_id"] h2c_id = hub_connection["h2c_channel_id"] h2c_commit = db.unnotified_commit(channel_id=h2c_id) c2h_revokes = db.unnotified_revokes(channel_id=c2h_id) receive_payments = db.unnotified_payments(payee_handle=handle) # save sync data h2c_commit_id = None if h2c_commit: h2c_commit_id = h2c_commit.pop("id") _save_sync_data( cursor, handle, next_revoke_secret_hash, receive_payments, h2c_commit_id, c2h_revokes, c2h_id, next_revoke_secret ) hub_wif = load_wif() return ( { "receive": receive_payments, "commit": h2c_commit, "revokes": [r["revoke_secret"] for r in c2h_revokes], "next_revoke_secret_hash": next_revoke_secret["secret_hash"] }, hub_wif )
def load_connection_data(handle, new_c2h_commit=None, new_h2c_revokes=None, cursor=None): from picopayments_hub import api # TODO this is getting dangerous, used in lib and verify, split it up! # connection data connection = db.hub_connection(handle=handle, cursor=cursor) if not connection: raise err.HandleNotFound(handle) asset = connection["asset"] terms = db.terms(id=connection["terms_id"], cursor=cursor) # h2c data h2c_state = db.load_channel_state( connection["h2c_channel_id"], connection["asset"], cursor=cursor ) if new_h2c_revokes is not None: h2c_state = api.mpc_revoke_all(state=h2c_state, secrets=new_h2c_revokes) h2c_deposit_address = deposit_address(h2c_state) h2c_transferred = get_transferred_quantity(h2c_state) h2c_deposit = get_balances(h2c_deposit_address, [asset])[asset] # TODO remove now impossable unnotified commit? h2c_unnotified_commit = db.unnotified_commit( channel_id=connection["h2c_channel_id"], cursor=cursor ) # c2h data c2h_state = db.load_channel_state( connection["c2h_channel_id"], connection["asset"], cursor=cursor ) if new_c2h_commit is not None: c2h_state = api.mpc_add_commit( state=c2h_state, commit_rawtx=new_c2h_commit["rawtx"], commit_script=new_c2h_commit["script"] ) c2h_transferred = get_transferred_quantity(c2h_state) # payments send_payments_sum = db.send_payments_sum(handle=handle, cursor=cursor) recv_payments_sum = db.recv_payments_sum(handle=handle, cursor=cursor) payments_sum = recv_payments_sum - send_payments_sum # sendable (what this channel can send to another) sendable_amount = c2h_transferred + payments_sum - h2c_transferred assert sendable_amount >= 0 # receivable (what this channel can receive from another) receivable_amount = h2c_deposit + c2h_transferred - payments_sum assert receivable_amount >= 0 return { "connection": connection, "h2c_state": h2c_state, "h2c_expired": is_expired(h2c_state, etc.expire_clearance), "c2h_state": c2h_state, "c2h_expired": is_expired(c2h_state, etc.expire_clearance), "h2c_unnotified_commit": h2c_unnotified_commit, "sendable_amount": sendable_amount, "receivable_amount": receivable_amount, "terms": terms, }
def hub_connection(handle): validate.is_hex(handle) connection = db.hub_connection(handle=handle) if not connection: raise err.HandleNotFound(handle) return connection
def load_connection_data(handle, new_c2h_commit=None, new_h2c_revokes=None, cursor=None): from picopayments_hub import api # FIXME this is getting dangerous, used in lib and verify, split it up! # connection data connection = db.hub_connection(handle=handle, cursor=cursor) if not connection: raise err.HandleNotFound(handle) asset = connection["asset"] terms = db.terms(id=connection["terms_id"], cursor=cursor) # h2c data h2c_state = db.load_channel_state(connection["h2c_channel_id"], connection["asset"], cursor=cursor) if new_h2c_revokes is not None: h2c_state = api.mpc_revoke_all(state=h2c_state, secrets=new_h2c_revokes) h2c_deposit_address = deposit_address(h2c_state) h2c_transferred = get_transferred_quantity(h2c_state) h2c_deposit = get_balances(h2c_deposit_address, [asset])[asset] h2c_unnotified_commit = db.unnotified_commit( channel_id=connection["h2c_channel_id"], cursor=cursor) # c2h data c2h_state = db.load_channel_state(connection["c2h_channel_id"], connection["asset"], cursor=cursor) if new_c2h_commit is not None: c2h_state = api.mpc_add_commit(state=c2h_state, commit_rawtx=new_c2h_commit["rawtx"], commit_script=new_c2h_commit["script"]) c2h_transferred = get_transferred_quantity(c2h_state) # payments send_payments_sum = db.send_payments_sum(handle=handle, cursor=cursor) recv_payments_sum = db.recv_payments_sum(handle=handle, cursor=cursor) payments_sum = recv_payments_sum - send_payments_sum # sendable (what this channel can send to another) sendable_amount = c2h_transferred + payments_sum - h2c_transferred assert sendable_amount >= 0 # receivable (what this channel can receive from another) receivable_amount = h2c_deposit + c2h_transferred - payments_sum assert receivable_amount >= 0 return { "connection": connection, "h2c_state": h2c_state, "h2c_expired": is_expired(h2c_state, etc.expire_clearance), "c2h_state": c2h_state, "c2h_expired": is_expired(c2h_state, etc.expire_clearance), "h2c_unnotified_commit": h2c_unnotified_commit, # FIXME remove "sendable_amount": sendable_amount, "receivable_amount": receivable_amount, "terms": terms, }