示例#1
0
print("Unsigned Refund Transaction Fee:", unsigned_refund_transaction.fee())
print("Unsigned Refund Transaction Hash:", unsigned_refund_transaction.hash())
print("Unsigned Refund Transaction Raw:", unsigned_refund_transaction.raw())
# print("Unsigned Refund Transaction Json:", json.dumps(unsigned_refund_transaction.json(), indent=4))
print("Unsigned Refund Transaction Type:", unsigned_refund_transaction.type())

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

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

# Initializing refund solver
refund_solver = RefundSolver(
    private_key=sender_private_key,
    secret_hash=sha256("Hello Meheret!".encode()).hex(),
    recipient_address=recipient_address,
    sender_address=sender_address,
    sequence=1000
)

# Singing unsigned claim transaction
signed_refund_transaction = unsigned_refund_transaction.sign(refund_solver)

print("Signed Refund Transaction Fee:", signed_refund_transaction.fee())
print("Signed Refund Transaction Hash:", signed_refund_transaction.hash())
print("Signed Refund Transaction Raw:", signed_refund_transaction.raw())
# print("Signed Refund Transaction Json:", json.dumps(signed_refund_transaction.json(), indent=4))
print("Signed Refund Transaction Type:", signed_refund_transaction.type())

print("=" * 10, "Refund Signature")
示例#2
0
def test_bitcoin_refund():
    # Initialization refund transaction
    unsigned_refund_transaction = RefundTransaction(version=2, network=network)
    # Building refund transaction
    unsigned_refund_transaction.build_transaction(
        transaction_id=fund_transaction_id,
        wallet=recipient_wallet,
        amount=2000
    )

    assert unsigned_refund_transaction.fee == 576
    assert unsigned_refund_transaction.hash() == "0a22fd29c2d2a8f0e162028737c8cbc1ea9e266d5f4cf42248aa22c1c96d1e15"
    assert unsigned_refund_transaction.raw() == \
           "0200000001888be7ec065097d95664763f276d425552d735fb1d974ae78bf72106dca0f3910000000000ffffffff0190050000" \
           "000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert unsigned_refund_transaction.json()

    unsigned_refund_raw = unsigned_refund_transaction.unsigned_raw()
    assert unsigned_refund_raw == \
           "eyJmZWUiOiA1NzYsICJyYXciOiAiMDIwMDAwMDAwMTg4OGJlN2VjMDY1MDk3ZDk1NjY0NzYzZjI3NmQ0MjU1NTJkNzM1ZmIxZDk3NG" \
           "FlNzhiZjcyMTA2ZGNhMGYzOTEwMDAwMDAwMDAwZmZmZmZmZmYwMTkwMDUwMDAwMDAwMDAwMDAxOTc2YTkxNDY0YTgzOTBiMGIxNjg1" \
           "ZmNiZjJkNGI0NTcxMThkYzhkYTkyZDU1MzQ4OGFjMDAwMDAwMDAiLCAib3V0cHV0cyI6IFt7ImFtb3VudCI6IDIwMDAsICJuIjogMC" \
           "wgInNjcmlwdCI6ICJhOTE0NmYwOGIyNTRlNGM1OGRjNjVmNmYzOTljM2JlNzE3N2I5MDFmNGE2Njg3In1dLCAicmVjaXBpZW50X2Fk" \
           "ZHJlc3MiOiAibXVUbmZmTERSNUx0RmVMUjJpM1dzS1ZmZHl2emZ5UG5WQiIsICJzZW5kZXJfYWRkcmVzcyI6ICJtcGhCUFpmMTVjUk" \
           "ZjTDV0VXE2bUNiRTg0WG9iWjF2ZzdRIiwgInNlY3JldCI6IG51bGwsICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRj" \
           "b2luX3JlZnVuZF91bnNpZ25lZCJ9"

    # Refunding HTLC solver
    refund_solver = RefundSolver(
        secret="Hello Meheret!",
        private_key=sender_private_key
    )

    signed_refund_transaction = unsigned_refund_transaction.sign(refund_solver)

    assert signed_refund_transaction.fee
    assert signed_refund_transaction.hash()
    assert signed_refund_transaction.raw()
    assert signed_refund_transaction.json()

    # Singing Hash Time Lock Contract (HTLC)
    refund_signature = RefundSignature(network=network)\
        .sign(unsigned_raw=unsigned_refund_raw, solver=refund_solver)

    signature = Signature(network=network) \
        .sign(unsigned_raw=unsigned_refund_raw, solver=refund_solver)

    assert signature.fee == refund_signature.fee == signed_refund_transaction.fee == 576
    assert signature.hash() == refund_signature.hash() == signed_refund_transaction.hash() == \
           "cab253322cfeaa066b0d52ab6f4a18a035d723271d4bbfb39d43d0aa0ca86c2e"
    assert signature.raw() == refund_signature.raw() == signed_refund_transaction.raw() == \
           "0200000001888be7ec065097d95664763f276d425552d735fb1d974ae78bf72106dca0f39100000000ca483045022100ce6ad4" \
           "458c1ba40b4d08f02b5bdf4aa0a2f73abf9cd7af3c4a1909187f00b7810220049a4733b994732fe52afd78b714bce067a4d31b" \
           "e4b02716f4fb7384f53786160121039213ebcaefdd3e109720c17867ce1bd6d076b0e65e3b6390e6e38548a65e76af004c5c63" \
           "aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a03" \
           "27b792fbe332b888ac670164b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac686400000001900500000000" \
           "00001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert signature.json() == refund_signature.json() == signed_refund_transaction.json()

    signed_refund_raw = refund_signature.signed_raw()
    assert signature.signed_raw() == signed_refund_raw == \
           "eyJyYXciOiAiMDIwMDAwMDAwMTg4OGJlN2VjMDY1MDk3ZDk1NjY0NzYzZjI3NmQ0MjU1NTJkNzM1ZmIxZDk3NGFlNzhiZjcyMTA2ZG" \
           "NhMGYzOTEwMDAwMDAwMGNhNDgzMDQ1MDIyMTAwY2U2YWQ0NDU4YzFiYTQwYjRkMDhmMDJiNWJkZjRhYTBhMmY3M2FiZjljZDdhZjNj" \
           "NGExOTA5MTg3ZjAwYjc4MTAyMjAwNDlhNDczM2I5OTQ3MzJmZTUyYWZkNzhiNzE0YmNlMDY3YTRkMzFiZTRiMDI3MTZmNGZiNzM4NG" \
           "Y1Mzc4NjE2MDEyMTAzOTIxM2ViY2FlZmRkM2UxMDk3MjBjMTc4NjdjZTFiZDZkMDc2YjBlNjVlM2I2MzkwZTZlMzg1NDhhNjVlNzZh" \
           "ZjAwNGM1YzYzYWEyMDgyMTEyNGI1NTRkMTNmMjQ3YjFlNWQxMGI4NGU0NGZiMTI5NmYxOGYzOGJiYWExYmVhMzRhMTJjODQzZTAxNT" \
           "g4ODc2YTkxNDk4Zjg3OWZiN2Y4YjQ5NTFkZWU5YmM4YTAzMjdiNzkyZmJlMzMyYjg4OGFjNjcwMTY0YjI3NTc2YTkxNDY0YTgzOTBi" \
           "MGIxNjg1ZmNiZjJkNGI0NTcxMThkYzhkYTkyZDU1MzQ4OGFjNjg2NDAwMDAwMDAxOTAwNTAwMDAwMDAwMDAwMDE5NzZhOTE0NjRhOD" \
           "M5MGIwYjE2ODVmY2JmMmQ0YjQ1NzExOGRjOGRhOTJkNTUzNDg4YWMwMDAwMDAwMCIsICJmZWUiOiA1NzYsICJuZXR3b3JrIjogInRl" \
           "c3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX3JlZnVuZF9zaWduZWQifQ=="
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))
示例#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_bitcoin_refund_signature():

    unsigned_refund_transaction_raw = "eyJmZWUiOiA1NzYsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMDAwMDAwMDAwZmZmZmZmZmYwMWQwMjQwMDAwMDAwMDAwMDAxOTc2YTkxNDY0YTgzOTBiMGIxNjg1ZmNiZjJkNGI0NTcxMThkYzhkYTkyZDU1MzQ4OGFjMDAwMDAwMDAiLCAib3V0cHV0cyI6IHsidmFsdWUiOiAxMDAwMCwgIm4iOiAwLCAic2NyaXB0X3B1YmtleSI6ICJhOTE0MmJiMDEzYzNlNGJlYjA4NDIxZGVkY2Y4MTVjYjY1YTVjMzg4MTc4Yjg3In0sICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX3JlZnVuZF91bnNpZ25lZCJ9"

    signature = Signature(version=2, network=network).sign(
        unsigned_raw=unsigned_refund_transaction_raw,
        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))

    refund_signature = RefundSignature(version=2, network=network).sign(
        unsigned_raw=unsigned_refund_transaction_raw,
        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))

    assert signature.fee() == refund_signature.fee() == 576
    assert signature.hash() == refund_signature.hash(
    ) == "9b429fdff11ccb19e4642521fed4ae7d89129c49a08214f41e709bd3e2a0e4f5"
    assert signature.raw() == refund_signature.raw(
    ) == "0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef300000000ca47304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e4506659012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84004c5d63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68e803000001d0240000000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert signature.json() == refund_signature.json() == {
        'hex':
        '0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef300000000ca47304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e4506659012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84004c5d63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68e803000001d0240000000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000',
        'txid':
        '9b429fdff11ccb19e4642521fed4ae7d89129c49a08214f41e709bd3e2a0e4f5',
        'hash':
        '9b429fdff11ccb19e4642521fed4ae7d89129c49a08214f41e709bd3e2a0e4f5',
        'size':
        287,
        'vsize':
        287,
        'version':
        2,
        'locktime':
        0,
        'vin': [{
            'txid':
            'f34eb8e86f7753e681dc44387f7d14ab624b3418498d23f6157b38d8922e31ec',
            'vout': 0,
            'scriptSig': {
                'asm':
                '304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e450665901 03c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84 OP_0 63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68',
                'hex':
                '47304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e4506659012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84004c5d63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68'
            },
            'sequence': '1000'
        }],
        'vout': [{
            'value': '0.00009424',
            'n': 0,
            'scriptPubKey': {
                'asm':
                'OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG',
                'hex': '76a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac',
                'type': 'p2pkh',
                'address': 'mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q'
            }
        }]
    }
    assert signature.type() == refund_signature.type(
    ) == "bitcoin_refund_signed"
    assert signature.signed_raw() == refund_signature.signed_raw(
    ) == "eyJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMDAwMDAwMGNhNDczMDQ0MDIyMDBiMGZjM2IzYjg5MTc2MWU1Y2JlZTViYzFmM2M2ZDdiMDkwNGMxMzQ3NWVlZjViNzk2NWM5YmZkYTFkMDhhMmEwMjIwNWViZGM3MmNiNzYzYTJlN2YyOTA3ODdiOGQ3ZGVmZDk3MmI0MWEyYjRkYzFjNDk5ZDY5OTkxZjBlNDUwNjY1OTAxMjEwM2M1NmE2MDA1ZDRhODg5MmQyOGNjM2Y3MjY1ZTU2ODViNTQ4NjI3ZDU5MTA4OTczZTQ3NGM0ZTI2ZjY5YTRjODQwMDRjNWQ2M2FhMjA4MjExMjRiNTU0ZDEzZjI0N2IxZTVkMTBiODRlNDRmYjEyOTZmMThmMzhiYmFhMWJlYTM0YTEyYzg0M2UwMTU4ODg3NmE5MTQ5OGY4NzlmYjdmOGI0OTUxZGVlOWJjOGEwMzI3Yjc5MmZiZTMzMmI4ODhhYzY3MDJlODAzYjI3NTc2YTkxNDY0YTgzOTBiMGIxNjg1ZmNiZjJkNGI0NTcxMThkYzhkYTkyZDU1MzQ4OGFjNjhlODAzMDAwMDAxZDAyNDAwMDAwMDAwMDAwMDE5NzZhOTE0NjRhODM5MGIwYjE2ODVmY2JmMmQ0YjQ1NzExOGRjOGRhOTJkNTUzNDg4YWMwMDAwMDAwMCIsICJmZWUiOiA1NzYsICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX3JlZnVuZF9zaWduZWQifQ=="
