Commit 2e13d4e8 authored by inso's avatar inso

Fix parsing of advanced tx

parent 7f83f10d
......@@ -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)
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)
......
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, ')')])))
......@@ -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()
......
This diff is collapsed.
......@@ -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)
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