示例#1
0
def test_bitcoin_fund_solver():

    fund_solver = FundSolver(private_key=sender_wallet.private_key())

    assert sender_wallet.private_key() == fund_solver.private_key.hexlify()

    assert isinstance(fund_solver.solve(), P2pkhSolver)

    with pytest.raises(TypeError, match="private key must be string format"):
        FundSolver(float())
示例#2
0
文件: fund.py 项目: xeroc/shuttle
unsigned_fund_transaction.build_transaction(wallet=sender_wallet,
                                            htlc=htlc,
                                            amount=10000)

print("Unsigned Fund Transaction Fee:", unsigned_fund_transaction.fee)
print("Unsigned Fund Transaction Hash:", unsigned_fund_transaction.hash())
print("Unsigned Fund Transaction Raw:", unsigned_fund_transaction.raw())
# print("Unsigned Fund Transaction Json:", json.dumps(unsigned_fund_transaction.json(), indent=4))

unsigned_fund_raw = unsigned_fund_transaction.unsigned_raw()
print("Unsigned Fund Transaction Unsigned Raw:", unsigned_fund_raw)

print("=" * 10, "Signed Fund Transaction")

# Initialize solver
fund_solver = FundSolver(private_key=sender_private_key)

# Singing Hash Time Lock Contract (HTLC)
signed_fund_transaction = unsigned_fund_transaction.sign(fund_solver)

print("Signed Fund Transaction Fee:", signed_fund_transaction.fee)
print("Signed Fund Transaction Hash:", signed_fund_transaction.hash())
print("Signed Fund Transaction Raw:", signed_fund_transaction.raw())
# print("Signed Fund Transaction Json:", json.dumps(signed_fund_transaction.json(), indent=4))

print("=" * 10, "Fund Signature")

# Singing Hash Time Lock Contract (HTLC)
fund_signature = FundSignature(network=network)\
    .sign(unsigned_raw=unsigned_fund_raw, solver=fund_solver)