示例#6
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()
示例#7
0
def test_bitcoin_refund_solver():

    htlc_refund_solver = RefundSolver(
        private_key=sender_wallet.private_key(),
        # Witness from HTLC agreements
        secret_hash=sha256("Hello Meheret!".encode()).hex(),
        recipient_address=recipient_wallet.address(),
        sender_address=sender_wallet.address(),
        sequence=1000)

    assert sender_wallet.private_key(
    ) == htlc_refund_solver.private_key.hexlify()
    assert isinstance(htlc_refund_solver.solve(), IfElseSolver)
    assert isinstance(htlc_refund_solver.witness("testnet"), IfElseScript)

    bytecode_refund_solver = RefundSolver(
        private_key=sender_wallet.private_key(),
        # Witness from HTLC bytecode
        bytecode=
        "63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8"
        "b4951dee9bc8a0327b792fbe332b888ac670164b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68"
    )

    assert sender_wallet.private_key(
    ) == bytecode_refund_solver.private_key.hexlify()
    assert isinstance(bytecode_refund_solver.solve(), IfElseSolver)
    assert isinstance(bytecode_refund_solver.witness("testnet"), IfElseScript)

    with pytest.raises(TypeError, match="private key must be string format"):
        RefundSolver(int())
    with pytest.raises(TypeError, match="secret hash must be string format"):
        RefundSolver(str(), int())
    with pytest.raises(ValueError,
                       match="invalid secret hash, length must be 64"):
        RefundSolver(str(), str())
    with pytest.raises(AddressError, match=r"invalid recipient *.* address"):
        RefundSolver(str(), sha256(b"Hello Meheret!").hex(), "adsfsdfsd")
    with pytest.raises(AddressError, match=r"invalid sender *.* address"):
        RefundSolver(str(),
                     sha256(b"Hello Meheret!").hex(),
                     "2N729UBGZB3xjsGFRgKivy4bSjkaJGMVSpB", "adsfsdfsd")
    with pytest.raises(TypeError, match="sequence must be integer format"):
        RefundSolver(str(),
                     sha256(b"Hello Meheret!").hex(),
                     "2N729UBGZB3xjsGFRgKivy4bSjkaJGMVSpB",
                     "2N729UBGZB3xjsGFRgKivy4bSjkaJGMVSpB", float())
    with pytest.raises(TypeError, match="bytecode must be string format"):
        RefundSolver(str(), bytecode=123423423423)
