def test_events_for_close(): """ Channel must be closed when the unsafe region is reached and the secret is known. """ amount = 3 expire = 10 initiator = factories.HOP1 our_address = factories.ADDR secret = factories.UNIT_SECRET from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, secret=secret, ) safe_to_wait = expire - from_route.reveal_timeout - 1 unsafe_to_wait = expire - from_route.reveal_timeout state = TargetState( our_address, from_route, from_transfer, block_number=safe_to_wait, ) events = target.events_for_close(state) assert not events state.block_number = unsafe_to_wait events = target.events_for_close(state) assert events assert isinstance(events[0], ContractSendChannelClose) assert from_transfer.secret is not None assert events[0].channel_address == from_route.channel_address
def test_events_for_close_secret_unknown(): """ Channel must not be closed when the unsafe region is reached and the secret is not known. """ amount = 3 expire = 10 initiator = factories.HOP1 our_address = factories.ADDR from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) state = TargetState( our_address, from_route, from_transfer, block_number=expire, ) events = target.events_for_close(state) assert not events events = target.events_for_close(state) assert not events assert from_transfer.secret is None
def test_no_valid_routes(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT - 1), factories.make_route(factories.HOP3, available_balance=1), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch( init_state_change, ) assert mediator_state_machine.current_state is None assert len(events) == 1 assert isinstance(events[0], SendRefundTransfer)
def test_no_valid_routes(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT - 1), factories.make_route(factories.HOP3, available_balance=1), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch( init_state_change, ) assert mediator_state_machine.current_state is None assert len(events) == 1 assert isinstance(events[0], SendRefundTransfer)
def test_handle_inittarget(): """ Init transfer must send a secret request if the expiration is valid. """ block_number = 1 amount = 3 expire = factories.UNIT_REVEAL_TIMEOUT + block_number + 1 initiator = factories.HOP1 from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) state_change = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) iteration = target.handle_inittarget(state_change) events = iteration.events assert isinstance(events[0], SendSecretRequest) assert events[0].identifier == from_transfer.identifier assert events[0].amount == from_transfer.amount assert events[0].hashlock == from_transfer.hashlock assert events[0].receiver == initiator
def test_events_for_close(): """ Channel must be closed when the unsafe region is reached and the secret is known. """ amount = 3 expire = 10 initiator = factories.HOP1 our_address = factories.ADDR secret = factories.UNIT_SECRET from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, secret=secret, ) safe_to_wait = expire - from_route.reveal_timeout - 1 unsafe_to_wait = expire - from_route.reveal_timeout state = TargetState( our_address, from_route, from_transfer, block_number=safe_to_wait, ) events = target.events_for_close(state) assert not events state.block_number = unsafe_to_wait events = target.events_for_close(state) assert events assert isinstance(events[0], ContractSendChannelClose) assert from_transfer.secret is not None assert events[0].channel_address == from_route.channel_address
def test_handle_inittarget(): """ Init transfer must send a secret request if the expiration is valid. """ block_number = 1 amount = 3 expire = factories.UNIT_REVEAL_TIMEOUT + block_number + 1 initiator = factories.HOP1 from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) state_change = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) iteration = target.handle_inittarget(state_change) events = iteration.events assert isinstance(events[0], SendSecretRequest) assert events[0].identifier == from_transfer.identifier assert events[0].amount == from_transfer.amount assert events[0].hashlock == from_transfer.hashlock assert events[0].receiver == initiator
def test_events_for_close_secret_unknown(): """ Channel must not be closed when the unsafe region is reached and the secret is not known. """ amount = 3 expire = 10 initiator = factories.HOP1 our_address = factories.ADDR from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) state = TargetState( our_address, from_route, from_transfer, block_number=expire, ) events = target.events_for_close(state) assert not events events = target.events_for_close(state) assert not events assert from_transfer.secret is None
def test_state_transition(): """ Happy case testing. """ amount = 7 block_number = 1 initiator = factories.HOP6 expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) init = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) init_transition = target.state_transition(None, init) assert init_transition.new_state is not None assert init_transition.new_state.from_route == from_route assert init_transition.new_state.from_transfer == from_transfer first_new_block = Block(block_number + 1) first_block_iteration = target.state_transition(init_transition.new_state, first_new_block) assert first_block_iteration.new_state.block_number == block_number + 1 secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition(first_block_iteration.new_state, secret_reveal) assert reveal_iteration.new_state.from_transfer.secret == factories.UNIT_SECRET second_new_block = Block(block_number + 2) second_block_iteration = target.state_transition(init_transition.new_state, second_new_block) assert second_block_iteration.new_state.block_number == block_number + 2 nonce = 11 transferred_amount = 13 locksroot = '' message_hash = '' balance_proof = ReceiveBalanceProof( from_transfer.identifier, from_route.node_address, nonce, transferred_amount, locksroot, from_route.channel_address, message_hash, ) proof_iteration = target.state_transition(init_transition.new_state, balance_proof) assert proof_iteration.new_state is None
def test_secret_learned(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] state = make_mediator_state( from_transfer, from_route, list(routes), ) secret = factories.UNIT_SECRET payee_address = factories.HOP2 iteration = mediator.secret_learned( state, secret, payee_address, 'payee_secret_revealed', ) transfer_pair = iteration.new_state.transfers_pair[0] assert from_transfer.expiration > transfer_pair.payee_transfer.expiration assert transfer_pair.payee_transfer.almost_equal(from_transfer) assert transfer_pair.payee_route == routes[0] assert transfer_pair.payer_route == from_route assert transfer_pair.payer_transfer == from_transfer assert iteration.new_state.secret == secret assert transfer_pair.payee_transfer.secret == secret assert transfer_pair.payer_transfer.secret == secret assert transfer_pair.payee_state == 'payee_balance_proof' assert transfer_pair.payer_state == 'payer_secret_revealed' reveal_events = [ e for e in iteration.events if isinstance(e, SendRevealSecret) ] assert len(reveal_events) == 1 balance_events = [ e for e in iteration.events if isinstance(e, SendBalanceProof) ] assert len(balance_events) == 1
def test_init_mediator(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch(init_state_change, ) mediator_state = mediator_state_machine.current_state assert isinstance(mediator_state, MediatorState) assert mediator_state.our_address == factories.ADDR assert mediator_state.block_number == init_state_change.block_number assert mediator_state.transfers_pair[0].payer_transfer == from_transfer assert mediator_state.transfers_pair[0].payer_route == from_route assert len( events ), 'we have a valid route, the mediated transfer event must be emited' mediated_transfers = [ e for e in events if isinstance(e, SendMediatedTransfer) ] assert len(mediated_transfers ) == 1, 'mediated_transfer should /not/ split the transfer' mediated_transfer = mediated_transfers[0] assert mediated_transfer.token == from_transfer.token, 'transfer token address mismatch' assert mediated_transfer.amount == from_transfer.amount, 'transfer amount mismatch' assert mediated_transfer.expiration < from_transfer.expiration, 'transfer expiration mismatch' assert mediated_transfer.hashlock == from_transfer.hashlock, 'wrong hashlock'
def test_init_mediator(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] init_state_change = make_init_statechange( from_transfer, from_route, routes, ) mediator_state_machine = StateManager( mediator.state_transition, None, ) assert mediator_state_machine.current_state is None events = mediator_state_machine.dispatch( init_state_change, ) mediator_state = mediator_state_machine.current_state assert isinstance(mediator_state, MediatorState) assert mediator_state.our_address == factories.ADDR assert mediator_state.block_number == init_state_change.block_number assert mediator_state.transfers_pair[0].payer_transfer == from_transfer assert mediator_state.transfers_pair[0].payer_route == from_route assert len(events), 'we have a valid route, the mediated transfer event must be emited' mediated_transfers = [ e for e in events if isinstance(e, SendMediatedTransfer) ] assert len(mediated_transfers) == 1, 'mediated_transfer should /not/ split the transfer' mediated_transfer = mediated_transfers[0] assert mediated_transfer.token == from_transfer.token, 'transfer token address mismatch' assert mediated_transfer.amount == from_transfer.amount, 'transfer amount mismatch' assert mediated_transfer.expiration < from_transfer.expiration, 'transfer expiration mismatch' assert mediated_transfer.hashlock == from_transfer.hashlock, 'wrong hashlock'
def test_secret_learned(): from_route, from_transfer = factories.make_from( amount=factories.UNIT_TRANSFER_AMOUNT, target=factories.HOP2, from_expiration=factories.HOP1_TIMEOUT, ) routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] state = make_mediator_state( from_transfer, from_route, list(routes), ) secret = factories.UNIT_SECRET payee_address = factories.HOP2 iteration = mediator.secret_learned( state, secret, payee_address, 'payee_secret_revealed', ) transfer_pair = iteration.new_state.transfers_pair[0] assert from_transfer.expiration > transfer_pair.payee_transfer.expiration assert transfer_pair.payee_transfer.almost_equal(from_transfer) assert transfer_pair.payee_route == routes[0] assert transfer_pair.payer_route == from_route assert transfer_pair.payer_transfer == from_transfer assert iteration.new_state.secret == secret assert transfer_pair.payee_transfer.secret == secret assert transfer_pair.payer_transfer.secret == secret assert transfer_pair.payee_state == 'payee_balance_proof' assert transfer_pair.payer_state == 'payer_secret_revealed' reveal_events = [e for e in iteration.events if isinstance(e, SendRevealSecret)] assert len(reveal_events) == 1 balance_events = [e for e in iteration.events if isinstance(e, SendBalanceProof)] assert len(balance_events) == 1
def make_init_state_change(our_address, amount, block_number, initiator, expire=None): if expire is None: expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) init = ActionInitTarget( our_address, from_route, from_transfer, block_number, ) return init
def make_target_state(our_address, amount, block_number, initiator, expire=None): if expire is None: expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) state = TargetState( our_address, from_route, from_transfer, block_number, ) return state
def test_mediate_transfer(): amount = 10 block_number = 5 expiration = 30 routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] routes_state = RoutesState(routes) state = MediatorState( factories.ADDR, routes_state, block_number, factories.UNIT_HASHLOCK, ) payer_route, payer_transfer = factories.make_from(amount, factories.HOP6, expiration) iteration = mediator.mediate_transfer( state, payer_route, payer_transfer, ) events_mediated = [ e for e in iteration.events if isinstance(e, SendMediatedTransfer) ] assert len(events_mediated) == 1 transfer = events_mediated[0] assert transfer.identifier == payer_transfer.identifier assert transfer.token == payer_transfer.token assert transfer.amount == payer_transfer.amount assert transfer.hashlock == payer_transfer.hashlock assert transfer.target == payer_transfer.target assert payer_transfer.expiration > transfer.expiration assert transfer.receiver == routes[0].node_address
def test_mediate_transfer(): amount = 10 block_number = 5 expiration = 30 routes = [ factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT), ] routes_state = RoutesState(routes) state = MediatorState( factories.ADDR, routes_state, block_number, factories.UNIT_HASHLOCK, ) payer_route, payer_transfer = factories.make_from(amount, factories.HOP6, expiration) iteration = mediator.mediate_transfer( state, payer_route, payer_transfer, ) events_mediated = [ e for e in iteration.events if isinstance(e, SendMediatedTransfer) ] assert len(events_mediated) == 1 transfer = events_mediated[0] assert transfer.identifier == payer_transfer.identifier assert transfer.token == payer_transfer.token assert transfer.amount == payer_transfer.amount assert transfer.hashlock == payer_transfer.hashlock assert transfer.target == payer_transfer.target assert payer_transfer.expiration > transfer.expiration assert transfer.receiver == routes[0].node_address
def make_init_state_change(our_address, amount, block_number, initiator, expire=None): if expire is None: expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) init = ActionInitTarget( our_address, from_route, from_transfer, block_number, ) return init
def test_handle_inittarget_bad_expiration(): """ Init transfer must do nothing if the expiration is bad. """ block_number = 1 amount = 3 expire = block_number + factories.UNIT_REVEAL_TIMEOUT initiator = factories.HOP1 from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) state_change = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) iteration = target.handle_inittarget(state_change) assert len(iteration.events) == 0
def test_handle_inittarget_bad_expiration(): """ Init transfer must do nothing if the expiration is bad. """ block_number = 1 amount = 3 expire = block_number + factories.UNIT_REVEAL_TIMEOUT initiator = factories.HOP1 from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) state_change = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) iteration = target.handle_inittarget(state_change) assert len(iteration.events) == 0
def make_target_state(our_address, amount, block_number, initiator, expire=None): if expire is None: expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) state = TargetState( our_address, from_route, from_transfer, block_number, ) return state
def test_clear_if_finalized_expired(): """ Clear expired locks that we don't know the secret for. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 10 expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) before_state = TargetState( our_address, from_route, from_transfer, block_number=expire, ) before_iteration = TransitionResult(before_state, list()) before_iteration = target.clear_if_finalized(before_iteration) assert before_iteration.new_state.from_transfer.secret is None assert before_iteration.new_state is not None expired_state = TargetState( our_address, from_route, from_transfer, block_number=expire + 1, ) expired_iteration = TransitionResult(expired_state, list()) expired_iteration = target.clear_if_finalized(expired_iteration) assert expired_iteration.new_state is None
def test_clear_if_finalized_expired(): """ Clear expired locks that we don't know the secret for. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 10 expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, our_address, expire, initiator, ) before_state = TargetState( our_address, from_route, from_transfer, block_number=expire, ) before_iteration = TransitionResult(before_state, list()) before_iteration = target.clear_if_finalized(before_iteration) assert before_iteration.new_state.from_transfer.secret is None assert before_iteration.new_state is not None expired_state = TargetState( our_address, from_route, from_transfer, block_number=expire + 1, ) expired_iteration = TransitionResult(expired_state, list()) expired_iteration = target.clear_if_finalized(expired_iteration) assert expired_iteration.new_state is None
def test_state_transition(): """ Happy case testing. """ amount = 7 block_number = 1 initiator = factories.HOP6 expire = block_number + factories.UNIT_REVEAL_TIMEOUT from_route, from_transfer = factories.make_from( amount, factories.ADDR, expire, initiator, ) init = ActionInitTarget( factories.ADDR, from_route, from_transfer, block_number, ) init_transition = target.state_transition(None, init) assert init_transition.new_state is not None assert init_transition.new_state.from_route == from_route assert init_transition.new_state.from_transfer == from_transfer first_new_block = Block(block_number + 1) first_block_iteration = target.state_transition(init_transition.new_state, first_new_block) assert first_block_iteration.new_state.block_number == block_number + 1 secret_reveal = ReceiveSecretReveal(factories.UNIT_SECRET, initiator) reveal_iteration = target.state_transition(first_block_iteration.new_state, secret_reveal) assert reveal_iteration.new_state.from_transfer.secret == factories.UNIT_SECRET second_new_block = Block(block_number + 2) second_block_iteration = target.state_transition(init_transition.new_state, second_new_block) assert second_block_iteration.new_state.block_number == block_number + 2 nonce = 11 transferred_amount = 13 locksroot = '' message_hash = '' signature = None balance_proof = BalanceProofState( nonce, transferred_amount, locksroot, from_route.channel_address, message_hash, signature, ) balance_proof_state_change = ReceiveBalanceProof( from_transfer.identifier, from_route.node_address, balance_proof, ) proof_iteration = target.state_transition( init_transition.new_state, balance_proof_state_change, ) assert proof_iteration.new_state is None