[tor-commits] [stem/master] Refactor apply_digest to remove side effects

atagar at torproject.org atagar at torproject.org
Sun Aug 26 20:49:21 UTC 2018


commit 1a151d445832df3fdecdb99aa1ecbbe0fee14563
Author: Dave Rolek <dmr-x at riseup.net>
Date:   Wed Aug 15 03:28:03 2018 +0000

    Refactor apply_digest to remove side effects
    
    Per discussion with Damian over IRC, instances of our Cell classes are
    intended to be immutable objects. So instead of modifying the RelayCell
    and having an additional side effect on the digest, this provides a
    modified copy of each, in a tuple.
    
    That makes apply_digest() a pure function, currently with referential
    transparency (i.e. also deterministic). In the future, it may utilize
    randomness for cell padding, which would make it non-deterministic.
    
    Overall this now more generally follows a functional-programming
    paradigm.
---
 stem/client/__init__.py |  4 ++--
 stem/client/cell.py     | 33 +++++++++++++++++++++------------
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/stem/client/__init__.py b/stem/client/__init__.py
index 74b6d2bf..b64956ff 100644
--- a/stem/client/__init__.py
+++ b/stem/client/__init__.py
@@ -239,8 +239,8 @@ class Circuit(object):
 
       try:
         cell = stem.client.cell.RelayCell(self.id, command, data, stream_id = stream_id)
-        cell.apply_digest(self.forward_digest)
-        payload_with_digest = cell.pack_payload()
+        cell_with_digest, self.forward_digest = cell.apply_digest(self.forward_digest)
+        payload_with_digest = cell_with_digest.pack_payload()
 
         encrypted_payload = self.forward_key.update(payload_with_digest)
         encrypted_cell = stem.client.cell.RawRelayCell(self.id, encrypted_payload)
diff --git a/stem/client/cell.py b/stem/client/cell.py
index c1751ed6..fec8bb1b 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -458,7 +458,7 @@ class RelayCell(CircuitCell):
 
   def apply_digest(self, digest, prep_cell = True):
     """
-    Calculates, updates, and applies the digest to the cell payload.
+    Calculates, updates, and applies the digest to the cell payload, returning a new (cell, digest) tuple.
 
     :param HASH digest: running digest held with the relay
     :param bool prep_cell: preps the cell payload according to the spec, if **True** (default)
@@ -468,22 +468,31 @@ class RelayCell(CircuitCell):
         and any 'unused' padding will be taken as-is.
       Use with caution.
 
-    :sideeffect digest: this object will be updated via digest.update(payload)
-    :sideeffect self.recognized: this will be set to 0, if prep_cell is **True**
-    :sideeffect self.digest: this will be updated with the calculated digest
-    :sideeffect self.unused: this will be treated as padding and overwritten, if prep_cell is **True**
+    :returns: (:class:`~stem.client.cell.RelayCell`, HASH) tuple updated as follows:
+      digest: updated via digest.update(payload)
+      RelayCell: a copy of self, with the following updates:
+      RelayCell.recognized: set to 0, if prep_cell is **True**
+      RelayCell.digest: updated with the calculated digest
+      RelayCell.unused: treated as padding and overwritten, if prep_cell is **True**
     """
 
     if prep_cell:
-      self.recognized = 0
-      self.digest = 0
-      self.unused = b''
+      new_cell_recognized = 0
+      new_cell_digest = 0
+      new_cell_unused = b''
+    else:
+      new_cell_recognized = self.recognized
+      new_cell_digest = self.digest
+      new_cell_unused = self.unused
+
+    new_digest = digest.copy()
+    new_cell = RelayCell(self.circ_id, self.command, self.data, digest = new_cell_digest, stream_id = self.stream_id, recognized = new_cell_recognized, unused = new_cell_unused)
 
-    payload_without_updated_digest = self.pack_payload()
-    digest.update(payload_without_updated_digest)
-    self.digest = RelayCell._coerce_digest(digest)
+    payload_without_updated_digest = new_cell.pack_payload()
+    new_digest.update(payload_without_updated_digest)
+    new_cell.digest = RelayCell._coerce_digest(new_digest)
 
-    return
+    return new_cell, new_digest
 
   def pack_payload(self, **kwargs):
     """





More information about the tor-commits mailing list