chainside / btcpy

A Python3 SegWit-compliant library which provides tools to handle Bitcoin data structures in a simple fashion.
https://www.chainside.net
GNU Lesser General Public License v3.0
270 stars 73 forks source link

added attribute check in SegWitTransaction's __getattr__ #49

Open GavinShox opened 6 years ago

GavinShox commented 6 years ago

This allows SegWitTransaction to be pickled successfully. Before, when deserializing a SegWitTransaction object, pickle would throw a RecursionError as it would attempt to call getattr before self.transaction existed, which would cause it to infinitely recall getattr when it couldn't resolve self.transaction.

SimoneBronzini commented 5 years ago

Hi, sorry for the delayed answer, can you provide a minimal working example of the problem? I am not sure in which cases it appears.

GavinShox commented 5 years ago

When you serialize a SegWitTransaction object using python's pickle module, it works. But the problem is when you try to deserialize that pickled object, you get this exception:

Traceback (most recent call last):
  File "C:/Users/gavin/PycharmProjects/Bit-Store/main.py", line 46, in <module>
    tx = w.import_transaction(ex)
  File "C:\Users\gavin\PycharmProjects\Bit-Store\lib\core\wallet.py", line 366, in import_transaction
    txn = self.deserialize_transaction(txn_bytes)
  File "C:\Users\gavin\PycharmProjects\Bit-Store\lib\core\wallet.py", line 307, in deserialize_transaction
    obj = pickle.loads(txn_bytes)
  File "C:\Users\gavin\AppData\Local\Programs\Python\Python36-32\lib\site-packages\btcpy\structs\transaction.py", line 744, in __getattr__
    return getattr(self.transaction, item)
  File "C:\Users\gavin\AppData\Local\Programs\Python\Python36-32\lib\site-packages\btcpy\structs\transaction.py", line 744, in __getattr__
    return getattr(self.transaction, item)
  File "C:\Users\gavin\AppData\Local\Programs\Python\Python36-32\lib\site-packages\btcpy\structs\transaction.py", line 744, in __getattr__
    return getattr(self.transaction, item)
  [Previous line repeated 328 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object

The issue is that pickle will actually attempt to get attributes from the SegWitTransaction object before self.transaction is actaully an attribute of the object. So in __getattr__, the function call getattr(self.transaction, item) will just recursivly re-call __getattr__ because self.transaction isn't defined yet.