示例#3
0
def test_bitcoin_fund():
    # Initialization fund transaction
    unsigned_fund_transaction = FundTransaction(version=2, network=network)
    # Building fund transaction
    unsigned_fund_transaction.build_transaction(wallet=sender_wallet,
                                                htlc=htlc,
                                                amount=10000)

    assert unsigned_fund_transaction.fee == 678
    assert unsigned_fund_transaction.hash(
    ) == "8e153f98a1e1ae918d59ac94e1ef08d139b7a3b492c3354ecf47e9d3705c2acf"
    assert unsigned_fund_transaction.raw() == \
           "020000000180dea6505f075127bd47d6527a0eb817b1f6e39e592b0d53e14bbd600a0fb18f0000000000ffffffff02102700" \
           "000000000017a9148726547c18c325ac7fab7a7c8209bbdbb7cf1d87875a970000000000001976a9146bce65e58a50b97989" \
           "930e9a4ff1ac1a77515ef188ac00000000"
    assert unsigned_fund_transaction.unsigned_raw() == \
           "eyJmZWUiOiA2NzgsICJyYXciOiAiMDIwMDAwMDAwMTgwZGVhNjUwNWYwNzUxMjdiZDQ3ZDY1MjdhMGViODE3YjFmNmUzOWU1OTJi" \
           "MGQ1M2UxNGJiZDYwMGEwZmIxOGYwMDAwMDAwMDAwZmZmZmZmZmYwMjEwMjcwMDAwMDAwMDAwMDAxN2E5MTQ4NzI2NTQ3YzE4YzMy" \
           "NWFjN2ZhYjdhN2M4MjA5YmJkYmI3Y2YxZDg3ODc1YTk3MDAwMDAwMDAwMDAwMTk3NmE5MTQ2YmNlNjVlNThhNTBiOTc5ODk5MzBl" \
           "OWE0ZmYxYWMxYTc3NTE1ZWYxODhhYzAwMDAwMDAwIiwgIm91dHB1dHMiOiBbeyJhbW91bnQiOiA0OTQyNCwgIm4iOiAwLCAic2Ny" \
           "aXB0IjogIjc2YTkxNDZiY2U2NWU1OGE1MGI5Nzk4OTkzMGU5YTRmZjFhYzFhNzc1MTVlZjE4OGFjIn1dLCAibmV0d29yayI6ICJ0" \
           "ZXN0bmV0IiwgInR5cGUiOiAiYml0Y29pbl9mdW5kX3Vuc2lnbmVkIn0="
    assert unsigned_fund_transaction.json()

    fund_solver = FundSolver(private_key=sender_private_key)
    assert unsigned_fund_transaction.sign(fund_solver)

    fund_signature = FundSignature(network=network)\
        .sign(unsigned_raw=unsigned_fund_transaction.unsigned_raw(), solver=fund_solver)

    assert fund_signature.fee == 678
    assert fund_signature.hash(
    ) == "5f9eed11af4e5d495733da6d258d9ef3f82bc1fd9f9b9fb54184c4dd03ecdba6"
    assert fund_signature.raw() == \
           "020000000180dea6505f075127bd47d6527a0eb817b1f6e39e592b0d53e14bbd600a0fb18f000000006a4730440220523ea5" \
           "0108a454cc90eee9189a6f745d0dd8f50e83840d489f6108fd704e0abd0220368d2ffd66d7e1b9258773220a0ec1056a2b94" \
           "ec9bccc88ec27365b60543010c012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84ffff" \
           "ffff02102700000000000017a9148726547c18c325ac7fab7a7c8209bbdbb7cf1d87875a970000000000001976a9146bce65" \
           "e58a50b97989930e9a4ff1ac1a77515ef188ac00000000"
    assert fund_signature.signed_raw() == \
           "eyJyYXciOiAiMDIwMDAwMDAwMTgwZGVhNjUwNWYwNzUxMjdiZDQ3ZDY1MjdhMGViODE3YjFmNmUzOWU1OTJiMGQ1M2UxNGJiZDYw" \
           "MGEwZmIxOGYwMDAwMDAwMDZhNDczMDQ0MDIyMDUyM2VhNTAxMDhhNDU0Y2M5MGVlZTkxODlhNmY3NDVkMGRkOGY1MGU4Mzg0MGQ0" \
           "ODlmNjEwOGZkNzA0ZTBhYmQwMjIwMzY4ZDJmZmQ2NmQ3ZTFiOTI1ODc3MzIyMGEwZWMxMDU2YTJiOTRlYzliY2NjODhlYzI3MzY1" \
           "YjYwNTQzMDEwYzAxMjEwM2M1NmE2MDA1ZDRhODg5MmQyOGNjM2Y3MjY1ZTU2ODViNTQ4NjI3ZDU5MTA4OTczZTQ3NGM0ZTI2ZjY5" \
           "YTRjODRmZmZmZmZmZjAyMTAyNzAwMDAwMDAwMDAwMDE3YTkxNDg3MjY1NDdjMThjMzI1YWM3ZmFiN2E3YzgyMDliYmRiYjdjZjFk" \
           "ODc4NzVhOTcwMDAwMDAwMDAwMDAxOTc2YTkxNDZiY2U2NWU1OGE1MGI5Nzk4OTkzMGU5YTRmZjFhYzFhNzc1MTVlZjE4OGFjMDAw" \
           "MDAwMDAiLCAiZmVlIjogNjc4LCAibmV0d29yayI6ICJ0ZXN0bmV0IiwgInR5cGUiOiAiYml0Y29pbl9mdW5kX3NpZ25lZCJ9"
    assert fund_signature.json()

    signature = Signature(network=network) \
        .sign(unsigned_raw=unsigned_fund_transaction.unsigned_raw(), solver=fund_solver)

    assert signature.fee == 678
    assert signature.hash(
    ) == "5f9eed11af4e5d495733da6d258d9ef3f82bc1fd9f9b9fb54184c4dd03ecdba6"
    assert signature.raw() == \
           "020000000180dea6505f075127bd47d6527a0eb817b1f6e39e592b0d53e14bbd600a0fb18f000000006a4730440220523ea5" \
           "0108a454cc90eee9189a6f745d0dd8f50e83840d489f6108fd704e0abd0220368d2ffd66d7e1b9258773220a0ec1056a2b94" \
           "ec9bccc88ec27365b60543010c012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84ffff" \
           "ffff02102700000000000017a9148726547c18c325ac7fab7a7c8209bbdbb7cf1d87875a970000000000001976a9146bce65" \
           "e58a50b97989930e9a4ff1ac1a77515ef188ac00000000"
    assert signature.signed_raw() == \
           "eyJyYXciOiAiMDIwMDAwMDAwMTgwZGVhNjUwNWYwNzUxMjdiZDQ3ZDY1MjdhMGViODE3YjFmNmUzOWU1OTJiMGQ1M2UxNGJiZDYw" \
           "MGEwZmIxOGYwMDAwMDAwMDZhNDczMDQ0MDIyMDUyM2VhNTAxMDhhNDU0Y2M5MGVlZTkxODlhNmY3NDVkMGRkOGY1MGU4Mzg0MGQ0" \
           "ODlmNjEwOGZkNzA0ZTBhYmQwMjIwMzY4ZDJmZmQ2NmQ3ZTFiOTI1ODc3MzIyMGEwZWMxMDU2YTJiOTRlYzliY2NjODhlYzI3MzY1" \
           "YjYwNTQzMDEwYzAxMjEwM2M1NmE2MDA1ZDRhODg5MmQyOGNjM2Y3MjY1ZTU2ODViNTQ4NjI3ZDU5MTA4OTczZTQ3NGM0ZTI2ZjY5" \
           "YTRjODRmZmZmZmZmZjAyMTAyNzAwMDAwMDAwMDAwMDE3YTkxNDg3MjY1NDdjMThjMzI1YWM3ZmFiN2E3YzgyMDliYmRiYjdjZjFk" \
           "ODc4NzVhOTcwMDAwMDAwMDAwMDAxOTc2YTkxNDZiY2U2NWU1OGE1MGI5Nzk4OTkzMGU5YTRmZjFhYzFhNzc1MTVlZjE4OGFjMDAw" \
           "MDAwMDAiLCAiZmVlIjogNjc4LCAibmV0d29yayI6ICJ0ZXN0bmV0IiwgInR5cGUiOiAiYml0Y29pbl9mdW5kX3NpZ25lZCJ9"
    assert signature.json()

    with pytest.raises(ValueError,
                       match="transaction script is none, sign first"):
        Signature().hash()
    with pytest.raises(ValueError,
                       match="transaction script is none, sign first"):
        Signature().json()
    with pytest.raises(
            ValueError,
            match="transaction script is none, build transaction first"):
        Signature().raw()
    # with pytest.raises(ValueError, match="not found type, sign first"):
    #     Signature().type()
    with pytest.raises(ValueError,
                       match="there is no signed data, sign first"):
        Signature().signed_raw()
    with pytest.raises(ValueError, match="invalid unsigned transaction raw"):
        Signature().sign("eyJtIjogImFzZCJ9", "")
