diff --git a/duniterpy/documents/constants.py b/duniterpy/documents/constants.py index 7b7271989e712dcaee7c1ca024a075b551a28760..51d34b44ac74f44850f3839242f4993f5c386577 100644 --- a/duniterpy/documents/constants.py +++ b/duniterpy/documents/constants.py @@ -4,6 +4,9 @@ pubkey_regex = "(?![OIl])[1-9A-Za-z]{42,45}" signature_regex = "[A-Za-z0-9+/]+(?:=|==)?" block_hash_regex = "[0-9a-fA-F]{5,64}" transaction_hash_regex = "[0-9a-fA-F]{5,64}" +hash_regex = "[A-F0-9]{64}" block_id_regex = "[0-9]+" block_uid_regex = "{block_id_regex}-{block_hash_regex}".format(block_id_regex=block_id_regex, - block_hash_regex=block_hash_regex) \ No newline at end of file + block_hash_regex=block_hash_regex) +conditions_regex = "(&&|\|\|| |[()]|(SIG\({pubkey_regex}\)|(XHX\({hash_regex}\))))*"\ + .format(pubkey_regex=pubkey_regex, hash_regex=hash_regex) diff --git a/duniterpy/documents/transaction.py b/duniterpy/documents/transaction.py index c27330a1356f1f0435a8fcc410528b5236092beb..580c2d7fd8e7d6f54c91435094ff931453d32e4b 100644 --- a/duniterpy/documents/transaction.py +++ b/duniterpy/documents/transaction.py @@ -1,5 +1,5 @@ from .document import Document, MalformedDocumentError -from .constants import pubkey_regex, transaction_hash_regex, block_id_regex, block_uid_regex +from .constants import pubkey_regex, transaction_hash_regex, block_id_regex, block_uid_regex, conditions_regex from ..grammars import output import pypeg2 import re @@ -576,7 +576,7 @@ class OutputSource: """ A Transaction OUTPUT """ - re_inline = re.compile("([0-9]+):([0-9]+):([A-Za-z0-9\(\)\s]+)\n") + re_inline = re.compile("([0-9]+):([0-9]+):(.*)\n") def __init__(self, amount, base, conditions): self.amount = amount @@ -590,8 +590,9 @@ class OutputSource: raise MalformedDocumentError("Inline output") amount = int(data.group(1)) base = int(data.group(2)) + conditions_text = data.group(3) try: - conditions = pypeg2.parse(data.group(3), output.Condition) + conditions = pypeg2.parse(conditions_text, output.Condition) except SyntaxError: raise MalformedDocumentError("Output source syntax error") return cls(amount, base, conditions) diff --git a/duniterpy/grammars/output.py b/duniterpy/grammars/output.py index 183543d070ae88f38c1f871e87712a02a4ccc0d0..dd54ba09fc00956158ca0049f0ea037da54892ec 100644 --- a/duniterpy/grammars/output.py +++ b/duniterpy/grammars/output.py @@ -1,5 +1,5 @@ from ..documents.constants import pubkey_regex -from ..documents.constants import block_hash_regex as hash_regex +from ..documents.constants import hash_regex from pypeg2 import * @@ -11,6 +11,10 @@ class Hash(str): regex = re.compile(hash_regex) +class Int(str): + regex = re.compile(r"[0-9]+") + + class SIG(str): grammar = "SIG(", attr('pubkey', Pubkey), ")" @@ -24,6 +28,32 @@ class SIG(str): return "SIG({0})".format(self.pubkey) +class CSV(str): + grammar = "CSV(", attr('time', Int), ")" + + @classmethod + def token(cls, time): + csv = cls() + csv.time = str(time) + return csv + + def compose(self, parser, grammar=None, attr_of=None): + return "CSV({0})".format(self.time) + + +class CLTV(str): + grammar = "CLTV(", attr('timestamp', Int), ")" + + @classmethod + def token(cls, timestamp): + cltv = cls() + cltv.timestamp = str(timestamp) + return cltv + + def compose(self, parser, grammar=None, attr_of=None): + return "CLTV({0})".format(self.timestamp) + + class XHX(str): grammar = "XHX(", attr('sha_hash', Hash), ")" @@ -38,7 +68,8 @@ class XHX(str): class Operator(Keyword): - grammar = Enum(K("AND"), K("OR")) + grammar = Enum(K("&&"), K("||"), K("AND"), K("OR")) + regex = re.compile(r"[&&|\|\||\w]+") @classmethod def token(cls, keyword): @@ -78,6 +109,6 @@ class Condition(str): result = left return result -Condition.grammar = contiguous(attr('left', [SIG, XHX, ('(', Condition, ')')]), +Condition.grammar = contiguous(attr('left', [SIG, XHX, CSV, CLTV, ('(', Condition, ')')]), maybe_some(whitespace, attr('op', Operator), whitespace, - attr('right', [SIG, XHX, ('(', Condition, ')')]))) + attr('right', [SIG, XHX, CSV, CLTV, ('(', Condition, ')')]))) diff --git a/tests/documents/test_block.py b/tests/documents/test_block.py index 4c37a55ddb85899c4c9a7f728d1bb66659a02e8c..eaa81dd8e52b67e794c7febb5a0199869218ef76 100644 --- a/tests/documents/test_block.py +++ b/tests/documents/test_block.py @@ -80,7 +80,7 @@ D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46 5:SIG(2) 120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) 146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) +49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(12CCC75A48B1502E4A4E5E9EC2C5153AE2DDF760D5B70262103309D4C7FA86EE)) -----@@@----- (why not this comment?) 42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r 2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX @@ -164,72 +164,6 @@ Nonce: 9906 5LZCFSnm5FkFihPBTpmsPyILEdvu8MXfJOp6OR4d1s+/e2jVWg4J6YSDfO2KBBPgubASyr2QwQuiBlYD2918Bw== """ -raw_block_with_tx_v3 = """Version: 3 -Type: Block -Currency: meta_brouzouf -Number: 34436 -PoWMin: 5 -Time: 1443896211 -MedianTime: 1443881811 -UnitBase: 3 -Issuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk -IssuersFrame: 43 -IssuersFrameVar: 2 -DifferentIssuersCount: 8 -PreviousHash: 000002B06C990DEBD5C1D947289C2CF4F4396FB2 -PreviousIssuer: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk -MembersCount: 19 -Identities: -Joiners: -Actives: -ATkjQPa4sn4LBF69jqEPzFtRdHYJs6MJQjvP8JdN7MtN:QTowsupV+uXrcomL44WCxbu3LQoJM2C2VPMet5Xg6gXGAHEtGRp47FfQLb2ok1+/588JiIHskCyazj3UOsmKDw==:34434-00000D21F80687248A8C02F16BB19A975B4F983D:34432-00000D21F80687248A8C02F16BB19A975B4F983D:urodelus -Leavers: -Revoked: -Excluded: -Certifications: -5ocqzyDMMWf1V8bsoNhWb1iNwax1e9M7VTUN6navs8of:ATkjQPa4sn4LBF69jqEPzFtRdHYJs6MJQjvP8JdN7MtN:0:6TuxRcARnpo13l3cXtgPTkjJlv8DZOUvsAzmZJMbjHZbbZfDQ6MJpH9DIuH0eyG3WGc0EX/046mbMGBrKKg9DQ== -ATkjQPa4sn4LBF69jqEPzFtRdHYJs6MJQjvP8JdN7MtN:2qwGeLWoPG7db72bKXPfJpAtj67FYDnPaJn2JB7tyXxJ:0:LusTbb7CgwrqqacDKjtldw60swwvDBH8wVUIJN4SWRb2pZPJSpDxgqaGyjC5P9i/DendfyQWc7cfzPDqSZmZAg== -Transactions: -TX:3:1:3:3:1:0:0 -32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD -HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY -5:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:0 -1:1:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:10 -35:0:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:88 -0:SIG(0) -1:SIG(0) -2:SIG(0) -30:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) -42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r -TX:3:3:6:6:3:1:0 -3-DB30D958EE5CB75186972286ED3F4686B8A1C2CD -HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY -CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp -9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB -30:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2 -25:0:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8 -5:1:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46 -10:1:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3 -60:0:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5 -50:0:D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46 -0:SIG(0) -1:XHX(7665798292) -2:SIG(0) -3:SIG(0) SIG(2) -4:SIG(0) SIG(1) SIG(2) -5:SIG(2) -120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) -146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) ------@@@----- (why not this comment?) -42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r -2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX -2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk -InnerHash: DB30D958EE5CB75186972286ED3F4686B8A1C2CD -Nonce: 581 -nY/MsFU2luiohLmSiOOimL1RIqbriOBgc22ua03Z2dhxtSJxKZeGNGDvl1jaXgmEBRnXU87yXbZ7ioOS/AAVCA== -""" - raw_block_with_excluded = """Version: 3 Type: Block @@ -452,31 +386,6 @@ class Test_Block(unittest.TestCase): self.assertEqual(block.signed_raw(), raw_block_with_tx) - def test_raw_with_tx_v3(self): - block = Block.from_signed_raw(raw_block_with_tx_v3) - rendered_raw = block.signed_raw() - from_rendered_raw = block.from_signed_raw(rendered_raw) - - self.assertEqual(from_rendered_raw.version, 3) - self.assertEqual(from_rendered_raw.currency, "meta_brouzouf") - self.assertEqual(from_rendered_raw.noonce, 581) - self.assertEqual(from_rendered_raw.number, 34436) - self.assertEqual(from_rendered_raw.powmin, 5) - self.assertEqual(from_rendered_raw.time, 1443896211) - self.assertEqual(from_rendered_raw.mediantime, 1443881811) - self.assertEqual(from_rendered_raw.issuer, "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk") - self.assertEqual(from_rendered_raw.parameters, None) - self.assertEqual(from_rendered_raw.members_count, 19) - self.assertEqual(from_rendered_raw.identities, []) - self.assertEqual(from_rendered_raw.joiners, []) - self.assertEqual(len(from_rendered_raw.actives), 1) - self.assertEqual(from_rendered_raw.leavers, []) - self.assertEqual(from_rendered_raw.excluded, []) - self.assertEqual(len(from_rendered_raw.certifications), 2) - self.assertEqual(len(from_rendered_raw.transactions), 2) - - self.assertEqual(block.signed_raw(), raw_block_with_tx_v3) - def test_raw_with_leavers(self): block = Block.from_signed_raw(raw_block_with_leavers) rendered_raw = block.signed_raw() diff --git a/tests/documents/test_transaction.py b/tests/documents/test_transaction.py index 24246811b86b4df7bc74b78d6262515c2da111c3..a14fe4e117fc193e5554e663285bd478cea34521 100644 --- a/tests/documents/test_transaction.py +++ b/tests/documents/test_transaction.py @@ -9,6 +9,35 @@ from duniterpy.grammars import output from duniterpy.documents.transaction import Transaction, reduce_base, SimpleTransaction +compact_change = """TX:10:1:1:1:1:1:0 +13410-000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC +D8BsQZN9hangHVuqwD6McfxM1xvGJ8DPuPYrswwnSif3 +1500:1:T:0D0264F324BC4A23C4B2C696CD1907BD6E70FD1F409BB1D42E84847AA4C1E87C:0 +0:SIG(0) +1500:1:(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(36j6pCNzKDPo92m7UXJLFpgDbcLFAZBgThD2TCwTwGrd)) || (SIG(D8BsQZN9hangHVuqwD6McfxM1xvGJ8DPuPYrswwnSif3) && SIG(36j6pCNzKDPo92m7UXJLFpgDbcLFAZBgThD2TCwTwGrd)) +META tic to toc +eNAZpJjhZaPKbx5pUvuDDM1j4XNWJ4ABK48ouTvimvg3ceIcoZUvgLHmXuSwk2bgxZaB5qSKP9H6T7qsBcLtBg== +""" + + +xhx_output = """Version: 10 +Type: Transaction +Currency: gtest +Blockstamp: 13739-000087835A9B746C1A6E173DB13A2C3D23DBDE8B2C5E93565B644313FE3D179B +Locktime: 0 +Issuers: +95ApcNEeoFnjUYPwh4fbGqKPDe5mCJysfJfezLngEZcu +Inputs: +250:1:T:7AEDF83C99071E040698ED6E1445BF02FADEF37DA380795684D5C9271C037D5A:0 +Unlocks: +0:SIG(0) +Outputs: +250:1:(XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36) && SIG(DCYELkvV1aAsxFv58SbfRerHy5giJwKA1i4ZKTTcVGZe)) || (SIG(95ApcNEeoFnjUYPwh4fbGqKPDe5mCJysfJfezLngEZcu) && SIG(DCYELkvV1aAsxFv58SbfRerHy5giJwKA1i4ZKTTcVGZe)) +Comment: XHX for pubkey DCYELkvV1aAsxFv58SbfRerHy5giJwKA1i4ZKTTcVGZe +GXGephqTSJfb+8xsG/UMKRW0y+edL4RoMHM+OlgFq1aYOuaQ3/CtBKVSA01n2mkI7zwepeIABSjS94iVH4vZDg== +""" + + tx_compact = """TX:2:3:6:6:3:1:0 HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp @@ -27,13 +56,14 @@ D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46 5:SIG(2) 120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) 146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) +49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36)) -----@@@----- (why not this comment?) 42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r 2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX 2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk """ + tx_compact_2 = """TX:2:1:1:1:2:0:0 GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92 D:GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92:471 @@ -43,32 +73,6 @@ D:GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92:471 XDQeEMcJDd+XVGaFIZc8d4kKRJgsPuWAPVNG5UKNk8mDZx2oE1kTP/hbxiFx6yDouBELCswuf/X6POK9ES7JCA== """ -tx_compact_v3 = """TX:3:3:6:6:3:1:0 -32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD -HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY -CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp -9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB -30:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2 -25:0:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8 -5:1:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46 -10:1:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3 -60:0:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5 -50:0:D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46 -0:SIG(0) -1:XHX(7665798292) -2:SIG(0) -3:SIG(0) SIG(2) -4:SIG(0) SIG(1) SIG(2) -5:SIG(2) -120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) -146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) ------@@@----- (why not this comment?) -42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r -2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX -2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk -""" - tx_raw = """Version: 2 Type: Transaction Currency: beta_brousouf @@ -94,13 +98,14 @@ Unlocks: Outputs: 120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) 146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) +49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36)) Comment: -----@@@----- (why not this comment?) 42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r 2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX 2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk """ + tx_raw_v3 = """Version: 3 Type: Transaction Currency: beta_brousouf @@ -127,13 +132,14 @@ Unlocks: Outputs: 120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g) 146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx) -49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85)) +49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36)) Comment: -----@@@----- (why not this comment?) 42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r 2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX 2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk """ + class Test_Transaction(unittest.TestCase): def test_fromcompact(self): tx = Transaction.from_compact("zeta_brousouf", tx_compact) @@ -191,7 +197,7 @@ class Test_Transaction(unittest.TestCase): self.assertEqual(pypeg2.compose(tx.outputs[1].conditions, output.Condition), "SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)") self.assertEqual(tx.outputs[2].amount, 49) self.assertEqual(tx.outputs[2].base, 2) - self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85))") + self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))") self.assertEqual(tx.comment, "-----@@@----- (why not this comment?)") @@ -227,72 +233,6 @@ class Test_Transaction(unittest.TestCase): self.assertEqual(type(tx.outputs[1].conditions.left), output.SIG) self.assertEqual(tx.signatures[0], "XDQeEMcJDd+XVGaFIZc8d4kKRJgsPuWAPVNG5UKNk8mDZx2oE1kTP/hbxiFx6yDouBELCswuf/X6POK9ES7JCA==") - def test_fromcompact_v3(self): - tx = Transaction.from_compact("zeta_brousouf", tx_compact_v3) - self.assertEqual(tx.version, 3) - self.assertEqual(tx.currency, "zeta_brousouf") - self.assertEqual(tx.blockstamp.number, 32) - self.assertEqual(tx.blockstamp.sha_hash, "DB30D958EE5CB75186972286ED3F4686B8A1C2CD") - self.assertEqual(len(tx.issuers), 3) - self.assertEqual(len(tx.inputs), 6) - self.assertEqual(len(tx.unlocks), 6) - self.assertEqual(len(tx.outputs), 3) - - self.assertEqual(tx.issuers[0], "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY") - self.assertEqual(tx.issuers[1], "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp") - self.assertEqual(tx.issuers[2], "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB") - - self.assertEqual(tx.inputs[0].source, 'T') - self.assertEqual(tx.inputs[0].origin_id, "6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3") - self.assertEqual(tx.inputs[0].index, 2) - self.assertEqual(tx.inputs[1].source, 'T') - self.assertEqual(tx.inputs[1].origin_id, "3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435") - self.assertEqual(tx.inputs[1].index, 8) - self.assertEqual(tx.inputs[2].source, 'D') - self.assertEqual(tx.inputs[2].origin_id, "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY") - self.assertEqual(tx.inputs[2].index, 46) - self.assertEqual(tx.inputs[3].source, 'T') - self.assertEqual(tx.inputs[3].origin_id, "A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956") - self.assertEqual(tx.inputs[3].index, 3) - self.assertEqual(tx.inputs[4].source, 'T') - self.assertEqual(tx.inputs[4].origin_id, "67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B") - self.assertEqual(tx.inputs[4].index, 5) - self.assertEqual(tx.inputs[5].source, 'D') - self.assertEqual(tx.inputs[5].origin_id, "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB") - self.assertEqual(tx.inputs[5].index, 46) - - self.assertEqual(tx.unlocks[0].index, 0) - self.assertEqual(str(tx.unlocks[0].parameters[0]), "SIG(0)") - self.assertEqual(tx.unlocks[1].index, 1) - self.assertEqual(str(tx.unlocks[1].parameters[0]), "XHX(7665798292)") - self.assertEqual(tx.unlocks[2].index, 2) - self.assertEqual(str(tx.unlocks[2].parameters[0]), "SIG(0)") - self.assertEqual(tx.unlocks[3].index, 3) - self.assertEqual(str(tx.unlocks[3].parameters[0]), "SIG(0)") - self.assertEqual(str(tx.unlocks[3].parameters[1]), "SIG(2)") - self.assertEqual(tx.unlocks[4].index, 4) - self.assertEqual(str(tx.unlocks[4].parameters[0]), "SIG(0)") - self.assertEqual(str(tx.unlocks[4].parameters[1]), "SIG(1)") - self.assertEqual(str(tx.unlocks[4].parameters[2]), "SIG(2)") - self.assertEqual(tx.unlocks[5].index, 5) - self.assertEqual(str(tx.unlocks[5].parameters[0]), "SIG(2)") - - self.assertEqual(tx.outputs[0].amount, 120) - self.assertEqual(tx.outputs[0].base, 2) - self.assertEqual(pypeg2.compose(tx.outputs[0].conditions, output.Condition), "SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)") - self.assertEqual(tx.outputs[1].amount, 146) - self.assertEqual(tx.outputs[1].base, 2) - self.assertEqual(pypeg2.compose(tx.outputs[1].conditions, output.Condition), "SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)") - self.assertEqual(tx.outputs[2].amount, 49) - self.assertEqual(tx.outputs[2].base, 2) - self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85))") - - self.assertEqual(tx.comment, "-----@@@----- (why not this comment?)") - - self.assertEqual(tx.signatures[0], "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r") - self.assertEqual(tx.signatures[1], "2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX") - self.assertEqual(tx.signatures[2], "2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk") - def test_fromraw(self): tx = Transaction.from_signed_raw(tx_raw) self.assertEqual(tx.version, 2) @@ -349,7 +289,7 @@ class Test_Transaction(unittest.TestCase): self.assertEqual(pypeg2.compose(tx.outputs[1].conditions, output.Condition), "SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)") self.assertEqual(tx.outputs[2].amount, 49) self.assertEqual(tx.outputs[2].base, 2) - self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85))") + self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))") self.assertEqual(tx.comment, "-----@@@----- (why not this comment?)") @@ -416,7 +356,7 @@ class Test_Transaction(unittest.TestCase): self.assertEqual(pypeg2.compose(tx.outputs[1].conditions, output.Condition), "SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)") self.assertEqual(tx.outputs[2].amount, 49) self.assertEqual(tx.outputs[2].base, 2) - self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85))") + self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))") self.assertEqual(tx.comment, "-----@@@----- (why not this comment?)") @@ -485,7 +425,7 @@ class Test_Transaction(unittest.TestCase): self.assertEqual(pypeg2.compose(tx.outputs[1].conditions, output.Condition), "SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)") self.assertEqual(tx.outputs[2].amount, 49) self.assertEqual(tx.outputs[2].base, 2) - self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) OR XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85))") + self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition), "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))") self.assertEqual(tx.comment, "-----@@@----- (why not this comment?)") @@ -493,6 +433,11 @@ class Test_Transaction(unittest.TestCase): self.assertEqual(tx.signatures[1], "2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX") self.assertEqual(tx.signatures[2], "2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk") + def test_compact_change(self): + tx = Transaction.from_compact("gtest", compact_change) + rendered_tx = tx.signed_raw() + from_rendered_tx = Transaction.from_signed_raw(rendered_tx) + def test_reduce_base(self): amount = 1200 base = 0 diff --git a/tests/grammars/test_output.py b/tests/grammars/test_output.py index f6835060428a4abb95c21cd38274c6a7fe24b376..b3a1c9506cca05525a2787033c39b6f8497dc88f 100644 --- a/tests/grammars/test_output.py +++ b/tests/grammars/test_output.py @@ -34,44 +34,54 @@ class Test_OutputGrammar(unittest.TestCase): self.assertEqual(pypeg2.compose(result, output.Condition), condition) def test_simple_and_condition(self): - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) AND XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6))" + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6))" result = pypeg2.parse(condition, output.Condition) self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") - self.assertEqual(result.left.op.name, "AND") + self.assertEqual(result.left.op.name, "&&") self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(pypeg2.compose(result, output.Condition), condition) def test_simple_or_condition(self): - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) OR XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6))" + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6))" result = pypeg2.parse(condition, output.Condition) self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") - self.assertEqual(result.left.op.name, "OR") + self.assertEqual(result.left.op.name, "||") self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(pypeg2.compose(result, output.Condition), condition) def test_complex_condition(self): - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) OR (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) AND XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" result = pypeg2.parse(condition, output.Condition) self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") - self.assertEqual(result.left.op.name, "OR") + self.assertEqual(result.left.op.name, "||") self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") - self.assertEqual(result.left.right.op.name, "AND") + self.assertEqual(result.left.right.op.name, "&&") self.assertEqual(result.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(pypeg2.compose(result, output.Condition), condition) + def test_csv_cltv_condition(self): + condition = "(CSV(1654300) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && CLTV(2594024)))" + result = pypeg2.parse(condition, output.Condition) + self.assertEqual(result.left.left.time, "1654300") + self.assertEqual(result.left.op.name, "||") + self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") + self.assertEqual(result.left.right.op.name, "&&") + self.assertEqual(result.left.right.right.timestamp, "2594024") + self.assertEqual(pypeg2.compose(result, output.Condition), condition) + def test_instanciate_condition(self): inst = output.Condition.token(output.SIG.token("HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"), - output.Operator.token("OR"), + output.Operator.token("||"), output.Condition.token( output.SIG.token("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"), - output.Operator.token("AND"), + output.Operator.token("&&"), output.XHX.token("309BC5E644F797F53E5A2065EAF38A173437F2E6") )) - condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) OR (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) AND XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" + condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))" inst = pypeg2.parse(condition, output.Condition) self.assertEqual(inst.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd") - self.assertEqual(inst.left.op.name, "OR") + self.assertEqual(inst.left.op.name, "||") self.assertEqual(inst.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV") - self.assertEqual(inst.left.right.op.name, "AND") + self.assertEqual(inst.left.right.op.name, "&&") self.assertEqual(inst.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6") self.assertEqual(pypeg2.compose(inst, output.Condition), condition)