From 4b0225e8d9456b0fe4f9b9b8afd9deba19cc417f Mon Sep 17 00:00:00 2001
From: Inso <insomniak.fr@gmail.com>
Date: Fri, 12 Dec 2014 17:29:36 +0100
Subject: [PATCH] More tests and working on documents parsing

---
 _ucoinpy_test/documents/test_block.py         |   1 -
 _ucoinpy_test/documents/test_certification.py |  17 +-
 _ucoinpy_test/documents/test_membership.py    |  16 ++
 _ucoinpy_test/documents/test_transaction.py   |  48 +++++
 ucoinpy/documents/__init__.py                 |   7 +-
 ucoinpy/documents/block.py                    |  36 ++--
 ucoinpy/documents/certification.py            |  24 ++-
 ucoinpy/documents/membership.py               |  18 +-
 ucoinpy/documents/peer.py                     |   9 +-
 ucoinpy/documents/status.py                   |  11 +-
 ucoinpy/documents/transaction.py              | 184 +++++++++++++++---
 11 files changed, 276 insertions(+), 95 deletions(-)
 create mode 100644 _ucoinpy_test/documents/test_membership.py
 create mode 100644 _ucoinpy_test/documents/test_transaction.py

diff --git a/_ucoinpy_test/documents/test_block.py b/_ucoinpy_test/documents/test_block.py
index 0dcc8d74..da3f788f 100644
--- a/_ucoinpy_test/documents/test_block.py
+++ b/_ucoinpy_test/documents/test_block.py
@@ -7,7 +7,6 @@ import pytest
 from ucoinpy.documents.block import Block
 from mock import Mock
 
-
 raw_block = "Version: 1\nType: \
 Block\nCurrency: zeta_brouzouf\n\
 Nonce: 45079\nNumber: 15\nPoWMin: 4\n\
diff --git a/_ucoinpy_test/documents/test_certification.py b/_ucoinpy_test/documents/test_certification.py
index 0d53c3b3..62499b97 100644
--- a/_ucoinpy_test/documents/test_certification.py
+++ b/_ucoinpy_test/documents/test_certification.py
@@ -6,20 +6,9 @@ Created on 6 déc. 2014
 
 import pytest
 from ucoinpy.documents.certification import SelfCertification
-from ucoinpy.key import Base58Encoder
 from mock import Mock
 
-from nacl.signing import SigningKey
-
-uid = "lolcat"
-timestamp = 1409990782.24
-correct_certification = """UID:lolcat
-META:TS:1409990782
-J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci
-"""
-
-key = SigningKey()
-
+inline_selfcert = ""
 
 class Test_SelfCertification:
     '''
@@ -27,5 +16,5 @@ class Test_SelfCertification:
     '''
 
     def test_certification(self):
