Commit 236f9469 authored by Vincent Texier's avatar Vincent Texier

Merge branch 'output_condition' into 'dev'

Output condition

See merge request !57
parents 676b1099 e10c515a
Pipeline #5435 passed with stages
in 2 minutes and 33 seconds
...@@ -38,16 +38,14 @@ push_to_github: ...@@ -38,16 +38,14 @@ push_to_github:
- pyenv shell $PYENV_PYTHON_VERSION - pyenv shell $PYENV_PYTHON_VERSION
.changes: &changes .changes: &changes
except: only:
changes: changes:
- CHANGELOG.md - duniterpy/**/*.py
- ci/* - .gitlab-ci.yml
- config - requirements_dev.txt
- docs - requirements.txt
- LICENSE* - setup.py
- Makefile - tests/**/*.py
- README*
- release.sh
build: &build build: &build
<<: *pyenv <<: *pyenv
......
...@@ -486,8 +486,7 @@ class Transaction(Document): ...@@ -486,8 +486,7 @@ class Transaction(Document):
tx_data["currency"] = currency tx_data["currency"] = currency
for data_list in ('issuers', 'outputs', 'inputs', 'unlocks', 'signatures'): for data_list in ('issuers', 'outputs', 'inputs', 'unlocks', 'signatures'):
tx_data['multiline_{0}'.format(data_list)] = '\n'.join(tx_data[data_list]) tx_data['multiline_{0}'.format(data_list)] = '\n'.join(tx_data[data_list])
if tx_data["version"] >= 3: return cls.from_signed_raw("""Version: {version}
signed_raw = """Version: {version}
Type: Transaction Type: Transaction
Currency: {currency} Currency: {currency}
Blockstamp: {blockstamp} Blockstamp: {blockstamp}
...@@ -502,24 +501,7 @@ Outputs: ...@@ -502,24 +501,7 @@ Outputs:
{multiline_outputs} {multiline_outputs}
Comment: {comment} Comment: {comment}
{multiline_signatures} {multiline_signatures}
""".format(**tx_data) """.format(**tx_data))
else:
signed_raw = """Version: {version}
Type: Transaction
Currency: {currency}
Locktime: {locktime}
Issuers:
{multiline_issuers}
Inputs:
{multiline_inputs}
Unlocks:
{multiline_unlocks}
Outputs:
{multiline_outputs}
Comment: {comment}
{multiline_signatures}
""".format(**tx_data)
return cls.from_signed_raw(signed_raw)
@classmethod @classmethod
def from_compact(cls: Type[TransactionType], currency: str, compact: str) -> TransactionType: def from_compact(cls: Type[TransactionType], currency: str, compact: str) -> TransactionType:
...@@ -613,10 +595,8 @@ Comment: {comment} ...@@ -613,10 +595,8 @@ Comment: {comment}
currency = Transaction.parse_field("Currency", lines[n]) currency = Transaction.parse_field("Currency", lines[n])
n += 1 n += 1
blockstamp = None # type: Optional[BlockUID] blockstamp = BlockUID.from_str(Transaction.parse_field("Blockstamp", lines[n]))
if version >= 3: n += 1
blockstamp = BlockUID.from_str(Transaction.parse_field("Blockstamp", lines[n]))
n += 1
locktime = Transaction.parse_field("Locktime", lines[n]) locktime = Transaction.parse_field("Locktime", lines[n])
n += 1 n += 1
...@@ -679,8 +659,7 @@ Currency: {1} ...@@ -679,8 +659,7 @@ Currency: {1}
""".format(self.version, """.format(self.version,
self.currency) self.currency)
if self.version >= 3: doc += "Blockstamp: {0}\n".format(self.blockstamp)
doc += "Blockstamp: {0}\n".format(self.blockstamp)
doc += "Locktime: {0}\n".format(self.locktime) doc += "Locktime: {0}\n".format(self.locktime)
...@@ -727,8 +706,7 @@ COMMENT ...@@ -727,8 +706,7 @@ COMMENT
len(self.outputs), len(self.outputs),
'1' if self.comment != "" else '0', '1' if self.comment != "" else '0',
self.locktime) self.locktime)
if self.version >= 3: doc += "{0}\n".format(self.blockstamp)
doc += "{0}\n".format(self.blockstamp)
for pubkey in self.issuers: for pubkey in self.issuers:
doc += "{0}\n".format(pubkey) doc += "{0}\n".format(pubkey)
......
...@@ -32,7 +32,7 @@ SIGType = TypeVar('SIGType', bound='SIG') ...@@ -32,7 +32,7 @@ SIGType = TypeVar('SIGType', bound='SIG')
class SIG: class SIG:
""" """
Signature function in transaction output condition SIGnature function in transaction output condition
""" """
grammar = "SIG(", attr('pubkey', Pubkey), ")" grammar = "SIG(", attr('pubkey', Pubkey), ")"
...@@ -60,7 +60,7 @@ class SIG: ...@@ -60,7 +60,7 @@ class SIG:
sig.pubkey = pubkey sig.pubkey = pubkey
return sig return sig
def compose(self, parser: Any, grammar: Any = None, attr_of: Any = None) -> str: def compose(self, parser: Any = None, grammar: Any = None, attr_of: Any = None) -> str:
""" """
Return the SIG(pubkey) expression as string format Return the SIG(pubkey) expression as string format
...@@ -106,7 +106,7 @@ class CSV: ...@@ -106,7 +106,7 @@ class CSV:
csv.time = str(time) csv.time = str(time)
return csv return csv
def compose(self, parser: Any, grammar: Any = None, attr_of: str = None): def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None):
""" """
Return the CSV(time) expression as string format Return the CSV(time) expression as string format
...@@ -151,7 +151,7 @@ class CLTV: ...@@ -151,7 +151,7 @@ class CLTV:
cltv.timestamp = str(timestamp) cltv.timestamp = str(timestamp)
return cltv return cltv
def compose(self, parser: Any, grammar: Any = None, attr_of: str = None): def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None):
""" """
Return the CLTV(timestamp) expression as string format Return the CLTV(timestamp) expression as string format
...@@ -196,7 +196,7 @@ class XHX: ...@@ -196,7 +196,7 @@ class XHX:
xhx.sha_hash = sha_hash xhx.sha_hash = sha_hash
return xhx return xhx
def compose(self, parser: Any, grammar: Any = None, attr_of: str = None) -> str: def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None) -> str:
""" """
Return the XHX(sha_hash) expression as string format Return the XHX(sha_hash) expression as string format
...@@ -229,7 +229,7 @@ class Operator(Keyword): ...@@ -229,7 +229,7 @@ class Operator(Keyword):
op = cls(keyword) op = cls(keyword)
return op return op
def compose(self, parser: Any, grammar: Any = None, attr_of: str = None) -> str: def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None) -> str:
""" """
Return the Operator keyword as string format Return the Operator keyword as string format
......
...@@ -2,92 +2,109 @@ import unittest ...@@ -2,92 +2,109 @@ import unittest
import pypeg2 import pypeg2
from duniterpy.grammars import output from duniterpy.grammars.output import SIG, CLTV, CSV, XHX, Operator, Condition
pubkey = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"
class TestOutputgrammar(unittest.TestCase): class TestOutputgrammar(unittest.TestCase):
def test_sig(self): def test_sig(self):
condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)" condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)"
result = pypeg2.parse(condition, output.SIG) result = pypeg2.parse(condition, SIG)
self.assertEqual(result.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_xhx(self): def test_xhx(self):
condition = "XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)" condition = "XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)"
result = pypeg2.parse(condition, output.XHX) result = pypeg2.parse(condition, XHX)
self.assertEqual(result.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(result.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
def test_sig_condition(self): def test_sig_condition(self):
condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)" condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)"
result = pypeg2.parse(condition, output.Condition) result = pypeg2.parse(condition, Condition)
self.assertEqual(result.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_xhr_condition(self): def test_xhr_condition(self):
condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)" condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)"
result = pypeg2.parse(condition, output.Condition) result = pypeg2.parse(condition, Condition)
self.assertEqual(result.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_simple_condition(self): def test_simple_condition(self):
condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd))" condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd))"
result = pypeg2.parse(condition, output.Condition) result = pypeg2.parse(condition, Condition)
self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_simple_and_condition(self): def test_simple_and_condition(self):
condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) && XHX(" \ condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) && XHX(" \
"309BC5E644F797F53E5A2065EAF38A173437F2E6))" "309BC5E644F797F53E5A2065EAF38A173437F2E6))"
result = pypeg2.parse(condition, output.Condition) result = pypeg2.parse(condition, Condition)
self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(result.left.op.name, "&&") self.assertEqual(result.left.op.name, "&&")
self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_simple_or_condition(self): def test_simple_or_condition(self):
condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || XHX(" \ condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || XHX(" \
"309BC5E644F797F53E5A2065EAF38A173437F2E6))" "309BC5E644F797F53E5A2065EAF38A173437F2E6))"
result = pypeg2.parse(condition, output.Condition) result = pypeg2.parse(condition, Condition)
self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(result.left.op.name, "||") self.assertEqual(result.left.op.name, "||")
self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_complex_condition(self): def test_complex_condition(self):
condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \ condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \
"DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))"
result = pypeg2.parse(condition, output.Condition) result = pypeg2.parse(condition, Condition)
self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(result.left.op.name, "||") self.assertEqual(result.left.op.name, "||")
self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
self.assertEqual(result.left.right.op.name, "&&") self.assertEqual(result.left.right.op.name, "&&")
self.assertEqual(result.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(result.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_csv_cltv_condition(self): def test_csv_cltv_condition(self):
condition = "(CSV(1654300) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && CLTV(2594024)))" condition = "(CSV(1654300) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && CLTV(2594024)))"
result = pypeg2.parse(condition, output.Condition) result = pypeg2.parse(condition, Condition)
self.assertEqual(result.left.left.time, "1654300") self.assertEqual(result.left.left.time, "1654300")
self.assertEqual(result.left.op.name, "||") self.assertEqual(result.left.op.name, "||")
self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
self.assertEqual(result.left.right.op.name, "&&") self.assertEqual(result.left.right.op.name, "&&")
self.assertEqual(result.left.right.right.timestamp, "2594024") self.assertEqual(result.left.right.right.timestamp, "2594024")
self.assertEqual(pypeg2.compose(result, output.Condition), condition) self.assertEqual(pypeg2.compose(result, Condition), condition)
def test_instanciate_condition(self): def test_instanciate_condition(self):
output.Condition.token(output.SIG.token("HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"), Condition.token(SIG.token("HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"),
output.Operator.token("||"), Operator.token("||"),
output.Condition.token( Condition.token(
output.SIG.token("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"), SIG.token("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"),
output.Operator.token("&&"), Operator.token("&&"),
output.XHX.token("309BC5E644F797F53E5A2065EAF38A173437F2E6") XHX.token("309BC5E644F797F53E5A2065EAF38A173437F2E6")
)) ))
condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \ condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \
"DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))"
inst = pypeg2.parse(condition, output.Condition) inst = pypeg2.parse(condition, Condition)
self.assertEqual(inst.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") self.assertEqual(inst.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
self.assertEqual(inst.left.op.name, "||") self.assertEqual(inst.left.op.name, "||")
self.assertEqual(inst.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") self.assertEqual(inst.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
self.assertEqual(inst.left.right.op.name, "&&") self.assertEqual(inst.left.right.op.name, "&&")
self.assertEqual(inst.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(inst.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
self.assertEqual(pypeg2.compose(inst, output.Condition), condition) self.assertEqual(pypeg2.compose(inst, Condition), condition)
def test_SIG_token_and_compose(self):
self.assertEqual(SIG.token(pubkey).compose(), "SIG(" + pubkey + ")")
def test_CSV_token_and_compose(self):
self.assertEqual(CSV.token(pubkey).compose(), "CSV(" + pubkey + ")")
def test_CLTV_token_and_compose(self):
self.assertEqual(CLTV.token(pubkey).compose(), "CLTV(" + pubkey + ")")
def test_HXH_token_and_compose(self):
self.assertEqual(XHX.token(pubkey).compose(), "XHX(" + pubkey + ")")
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