def restore_state( transition_function: Callable, storage: SerializedSQLiteStorage, state_change_identifier: StateChangeID, node_address: Address, ) -> Optional[State]: snapshot = storage.get_snapshot_before_state_change( state_change_identifier=state_change_identifier) if snapshot is None: return None log.debug( "Snapshot found", from_state_change_id=snapshot.state_change_identifier, to_state_change_id=state_change_identifier, node=to_checksum_address(node_address), ) state, _ = replay_state_changes( node_address=node_address, state=snapshot.data, state_change_range=Range(snapshot.state_change_identifier, state_change_identifier), storage=storage, transition_function=transition_function, ) return state
def restore_to_state_change( transition_function: Callable, storage: SerializedSQLiteStorage, state_change_identifier: StateChangeID, node_address: Address, ) -> Tuple[int, int, "WriteAheadLog"]: chain_state: Optional[State] from_identifier: StateChangeID snapshot = storage.get_snapshot_before_state_change( state_change_identifier=state_change_identifier) if snapshot is not None: log.debug( "Restoring from snapshot", from_state_change_id=snapshot.state_change_identifier, to_state_change_id=state_change_identifier, node=to_checksum_address(node_address), ) from_identifier = snapshot.state_change_identifier chain_state = snapshot.data state_change_qty = snapshot.state_change_qty else: log.debug( "No snapshot found, replaying all state changes", to_state_change_id=state_change_identifier, node=to_checksum_address(node_address), ) from_identifier = LOW_STATECHANGE_ULID chain_state = None state_change_qty = 0 state_manager = StateManager(transition_function, chain_state) wal = WriteAheadLog(state_manager, storage) unapplied_state_changes = storage.get_statechanges_by_range( Range(from_identifier, state_change_identifier)) if unapplied_state_changes: log.debug( "Replaying state changes", replayed_state_changes=[ redact_secret(DictSerializer.serialize(state_change)) for state_change in unapplied_state_changes ], node=to_checksum_address(node_address), ) for state_change in unapplied_state_changes: wal.state_manager.dispatch(state_change) return state_change_qty, len(unapplied_state_changes), wal
def test_get_state_change_with_balance_proof(): """ All state changes which contain a balance proof must be found when querying the database. """ serializer = JSONSerializer() storage = SerializedSQLiteStorage(":memory:", serializer) counter = itertools.count() balance_proof = make_signed_balance_proof_from_counter(counter) lock_expired = ReceiveLockExpired( sender=balance_proof.sender, balance_proof=balance_proof, secrethash=factories.make_secret_hash(next(counter)), message_identifier=MessageID(next(counter)), ) received_balance_proof = make_signed_balance_proof_from_counter(counter) unlock = ReceiveUnlock( sender=received_balance_proof.sender, message_identifier=MessageID(next(counter)), secret=factories.make_secret(next(counter)), balance_proof=received_balance_proof, ) transfer = make_signed_transfer_from_counter(counter) transfer_refund = ReceiveTransferRefund( transfer=transfer, balance_proof=transfer.balance_proof, sender=transfer.balance_proof.sender, # pylint: disable=no-member ) transfer = make_signed_transfer_from_counter(counter) transfer_reroute = ActionTransferReroute( transfer=transfer, balance_proof=transfer.balance_proof, sender=transfer.balance_proof.sender, # pylint: disable=no-member secret=sha3(factories.make_secret(next(counter))), ) mediator_from_route, mediator_signed_transfer = make_from_route_from_counter( counter) action_init_mediator = ActionInitMediator( route_states=[ RouteState( route=[factories.make_address(), factories.make_address()], forward_channel_id=factories.make_channel_identifier(), ) ], from_hop=mediator_from_route, from_transfer=mediator_signed_transfer, balance_proof=mediator_signed_transfer.balance_proof, sender=mediator_signed_transfer.balance_proof.sender, # pylint: disable=no-member ) target_from_route, target_signed_transfer = make_from_route_from_counter( counter) action_init_target = ActionInitTarget( from_hop=target_from_route, transfer=target_signed_transfer, balance_proof=target_signed_transfer.balance_proof, sender=target_signed_transfer.balance_proof.sender, # pylint: disable=no-member ) statechanges_balanceproofs = [ (lock_expired, lock_expired.balance_proof), (unlock, unlock.balance_proof), (transfer_refund, transfer_refund.transfer.balance_proof), (transfer_reroute, transfer_reroute.transfer.balance_proof), (action_init_mediator, action_init_mediator.from_transfer.balance_proof), (action_init_target, action_init_target.transfer.balance_proof), ] assert storage.count_state_changes() == 0 state_change_ids = storage.write_state_changes( [state_change for state_change, _ in statechanges_balanceproofs]) assert storage.count_state_changes() == len(statechanges_balanceproofs) msg_in_order = "Querying must return state changes in order" stored_statechanges_records = storage.get_statechanges_records_by_range( RANGE_ALL_STATE_CHANGES) assert len(stored_statechanges_records) == 6, msg_in_order pair_elements = zip(statechanges_balanceproofs, state_change_ids, stored_statechanges_records) for statechange_balanceproof, statechange_id, record in pair_elements: assert record.data == statechange_balanceproof[0], msg_in_order assert record.state_change_identifier == statechange_id, msg_in_order # Make sure state changes are returned in the correct order in which they were stored stored_statechanges = storage.get_statechanges_by_range( Range( stored_statechanges_records[1].state_change_identifier, stored_statechanges_records[2].state_change_identifier, )) assert len(stored_statechanges) == 2 assert isinstance(stored_statechanges[0], ReceiveUnlock) assert isinstance(stored_statechanges[1], ReceiveTransferRefund) for state_change, balance_proof in statechanges_balanceproofs: state_change_record = get_state_change_with_balance_proof_by_balance_hash( storage=storage, canonical_identifier=balance_proof.canonical_identifier, sender=balance_proof.sender, balance_hash=balance_proof.balance_hash, ) assert state_change_record assert state_change_record.data == state_change state_change_record = get_state_change_with_balance_proof_by_locksroot( storage=storage, canonical_identifier=balance_proof.canonical_identifier, sender=balance_proof.sender, locksroot=balance_proof.locksroot, ) assert state_change_record assert state_change_record.data == state_change storage.close()