-        cert = SelfCertification(timestamp, uid)
-        assert cert.signed(key) == correct_certification
+        selfcert = SelfCertification.from_inline(version, inline_selfcert)
+        
diff --git a/_ucoinpy_test/documents/test_membership.py b/_ucoinpy_test/documents/test_membership.py
new file mode 100644
index 00000000..b9b6c022
--- /dev/null
+++ b/_ucoinpy_test/documents/test_membership.py
@@ -0,0 +1,16 @@
+'''
+Created on 12 déc. 2014
+
+@author: inso
+'''
+import pytest
+from ucoinpy.documents.transaction import Transaction
+from mock import Mock
+
+inline_membership = ""
+
+class Test_Membership:
+    def test_frominline(self):
+        membership = Membership.from_inline(inline_membership)
+
+        
\ No newline at end of file
diff --git a/_ucoinpy_test/documents/test_transaction.py b/_ucoinpy_test/documents/test_transaction.py
new file mode 100644
index 00000000..1b6b8951
--- /dev/null
+++ b/_ucoinpy_test/documents/test_transaction.py
@@ -0,0 +1,48 @@
+'''
+Created on 12 déc. 2014
+
+@author: inso
+'''
+import pytest
+from ucoinpy.documents.transaction import Transaction
+from mock import Mock
+
+
+compact_transaction = """TX:1:1:3:1:0
+HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
+0:T:65:D717FEC1993554F8EAE4CEA88DE5FBB6887CFAE8:4
+0:T:77:F80993776FB55154A60B3E58910C942A347964AD:15
+0:D:88:F4A47E39BC2A20EE69DCD5CAB0A9EB3C92FD8F7B:11
+BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g:30
+42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
+"""
+
+
+class Test_Transaction:
+    def test_fromraw(self):
+        tx = Transaction.from_compact(compact_transaction)
+        assert tx.version == 1
+        assert tx.issuers.len == 1
+        assert tx.inputs.len == 1
+        assert tx.outputs.len == 3
+        
+        assert tx.inputs[0].index == 0
+        assert tx.inputs[0].source == 'T'
+        assert tx.inputs[0].number == 65
+        assert tx.inputs[0].pubkey == "D717FEC1993554F8EAE4CEA88DE5FBB6887CFAE8"
+        assert tx.inputs[0].amount == 4
+        
+        assert tx.inputs[1].index == 0
+        assert tx.inputs[1].source == 'T'
+        assert tx.inputs[1].number == 77
+        assert tx.inputs[1].pubkey == "F80993776FB55154A60B3E58910C942A347964AD"
+        assert tx.inputs[1].amount == 15
+        
+        assert tx.inputs[2].index == 0
+        assert tx.inputs[2].source == 'D'
+        assert tx.inputs[2].number == 88
+        assert tx.inputs[2].pubkey == "F4A47E39BC2A20EE69DCD5CAB0A9EB3C92FD8F7B"
+        assert tx.inputs[2].amount == 11
+        
+        assert tx.outputs[0].pubkey == "BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g"
+        assert tx.outputs[1].amount == 30
diff --git a/ucoinpy/documents/__init__.py b/ucoinpy/documents/__init__.py
index 4e993849..37411ace 100644
--- a/ucoinpy/documents/__init__.py
+++ b/ucoinpy/documents/__init__.py
@@ -9,7 +9,10 @@ from ..key import Base58Encoder
 
 
 class Document:
-    RE_VERSION = re.compile("Version: ([0-9]+)\n")
+    re_version = re.compile("Version: ([0-9]+)\n")
+    re_currency = re.compile("Currency: ([^\n]+)\n")
 
-    def __init__(self, version):
+    def __init__(self, version, currency, signatures):
         self.version = version
+        self.currency = currency
+        self.signatures = signatures
diff --git a/ucoinpy/documents/block.py b/ucoinpy/documents/block.py
index 55bb26a2..34db3545 100644
--- a/ucoinpy/documents/block.py
+++ b/ucoinpy/documents/block.py
@@ -78,12 +78,11 @@ BOTTOM_SIGNATURE
                  mediantime, ud, issuer, prev_hash, prev_issuer,
                  parameters, members_count, identities, joiners,
                  actives, leavers, excluded, certifications,
-                 transactions, sign):
+                 transactions, signature):
         '''
         Constructor
         '''
-        super(version)
-        self.currency = currency
+        super(version, currency, [signature])
         self.noonce = noonce
         self.number = number
         self.powmin = powmin
@@ -102,13 +101,10 @@ BOTTOM_SIGNATURE
         self.excluded = excluded
         self.certifications = certifications
         self.transactions = transactions
-        self.sign = sign
 
     @classmethod
     def from_raw(cls, raw):
-        #TODO : Parsing
         lines = raw.splitlines(True)
-
         n = 0
 
         version = Block.re_version.match(lines[n]).group(1)
@@ -170,50 +166,56 @@ BOTTOM_SIGNATURE
                 identities.append(selfcert)
                 lines = lines + 1
 
-        if Block.re_joiners.match(lines[n]) is not None:
+        if Block.re_joiners.match(lines[n]):
+            lines = lines + 1
             while Block.re_actives.match(lines[n]) is None:
                 membership = Membership.from_inline(version, currency, "IN", lines[n])
                 joiners.append(membership)
                 lines = lines + 1
 
