# Buggy code
def _hook_var_send_(hook_self):
    def send_(self, workers):
        """
        Sends a Variable object to a (sequence of) Grid workers.

        Args:
        workers: string (or sequence) containing IPFS address(es)
            of worker node(s).
        """

        # makes singleton if needed
        workers = hook_self.local_worker._check_workers(self, workers)
        self = hook_self.local_worker.register_object(
            hook_self.local_worker, obj=self, id=self.id, owners=workers
        )
        for worker in workers:
            # TODO: sync or async? likely won't be worth doing async,
            #       but should check (low priority)
            hook_self.local_worker.send_obj(self, worker)

        hook_self.local_worker.register_object(
            hook_self.local_worker,
            obj=self,
            id=self.id,
            owners=self.owners,
            is_pointer=True,
        )

        return hook_self._var_to_pointer(self, hook_self)

    setattr(torch.autograd.variable.Variable, "send_", send_)


# Traceback (RuntimeError)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-14-4207de4e45fd> in <module>()
10 loss.backward()
11
---> 12 model.send_(remote)

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/hooks.py in send_(self, workers)
907                                                    owners=self.owners, is_pointer=True)
908
--> 909             return hook_self._var_to_pointer(self, hook_self)
910
911         setattr(torch.autograd.variable.Variable, 'send_', send_)

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/hooks.py in _var_to_pointer(self, var, hook_self)
982         print("_var_to_pointer:" + str(var.data.id))
983         if var.grad is not None:
--> 984             self._var_to_pointer(var.grad, hook_self)
985
986         var.data.old_set_(var.data.__class__(0))

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/hooks.py in _var_to_pointer(self, var, hook_self)
989                                           id=var.data.id,
990                                           owners=var.owners,
--> 991                                           is_pointer=True)
992         return var
993

/Users/atrask/anaconda/lib/python3.6/site-packages/syft-0.1.0-py3.6.egg/syft/core/workers.py in register_object(self, worker, obj, force_attach_to_worker, temporary, **kwargs)
508             raise RuntimeError(
509                 'Invalid registry: is_pointer is {} but owners is {} on tensor {}'.format(
--> 510                     obj.is_pointer, obj.owners, obj.id))
511         # print("setting object:" + str(obj.id))
512         self.set_obj(obj.id, obj, force=force_attach_to_worker, tmp=temporary)

RuntimeError: Invalid registry: is_pointer is True but owners is [0] on tensor 2841986768

# Fixed code
def _hook_var_send_(hook_self):
    def send_(self, workers):
        """
        Sends a Variable object to a (sequence of) Grid workers.

        Args:
        workers: string (or sequence) containing IPFS address(es)
            of worker node(s).
        """

        # makes singleton if needed
        workers = hook_self.local_worker._check_workers(self, workers)

        # NEW OWNERS: this re-registers the current variable to have new owners!
        #  After this line, self.owners should point to workers (the input variable)
        self = hook_self.local_worker.register_object(
            hook_self.local_worker, obj=self, id=self.id, owners=workers
        )

        for worker in workers:
            # TODO: sync or async? likely won't be worth doing async,
            #       but should check (low priority)
            hook_self.local_worker.send_obj(self, worker)

        # NEW IS_POINTER STATUS. This line changes the is_pointer flag to true.
        hook_self.local_worker.register_object(
            hook_self.local_worker,
            obj=self,
            id=self.id,
            owners=self.owners,
            is_pointer=True,
        )

        return hook_self._var_to_pointer(self, hook_self)

    setattr(torch.autograd.variable.Variable, "send_", send_)