From 97681c30277f6682b855cc2910c6f940844bb918 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Thu, 23 Apr 2020 09:32:41 -0400 Subject: [PATCH] Load the counter value from the database and from json representation --- src/_zkapauthorizer/model.py | 40 +++++++++++++++++--- src/_zkapauthorizer/tests/strategies.py | 7 +++- src/_zkapauthorizer/tests/test_controller.py | 2 +- src/_zkapauthorizer/tests/test_model.py | 4 +- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/_zkapauthorizer/model.py b/src/_zkapauthorizer/model.py index 8615b43..f8d69c2 100644 --- a/src/_zkapauthorizer/model.py +++ b/src/_zkapauthorizer/model.py @@ -211,7 +211,7 @@ class VoucherStore(object): cursor.execute( """ SELECT - [number], [created], [state], [finished], [token-count], [public-key] + [number], [created], [state], [finished], [token-count], [public-key], [counter] FROM [vouchers] WHERE @@ -295,7 +295,7 @@ class VoucherStore(object): cursor.execute( """ SELECT - [number], [created], [state], [finished], [token-count], [public-key] + [number], [created], [state], [finished], [token-count], [public-key], [counter] FROM [vouchers] """, @@ -637,6 +637,20 @@ def has_length(expected): ) return validate_has_length +def greater_than(expected): + def validate_relation(inst, attr, value): + if value > expected: + return None + + raise ValueError( + "{name!r} must be greater than {expected}, instead it was {actual}".format( + name=attr.name, + expected=expected, + actual=value, + ), + ) + return validate_relation + @attr.s(frozen=True) class UnblindedToken(object): @@ -710,12 +724,26 @@ class RandomToken(object): @attr.s(frozen=True) class Pending(object): + """ + The voucher has not yet been completely redeemed for ZKAPs. + + :ivar int counter: The number of partial redemptions which have been + successfully performed for the voucher. + """ + counter = attr.ib( + validator=attr.validators.and_( + attr.validators.instance_of((int, long)), + greater_than(-1), + ), + ) + def should_start_redemption(self): return True def to_json_v1(self): return { u"name": u"pending", + u"counter": self.counter, } @@ -845,13 +873,15 @@ class Voucher(object): default=None, validator=attr.validators.optional(attr.validators.instance_of(datetime)), ) - state = attr.ib(default=Pending()) + state = attr.ib(default=Pending(counter=0)) @classmethod def from_row(cls, row): def state_from_row(state, row): if state == u"pending": - return Pending() + # TODO: The 0 here should be row[3] but I can't write a test + # to prove it yet. + return Pending(counter=0) if state == u"double-spend": return DoubleSpend( parse_datetime(row[0], delimiter=u" "), @@ -888,7 +918,7 @@ class Voucher(object): state_json = values[u"state"] state_name = state_json[u"name"] if state_name == u"pending": - state = Pending() + state = Pending(counter=state_json[u"counter"]) elif state_name == u"redeeming": state = Redeeming( started=parse_datetime(state_json[u"started"]), diff --git a/src/_zkapauthorizer/tests/strategies.py b/src/_zkapauthorizer/tests/strategies.py index b648c5c..7776ff7 100644 --- a/src/_zkapauthorizer/tests/strategies.py +++ b/src/_zkapauthorizer/tests/strategies.py @@ -310,10 +310,13 @@ def redeemed_states(): def voucher_states(): """ - Build unicode strings giving states a Voucher can be in. + Build Python objects representing states a Voucher can be in. """ return one_of( - just(Pending()), + builds( + Pending, + integers(min_value=0), + ), redeemed_states(), builds( DoubleSpend, diff --git a/src/_zkapauthorizer/tests/test_controller.py b/src/_zkapauthorizer/tests/test_controller.py index 608ef72..16d1255 100644 --- a/src/_zkapauthorizer/tests/test_controller.py +++ b/src/_zkapauthorizer/tests/test_controller.py @@ -153,7 +153,7 @@ class PaymentControllerTests(TestCase): persisted_voucher = store.get(voucher) self.assertThat( persisted_voucher.state, - Equals(model_Pending()), + Equals(model_Pending(counter=0)), ) @given(tahoe_configs(), dummy_ristretto_keys(), datetimes(), vouchers()) diff --git a/src/_zkapauthorizer/tests/test_model.py b/src/_zkapauthorizer/tests/test_model.py index 27fbcab..e6df76c 100644 --- a/src/_zkapauthorizer/tests/test_model.py +++ b/src/_zkapauthorizer/tests/test_model.py @@ -129,7 +129,7 @@ class VoucherStoreTests(TestCase): store.get(voucher), MatchesStructure( number=Equals(voucher), - state=Equals(Pending()), + state=Equals(Pending(counter=0)), created=Equals(now), ), ) @@ -148,7 +148,7 @@ class VoucherStoreTests(TestCase): MatchesStructure( number=Equals(voucher), created=Equals(now), - state=Equals(Pending()), + state=Equals(Pending(counter=0)), ), ) self.assertThat( -- GitLab