-        if Block.re_actives.match(lines[n]) is not None:
+        if Block.re_actives.match(lines[n]):
+            lines = lines + 1
             while Block.re_leavers.match(lines[n]) is None:
                 membership = Membership.from_inline(version, currency, "IN", lines[n])
                 actives.append(membership)
                 lines = lines + 1
 
-        if Block.re_leavers.match(lines[n]) is not None:
+        if Block.re_leavers.match(lines[n]):
+            lines = lines + 1
             while Block.re_excluded.match(lines[n]) is None:
                 membership = Membership.from_inline(version, currency, "OUT", lines[n])
                 leavers.append(membership)
                 lines = lines + 1
 
-        if Block.re_excluded.match(lines[n]) is not None:
+        if Block.re_excluded.match(lines[n]):
+            lines = lines + 1
             while Block.re_certifications.match(lines[n]) is None:
                 membership = Membership.from_inline(version, currency, "OUT", lines[n])
                 excluded.append(membership)
                 lines = lines + 1
 
-        if Block.re_certifications.match(lines[n]) is not None:
+        if Block.re_certifications.match(lines[n]):
+            lines = lines + 1
             while Block.re_transactions.match(lines[n]) is None:
                 certification = Certification.from_inline(version, lines[n])
                 certifications.append(certification)
                 lines = lines + 1
 
-        if Block.re_transactions.match(lines[n]) is not None:
-            while Block.re_transactions.match(lines[n]) is None:
+        if Block.re_transactions.match(lines[n]):
+            lines = lines + 1
+            while Block.re_sign.match(lines[n]) is None:
                 transaction = Transaction.from_compact(version, lines[n])
                 transactions.append(transaction)
                 lines = lines + 1
 