示例#4
0
def sign(private, raw, bytecode, secret, sequence, version):
    if len(private) != 64:
        click.echo(
            click.style("Error: {}").format("invalid Bitcoin private key"),
            err=True)
        sys.exit()

    # Cleaning unsigned raw
    unsigned_raw = str(raw + "=" * (-len(raw) % 4))
    try:
        transaction = json.loads(b64decode(unsigned_raw.encode()).decode())
    except (binascii.Error, json.decoder.JSONDecodeError) as exception:
        click.echo(click.style("Error: {}").format(
            "invalid Bitcoin unsigned transaction raw"),
                   err=True)
        sys.exit()
    if "type" not in transaction or "network" not in transaction:
        click.echo(click.style("Warning: {}", fg="yellow").format(
            "there is no type & network provided in Bitcoin unsigned transaction raw"
        ),
                   err=True)
        click.echo(click.style("Error: {}").format(
            "invalid Bitcoin unsigned transaction raw"),
                   err=True)
        sys.exit()

    try:
        if transaction["type"] == "bitcoin_fund_unsigned":
            # Fund HTLC solver
            fund_solver = FundSolver(private_key=private)
            # Fund signature
            fund_signature = FundSignature(network=transaction["network"],
                                           version=version)
            fund_signature.sign(unsigned_raw=unsigned_raw, solver=fund_solver)
            click.echo(fund_signature.signed_raw())

        elif transaction["type"] == "bitcoin_claim_unsigned":
            if secret is None:
                click.echo(click.style("Error: {}").format(
                    "secret key is required for claim, use -s or --secret \"Hello Meheret!\""
                ),
                           err=True)
                sys.exit()
            if bytecode is None:
                click.echo(click.style("Error: {}").format(
                    "witness bytecode is required for claim, use -b or --bytecode \"016...\""
                ),
                           err=True)
                sys.exit()

            # Claim HTLC solver
            claim_solver = ClaimSolver(private_key=private,
                                       secret=secret,
                                       bytecode=bytecode)
            # Claim signature
            claim_signature = ClaimSignature(network=transaction["network"],
                                             version=version)
            claim_signature.sign(unsigned_raw=unsigned_raw,
                                 solver=claim_solver)
            click.echo(claim_signature.signed_raw())

        elif transaction["type"] == "bitcoin_refund_unsigned":
            if bytecode is None:
                click.echo(click.style("Error: {}").format(
                    "witness bytecode is required for refund, use -b or --bytecode \"016...\""
                ),
                           err=True)
                sys.exit()

            # Refunding HTLC solver
            refund_solver = RefundSolver(private_key=private,
                                         sequence=int(sequence),
                                         bytecode=bytecode)
            # Refund signature
            refund_signature = RefundSignature(network=transaction["network"],
                                               version=version)
            refund_signature.sign(unsigned_raw=unsigned_raw,
                                  solver=refund_solver)
            click.echo(refund_signature.signed_raw())
        else:
            click.echo(click.style("Error: {}").format(
                "unknown Bitcoin unsigned transaction raw type"),
                       err=True)
            sys.exit()
    except Exception as exception:
        click.echo(click.style("Error: {}").format(str(exception)), err=True)
        sys.exit()
