# Copyright  2014-2022 Vincent Texier <vit@free.fr>
#
# DuniterPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DuniterPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import unittest

import pypeg2

from duniterpy.constants import G1_TEST_CURRENCY_CODENAME
from duniterpy.documents import BlockID
from duniterpy.documents.transaction import (
    InputSource,
    OutputSource,
    SIGParameter,
    SimpleTransaction,
    Transaction,
    Unlock,
    reduce_base,
)
from duniterpy.grammars import output
from duniterpy.key import SigningKey

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==
"""

tx_from_compact_change = """Version: 10
Type: Transaction
Currency: gtest
Blockstamp: 13410-000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC
Locktime: 0
Issuers:
D8BsQZN9hangHVuqwD6McfxM1xvGJ8DPuPYrswwnSif3
Inputs:
1500:1:T:0D0264F324BC4A23C4B2C696CD1907BD6E70FD1F409BB1D42E84847AA4C1E87C:0
Unlocks:
0:SIG(0)
Outputs:
1500:1:(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(36j6pCNzKDPo92m7UXJLFpgDbcLFAZBgThD2TCwTwGrd)) || (SIG(D8BsQZN9hangHVuqwD6McfxM1xvGJ8DPuPYrswwnSif3) && SIG(36j6pCNzKDPo92m7UXJLFpgDbcLFAZBgThD2TCwTwGrd))
Comment: 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:10:3:6:6:3:1:0
13410-000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC
HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp
9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB
230:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
2230:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
2430:2:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
2310:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
30:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
2330:2: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) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))
-----@@@----- (why not this comment?)
42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX
2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk
"""

simple_tx_compact = """TX:10:1:1:1:2:0:0
13410-000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC
GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92
100:0:D:GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92:471
0:SIG(0)
90:0:SIG(5zDvFjJB1PGDQNiExpfzL9c1tQGs6xPA8mf1phr3VoVi)
10:0:SIG(GNPdPNwSJAYw7ixkDeibo3YpdELgLmrZ2Q86HF4cyg92)
XDQeEMcJDd+XVGaFIZc8d4kKRJgsPuWAPVNG5UKNk8mDZx2oE1kTP/hbxiFx6yDouBELCswuf/X6POK9ES7JCA==
"""

tx_raw = """Version: 10
Type: Transaction
Currency: beta_brousouf
Blockstamp: 32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD
Locktime: 0
Issuers:
HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp
9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB
Inputs:
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
Unlocks:
0:SIG(0)
1:XHX(7665798292)
2:SIG(0)
3:SIG(0) SIG(2)
4:SIG(0) SIG(1) SIG(2)
5:SIG(2)
Outputs:
120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)
146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)
49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))
Comment: -----@@@----- (why not this comment?)
42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX
2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk
"""

# curl https://g1-test.duniter.org/blockchain/block/551979
g1_test_tx_multi_sig_compact = """TX:10:6:6:6:1:1:0
551977-0001108622DBA433872C547D342B033193B16E7C60C478C264DC4F1B5F36AC74
CLxmBmQDxT4r5thHhQHQk3LVJZoerpMArkTGSfkeexkg
5gHpK5sfijCkDDxSfiCWa3QxUsXnd38ZX3Frn7qaG42b
6bcCUCMmTVQjqc3VGuA1xQv3ETKDV1JJDM5GGCfn58A4
GM6jrbZSgd2WaE8LY9WP4V2v1MDpxbqMVUBBxdJswz1s
AfkSYeiqAVHPqaKHhw52fR4rgC4QGaLGCTBP9jHfeDMQ
8tqeZi9pKV8VFjY7CNce4FbHvv76f7y3uKcyJ865pZzB
250:2:T:9E5AB3FAED93C9C65D4D0C16C1387592A7B9E1AE7285DB6C687FFE6AAF542CF2:0
250:2:T:9E5AB3FAED93C9C65D4D0C16C1387592A7B9E1AE7285DB6C687FFE6AAF542CF2:1
250:2:T:9E5AB3FAED93C9C65D4D0C16C1387592A7B9E1AE7285DB6C687FFE6AAF542CF2:2
250:2:T:9E5AB3FAED93C9C65D4D0C16C1387592A7B9E1AE7285DB6C687FFE6AAF542CF2:3
250:2:T:9E5AB3FAED93C9C65D4D0C16C1387592A7B9E1AE7285DB6C687FFE6AAF542CF2:4
250:2:T:9E5AB3FAED93C9C65D4D0C16C1387592A7B9E1AE7285DB6C687FFE6AAF542CF2:5
0:SIG(0)
1:SIG(1)
2:SIG(2)
3:SIG(3)
4:SIG(4)
5:SIG(5)
1500:2:SIG(AhRMHUxMPXSeG7qXZrE6qCdjwK9p2bu5Eqei7xAWVEDK)
G1Don
ukn60jVqcaR5ZJdGOW6aZapUSyCpRQkQWtKBcndTXtLJP5zs26bAl5XfASDCqivecuWyNedU1y2sAhA/OqcADg==
kcybaONx12s8ZJuRVVyGrRXBgYlnUr7CGOdm0/75F9yNpQ8U/8lzyPMKugbJ6txPQ7/TBf6cS6XMTwoZH8PPBQ==
UM9eT2iW0br42yBznimxjuVJJNFtGICUwNHspPsYOraWqk4prEte5lh9b88Q/HtDZN9o4qZzXuoVYOwbvNfgBg==
LSqXaG4MylpG39r4OuxGbTXm/cLXOvCv60BarTR9QABW7uKjgIra5+EELRxW8Ueg9QAimfNBBIHy/ZVO+saHAQ==
wI7cEq8nhZbi/uDOx4DawqQNoVlqpWQ1N2XgFwz0AdTubgJc8/JxDOG+xDYk8P+9m4oni3NjC58jNWzOqd+TDA==
KjAnwP8gDyHr228py7xAFvaYoK2NQ6CHbZADK0m1qx0pxViB18m5Qs9MVAFjYTDQop9qfSie8nX/9NLdW09jBQ==
"""

input_source_str = (
    "30:0:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2"
)

output_source_str = "460:0:SIG(8kXygUHh1vLjmcRzXVM86t38EL8dfFJgfBeHmkaWLamu)"


class TestTransaction(unittest.TestCase):
    def test_fromcompact(self):
        tx = Transaction.from_compact(tx_compact, "zeta_brousouf")
        self.assertEqual(tx.version, 10)
        self.assertEqual(tx.currency, "zeta_brousouf")
        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].amount, 230)
        self.assertEqual(tx.inputs[0].base, 2)
        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].amount, 2230)
        self.assertEqual(tx.inputs[1].base, 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].amount, 2430)
        self.assertEqual(tx.inputs[2].base, 2)
        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].amount, 2310)
        self.assertEqual(tx.inputs[3].base, 2)
        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].amount, 30)
        self.assertEqual(tx.inputs[4].base, 2)
        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].amount, 2330)
        self.assertEqual(tx.inputs[5].base, 2)
        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].condition, 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].condition, 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].condition, output.Condition),
            "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))",
        )

        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_toraw(self):
        tx = Transaction.from_signed_raw(tx_raw)
        rendered_tx = tx.signed_raw()
        self.assertEqual(tx_raw, rendered_tx)
        Transaction.from_signed_raw(rendered_tx)

        self.assertEqual(tx.version, 10)
        self.assertEqual(tx.currency, "beta_brousouf")
        self.assertEqual(tx.block_id.number, 32)
        self.assertEqual(
            tx.block_id.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].condition, 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].condition, 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].condition, output.Condition),
            "(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(8FAA0ED653CA4D2C1156D511F0D0036F5168ABA4DAC2929676D279C8A2A12E36))",
        )

        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_compact_change(self):
        tx = Transaction.from_compact(compact_change, "gtest")
        rendered_tx = tx.signed_raw()
        self.assertEqual(tx_from_compact_change, rendered_tx)
        Transaction.from_signed_raw(rendered_tx)

    def test_reduce_base(self):
        amount = 1200
        base = 0
        computed = reduce_base(amount, base)
        self.assertEqual(computed[0], 12)
        self.assertEqual(computed[1], 2)

    def test_reduce_base_2(self):
        amount = 120
        base = 4
        computed = reduce_base(amount, base)
        self.assertEqual(computed[0], 12)
        self.assertEqual(computed[1], 5)

    def test_is_simple(self):
        tx = Transaction.from_compact(simple_tx_compact, "zeta_brousouf")
        self.assertTrue(SimpleTransaction.is_simple(tx))

        tx = Transaction.from_compact(tx_compact, "zeta_brousouf")
        self.assertFalse(SimpleTransaction.is_simple(tx))

    def test_inputsource_from_inline(self):
        i = InputSource.from_inline(input_source_str)
        self.assertEqual(i.inline(), input_source_str)

    def test_outputsource_from_inline(self):
        o = OutputSource.from_inline(output_source_str)
        self.assertEqual(o.inline(), output_source_str)

    def test_outputsource_inline_condition(self):
        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)

    def test_transaction_document_generation(self):
        transaction = Transaction(
            block_id=BlockID(
                8979, "000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC"
            ),
            locktime=0,
            issuers=list("8kXygUHh1vLjmcRzXVM86t38EL8dfFJgfBeHmkaWLamu"),
            inputs=[InputSource.from_inline(input_source_str)],
            unlocks=[Unlock(index=0, parameters=[SIGParameter(0)])],
            outputs=[OutputSource.from_inline(output_source_str)],
            comment="",
            currency="gtest",
        )
        self.assertTrue(transaction.time is None)
        self.assertTrue(transaction.currency == "gtest")
        self.assertTrue(transaction.inputs[0].amount == 30)

    def test_unlock(self):
        unlock1 = Unlock(0, [SIGParameter(0)])
        unlock2 = Unlock.from_inline("0:SIG(0)")
        self.assertEqual(unlock1, unlock2)

    def test_check_signature(self):
        # create 3 wallets
        signing_key = SigningKey.from_credentials("1", "1")

        issuer = signing_key.pubkey

        transaction = Transaction(
            block_id=BlockID(
                8979, "000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC"
            ),
            locktime=0,
            issuers=[issuer],
            inputs=[InputSource.from_inline(input_source_str)],
            unlocks=[Unlock(index=0, parameters=[SIGParameter(0)])],
            outputs=[OutputSource.from_inline(output_source_str)],
            comment="",
            currency=G1_TEST_CURRENCY_CODENAME,
        )

        # multi-signature on the transaction
        transaction.sign(signing_key)

        self.assertTrue(transaction.check_signature(issuer))

    def test_check_signatures(self):
        # create 3 wallets
        signing_key_01 = SigningKey.from_credentials("1", "1")
        signing_key_02 = SigningKey.from_credentials("2", "2")
        signing_key_03 = SigningKey.from_credentials("3", "3")

        issuers = [
            signing_key_01.pubkey,
            signing_key_02.pubkey,
            signing_key_03.pubkey,
        ]

        transaction = Transaction(
            block_id=BlockID(
                8979, "000041DF0CCA173F09B5FBA48F619D4BC934F12ADF1D0B798639EB2149C4A8CC"
            ),
            locktime=0,
            issuers=issuers,
            inputs=[InputSource.from_inline(input_source_str)],
            unlocks=[Unlock(index=0, parameters=[SIGParameter(0)])],
            outputs=[OutputSource.from_inline(output_source_str)],
            comment="",
            currency=G1_TEST_CURRENCY_CODENAME,
        )

        # multi-signature on the transaction
        transaction.multi_sign(
            [
                signing_key_01,
                signing_key_02,
                signing_key_03,
            ]
        )

        self.assertTrue(transaction.check_signatures(issuers))

    def test_g1_test_tx_check_signatures(self):
        tx_multi = Transaction.from_compact(
            g1_test_tx_multi_sig_compact,
            G1_TEST_CURRENCY_CODENAME,
        )
        # multi signatures check for the pubkeys on the signatures
        self.assertTrue(tx_multi.check_signatures(tx_multi.issuers))
