def test_handle_block(): """ Increase the block number. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 1 pseudo_random_generator = random.Random() from_channel, state = make_target_state( our_address, amount, block_number, initiator, ) new_block = Block( block_number=block_number + 1, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = target.state_transition( state, new_block, from_channel, pseudo_random_generator, new_block.block_number, ) assert iteration.new_state assert not iteration.events
def test_mediated_after_direct_transfer(reveal_timeout, settle_timeout, deposit, tester_state, tester_channels, tester_token): """ The transfer types must not change the behavior of the dispute. """ pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial_balance0 = tester_token.balanceOf(address0, sender=pkey0) initial_balance1 = tester_token.balanceOf(address1, sender=pkey0) first_amount0 = 90 block_number = tester_state.block.number make_direct_transfer_from_channel( block_number, channel0, channel1, first_amount0, pkey0, ) lock_expiration = tester_state.block.number + reveal_timeout + 5 new_block = Block(tester_state.block.number) channel0.state_transition(new_block) channel1.state_transition(new_block) lock1 = Lock(amount=31, expiration=lock_expiration, hashlock=sha3('lock2')) second_mediated0 = make_mediated_transfer( channel0, channel1, address0, address1, lock1, pkey0, tester_state.block.number, ) nettingchannel.close(sender=pkey0) second_mediated0_hash = sha3(second_mediated0.packed().data[:-65]) nettingchannel.updateTransfer( second_mediated0.nonce, second_mediated0.transferred_amount, second_mediated0.locksroot, second_mediated0_hash, second_mediated0.signature, sender=pkey1, ) tester_state.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey0) # the balances only change by transferred_amount because the lock was /not/ unlocked balance0 = initial_balance0 + deposit - first_amount0 balance1 = initial_balance1 + deposit + first_amount0 assert tester_token.balanceOf(nettingchannel.address, sender=pkey1) == 0 assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey1) == balance1
def test_target_lock_is_expired_if_secret_is_not_registered_onchain(): lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() our_balance = 100 our_address = factories.make_address() partner_balance = 130 from_channel = factories.make_channel( our_address=our_address, our_balance=our_balance, partner_address=UNIT_TRANSFER_SENDER, partner_balance=partner_balance, ) from_route = factories.route_from_channel(from_channel) expiration = block_number + from_channel.settle_timeout - from_channel.reveal_timeout from_transfer = factories.make_signed_transfer_for( from_channel, lock_amount, initiator, our_address, expiration, UNIT_SECRET, ) init = ActionInitTarget( from_route, from_transfer, ) init_transition = target.state_transition( None, init, from_channel, pseudo_random_generator, block_number, ) assert init_transition.new_state is not None secret_reveal_iteration = target.state_transition( target_state=init_transition.new_state, state_change=ReceiveSecretReveal(UNIT_SECRET, from_channel.partner_state.address), channel_state=from_channel, pseudo_random_generator=pseudo_random_generator, block_number=block_number, ) expired_block_number = from_transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS iteration = target.state_transition( target_state=secret_reveal_iteration.new_state, state_change=Block(expired_block_number, None, None), channel_state=from_channel, pseudo_random_generator=pseudo_random_generator, block_number=expired_block_number, ) assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {})
def test_events_loaded_from_storage_should_deserialize(tmp_path): filename = Path(f"{tmp_path}/v{RAIDEN_DB_VERSION}_log.db") storage = SerializedSQLiteStorage(filename, serializer=JSONSerializer()) # Satisfy the foreign-key constraint for state change ID ids = storage.write_state_changes([ Block( block_number=BlockNumber(1), gas_limit=BlockGasLimit(1), block_hash=factories.make_block_hash(), ) ]) canonical_identifier = factories.make_canonical_identifier() recipient = factories.make_address() participant = factories.make_address() event = SendWithdrawRequest( recipient=recipient, canonical_identifier=canonical_identifier, message_identifier=factories.make_message_identifier(), total_withdraw=WithdrawAmount(1), participant=participant, expiration=BlockExpiration(10), nonce=Nonce(15), ) storage.write_events([(ids[0], event)]) stored_events = storage.get_events() assert stored_events[0] == event
def set_block_number(self, block_number): state_change = Block(block_number) self.handle_state_change(state_change, block_number) # To avoid races, only update the internal cache after all the state # tasks have been updated. self._block_number = block_number
def test_handle_block_lower_block_number(): """ Nothing changes. """ initiator = factories.HOP6 our_address = factories.ADDR amount = 3 block_number = 10 pseudo_random_generator = random.Random() from_channel, state = make_target_state( our_address, amount, block_number, initiator, ) new_block = Block(block_number - 1) iteration = target.state_transition( state, new_block, from_channel, pseudo_random_generator, new_block.block_number, ) assert iteration.new_state assert not iteration.events
def test_lock_expiry_updates_balance_proof(): setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10) transfer = setup.current_state.initiator.transfer assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks nonce_before_lock_expiry = setup.channel.our_state.balance_proof.nonce # Trigger lock expiry state_change = Block( block_number=transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2, gas_limit=1, block_hash=factories.make_transaction_hash(), ) initiator_manager.state_transition( setup.current_state, state_change, setup.channel_map, setup.prng, setup.block_number, ) balance_proof = setup.channel.our_state.balance_proof assert balance_proof.nonce == nonce_before_lock_expiry + 1 assert balance_proof.transferred_amount == 0 assert balance_proof.locked_amount == 0
def test_withdraw_twice(tester_registry_address, reveal_timeout, tester_channels, tester_chain): """ A lock can be withdrawn only once, the second try must fail. """ pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] pseudo_random_generator = random.Random() lock_expiration = tester_chain.block.number + reveal_timeout + 5 secret = b'secretsecretsecretsecretsecretse' new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) lock = Lock(17, lock_expiration, sha3(secret)) mediated0 = make_mediated_transfer( tester_registry_address, channel1, channel0, privatekey_to_address(pkey1), privatekey_to_address(pkey0), lock, pkey1, secret, ) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.close( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey0, ) unlock_proofs = channel.get_known_unlocks(channel0.partner_state) proof = unlock_proofs[0] nettingchannel.withdraw( proof.lock_encoded, b''.join(proof.merkle_proof), proof.secret, sender=pkey0, ) with pytest.raises(TransactionFailed): nettingchannel.withdraw( proof.lock_encoded, b''.join(proof.merkle_proof), proof.secret, sender=pkey0, )
def test_settle_with_locked_mediated_transfer_for_counterparty( deposit, settle_timeout, reveal_timeout, tester_chain, tester_channels, tester_token): """ Test settle with a locked mediated transfer for the counter party. """ pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] payment_network_identifier = factories.make_address() address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial0 = tester_token.balanceOf(address0, sender=pkey0) initial1 = tester_token.balanceOf(address1, sender=pkey0) transferred_amount0 = 30 increase_transferred_amount( payment_network_identifier, channel0, channel1, transferred_amount0, pkey0, ) expiration0 = tester_chain.block.number + reveal_timeout + 5 new_block = Block(tester_chain.block.number) channel.state_transition(channel0, new_block, new_block.block_number) channel.state_transition(channel1, new_block, new_block.block_number) lock0 = Lock(amount=29, expiration=expiration0, secrethash=sha3(b'lock1')) mediated0 = make_mediated_transfer( channel0, channel1, address0, address1, lock0, pkey0, ) nettingchannel.close(sender=pkey0) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.updateTransfer( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey1, ) tester_chain.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey1) # the balances only change by transferred_amount because the lock was /not/ unlocked balance0 = initial0 + deposit - transferred_amount0 balance1 = initial1 + transferred_amount0 assert tester_token.balanceOf(nettingchannel.address, sender=pkey0) == 0 assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey0) == balance1
def test_write_read_log() -> None: wal = new_wal(state_transition_noop) block_number = BlockNumber(1337) block_hash = make_block_hash() block = Block(block_number=block_number, gas_limit=BlockGasLimit(1), block_hash=block_hash) unlocked_amount = TokenAmount(10) returned_amount = TokenAmount(5) participant = make_address() partner = make_address() locksroot = make_locksroot() contract_receive_unlock = ContractReceiveChannelBatchUnlock( transaction_hash=make_transaction_hash(), canonical_identifier=make_canonical_identifier( token_network_address=make_address()), receiver=participant, sender=partner, locksroot=locksroot, unlocked_amount=unlocked_amount, returned_tokens=returned_amount, block_number=block_number, block_hash=block_hash, ) state_changes1 = wal.storage.get_statechanges_by_range( RANGE_ALL_STATE_CHANGES) count1 = len(state_changes1) dispatch(wal, [block]) state_changes2 = wal.storage.get_statechanges_by_range( RANGE_ALL_STATE_CHANGES) count2 = len(state_changes2) assert count1 + 1 == count2 dispatch(wal, [contract_receive_unlock]) state_changes3 = wal.storage.get_statechanges_by_range( RANGE_ALL_STATE_CHANGES) count3 = len(state_changes3) assert count2 + 1 == count3 result1, result2 = state_changes3[-2:] assert isinstance(result1, Block) assert result1.block_number == block_number assert isinstance(result2, ContractReceiveChannelBatchUnlock) assert result2.receiver == participant assert result2.sender == partner assert result2.locksroot == locksroot assert result2.unlocked_amount == unlocked_amount assert result2.returned_tokens == returned_amount # Make sure state snapshot can only go for corresponding state change ids with pytest.raises(sqlite3.IntegrityError): wal.storage.write_state_snapshot(State(), StateChangeID(make_ulid()), 1)
def test_subdispatch_to_paymenttask_target(chain_state, netting_channel_state): target_state = TargetTransferState( from_hop=HopState( node_address=netting_channel_state.partner_state.address, channel_identifier=netting_channel_state.canonical_identifier. channel_identifier, ), transfer=factories.create( factories.LockedTransferSignedStateProperties()), secret=UNIT_SECRET, ) subtask = TargetTask( canonical_identifier=netting_channel_state.canonical_identifier, target_state=target_state) chain_state.payment_mapping.secrethashes_to_task[UNIT_SECRETHASH] = subtask lock = factories.HashTimeLockState(amount=0, expiration=2, secrethash=UNIT_SECRETHASH) netting_channel_state.partner_state.secrethashes_to_lockedlocks[ UNIT_SECRETHASH] = lock netting_channel_state.partner_state.pending_locks = PendingLocksState( [bytes(lock.encoded)]) state_change = Block( block_number=chain_state.block_number, gas_limit=GAS_LIMIT, block_hash=chain_state.block_hash, ) transition_result = subdispatch_to_paymenttask(chain_state=chain_state, state_change=state_change, secrethash=UNIT_SECRETHASH) assert transition_result.events == [] assert transition_result.new_state == chain_state chain_state.block_number = 20 balance_proof: BalanceProofSignedState = factories.create( factories.BalanceProofSignedStateProperties( canonical_identifier=netting_channel_state.canonical_identifier, sender=netting_channel_state.partner_state.address, transferred_amount=0, pkey=factories.UNIT_TRANSFER_PKEY, locksroot=LOCKSROOT_OF_NO_LOCKS, )) state_change = ReceiveLockExpired( balance_proof=balance_proof, sender=netting_channel_state.partner_state.address, secrethash=UNIT_SECRETHASH, message_identifier=factories.make_message_identifier(), ) transition_result = subdispatch_to_paymenttask(chain_state=chain_state, state_change=state_change, secrethash=UNIT_SECRETHASH) msg = "ReceiveLockExpired should have cleared the task" assert UNIT_SECRETHASH not in chain_state.payment_mapping.secrethashes_to_task, msg assert len( transition_result.events), "ReceiveLockExpired should generate events" assert transition_result.new_state == chain_state
def test_regression_mediator_send_lock_expired_with_new_block(): """The mediator must send the lock expired, but it must **not** clear itself if it has not **received** the corresponding message. """ pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_signed_transfer_for( channels[0], LONG_EXPIRATION) init_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action( channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, addresses_to_channel=channels.addresses_to_channel(), nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=5, block_hash=factories.make_block_hash(), ) assert init_iteration.new_state is not None send_transfer = search_for_item(init_iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = channel.get_sender_expiration_threshold( transfer.lock.expiration) block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=block, channelidentifiers_to_channels=channels.channel_map, addresses_to_channel=channels.addresses_to_channel(), nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, block_hash=factories.make_block_hash(), ) msg = ("The payer's lock has also expired, " "but it must not be removed locally (without an Expired lock)") assert transfer.lock.secrethash in channels[ 0].partner_state.secrethashes_to_lockedlocks, msg msg = "The payer has not yet sent an expired lock, the task can not be cleared yet" assert iteration.new_state is not None, msg assert search_for_item(iteration.events, SendLockExpired, {"secrethash": transfer.lock.secrethash}) assert transfer.lock.secrethash not in channels[ 1].our_state.secrethashes_to_lockedlocks
def _callback_new_block(self, latest_block: Dict): """Called once a new block is detected by the alarm task. Note: This should be called only once per block, otherwise there will be duplicated `Block` state changes in the log. Therefore this method should be called only once a new block is mined with the corresponding block data from the AlarmTask. """ # User facing APIs, which have on-chain side-effects, force polled the # blockchain to update the node's state. This force poll is used to # provide a consistent view to the user, e.g. a channel open call waits # for the transaction to be mined and force polled the event to update # the node's state. This pattern introduced a race with the alarm task # and the task which served the user request, because the events are # returned only once per filter. The lock below is to protect against # these races (introduced by the commit # 3686b3275ff7c0b669a6d5e2b34109c3bdf1921d) with self.event_poll_lock: latest_block_number = latest_block["number"] # Handle testing with private chains. The block number can be # smaller than confirmation_blocks confirmed_block_number = max( GENESIS_BLOCK_NUMBER, latest_block_number - self.config["blockchain"]["confirmation_blocks"], ) confirmed_block = self.chain.client.web3.eth.getBlock( confirmed_block_number) # These state changes will be procesed with a block_number which is # /larger/ than the ChainState's block_number. for event in self.blockchain_events.poll_blockchain_events( confirmed_block_number): on_blockchain_event(self, event) # On restart the Raiden node will re-create the filters with the # ethereum node. These filters will have the from_block set to the # value of the latest Block state change. To avoid missing events # the Block state change is dispatched only after all of the events # have been processed. # # This means on some corner cases a few events may be applied # twice, this will happen if the node crashed and some events have # been processed but the Block state change has not been # dispatched. state_change = Block( block_number=confirmed_block_number, gas_limit=confirmed_block["gasLimit"], block_hash=BlockHash(bytes(confirmed_block["hash"])), ) # Note: It's important to /not/ block here, because this function # can be called from the alarm task greenlet, which should not # starve. self.handle_and_track_state_change(state_change)
def test_write_read_log(): wal = new_wal() block_number = 1337 block = Block(block_number) unlocked_amount = 10 returned_amount = 5 channel_identifier = factories.make_address() contract_receive_unlock = ContractReceiveChannelBatchUnlock( factories.make_address(), channel_identifier, factories.ADDR, unlocked_amount, returned_amount, ) state_changes1 = wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) count1 = len(state_changes1) wal.log_and_dispatch(block, block_number) state_changes2 = wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) count2 = len(state_changes2) assert count1 + 1 == count2 wal.log_and_dispatch(contract_receive_unlock, block_number) state_changes3 = wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) count3 = len(state_changes3) assert count2 + 1 == count3 result1, result2 = state_changes3[-2:] assert isinstance(result1, Block) assert result1.block_number == block_number assert isinstance(result2, ContractReceiveChannelBatchUnlock) assert result2.channel_identifier == channel_identifier # Make sure state snapshot can only go for corresponding state change ids with pytest.raises(sqlite3.IntegrityError): wal.storage.write_state_snapshot(34, 'AAAA') # Make sure we can only have a single state snapshot assert wal.storage.get_state_snapshot() is None wal.storage.write_state_snapshot(1, 'AAAA') assert wal.storage.get_state_snapshot() == (1, 'AAAA') wal.storage.write_state_snapshot(2, 'BBBB') assert wal.storage.get_state_snapshot() == (2, 'BBBB')
def set_block_number(self, blocknumber): self._blocknumber = blocknumber state_change = Block(blocknumber) self.state_machine_event_handler.dispatch_to_all_tasks(state_change) for graph in self.channelgraphs.itervalues(): for channel in graph.address_channel.itervalues(): channel.state_transition(state_change)
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 balance_proof = ReceiveBalanceProof( from_transfer.identifier, from_route.channel_address, from_route.node_address, ) proof_iteration = target.state_transition(init_transition.new_state, balance_proof) assert proof_iteration.new_state is None
def test_transfer_statechange_operators(): # pylint: disable=unneeded-not a = Block(2) b = Block(2) c = Block(3) assert a == b assert not a != b assert a != c assert not a == c a = ActionCancelPayment(2) b = ActionCancelPayment(2) c = ActionCancelPayment(3) assert a == b assert not a != b assert a != c assert not a == c token_network_identifier = factories.make_address() a = ActionTransferDirect( token_network_identifier, receiver_address=ADDRESS, payment_identifier=2, amount=2, ) b = ActionTransferDirect( token_network_identifier, receiver_address=ADDRESS, payment_identifier=2, amount=2, ) c = ActionTransferDirect( token_network_identifier, receiver_address=ADDRESS2, # different recipient payment_identifier=2, amount=2, ) assert a == b assert not a != b assert a != c assert not a == c
def test_withdraw_expired_lock(reveal_timeout, tester_channels, tester_chain): pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] pseudo_random_generator = random.Random() lock_timeout = reveal_timeout + 5 lock_expiration = tester_chain.block.number + lock_timeout secret = b'expiredlockexpiredlockexpiredloc' secrethash = sha3(secret) new_block = Block(tester_chain.block.number) channel.state_transition( channel0, new_block, pseudo_random_generator, new_block.block_number, ) channel.state_transition( channel1, new_block, pseudo_random_generator, new_block.block_number, ) lock1 = Lock(amount=31, expiration=lock_expiration, secrethash=secrethash) mediated0 = make_mediated_transfer( channel1, channel0, privatekey_to_address(pkey0), privatekey_to_address(pkey1), lock1, pkey1, secret, ) mediated0_hash = sha3(mediated0.packed().data[:-65]) nettingchannel.close( mediated0.nonce, mediated0.transferred_amount, mediated0.locksroot, mediated0_hash, mediated0.signature, sender=pkey0, ) # expire the lock tester_chain.mine(number_of_blocks=lock_timeout + 1) unlock_proofs = channel.get_known_unlocks(channel0.partner_state) proof = unlock_proofs[0] with pytest.raises(TransactionFailed): nettingchannel.withdraw( proof.lock_encoded, b''.join(proof.merkle_proof), proof.secret, sender=pkey0, )
def test_unlock(deposit, settle_timeout, reveal_timeout, tester_channels, tester_state, tester_token): pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial_balance0 = tester_token.balanceOf(address0, sender=pkey0) initial_balance1 = tester_token.balanceOf(address1, sender=pkey0) lock_amount = 31 lock_expiration = tester_state.block.number + reveal_timeout + 5 secret = 'secretsecretsecretsecretsecretse' hashlock = sha3(secret) new_block = Block(tester_state.block.number) channel0.state_transition(new_block) channel1.state_transition(new_block) lock0 = Lock(lock_amount, lock_expiration, hashlock) mediated0 = make_mediated_transfer( channel0, channel1, address0, address1, lock0, pkey0, tester_state.block.number, secret, ) mediated0_data = str(mediated0.packed().data) proof = channel1.our_state.balance_proof.compute_proof_for_lock( secret, mediated0.lock, ) nettingchannel.close(mediated0_data, sender=pkey1) tester_state.mine(number_of_blocks=1) nettingchannel.unlock( proof.lock_encoded, ''.join(proof.merkle_proof), proof.secret, sender=pkey1, ) tester_state.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey0) balance0 = initial_balance0 + deposit - lock0.amount balance1 = initial_balance1 + deposit + lock0.amount assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey0) == balance1 assert tester_token.balanceOf(nettingchannel.address, sender=pkey0) == 0
def test_regression_mediator_send_lock_expired_with_new_block(): """ The mediator must send the lock expired, but it must **not** clear itself if it has not **received** the corresponding message. """ pseudo_random_generator = random.Random() channels = factories.mediator_make_channel_pair() payer_transfer = factories.make_default_signed_transfer_for( channels[0], initiator=HOP1, expiration=30, ) init_iteration = mediator.state_transition( mediator_state=None, state_change=factories.mediator_make_init_action( channels, payer_transfer), channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=5, ) assert init_iteration.new_state is not None send_transfer = must_contain_entry(init_iteration.events, SendLockedTransfer, {}) assert send_transfer transfer = send_transfer.transfer block_expiration_number = transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2 block = Block( block_number=block_expiration_number, gas_limit=1, block_hash=factories.make_transaction_hash(), ) iteration = mediator.state_transition( mediator_state=init_iteration.new_state, state_change=block, channelidentifiers_to_channels=channels.channel_map, pseudo_random_generator=pseudo_random_generator, block_number=block_expiration_number, ) msg = ("The payer's lock has also expired, " "but it must not be removed locally (without an Expired lock)") assert transfer.lock.secrethash in channels[ 0].partner_state.secrethashes_to_lockedlocks, msg msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet' assert iteration.new_state is not None, msg assert must_contain_entry(iteration.events, SendLockExpired, { 'secrethash': transfer.lock.secrethash, }) assert transfer.lock.secrethash not in channels[ 1].our_state.secrethashes_to_lockedlocks
def test_transfer_statechange_operators(): # pylint: disable=unneeded-not block_hash = factories.make_transaction_hash() a = Block(block_number=2, gas_limit=1, block_hash=block_hash) b = Block(block_number=2, gas_limit=1, block_hash=block_hash) c = Block(block_number=3, gas_limit=1, block_hash=factories.make_transaction_hash()) assert a == b assert not a != b assert a != c assert not a == c a = ActionCancelPayment(2) b = ActionCancelPayment(2) c = ActionCancelPayment(3) assert a == b assert not a != b assert a != c assert not a == c
def set_block_number(self, blocknumber): state_change = Block(blocknumber) self.state_machine_event_handler.log_and_dispatch_to_all_tasks(state_change) for graph in self.token_to_channelgraph.itervalues(): for channel in graph.address_to_channel.itervalues(): channel.state_transition(state_change) # To avoid races, only update the internal cache after all the state # tasks have been updated. self._blocknumber = blocknumber
def test_write_read_log(): wal = new_wal() block_number = 1337 block = Block(block_number) contract_receive_withdraw = ContractReceiveChannelWithdraw( factories.make_address(), factories.make_address(), factories.ADDR, factories.UNIT_SECRET, factories.HOP1) state_changes1 = wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) count1 = len(state_changes1) wal.log_and_dispatch(block, block_number) state_changes2 = wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) count2 = len(state_changes2) assert count1 + 1 == count2 wal.log_and_dispatch(contract_receive_withdraw, block_number) state_changes3 = wal.storage.get_statechanges_by_identifier( from_identifier=0, to_identifier='latest', ) count3 = len(state_changes3) assert count2 + 1 == count3 result1, result2 = state_changes3[-2:] assert isinstance(result1, Block) assert result1.block_number == block_number assert isinstance(result2, ContractReceiveChannelWithdraw) assert result2.channel_identifier == factories.ADDR assert result2.secret == factories.UNIT_SECRET assert result2.receiver == factories.HOP1 # Make sure state snapshot can only go for corresponding state change ids with pytest.raises(sqlite3.IntegrityError): wal.storage.write_state_snapshot(34, 'AAAA') # Make sure we can only have a single state snapshot assert wal.storage.get_state_snapshot() is None wal.storage.write_state_snapshot(1, 'AAAA') assert wal.storage.get_state_snapshot() == 'AAAA' wal.storage.write_state_snapshot(2, 'BBBB') assert wal.storage.get_state_snapshot() == 'BBBB'
def test_lock_expiry_updates_balance_proof(): amount = UNIT_TRANSFER_AMOUNT * 2 channel1 = factories.make_channel( our_balance=amount, token_address=UNIT_TOKEN_ADDRESS, token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS, ) pseudo_random_generator = random.Random() channel_map = { channel1.identifier: channel1, } available_routes = [ factories.route_from_channel(channel1), ] block_number = 10 current_state = make_initiator_manager_state( available_routes, factories.UNIT_TRANSFER_DESCRIPTION, channel_map, pseudo_random_generator, block_number, ) transfer = current_state.initiator.transfer assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks nonce_before_lock_expiry = channel1.our_state.balance_proof.nonce # Trigger lock expiry state_change = Block( block_number=transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2, gas_limit=1, block_hash=factories.make_transaction_hash(), ) initiator_manager.state_transition( current_state, state_change, channel_map, pseudo_random_generator, block_number, ) balance_proof = channel1.our_state.balance_proof assert balance_proof.nonce == nonce_before_lock_expiry + 1 assert balance_proof.transferred_amount == 0 assert balance_proof.locked_amount == 0
def test_restore_without_snapshot_in_batches(): wal = new_wal(state_transition_noop, AccState()) block1 = Block(block_number=5, gas_limit=1, block_hash=make_transaction_hash()) block2 = Block(block_number=7, gas_limit=1, block_hash=make_transaction_hash()) block3 = Block(block_number=8, gas_limit=1, block_hash=make_transaction_hash()) dispatch(wal, [block1, block2, block3]) aggregate = restore_state( transition_function=state_transtion_acc, storage=wal.storage, state_change_identifier=HIGH_STATECHANGE_ULID, node_address=make_address(), ) assert aggregate.state_changes == [block1, block2, block3]
def new_blocks(self, number): events = list() for _ in range(number): block_state_change = Block( block_number=self.block_number + 1, gas_limit=1, block_hash=factories.make_keccak_hash(), ) result = node.state_transition(self.chain_state, block_state_change) events.extend(result.events) self.block_number += 1
def test_restore_without_snapshot_in_batches(): wal = new_wal(state_transition_noop) block1 = Block(block_number=5, gas_limit=1, block_hash=make_transaction_hash()) block2 = Block(block_number=7, gas_limit=1, block_hash=make_transaction_hash()) block3 = Block(block_number=8, gas_limit=1, block_hash=make_transaction_hash()) wal.log_and_dispatch([block1, block2, block3]) _, _, newwal = restore_to_state_change( transition_function=state_transtion_acc, storage=wal.storage, state_change_identifier=HIGH_STATECHANGE_ULID, node_address=make_address(), ) aggregate = newwal.state_manager.current_state assert aggregate.state_changes == [block1, block2, block3]
def test_settle_with_locked_mediated_transfer_for_counterparty( deposit, settle_timeout, reveal_timeout, tester_state, tester_channels, tester_token): """ Test settle with a locked mediated transfer for the counter party. """ pkey0, pkey1, nettingchannel, channel0, channel1 = tester_channels[0] address0 = privatekey_to_address(pkey0) address1 = privatekey_to_address(pkey1) initial0 = tester_token.balanceOf(address0, sender=pkey0) initial1 = tester_token.balanceOf(address1, sender=pkey0) transferred_amount0 = 30 increase_transferred_amount(channel0, channel1, transferred_amount0) expiration0 = tester_state.block.number + reveal_timeout + 5 new_block = Block(tester_state.block.number) channel0.state_transition(new_block) channel1.state_transition(new_block) lock0 = Lock(amount=29, expiration=expiration0, hashlock=sha3('lock1')) mediated = make_mediated_transfer( channel0, channel1, address0, address1, lock0, pkey0, tester_state.block.number, ) nettingchannel.close('', sender=pkey0) transfer_data = str(mediated.packed().data) nettingchannel.updateTransfer(transfer_data, sender=pkey1) tester_state.mine(number_of_blocks=settle_timeout + 1) nettingchannel.settle(sender=pkey1) # the balances only change by transferred_amount because the lock was /not/ unlocked balance0 = initial0 + deposit - transferred_amount0 balance1 = initial1 + transferred_amount0 assert tester_token.balanceOf(nettingchannel.address, sender=pkey0) == 0 assert tester_token.balanceOf(address0, sender=pkey0) == balance0 assert tester_token.balanceOf(address1, sender=pkey0) == balance1
def new_blocks(self, number): for _ in range(number): block_state_change = Block( block_number=self.block_number + 1, gas_limit=1, block_hash=factories.make_keccak_hash(), ) for client in self.address_to_client.values(): events = list() result = node.state_transition(client.chain_state, block_state_change) events.extend(result.events) # TODO assert on events self.block_number += 1
def test_get_snapshot_closest_to_state_change(): wal = new_wal(state_transtion_acc) block1 = Block(block_number=5, gas_limit=1, block_hash=factories.make_transaction_hash()) wal.log_and_dispatch(block1) wal.snapshot() block2 = Block(block_number=7, gas_limit=1, block_hash=factories.make_transaction_hash()) wal.log_and_dispatch(block2) wal.snapshot() block3 = Block(block_number=8, gas_limit=1, block_hash=factories.make_transaction_hash()) wal.log_and_dispatch(block3) wal.snapshot() _, snapshot = wal.storage.get_snapshot_closest_to_state_change("latest") assert snapshot.state_changes == [block1, block2, block3]