def test_signature_exceptions():

    with pytest.raises(
            ValueError,
            match=
            "invalid network, please choose only mainnet or testnet networks"):
        Signature(network="solonet")

    with pytest.raises(ValueError,
                       match="transaction script is none, sign first"):
        Signature().hash()

    with pytest.raises(ValueError,
                       match="transaction script is none, sign first"):
        Signature().json()

    with pytest.raises(
            ValueError,
            match="transaction script is none, build transaction first"):
        Signature().raw()

    with pytest.raises(ValueError, match="not found type, sign first"):
        Signature().type()

    with pytest.raises(ValueError,
                       match="there is no signed data, sign first"):
        Signature().signed_raw()

    with pytest.raises(
            TypeError,
            match=r"invalid Bitcoin fund unsigned transaction type, .*"):
        FundSignature().sign(
            unsigned_raw=
            "eyJmZWUiOiA1NzYsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMDAwMDAwMDAwZmZmZmZmZmYwMWQwMjQwMDAwMDAwMDAwMDAxOTc2YTkxNDY0YTgzOTBiMGIxNjg1ZmNiZjJkNGI0NTcxMThkYzhkYTkyZDU1MzQ4OGFjMDAwMDAwMDAiLCAib3V0cHV0cyI6IHsidmFsdWUiOiAxMDAwMCwgIm4iOiAwLCAic2NyaXB0X3B1YmtleSI6ICJhOTE0MmJiMDEzYzNlNGJlYjA4NDIxZGVkY2Y4MTVjYjY1YTVjMzg4MTc4Yjg3In0sICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX3JlZnVuZF91bnNpZ25lZCJ9",
            solver=FundSolver(private_key=sender_wallet.private_key()))

    with pytest.raises(
            TypeError,
            match=r"invalid Bitcoin claim unsigned transaction type, .*"):
        ClaimSignature().sign(
            unsigned_raw=
            "eyJmZWUiOiA2NzgsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMTAwMDAwMDAwZmZmZmZmZmYwMjEwMjcwMDAwMDAwMDAwMDAxN2E5MTQyYmIwMTNjM2U0YmViMDg0MjFkZWRjZjgxNWNiNjVhNWMzODgxNzhiODc1MDhhMGUwMDAwMDAwMDAwMTk3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYzAwMDAwMDAwIiwgIm91dHB1dHMiOiBbeyJhbW91bnQiOiA5NjM1OTAsICJuIjogMSwgInNjcmlwdCI6ICI3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYyJ9XSwgIm5ldHdvcmsiOiAidGVzdG5ldCIsICJ0eXBlIjogImJpdGNvaW5fZnVuZF91bnNpZ25lZCJ9",
            solver=ClaimSolver(private_key=recipient_wallet.private_key(),
                               secret="Hello Meheret!",
                               secret_hash=sha256(
                                   "Hello Meheret!".encode()).hex(),
                               recipient_address=recipient_wallet.address(),
                               sender_address=sender_wallet.address(),
                               sequence=1000))

    with pytest.raises(
            TypeError,
            match=r"invalid Bitcoin refund unsigned transaction type, .*"):
        RefundSignature().sign(
            unsigned_raw=
            "eyJmZWUiOiA1NzYsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMDAwMDAwMDAwZmZmZmZmZmYwMWQwMjQwMDAwMDAwMDAwMDAxOTc2YTkxNDk4Zjg3OWZiN2Y4YjQ5NTFkZWU5YmM4YTAzMjdiNzkyZmJlMzMyYjg4OGFjMDAwMDAwMDAiLCAib3V0cHV0cyI6IHsiYW1vdW50IjogMTAwMDAsICJuIjogMCwgInNjcmlwdCI6ICJhOTE0MmJiMDEzYzNlNGJlYjA4NDIxZGVkY2Y4MTVjYjY1YTVjMzg4MTc4Yjg3In0sICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX2NsYWltX3Vuc2lnbmVkIn0",
            solver=RefundSolver(private_key=sender_wallet.private_key(),
                                secret_hash=sha256(
                                    "Hello Meheret!".encode()).hex(),
                                recipient_address=recipient_wallet.address(),
                                sender_address=sender_wallet.address(),
                                sequence=1000))

    with pytest.raises(ValueError,
                       match="invalid Bitcoin unsigned transaction raw"):
        Signature().sign("eyJtIjogImFzZCJ9", "")

    with pytest.raises(ValueError,
                       match="invalid Bitcoin unsigned fund transaction raw"):
        FundSignature().sign("eyJtIjogImFzZCJ9", "")

    with pytest.raises(ValueError,
                       match="invalid Bitcoin unsigned claim transaction raw"):
        ClaimSignature().sign("eyJtIjogImFzZCJ9", "")

    with pytest.raises(
            ValueError,
            match="invalid Bitcoin unsigned refund transaction raw"):
        RefundSignature().sign("eyJtIjogImFzZCJ9", "")

    with pytest.raises(
            TypeError,
            match=
            "invalid Bitcoin solver, it's only takes Bitcoin FundSolver class"
    ):
        FundSignature().sign(
            unsigned_raw=
            "eyJmZWUiOiA2NzgsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMTAwMDAwMDAwZmZmZmZmZmYwMjEwMjcwMDAwMDAwMDAwMDAxN2E5MTQyYmIwMTNjM2U0YmViMDg0MjFkZWRjZjgxNWNiNjVhNWMzODgxNzhiODc1MDhhMGUwMDAwMDAwMDAwMTk3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYzAwMDAwMDAwIiwgIm91dHB1dHMiOiBbeyJhbW91bnQiOiA5NjM1OTAsICJuIjogMSwgInNjcmlwdCI6ICI3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYyJ9XSwgIm5ldHdvcmsiOiAidGVzdG5ldCIsICJ0eXBlIjogImJpdGNvaW5fZnVuZF91bnNpZ25lZCJ9",
            solver=RefundSolver(private_key=sender_wallet.private_key(),
                                secret_hash=sha256(
                                    "Hello Meheret!".encode()).hex(),
                                recipient_address=recipient_wallet.address(),
                                sender_address=sender_wallet.address(),
                                sequence=1000))

    with pytest.raises(
            TypeError,
            match=
            "invalid Bitcoin solver, it's only takes Bitcoin ClaimSolver class"
    ):
        ClaimSignature().sign(
            unsigned_raw=
            "eyJmZWUiOiA1NzYsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMDAwMDAwMDAwZmZmZmZmZmYwMWQwMjQwMDAwMDAwMDAwMDAxOTc2YTkxNDk4Zjg3OWZiN2Y4YjQ5NTFkZWU5YmM4YTAzMjdiNzkyZmJlMzMyYjg4OGFjMDAwMDAwMDAiLCAib3V0cHV0cyI6IHsiYW1vdW50IjogMTAwMDAsICJuIjogMCwgInNjcmlwdCI6ICJhOTE0MmJiMDEzYzNlNGJlYjA4NDIxZGVkY2Y4MTVjYjY1YTVjMzg4MTc4Yjg3In0sICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX2NsYWltX3Vuc2lnbmVkIn0",
            solver=FundSolver(private_key=sender_wallet.private_key()))

    with pytest.raises(
            TypeError,
            match=
            "invalid Bitcoin solver, it's only takes Bitcoin RefundSolver class"
    ):
        RefundSignature().sign(
            unsigned_raw=
            "eyJmZWUiOiA1NzYsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMDAwMDAwMDAwZmZmZmZmZmYwMWQwMjQwMDAwMDAwMDAwMDAxOTc2YTkxNDY0YTgzOTBiMGIxNjg1ZmNiZjJkNGI0NTcxMThkYzhkYTkyZDU1MzQ4OGFjMDAwMDAwMDAiLCAib3V0cHV0cyI6IHsidmFsdWUiOiAxMDAwMCwgIm4iOiAwLCAic2NyaXB0X3B1YmtleSI6ICJhOTE0MmJiMDEzYzNlNGJlYjA4NDIxZGVkY2Y4MTVjYjY1YTVjMzg4MTc4Yjg3In0sICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX3JlZnVuZF91bnNpZ25lZCJ9",
            solver=ClaimSolver(private_key=recipient_wallet.private_key(),
                               secret="Hello Meheret!",
                               secret_hash=sha256(
                                   "Hello Meheret!".encode()).hex(),
                               recipient_address=recipient_wallet.address(),
                               sender_address=sender_wallet.address(),
                               sequence=1000))
