Commit 5311bba6 authored by Vincent Texier's avatar Vincent Texier

Merge branch 'tx_eq' into 'dev'

Transaction equality implementation

See merge request !58
parents e5132867 63a7a7d4
Pipeline #5500 passed with stages
in 3 minutes and 39 seconds
......@@ -230,6 +230,19 @@ class SIGParameter:
"""
self.index = index
def __eq__(self, other: Any) -> bool:
"""
Check SIGParameter instances equality
"""
if not isinstance(other, SIGParameter):
return NotImplemented
return self.index == other.index
def __hash__(self) -> int:
return hash((self.index))
@classmethod
def from_parameter(cls: Type[SIGParameterType], parameter: str) -> Optional[SIGParameterType]:
"""
......@@ -272,6 +285,19 @@ class XHXParameter:
"""
self.integer = integer
def __eq__(self, other: Any) -> bool:
"""
Check XHXParameter instances equality
"""
if not isinstance(other, XHXParameter):
return NotImplemented
return self.integer == other.integer
def __hash__(self) -> int:
return hash((self.integer))
@classmethod
def from_parameter(cls: Type[XHXParameterType], parameter: str) -> Optional[XHXParameterType]:
"""
......@@ -348,6 +374,24 @@ class Unlock:
self.index = index
self.parameters = parameters
def __eq__(self, other: Any) -> bool:
"""
Check Unlock instances equality
"""
if not isinstance(other, Unlock):
return NotImplemented
params_equals = True
for spar, opar in zip(self.parameters, other.parameters):
if spar != opar:
params_equals = False
return self.index == other.index and params_equals
def __hash__(self) -> int:
return hash((self.index, self.parameters))
@classmethod
def from_inline(cls: Type[UnlockType], inline: str) -> UnlockType:
"""
......@@ -448,7 +492,7 @@ class Transaction(Document):
def __init__(self, version: int, currency: str, blockstamp: Optional[BlockUID], locktime: int, issuers: List[str],
inputs: List[InputSource], unlocks: List[Unlock], outputs: List[OutputSource],
comment: str, signatures: List[str]) -> None:
comment: str, time: int, signatures: List[str]) -> None:
"""
Init Transaction instance
......@@ -461,6 +505,7 @@ class Transaction(Document):
:param unlocks: List of Unlock instances
:param outputs: List of OutputSource instances
:param comment: Comment field
:param time: time when the transaction enters the blockchain
:param signatures: List of signatures
"""
super().__init__(version, currency, signatures)
......@@ -471,6 +516,31 @@ class Transaction(Document):
self.unlocks = unlocks
self.outputs = outputs
self.comment = comment
self.time = time
def __eq__(self, other: Any) -> bool:
"""
Check Transaction instances equality
"""
if not isinstance(other, Transaction):
return NotImplemented
return self.version == other.version and \
self.currency == other.currency and \
self.signatures == other.signatures and \
self.blockstamp == other.blockstamp and \
self.locktime == other.locktime and \
self.issuers == other.issuers and \
self.inputs == other.inputs and \
self.unlocks == other.unlocks and \
self.outputs == other.outputs and \
self.comment == other.comment and \
self.time == other.time
def __hash__(self) -> int:
return hash((self.version, self.currency, self.signatures, self.blockstamp, self.locktime, self.issuers, self.inputs, self.unlocks, self.outputs, self.comment, self.time))
@classmethod
def from_bma_history(cls: Type[TransactionType], currency: str, tx_data: Dict) -> TransactionType:
......@@ -501,7 +571,7 @@ Outputs:
{multiline_outputs}
Comment: {comment}
{multiline_signatures}
""".format(**tx_data))
""".format(**tx_data), tx_data["time"])
@classmethod
def from_compact(cls: Type[TransactionType], currency: str, compact: str) -> TransactionType:
......@@ -572,10 +642,10 @@ Comment: {comment}
else:
raise MalformedDocumentError("Compact TX Signatures")
return cls(version, currency, blockstamp, locktime, issuers, inputs, unlocks, outputs, comment, signatures)
return cls(version, currency, blockstamp, locktime, issuers, inputs, unlocks, outputs, comment, 0, signatures)
@classmethod
def from_signed_raw(cls: Type[TransactionType], raw: str) -> TransactionType:
def from_signed_raw(cls: Type[TransactionType], raw: str, time: int = 0) -> TransactionType:
"""
Return a Transaction instance from a raw string format
......@@ -645,7 +715,7 @@ Comment: {comment}
n += 1
return cls(version, currency, blockstamp, locktime, issuers, inputs, unlocks, outputs,
comment, signatures)
comment, time, signatures)
def raw(self) -> str:
"""
......@@ -732,7 +802,7 @@ class SimpleTransaction(Transaction):
def __init__(self, version: int, currency: str, blockstamp: BlockUID, locktime: int, issuer: str,
single_input: InputSource, unlocks: List[Unlock], outputs: List[OutputSource], comment: str,
signature: str) -> None:
time: int, signature: str) -> None:
"""
Init instance
......@@ -745,10 +815,11 @@ class SimpleTransaction(Transaction):
:param unlocks: List of Unlock instances
:param outputs: List of OutputSource instances
:param comment: Comment field
:param time: time when the transaction enters the blockchain
:param signature: Signature
"""
super().__init__(version, currency, blockstamp, locktime, [issuer], [single_input], unlocks,
outputs, comment, [signature])
outputs, comment, time ,[signature])
@staticmethod
def is_simple(tx: Transaction) -> bool:
......
......@@ -48,6 +48,19 @@ class SIG:
def __str__(self) -> str:
return self.value
def __eq__(self, other: Any) -> bool:
"""
Check SIG instances equality
"""
if not isinstance(other, SIG):
return NotImplemented
return self.value == other.value and \
self.pubkey == other.pubkey
def __hash__(self) -> int:
return hash((self.value, self.pubkey))
@classmethod
def token(cls: Type[SIGType], pubkey: str) -> SIGType:
"""
......@@ -94,6 +107,19 @@ class CSV:
def __str__(self) -> str:
return self.value
def __eq__(self, other: Any) -> bool:
"""
Check CSV instances equality
"""
if not isinstance(other, CSV):
return NotImplemented
return self.value == other.value and \
self.time == other.time
def __hash__(self) -> int:
return hash((self.value, self.time))
@classmethod
def token(cls: Type[CSVType], time: int) -> CSVType:
"""
......@@ -139,6 +165,19 @@ class CLTV:
def __str__(self) -> str:
return self.value
def __eq__(self, other: Any) -> bool:
"""
Check CLTV instances equality
"""
if not isinstance(other, CLTV):
return NotImplemented
return self.value == other.value and \
self.timestamp == other.timestamp
def __hash__(self) -> int:
return hash((self.value, self.timestamp))
@classmethod
def token(cls: Type[CLTVType], timestamp: int) -> CLTVType:
"""
......@@ -184,6 +223,19 @@ class XHX:
def __str__(self) -> str:
return self.value
def __eq__(self, other: Any) -> bool:
"""
Check XHX instances equality
"""
if not isinstance(other, XHX):
return NotImplemented
return self.value == other.value and \
self.sha_hash == other.sha_hash
def __hash__(self) -> int:
return hash((self.value, self.sha_hash))
@classmethod
def token(cls: Type[XHXType], sha_hash: str) -> XHXType:
"""
......@@ -262,6 +314,21 @@ class Condition:
self.right = ''
self.op = ''
def __eq__(self, other: Any) -> bool:
"""
Check Condition instances equality
"""
if not isinstance(other, Condition):
return NotImplemented
return self.value == other.value and \
self.left == other.left and \
self.right == other.right and \
self.op == other.op
def __hash__(self) -> int:
return hash((self.value, self.left, self.right, self.op))
def __str__(self) -> str:
return self.value
......
......@@ -104,6 +104,9 @@ Comment: -----@@@----- (why not this comment?)
2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk
"""
input_source_str = "30:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2"
output_source_str = "460:0:SIG(8kXygUHh1vLjmcRzXVM86t38EL8dfFJgfBeHmkaWLamu)"
class TestTransaction(unittest.TestCase):
def test_fromcompact(self):
......@@ -291,18 +294,41 @@ class TestTransaction(unittest.TestCase):
def test_inputsource_from_inline(self):
input_source_str = "30:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2"
i = InputSource.from_inline(input_source_str)
self.assertEqual(i.inline(), input_source_str)
def test_outputsource_from_inline(self):
output_source_str = "460:0:SIG(8kXygUHh1vLjmcRzXVM86t38EL8dfFJgfBeHmkaWLamu)"
o = OutputSource.from_inline(output_source_str)
self.assertEqual(o.inline(), output_source_str)
def test_outputsource_inline_condition(self):
output_source_str = "460:0:SIG(8kXygUHh1vLjmcRzXVM86t38EL8dfFJgfBeHmkaWLamu)"
o = OutputSource.from_inline(output_source_str)
self.assertEqual(o.inline_condition(), output_source_str.split(":")[2])
def test_transaction_equality(self):
t1 = Transaction.from_signed_raw(tx_raw)
t2 = Transaction.from_signed_raw(tx_raw)
self.assertTrue(t1 == t2)
t2.signatures = ["NSTN"]
self.assertFalse(t1 == t2)
t2 = Transaction.from_signed_raw(tx_raw)
t2.issuers = ["NSTRNRST"]
self.assertFalse(t1 == t2)
t2 = Transaction.from_signed_raw(tx_raw)
t2.time = 123
self.assertFalse(t1 == t2)
t2 = Transaction.from_signed_raw(tx_raw)
t2.inputs = InputSource.from_inline(input_source_str)
self.assertFalse(t1 == t2)
t2 = Transaction.from_signed_raw(tx_raw)
t2.outputs = OutputSource.from_inline(output_source_str)
self.assertFalse(t1 == t2)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment