Janus Dam Nielsen <janus.niel...@alexandra.dk> writes:

> As you see when player 1 adds a share to the value list, the current
> result of the share is 13. However when player 1 comes around to add a
> new share with current result 9, the current result of the share
> already contained in the list has transformed into None! It is clear
> from the hashcode that it is still the same object, so why does the
> current value change??
> I have tried to boil down the code as much as possible.

Here is an even simpler version of your code:

from viff.test.util import RuntimeTestCase, protocol
from viff.field import GF
Zp = GF(53)

class DealerTest(RuntimeTestCase):

    def test_next_three_cards(self, runtime):
        values = []


        def append(x, a, r):
            print runtime.id, "append", "x:", x, "a:", a, "r:", r
            return r

        def next_card(a):
            print runtime.id, "next_card", a
            r = runtime.input([1], Zp, runtime.id == 1 and 23 or None)
            print runtime.id, "values before:", values
            runtime.schedule_callback(a, append, a, r)
            print runtime.id, "values after:", values
            print runtime.id, "next_card return", a
            return a

        fourtwo = runtime.input([1], Zp, runtime.id == 1 and 42 or None)
        return next_card(fourtwo)

It gives output like this:

% trial test_dealer.py | grep '^1'
1 next_card <Share at 0xaa88bec  current result: {42}>
1 values before: []
1 append x: {42} a: <Share at 0xaa88bec  current result: {42}>
                 r: <Share at 0xaa8f36c  current result: {42}>
1 values after: [<Share at 0xaa8f36c  current result: None>]
1 next_card return <Share at 0xaa88bec  current result: {42}>

Sure enough, the 0xaa8f36c Share in the values array is changed by the
append function. The reason is that append is used as a callback returns
a Deferred (r). When a callback returns a Deferred, the final return
value becomes the value of the Deferred.

This is done in Deferred._runCallbacks, which loops through the
callbacks and updates self.result. It then has this code:

        if isinstance(self.result, Deferred):
            self.callbacks = cb

            # note: this will cause _runCallbacks to be called
            # "recursively" sometimes... this shouldn't cause any
            # problems, since all the state has been set back to
            # the way it's supposed to be, but it is useful to know
            # in case something goes wrong.  deferreds really ought
            # not to return themselves from their callbacks.


    def _continue(self, result):
        self.result = result

So Deferred._continue is added as a callback to our r Deferred, and
since _continue return None, this becomes the value stored inside r.

I think the take-home message is that you have structured your code in
an unusual way. Whenever you add a callback to a Deferred but keep
referring to the Deferred inside the callback, then you're off track. At
least that's my experience :-)

Martin Geisler

VIFF (Virtual Ideal Functionality Framework) brings easy and efficient
SMPC (Secure Multiparty Computation) to Python. See: http://viff.dk/.
viff-devel mailing list (http://viff.dk/)

Reply via email to