def test_bitcoin_fund_signature():

    unsigned_fund_transaction_raw = "eyJmZWUiOiA2NzgsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMTAwMDAwMDAwZmZmZmZmZmYwMjEwMjcwMDAwMDAwMDAwMDAxN2E5MTQyYmIwMTNjM2U0YmViMDg0MjFkZWRjZjgxNWNiNjVhNWMzODgxNzhiODc1MDhhMGUwMDAwMDAwMDAwMTk3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYzAwMDAwMDAwIiwgIm91dHB1dHMiOiBbeyJhbW91bnQiOiA5NjM1OTAsICJuIjogMSwgInNjcmlwdCI6ICI3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYyJ9XSwgIm5ldHdvcmsiOiAidGVzdG5ldCIsICJ0eXBlIjogImJpdGNvaW5fZnVuZF91bnNpZ25lZCJ9"

    signature = Signature(version=2, network=network).sign(
        unsigned_raw=unsigned_fund_transaction_raw,
        solver=FundSolver(private_key=sender_wallet.private_key()))

    fund_signature = FundSignature(version=2, network=network).sign(
        unsigned_raw=unsigned_fund_transaction_raw,
        solver=FundSolver(private_key=sender_wallet.private_key()))

    assert signature.fee() == fund_signature.fee() == 678
    assert signature.hash() == fund_signature.hash(
    ) == "7e52333d38b7571807caac7971c925dd2c007dbf34a6c46138ff3d0213281d60"
    assert signature.raw() == fund_signature.raw(
    ) == "0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef3010000006b483045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84ffffffff02102700000000000017a9142bb013c3e4beb08421dedcf815cb65a5c388178b87508a0e00000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert signature.json() == fund_signature.json() == {
        'hex':
        '0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef3010000006b483045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84ffffffff02102700000000000017a9142bb013c3e4beb08421dedcf815cb65a5c388178b87508a0e00000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000',
        'txid':
        '7e52333d38b7571807caac7971c925dd2c007dbf34a6c46138ff3d0213281d60',
        'hash':
        '7e52333d38b7571807caac7971c925dd2c007dbf34a6c46138ff3d0213281d60',
        'size':
        224,
        'vsize':
        224,
        'version':
        2,
        'locktime':
        0,
        'vin': [{
            'txid':
            'f34eb8e86f7753e681dc44387f7d14ab624b3418498d23f6157b38d8922e31ec',
            'vout': 1,
            'scriptSig': {
                'asm':
                '3045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd01 03c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84',
                'hex':
                '483045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84'
            },
            'sequence': '4294967295'
        }],
        'vout': [{
            'value': '0.00010000',
            'n': 0,
            'scriptPubKey': {
                'asm':
                'OP_HASH160 2bb013c3e4beb08421dedcf815cb65a5c388178b OP_EQUAL',
                'hex': 'a9142bb013c3e4beb08421dedcf815cb65a5c388178b87',
                'type': 'p2sh',
                'address': '2MwEDybGC34949zgzWX4M9FHmE3crDSUydP'
            }
        }, {
            'value': '0.00952912',
            'n': 1,
            'scriptPubKey': {
                'asm':
                'OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG',
                'hex': '76a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac',
                'type': 'p2pkh',
                'address': 'mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q'
            }
        }]
    }
    assert signature.type() == fund_signature.type() == "bitcoin_fund_signed"
    assert signature.signed_raw() == fund_signature.signed_raw(
    ) == "eyJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMTAwMDAwMDZiNDgzMDQ1MDIyMTAwYjRkNGRlNGMxMGJlYzM4MGE5ZjA3MDE5ZDUyMzJhOWFmOWYwYzIzMjFlNWVmY2YzM2Y1MzI2YTYwMzc4MTQ0NTAyMjAzZTFhYjJkZGFhYzhhZmFkZTEzMjgzMmU3MTVmMDU1Zjk1NmQzZTczMGI5ZDAzNWE0ZTk5ZWM5ZGZkYzdhY2ZkMDEyMTAzYzU2YTYwMDVkNGE4ODkyZDI4Y2MzZjcyNjVlNTY4NWI1NDg2MjdkNTkxMDg5NzNlNDc0YzRlMjZmNjlhNGM4NGZmZmZmZmZmMDIxMDI3MDAwMDAwMDAwMDAwMTdhOTE0MmJiMDEzYzNlNGJlYjA4NDIxZGVkY2Y4MTVjYjY1YTVjMzg4MTc4Yjg3NTA4YTBlMDAwMDAwMDAwMDE5NzZhOTE0NjRhODM5MGIwYjE2ODVmY2JmMmQ0YjQ1NzExOGRjOGRhOTJkNTUzNDg4YWMwMDAwMDAwMCIsICJmZWUiOiA2NzgsICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX2Z1bmRfc2lnbmVkIn0="
