[viff-devel] Weird behaviour
Martin Geisler
mg at lazybytes.net
Wed Aug 5 02:47:08 PDT 2009
Janus Dam Nielsen <janus.nielsen at 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):
@protocol
def test_next_three_cards(self, runtime):
values = []
print
def append(x, a, r):
print runtime.id, "append", "x:", x, "a:", a, "r:", r
values.append(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.
self.pause()
self.result.addBoth(self._continue)
where
def _continue(self, result):
self.result = result
self.unpause()
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/.
More information about the viff-devel
mailing list