-        sign = Block.re_sign.match(lines[n])
+        signature = Block.re_sign.match(lines[n])
         n = n + 1
 
         return cls(version, currency, noonce, number, powmin, time,
                    mediantime, ud, issuer, prev_hash, prev_issuer,
                    parameters, members_count, identities, joiners,
                    actives, leavers, excluded, certifications,
-                   transactions, sign)
+                   transactions, signature)
 
     def raw(self):
         doc = """
@@ -231,7 +233,7 @@ PreviousHash: {9}
 PreviousIssuer: {10}
 Parameters: {11}
 MembersCount: {12}
-Identities:""".format(PROTOCOL_VERSION,
+Identities:""".format(self.version,
                       self.currency,
                       self.noonce,
                       self.number,
@@ -272,4 +274,4 @@ Identities:""".format(PROTOCOL_VERSION,
         for transaction in self.transactions:
             doc += "{0}\n".format(transaction.inline())
 
-        doc += self.sign
+        doc += self.signatures[0]
diff --git a/ucoinpy/documents/certification.py b/ucoinpy/documents/certification.py
index b9f821ea..66c9331e 100644
--- a/ucoinpy/documents/certification.py
+++ b/ucoinpy/documents/certification.py
@@ -15,21 +15,20 @@ class SelfCertification(Document):
 
     re_inline = re.compile("([1-9A-Za-z][^OIl]{43,45}):([A-Za-z0-9+/]+):([0-9]+):([^\n]+)\n")
 
-    def __init__(self, version, pubkey, ts, identifier, sign):
-        super(version)
+    def __init__(self, version, currency, pubkey, ts, identifier, signature):
+        super(version, currency, [signature])
         self.pubkey = pubkey
         self.timestamp = ts
         self.identifier = identifier
-        self.sign = sign
 
     @classmethod
     def from_inline(cls, version, inline):
         selfcert_data = SelfCertification.re_inline.match(inline)
         pubkey = selfcert_data.group(1)
-        sign = selfcert_data.group(2)
+        signature = selfcert_data.group(2)
         ts = selfcert_data.group(3)
         identifier = selfcert_data.group(4)
-        return cls(version, pubkey, ts, identifier, sign)
+        return cls(version, pubkey, ts, identifier, signature)
 
     @classmethod
     def from_raw(cls, raw):
@@ -43,7 +42,7 @@ class SelfCertification(Document):
         return "UID:{0}".format(self.identifier)
 
     def raw(self):
-        return "{0}\n{1}".format(self.uid(), self.ts())
+        return "{0}\n{1}\n{2}".format(self.uid(), self.ts(), self.signatures[0])
 
 
 class Certification(Document):
@@ -55,17 +54,16 @@ class Certification(Document):
     ([A-Za-z0-9+/]+)(==)?:([0-9]+):([0-9a-fA-F]{5,40}):\
     ([0-9]+):([^\n]+)\n")
 
-    def __init__(self, version, pubkey_from, pubkey_to,
-                 blockhash, blocknumber, sign):
+    def __init__(self, version, currency, pubkey_from, pubkey_to,
+                 blockhash, blocknumber, signature):
         '''
         Constructor
         '''
-        super(version)
+        super(version, currency, signature)
         self.pubkey_from = pubkey_from
         self.pubkey_to = pubkey_to
         self.blockhash = blockhash
         self.blocknumber = blocknumber
-        self.sign = sign
 
     @classmethod
     def from_inline(cls, version, blockhash, inline):
@@ -73,12 +71,12 @@ class Certification(Document):
         pubkey_from = cert_data.group(1)
         pubkey_to = cert_data.group(2)
         blocknumber = cert_data.group(3)
-        sign = cert_data.group(4)
+        signature = cert_data.group(4)
         return cls(version, pubkey_from, pubkey_to,
-                   blockhash, blocknumber, sign)
+                   blockhash, blocknumber, signature)
 
     def ts(self):
         return "META:TS:{0}-{1}".format(self.blockhash, self.blocknumber)
 
     def raw(self, selfcert):
-        return "{0}\n{1}".format(selfcert.content(), self.ts())
+        return "{0}\n{1}\n{2}".format(selfcert.raw(), self.ts(), self.signatures[0])
diff --git a/ucoinpy/documents/membership.py b/ucoinpy/documents/membership.py
index 49eef154..392ae9f9 100644
--- a/ucoinpy/documents/membership.py
+++ b/ucoinpy/documents/membership.py
@@ -27,38 +27,36 @@ class Membership(Document):
     ([0-9]+):([0-9a-fA-F]{5,40}):([0-9]+):([^\n]+)\n")
 
     def __init__(self, version, currency, issuer, block_number, block_hash,
-                 membership_type, userid, cert_ts, sign):
+                 membership_type, userid, cert_ts, signature):
         '''
         Constructor
         '''
-        super(version)
-        self.currency = currency
+        super(version, currency, [signature])
         self.issuer = issuer
         self.block_number = block_number
         self.block_hash = block_hash
         self.membership_type = membership_type
         self.userid = userid
         self.cert_ts = cert_ts
-        self.sign = sign
 
     @classmethod
     def from_inline(cls, version, currency, type, inline):
         data = Membership.re_inline.match(inline)
         issuer = data.group(1)
-        sign = data.group(2)
+        signature = data.group(2)
         block_number = data.group(3)
         block_hash = data.group(4)
         cert_ts = data.group(5)
         userid = data.group(6)
         return cls(version, currency, issuer, block_number,
-                   block_hash, type, userid, cert_ts, sign)
+                   block_hash, type, userid, cert_ts, signature)
 
     @classmethod
     def from_raw(cls, raw):
         #TODO : Parsing
         return cls()
 