示例#7
0
def sign(private, raw, secret, version):
    if secret is None:
        secret = str()
    if len(private) != 64:
        click.echo(click.style("Error: {}")
                   .format("invalid bitcoin private key"), err=True)
        sys.exit()

    unsigned_raw = str(raw + "=" * (-len(raw) % 4))
    try:
        transaction = json.loads(b64decode(unsigned_raw.encode()).decode())
    except (binascii.Error, json.decoder.JSONDecodeError) as exception:
        click.echo(click.style("Error: {}")
                   .format("invalid bitcoin unsigned transaction raw"), err=True)
        sys.exit()
    if "type" not in transaction or "network" not in transaction:
        click.echo(click.style("Warning: {}", fg="yellow")
                   .format("there is no type & network provided in bitcoin unsigned transaction raw"), err=True)
        click.echo(click.style("Error: {}")
                   .format("invalid bitcoin unsigned transaction raw"), err=True)
        sys.exit()

    if transaction["type"] == "bitcoin_fund_unsigned":
        # Fund HTLC solver
        fund_solver = FundSolver(private_key=private)
        try:
            # Fund signature
            fund_signature = FundSignature(network=transaction["network"], version=version)
            fund_signature.sign(unsigned_raw=unsigned_raw, solver=fund_solver)
            click.echo(fund_signature.signed_raw())
        except Exception as exception:
            click.echo(click.style("Error: {}").format(str(exception)), err=True)
            sys.exit()

    elif transaction["type"] == "bitcoin_claim_unsigned":
        if secret != str():
            _secret = secret
        elif "secret" not in transaction or transaction["secret"] is None:
            click.echo(click.style("Warning: {}")
                       .format("secret key is empty, use -s or --secret \"Hello Meheret!\""), err=False)
            _secret = str()
        else:
            _secret = transaction["secret"]
        # Claim HTLC solver
        claim_solver = ClaimSolver(
            secret=_secret,
            private_key=private
        )
        try:
            # Claim signature
            claim_signature = ClaimSignature(network=transaction["network"], version=version)
            claim_signature.sign(unsigned_raw=unsigned_raw, solver=claim_solver)
            click.echo(claim_signature.signed_raw())
        except Exception as exception:
            click.echo(click.style("Error: {}").format(str(exception)), err=True)
            sys.exit()

    elif transaction["type"] == "bitcoin_refund_unsigned":
        if secret != str():
            _secret = secret
        elif "secret" not in transaction or transaction["secret"] is None:
            click.echo(click.style("Warning: {}")
                       .format("secret key is empty, use -s or --secret \"Hello Meheret!\""), err=False)
            _secret = str()
        else:
            _secret = transaction["secret"]
        # Refunding HTLC solver
        refund_solver = RefundSolver(
            secret=_secret,
            private_key=private
        )
        try:
            # Refund signature
            refund_signature = RefundSignature(network=transaction["network"], version=version)
            refund_signature.sign(unsigned_raw=unsigned_raw, solver=refund_solver)
            click.echo(refund_signature.signed_raw())
        except Exception as exception:
            click.echo(click.style("Error: {}").format(str(exception)), err=True)
            sys.exit()