def test_bitcoin_refund_transaction():

    unsigned_refund_transaction = RefundTransaction(version=2, network=network)

    unsigned_refund_transaction.build_transaction(
        transaction_id=transaction_id, wallet=sender_wallet, amount=10_000)

    assert unsigned_refund_transaction.fee() == 576
    assert unsigned_refund_transaction.hash(
    ) == "a2022290e62f4073bc642d6b45f92ec3686c6524d0ef3d67d9edfd5f7dab0ea1"
    assert unsigned_refund_transaction.raw(
    ) == "0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef30000000000ffffffff01d0240000000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert unsigned_refund_transaction.json() == {
        'hex':
        '0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef30000000000ffffffff01d0240000000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000',
        'txid':
        'a2022290e62f4073bc642d6b45f92ec3686c6524d0ef3d67d9edfd5f7dab0ea1',
        'hash':
        'a2022290e62f4073bc642d6b45f92ec3686c6524d0ef3d67d9edfd5f7dab0ea1',
        'size':
        85,
        'vsize':
        85,
        'version':
        2,
        'locktime':
        0,
        'vin': [{
            'txid':
            'f34eb8e86f7753e681dc44387f7d14ab624b3418498d23f6157b38d8922e31ec',
            'vout': 0,
            'scriptSig': {
                'asm': '',
                'hex': ''
            },
            'sequence': '4294967295'
        }],
        'vout': [{
            'value': '0.00009424',
            'n': 0,
            'scriptPubKey': {
                'asm':
                'OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG',
                'hex': '76a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac',
                'type': 'p2pkh',
                'address': 'mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q'
            }
        }]
    }
    assert unsigned_refund_transaction.type() == "bitcoin_refund_unsigned"
    assert unsigned_refund_transaction.unsigned_raw(
    ) == "eyJmZWUiOiA1NzYsICJyYXciOiAiMDIwMDAwMDAwMWVjMzEyZTkyZDgzODdiMTVmNjIzOGQ0OTE4MzQ0YjYyYWIxNDdkN2YzODQ0ZGM4MWU2NTM3NzZmZThiODRlZjMwMDAwMDAwMDAwZmZmZmZmZmYwMWQwMjQwMDAwMDAwMDAwMDAxOTc2YTkxNDY0YTgzOTBiMGIxNjg1ZmNiZjJkNGI0NTcxMThkYzhkYTkyZDU1MzQ4OGFjMDAwMDAwMDAiLCAib3V0cHV0cyI6IHsidmFsdWUiOiAxMDAwMCwgIm4iOiAwLCAic2NyaXB0X3B1YmtleSI6ICJhOTE0MmJiMDEzYzNlNGJlYjA4NDIxZGVkY2Y4MTVjYjY1YTVjMzg4MTc4Yjg3In0sICJuZXR3b3JrIjogInRlc3RuZXQiLCAidHlwZSI6ICJiaXRjb2luX3JlZnVuZF91bnNpZ25lZCJ9"

    signed_refund_transaction = unsigned_refund_transaction.sign(
        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))

    assert signed_refund_transaction.fee() == 576
    assert signed_refund_transaction.hash(
    ) == "9b429fdff11ccb19e4642521fed4ae7d89129c49a08214f41e709bd3e2a0e4f5"
    assert signed_refund_transaction.raw(
    ) == "0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef300000000ca47304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e4506659012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84004c5d63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68e803000001d0240000000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000"
    assert signed_refund_transaction.json() == {
        'hex':
        '0200000001ec312e92d8387b15f6238d4918344b62ab147d7f3844dc81e653776fe8b84ef300000000ca47304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e4506659012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84004c5d63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68e803000001d0240000000000001976a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac00000000',
        'txid':
        '9b429fdff11ccb19e4642521fed4ae7d89129c49a08214f41e709bd3e2a0e4f5',
        'hash':
        '9b429fdff11ccb19e4642521fed4ae7d89129c49a08214f41e709bd3e2a0e4f5',
        'size':
        287,
        'vsize':
        287,
        'version':
        2,
        'locktime':
        0,
        'vin': [{
            'txid':
            'f34eb8e86f7753e681dc44387f7d14ab624b3418498d23f6157b38d8922e31ec',
            'vout': 0,
            'scriptSig': {
                'asm':
                '304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e450665901 03c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84 OP_0 63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68',
                'hex':
                '47304402200b0fc3b3b891761e5cbee5bc1f3c6d7b0904c13475eef5b7965c9bfda1d08a2a02205ebdc72cb763a2e7f290787b8d7defd972b41a2b4dc1c499d69991f0e4506659012103c56a6005d4a8892d28cc3f7265e5685b548627d59108973e474c4e26f69a4c84004c5d63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68'
            },
            'sequence': '1000'
        }],
        'vout': [{
            'value': '0.00009424',
            'n': 0,
            'scriptPubKey': {
                'asm':
                'OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG',
                'hex': '76a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac',
                'type': 'p2pkh',
                'address': 'mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q'
            }
        }]
    }
    assert signed_refund_transaction.type() == "bitcoin_refund_signed"
示例#9
0
                                       wallet=recipient_wallet,
                                       amount=5000)

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

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

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

# Refunding HTLC solver
refund_solver = RefundSolver(secret="Hello Meheret!",
                             private_key=sender_private_key,
                             sequence=5)

signed_refund_transaction = unsigned_refund_transaction.sign(refund_solver)

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

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

# Singing Hash Time Lock Contract (HTLC)
refund_signature = RefundSignature(network=network)\
    .sign(unsigned_raw=unsigned_fund_raw, solver=refund_solver)