-    def content(self):
+    def raw(self):
         return """
 Version: {0}
 Type: Membership
@@ -67,13 +65,15 @@ Issuer: {2}
 Block: {3}-{4}
 Membership: {5}
 UserID: {6}
-CertTS: {7}""".format(PROTOCOL_VERSION,
+CertTS: {7}
+{8}""".format(self.version,
                       self.currency,
                       self.issuer,
                       self.block_number, self.block_hash,
                       self.membership_type,
                       self.userid,
-                      self.cert_ts)
+                      self.cert_ts,
+                      self.signatures[0])
 
     def inline(self):
         return "{0}:{1}:{2}:{3}".format(self.issuer,
diff --git a/ucoinpy/documents/peer.py b/ucoinpy/documents/peer.py
index 0a387f79..30cafe51 100644
--- a/ucoinpy/documents/peer.py
+++ b/ucoinpy/documents/peer.py
@@ -24,7 +24,8 @@ class Peer(Document):
     [...]
     """
 
-    def __init__(self, currency, pubkey, blockid, endpoints):
+    def __init__(self, version, pubkey, blockid, endpoints, signature):
+        super(version, currency, [signature])
         self.currency = currency
         self.pubkey = pubkey
         self.blockid = blockid
@@ -35,7 +36,7 @@ class Peer(Document):
         #TODO : Parsing
         return cls()
 
-    def content(self):
+    def raw(self):
         doc = """
 Version: {0}
 Type: Peer
@@ -43,10 +44,12 @@ Currency: {1}
 PublicKey: {2}
 Block: {3}
 Endpoints:
-""".format(PROTOCOL_VERSION, self.currency, self.pubkey, self.blockid)
+""".format(self.version, self.currency, self.pubkey, self.blockid)
 
         for endpoint in self.endpoints:
             doc += "{0}\n".format(endpoint.inline())
+         
+        doc += "{0}\n".format(self.signatures[0])
         return doc
 
 
diff --git a/ucoinpy/documents/status.py b/ucoinpy/documents/status.py
index 3913e051..a05c083a 100644
--- a/ucoinpy/documents/status.py
+++ b/ucoinpy/documents/status.py
@@ -19,11 +19,11 @@ class Status(Document):
     To: RECIPIENT
     '''
 
-    def __init__(self, currency, status, blockid, sender, recipient):
+    def __init__(self, version, currency, status, blockid, sender, recipient, signature):
         '''
         Constructor
         '''
-        self.currency = currency
+        super(version, currency, [signature])
         self.status = status
         self.blockid = blockid
         self.sender = sender
@@ -34,7 +34,7 @@ class Status(Document):
         #TODO : Parsing
         return cls()
 
-    def content(self):
+    def raw(self):
         return '''
 Version: {0}
 Type: Status
@@ -43,5 +43,6 @@ Status: {2}
 Block: {3}
 From: {4}
 To: {5}
-'''.format(PROTOCOL_VERSION, self.currency, self.status,
-           self.blockid, self.sender, self.recipient)
+{6}
+'''.format(self.version, self.currency, self.status,
+           self.blockid, self.sender, self.recipient, self.signatures[0])
diff --git a/ucoinpy/documents/transaction.py b/ucoinpy/documents/transaction.py
index ee5a824b..38190895 100644
--- a/ucoinpy/documents/transaction.py
+++ b/ucoinpy/documents/transaction.py
@@ -10,6 +10,7 @@ from .. import PROTOCOL_VERSION
 
 class Transaction(Document):
     '''
+Document format : 
 Version: VERSION
 Type: Transaction
 Currency: CURRENCY_NAME
@@ -23,38 +24,130 @@ Outputs:
 PUBLIC_KEY:AMOUNT
 ...
 Comment: COMMENT
-SIGNATURES
+...
+
+
+Compact format : 
+TX:VERSION:NB_ISSUERS:NB_INPUTS:NB_OUTPUTS:HAS_COMMENT
+PUBLIC_KEY:INDEX
+...
+INDEX:SOURCE:FINGERPRINT:AMOUNT
+...
+PUBLIC_KEY:AMOUNT
+...
+COMMENT
+SIGNATURE
 ...
     '''
 
-    def __init__(self, currency, pubkeys, inputs, outputs, comment=None):
+    re_type = re.compile("Type: Transaction\n")
+    re_header = re.compile("TX:([0-9])+:([0-9])+:([0-9])+:([0-9])+:(0|1)\n")
+    re_issuers = re.compile("Issuers:\n")
+    re_inputs = re.compile("Inputs:\n")
+    re_outputs = re.compile("Outputs:\n")
+    re_pubkey = re.compile("([1-9A-Za-z][^OIl]{43,45})\n")
+
+    def __init__(self, version, currency, issuers, inputs, outputs, signatures):
         '''
         Constructor
         '''
-        self.currency = currency
-        self.pubkeys = pubkeys
+        super(version, currency, signatures)
+        self.issuers = issuers
         self.inputs = inputs
         self.outputs = outputs
         self.comment = comment
 
     @classmethod
-    def from_compact(cls, compact):
-        return None
+    def from_compact(cls, currency, number, compact):
+        lines = raw.splitlines(True)
+        n = 0
+        
+        header_data = re_header.match(lines[n])
+        version = header_data.group(2)
+        issuers_num = int(header_data.group(3))
+        inputs_num = int(header_data.group(3))
+        outputs_num = int(header_data.group(3))
+        n = n + 1
+        
+        issuers = []
+        inputs = []
+        outputs = []
+        signatures = []
+        
+        for i in range(0, issuers_num):
+            issuer = re_pubkey.match(lines[n]).group(1)
+            issuers.append(issuer)
+            n = n + 1
+        
+        for i in range(0, inputs_num):
+            input = InputSource.from_compact(lines[n])
+            inputs.append(issuer)
+            n = n + 1
+            
+        for i in range(0, outputs_num):
+            output = OutputSource.from_inline(lines[n])
+            outputs.append(output)
+            n = n + 1
+            
+        return cls(version, currency, issuers, inputs, outputs, signatures)
+
 
     @classmethod
     def from_raw(cls, raw):
-        #TODO : Parsing
-        return cls()
+        n = 0
+        
+        version = Transaction.re_version.match(lines[n]).group(1)
+        n = n + 1
+        
+        type = Transaction.re_type.match(lines[n]).group(1)
+        n = n + 1
+        
+        currency = Transaction.re_currency.match(lines[n]).group(1)
+        n = n + 1
+        
+        issuers = []
+        inputs = []
+        outputs = []
+        signatures = []
+        
+        if Transaction.re_issuers.match(lines[n]):
+            lines = lines + 1
+            while Transaction.re_inputs.match(lines[n]) is None:
+                issuer = Transaction.re_pubkey.match(lines[n]).group(1)
+                issuers.append(issuer)
+                lines = lines + 1
+
+        if Transaction.re_inputs.match(lines[n]):
+            lines = lines + 1
+            while Transaction.re_outputs.match(lines[n]) is None:
+                input = InputSource.from_compact(number, lines[n])
+                inputs.append(input)
+                lines = lines + 1
 
-    def content(self):
+        if Transaction.re_outputs.match(lines[n]) is not None:
+            while Transaction.re_sign.match(lines[n]) is None:
+                output = OutputSource.from_inline(lines[n])
+                outputs.append(output)
+                lines = lines + 1
+        
+        
+        if Transaction.re_sign.match(lines[n]) is not None:
+            while n < lines.len:
+                sign = re_sign.match(lines[n]).group(1)
+                signatures.append(sign)
+                lines = lines + 1
+            
+        return cls(version, currency, issuers, inputs, outputs, signatures)
+
+    def raw(self):
         doc = """
 Version: {0}
 Type: Transaction
 Currency: {1}
-Issuers:""".format(PROTOCOL_VERSION,
+Issuers:""".format(self.version,
                    self.currency)
 
-        for p in self.pubkeys:
+        for p in self.issuers:
             doc += "{0}\n".format(p)
 
         doc += "Inputs:\n"
@@ -70,6 +163,9 @@ COMMENT:
 {0}
 """.format(self.comment)
 
+        for signature in self.signatures:
+            doc += "{0}\n".format(signature)
+        
         return doc
 
     def compact(self):
@@ -85,12 +181,12 @@ PUBLIC_KEY:AMOUNT
 ...
 COMMENT
 """
-        doc = "TX:{0}:{1}:{2}:{3}:{4}".format(PROTOCOL_VERSION,
-                                              self.pubkeys.len,
+        doc = "TX:{0}:{1}:{2}:{3}:{4}".format(self.version,
+                                              self.issuers.len,
                                               self.inputs.len,
                                               self.outputs.len,
                                               '1' if self.Comment else '0')
-        for pubkey in self.pubkeys:
+        for pubkey in self.issuers:
             doc += "{0}\n".format(pubkey)
         for i in self.inputs:
             doc += "{0}\n".format(i.compact())
@@ -98,53 +194,71 @@ COMMENT
             doc += "{0}\n".format(o.inline())
         if self.comment:
             doc += "{0}\n".format(self.comment)
-        return doc
-
-    def sign(self, keys):
-        signatures = ""
-        for k in keys:
-            signatures += "{0}\n".format(super().sign(k))
-        return signatures
+        for s in self.signatures:
+            doc += "{0}\n".format(s)
 
+        return doc
 
 class SimpleTransaction(Transaction):
     '''
 As transaction class, but for only one issuer.
 ...
     '''
-    def __init__(self, currency, pubkey, single_input, outputs, comment):
+    def __init__(self, version, currency, issuer, single_input, outputs, comment, signature):
         '''
         Constructor
         '''
-        self.currency = currency
-        self.pubkeys = [pubkey]
-        self.inputs = [single_input]
-        self.outputs = outputs
-        self.comment = comment
+        super(version, currency, [issuer], [single_input], outputs, comment, [signature])
 
 
 class InputSource():
     '''
     A Transaction INPUT
+    
+    Compact : 
+    INDEX:SOURCE:FINGERPRINT:AMOUNT
     '''
-    def __init__(self, index, source, number, fingerprint, amount):
+    re_inline = re.compile("([0-9]+):(D|T):([0-9]+):([0-9a-fA-F]{5,40}):([0-9]+)")
+    re_compact = re.compile("([0-9]+):(D|T):([0-9a-fA-F]{5,40}):([0-9]+)")
+    
+    def __init__(self, index, source, number, txhash, amount):
         self.index = index
         self.source = source
         self.number = number
-        self.fingerprint = fingerprint
+        self.txhash = txhash
         self.amount = amount
 
+    @classmethod
+    def from_inline(cls, inline):
+        data = re_inline.match(inline)
+        index = data.group(1)
+        source = data.group(2)
+        number = data.group(3)
+        txhash = data.group(4)
+        amount = data;group(5)
+        return cls(data, index, source, number, txhash, amount)
+     
+     @classmethod
+     def from_compact(cls, number, compact):
+        data = re_compact.match(inline)
+        index = data.group(1)
+        source = data.group(2)
+        txhash = data.group(3)
+        amount = data;group(4)
+        return cls(data, index, source, number, txhash, amount)
+     
+        
     def inline(self):
         return "{0}:{1}:{2}:{3}:{4}".format(self.index,
                                             self.source,
                                             self.number,
-                                            self.fingerprint,
+                                            self.txhash,
                                             self.amount)
 
     def compact(self):
         return "{0}:{1}:{2}:{3}".format(self.index,
                                         self.source,
-                                        self.fingerprint,
+                                        self.txhash,
                                         self.amount)
 
 
@@ -152,9 +266,17 @@ class OutputSource():
     '''
     A Transaction OUTPUT
     '''
+    re_inline = "([1-9A-Za-z][^OIl]{43,45}):([0-9]+)"
     def __init__(self, pubkey, amount):
         self.pubkey = pubkey
         self.amount = amount
+    
+    @lassmethod
+    def from_inline(cls, inline):
+        data = re_inline.match(inline)
+        pubkey = data.group(1)
+        amount = data.group(2)
+        return cls(pubkey, amount)
 
     def inline(self):
         return "{0}:{1}".format(self.pubkey, self.amount)
-- 
GitLab