def test_bitcoin_fund_transaction():

    unsigned_fund_transaction = FundTransaction(version=2, network=network)

    unsigned_fund_transaction.build_transaction(
        wallet=sender_wallet,
        htlc=HTLC(network=network).init(
            secret_hash=sha256("Hello Meheret!".encode()).hex(),
            recipient_address=recipient_wallet.address(),
            sender_address=sender_wallet.address(),
            sequence=1000),
        amount=10_000)

    assert unsigned_fund_transaction.fee() == 678
    assert unsigned_fund_transaction.hash(
    ) == "f05f2afb0706020cc15b66d63e2fd9d89cfe5ce7a9f458f3a8a6fb3c1849cf20"
    assert unsigned_fund_transaction.raw(
    ) == "0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef30100000000ffffffff02102700000000000017a9142bb013c3e4beb08421dedcf815cb65a5c388178b87508a0e00000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert unsigned_fund_transaction.json() == {
        'hex':
        '0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef30100000000ffffffff02102700000000000017a9142bb013c3e4beb08421dedcf815cb65a5c388178b87508a0e00000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000',
        'txid':
        'f05f2afb0706020cc15b66d63e2fd9d89cfe5ce7a9f458f3a8a6fb3c1849cf20',
        'hash':
        'f05f2afb0706020cc15b66d63e2fd9d89cfe5ce7a9f458f3a8a6fb3c1849cf20',
        'size':
        117,
        'vsize':
        117,
        'version':
        2,
        'locktime':
        0,
        'vin': [{
            'txid':
            'f34eb8e86f7753e681dc44387f7d14ab624b3418498d23f6157b38d8922e31ec',
            'vout': 1,
            'scriptSig': {
                'asm': '',
                'hex': ''
            },
            'sequence': '4294967295'
        }],
        'vout': [{
            'value': '0.00010000',
            'n': 0,
            'scriptPubKey': {
                'asm':
                'OP_HASH160 2bb013c3e4beb08421dedcf815cb65a5c388178b OP_EQUAL',
                'hex': 'a9142bb013c3e4beb08421dedcf815cb65a5c388178b87',
                'type': 'p2sh',
                'address': '2MwEDybGC34949zgzWX4M9FHmE3crDSUydP'
            }
        }, {
            'value': '0.00952912',
            'n': 1,
            'scriptPubKey': {
                'asm':
                'OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG',
                'hex': '76a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac',
                'type': 'p2pkh',
                'address': 'mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q'
            }
        }]
    }
    assert unsigned_fund_transaction.type() == "bitcoin_fund_unsigned"
    assert unsigned_fund_transaction.unsigned_raw(
    ) == "eyJmZWUiOiA2NzgsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMTAwMDAwMDAwZmZmZmZmZmYwMjEwMjcwMDAwMDAwMDAwMDAxN2E5MTQyYmIwMTNjM2U0YmViMDg0MjFkZWRjZjgxNWNiNjVhNWMzODgxNzhiODc1MDhhMGUwMDAwMDAwMDAwMTk3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYzAwMDAwMDAwIiwgIm91dHB1dHMiOiBbeyJhbW91bnQiOiA5NjM1OTAsICJuIjogMSwgInNjcmlwdCI6ICI3NmE5MTQ2NGE4MzkwYjBiMTY4NWZjYmYyZDRiNDU3MTE4ZGM4ZGE5MmQ1NTM0ODhhYyJ9XSwgIm5ldHdvcmsiOiAidGVzdG5ldCIsICJ0eXBlIjogImJpdGNvaW5fZnVuZF91bnNpZ25lZCJ9"

    signed_fund_transaction = unsigned_fund_transaction.sign(solver=FundSolver(
        private_key=sender_wallet.private_key()))

    assert signed_fund_transaction.fee() == 678
    assert signed_fund_transaction.hash(
    ) == "7e52333d38b7571807caac7971c925dd2c007dbf34a6c46138ff3d0213281d60"
    assert signed_fund_transaction.raw(
    ) == "0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef3010000006b483045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84ffffffff02102700000000000017a9142bb013c3e4beb08421dedcf815cb65a5c388178b87508a0e00000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert signed_fund_transaction.json() == {
        'hex':
        '0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef3010000006b483045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84ffffffff02102700000000000017a9142bb013c3e4beb08421dedcf815cb65a5c388178b87508a0e00000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000',
        'txid':
        '7e52333d38b7571807caac7971c925dd2c007dbf34a6c46138ff3d0213281d60',
        'hash':
        '7e52333d38b7571807caac7971c925dd2c007dbf34a6c46138ff3d0213281d60',
        'size':
        224,
        'vsize':
        224,
        'version':
        2,
        'locktime':
        0,
        'vin': [{
            'txid':
            'f34eb8e86f7753e681dc44387f7d14ab624b3418498d23f6157b38d8922e31ec',
            'vout': 1,
            'scriptSig': {
                'asm':
                '3045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd01 03c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84',
                'hex':
                '483045022100b4d4de4c10bec380a9f07019d5232a9af9f0c2321e5efcf33f5326a60378144502203e1ab2ddaac8afade132832e715f055f956d3e730b9d035a4e99ec9dfdc7acfd012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84'
            },
            'sequence': '4294967295'
        }],
        'vout': [{
            'value': '0.00010000',
            'n': 0,
            'scriptPubKey': {
                'asm':
                'OP_HASH160 2bb013c3e4beb08421dedcf815cb65a5c388178b OP_EQUAL',
                'hex': 'a9142bb013c3e4beb08421dedcf815cb65a5c388178b87',
                'type': 'p2sh',
                'address': '2MwEDybGC34949zgzWX4M9FHmE3crDSUydP'
            }
        }, {
            'value': '0.00952912',
            'n': 1,
            'scriptPubKey': {
                'asm':
                'OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG',
                'hex': '76a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac',
                'type': 'p2pkh',
                'address': 'mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q'
            }
        }]
    }
    assert signed_fund_transaction.type() == "bitcoin_fund_signed"