Skip to content

Commit

Permalink
Refactoring project name
Browse files Browse the repository at this point in the history
  • Loading branch information
mohanson committed Dec 6, 2024
1 parent 43522e0 commit d6b5c9f
Show file tree
Hide file tree
Showing 28 changed files with 456 additions and 453 deletions.
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# Python SDK for BTC
# Plbtc: Bitcoin Library For Humans

Python BTC is an experimental project that aims to provide human-friendly interfaces for common BTC operations. Note that Python BTC is not a complete SDK, but only implements the BTC functions that I am interested in.
Plbtc is a project that aims to provide human-friendly interfaces for common btc operations. Using plbtc, you can easily and happily complete everything you want to do on btc.

Features:

- No third-party dependencies. All code is visible.
- Incredibly simple.
- No third-party dependencies, everything is visible.
- Incredibly simple, even a cat knows how to use it.

## Installation

```sh
$ git clone https://github.com/mohanson/pybtc
$ cd pybtc
$ pip install plbtc
# or
$ git clone https://github.com/mohanson/plbtc
$ cd plbtc
$ python -m pip install --editable .
```

## Usage

By default, plbtc is configured on the develop. To switch networks, use `plbtc.config.current = plbtc.config.mainnet`.

**example/addr.py**

Calculate the address from a private key.
Expand Down
51 changes: 0 additions & 51 deletions btc/ecdsa.py

This file was deleted.

18 changes: 9 additions & 9 deletions example/addr.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import argparse
import btc
import plbtc

# Calculate the address from a private key.

Expand All @@ -9,16 +9,16 @@
args = parser.parse_args()

if args.net == 'develop':
btc.config.current = btc.config.develop
plbtc.config.current = plbtc.config.develop
if args.net == 'mainnet':
btc.config.current = btc.config.mainnet
plbtc.config.current = plbtc.config.mainnet
if args.net == 'testnet':
btc.config.current = btc.config.testnet
plbtc.config.current = plbtc.config.testnet

prikey = btc.core.PriKey(int(args.prikey, 0))
prikey = plbtc.core.PriKey(int(args.prikey, 0))
pubkey = prikey.pubkey()

print('p2pkh ', btc.core.address_p2pkh(pubkey))
print('p2sh-p2wpkh', btc.core.address_p2sh_p2wpkh(pubkey))
print('p2wpkh ', btc.core.address_p2wpkh(pubkey))
print('p2tr ', btc.core.address_p2tr(pubkey, bytearray()))
print('p2pkh ', plbtc.core.address_p2pkh(pubkey))
print('p2sh-p2wpkh', plbtc.core.address_p2sh_p2wpkh(pubkey))
print('p2wpkh ', plbtc.core.address_p2wpkh(pubkey))
print('p2tr ', plbtc.core.address_p2tr(pubkey, bytearray()))
8 changes: 4 additions & 4 deletions example/message.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import argparse
import btc
import plbtc

# Sign a message with the private key and verify it.

Expand All @@ -9,11 +9,11 @@
parser.add_argument('--sig', type=str, default='', help='the signature of the message encoded in base 64')
args = parser.parse_args()

prikey = btc.core.PriKey(int(args.prikey, 0))
prikey = plbtc.core.PriKey(int(args.prikey, 0))
pubkey = prikey.pubkey()

if args.sig == '':
print(btc.core.Message(args.msg).sign(prikey))
print(plbtc.core.Message(args.msg).sign(prikey))

if args.sig != '':
print(btc.core.Message(args.msg).pubkey(args.sig) == pubkey)
print(plbtc.core.Message(args.msg).pubkey(args.sig) == pubkey)
24 changes: 12 additions & 12 deletions example/regtest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import btc
import plbtc

pub1 = btc.core.PriKey(1).pubkey()
pub2 = btc.core.PriKey(2).pubkey()
pub1 = plbtc.core.PriKey(1).pubkey()
pub2 = plbtc.core.PriKey(2).pubkey()

btc.rpc.call('createwallet', ['main', True, True, None, None, None, True])
plbtc.rpc.call('createwallet', ['main', True, True, None, None, None, True])
for d in [
f'pkh({pub1.sec().hex()})',
f'pkh({pub2.sec().hex()})',
Expand All @@ -16,14 +16,14 @@
f'tr({pub1.sec().hex()})',
f'tr({pub2.sec().hex()})',
]:
d = btc.rpc.get_descriptor_info(d)['descriptor']
btc.rpc.import_descriptors([{
d = plbtc.rpc.get_descriptor_info(d)['descriptor']
plbtc.rpc.import_descriptors([{
'desc': d,
'timestamp': 0,
}])
btc.rpc.generate_to_address(10, btc.core.address_p2pkh(pub1))
btc.rpc.generate_to_address(10, btc.core.address_p2sh_p2ms(2, [pub1, pub2]))
btc.rpc.generate_to_address(10, btc.core.address_p2sh_p2wpkh(pub1))
btc.rpc.generate_to_address(10, btc.core.address_p2wpkh(pub1))
btc.rpc.generate_to_address(10, btc.core.address_p2tr(pub1, bytearray()))
btc.rpc.generate_to_address(99, btc.core.address_p2pkh(pub1))
plbtc.rpc.generate_to_address(10, plbtc.core.address_p2pkh(pub1))
plbtc.rpc.generate_to_address(10, plbtc.core.address_p2sh_p2ms(2, [pub1, pub2]))
plbtc.rpc.generate_to_address(10, plbtc.core.address_p2sh_p2wpkh(pub1))
plbtc.rpc.generate_to_address(10, plbtc.core.address_p2wpkh(pub1))
plbtc.rpc.generate_to_address(10, plbtc.core.address_p2tr(pub1, bytearray()))
plbtc.rpc.generate_to_address(99, plbtc.core.address_p2pkh(pub1))
92 changes: 46 additions & 46 deletions example/taproot.py
Original file line number Diff line number Diff line change
@@ -1,111 +1,111 @@
import btc
import plbtc

# This example shows how to create a P2TR script with two unlock conditions: p2pk and p2ms.


# Here created two scripts, one of which is a p2pk script, which requires that it can only be unlocked by private key 2,
# and the other is an 2-of-2 multisig script.
mast = btc.core.TapNode(
btc.core.TapLeaf(btc.core.script([
btc.opcode.op_pushdata(btc.core.PriKey(2).pubkey().sec()[1:]),
btc.opcode.op_checksig,
mast = plbtc.core.TapNode(
plbtc.core.TapLeaf(plbtc.core.script([
plbtc.opcode.op_pushdata(plbtc.core.PriKey(2).pubkey().sec()[1:]),
plbtc.opcode.op_checksig,
])),
btc.core.TapLeaf(btc.core.script([
btc.opcode.op_pushdata(btc.core.PriKey(3).pubkey().sec()[1:]),
btc.opcode.op_checksig,
btc.opcode.op_pushdata(btc.core.PriKey(4).pubkey().sec()[1:]),
btc.opcode.op_checksigadd,
btc.opcode.op_n(2),
btc.opcode.op_equal,
plbtc.core.TapLeaf(plbtc.core.script([
plbtc.opcode.op_pushdata(plbtc.core.PriKey(3).pubkey().sec()[1:]),
plbtc.opcode.op_checksig,
plbtc.opcode.op_pushdata(plbtc.core.PriKey(4).pubkey().sec()[1:]),
plbtc.opcode.op_checksigadd,
plbtc.opcode.op_n(2),
plbtc.opcode.op_equal,
]))
)


class Tp2trp2pk:
def __init__(self, pubkey: btc.core.PubKey):
def __init__(self, pubkey: plbtc.core.PubKey):
self.pubkey = pubkey
self.addr = btc.core.address_p2tr(pubkey, mast.hash)
self.script = btc.core.script_pubkey_p2tr(self.addr)
output_pubkey_byte = bytearray([0x02]) + btc.bech32.decode(btc.config.current.prefix.bech32, 1, self.addr)
output_pubkey = btc.core.PubKey.sec_decode(output_pubkey_byte)
self.addr = plbtc.core.address_p2tr(pubkey, mast.hash)
self.script = plbtc.core.script_pubkey_p2tr(self.addr)
output_pubkey_byte = bytearray([0x02]) + plbtc.bech32.decode(plbtc.config.current.prefix.bech32, 1, self.addr)
output_pubkey = plbtc.core.PubKey.sec_decode(output_pubkey_byte)
# Control byte with leaf version and parity bit.
if output_pubkey.y & 1:
self.prefix = 0xc1
else:
self.prefix = 0xc0

def sign(self, tx: btc.core.Transaction):
def sign(self, tx: plbtc.core.Transaction):
for i, e in enumerate(tx.vin):
m = tx.digest_segwit_v1(i, btc.core.sighash_all, mast.l.script)
s = btc.core.PriKey(2).sign_schnorr(m) + bytearray([btc.core.sighash_all])
m = tx.digest_segwit_v1(i, plbtc.core.sighash_all, mast.l.script)
s = plbtc.core.PriKey(2).sign_schnorr(m) + bytearray([plbtc.core.sighash_all])
e.witness[0] = s

def txin(self, op: btc.core.OutPoint):
return btc.core.TxIn(op, bytearray(), 0xffffffff, [
def txin(self, op: plbtc.core.OutPoint):
return plbtc.core.TxIn(op, bytearray(), 0xffffffff, [
bytearray(65),
mast.l.script,
bytearray([self.prefix]) + self.pubkey.sec()[1:] + mast.r.hash,
])


class Tp2trp2ms:
def __init__(self, pubkey: btc.core.PubKey):
def __init__(self, pubkey: plbtc.core.PubKey):
self.pubkey = pubkey
self.addr = btc.core.address_p2tr(pubkey, mast.hash)
self.script = btc.core.script_pubkey_p2tr(self.addr)
output_pubkey_byte = bytearray([0x02]) + btc.bech32.decode(btc.config.current.prefix.bech32, 1, self.addr)
output_pubkey = btc.core.PubKey.sec_decode(output_pubkey_byte)
self.addr = plbtc.core.address_p2tr(pubkey, mast.hash)
self.script = plbtc.core.script_pubkey_p2tr(self.addr)
output_pubkey_byte = bytearray([0x02]) + plbtc.bech32.decode(plbtc.config.current.prefix.bech32, 1, self.addr)
output_pubkey = plbtc.core.PubKey.sec_decode(output_pubkey_byte)
# Control byte with leaf version and parity bit.
if output_pubkey.y & 1:
self.prefix = 0xc1
else:
self.prefix = 0xc0

def sign(self, tx: btc.core.Transaction):
def sign(self, tx: plbtc.core.Transaction):
for i, e in enumerate(tx.vin):
m = tx.digest_segwit_v1(i, btc.core.sighash_all, mast.r.script)
e.witness[0] = btc.core.PriKey(4).sign_schnorr(m) + bytearray([btc.core.sighash_all])
e.witness[1] = btc.core.PriKey(3).sign_schnorr(m) + bytearray([btc.core.sighash_all])
m = tx.digest_segwit_v1(i, plbtc.core.sighash_all, mast.r.script)
e.witness[0] = plbtc.core.PriKey(4).sign_schnorr(m) + bytearray([plbtc.core.sighash_all])
e.witness[1] = plbtc.core.PriKey(3).sign_schnorr(m) + bytearray([plbtc.core.sighash_all])

def txin(self, op: btc.core.OutPoint):
return btc.core.TxIn(op, bytearray(), 0xffffffff, [
def txin(self, op: plbtc.core.OutPoint):
return plbtc.core.TxIn(op, bytearray(), 0xffffffff, [
bytearray(65),
bytearray(65),
mast.r.script,
bytearray([self.prefix]) + self.pubkey.sec()[1:] + mast.l.hash,
])


mate = btc.wallet.Wallet(btc.wallet.Tp2pkh(1))
btc.rpc.generate_to_address(10, mate.addr)
mate = plbtc.wallet.Wallet(plbtc.wallet.Tp2pkh(1))
plbtc.rpc.generate_to_address(10, mate.addr)

user_p2tr = btc.wallet.Wallet(btc.wallet.Tp2tr(1, mast.hash))
btc.rpc.import_descriptors([{
'desc': btc.rpc.get_descriptor_info(f'addr({user_p2tr.addr})')['descriptor'],
user_p2tr = plbtc.wallet.Wallet(plbtc.wallet.Tp2tr(1, mast.hash))
plbtc.rpc.import_descriptors([{
'desc': plbtc.rpc.get_descriptor_info(f'addr({user_p2tr.addr})')['descriptor'],
'timestamp': 'now',
}])

# Spending by key path.
mate.transfer(user_p2tr.script, 1 * btc.denomination.bitcoin)
assert user_p2tr.balance() == btc.denomination.bitcoin
mate.transfer(user_p2tr.script, 1 * plbtc.denomination.bitcoin)
assert user_p2tr.balance() == plbtc.denomination.bitcoin
print('main: spending by key path')
user_p2tr.transfer_all(mate.script)
assert user_p2tr.balance() == 0
print('main: spending by key path done')

# Spending by script path: pay to public key.
mate.transfer(user_p2tr.script, 1 * btc.denomination.bitcoin)
assert user_p2tr.balance() == btc.denomination.bitcoin
user_p2pk = btc.wallet.Wallet(Tp2trp2pk(user_p2tr.signer.pubkey))
mate.transfer(user_p2tr.script, 1 * plbtc.denomination.bitcoin)
assert user_p2tr.balance() == plbtc.denomination.bitcoin
user_p2pk = plbtc.wallet.Wallet(Tp2trp2pk(user_p2tr.signer.pubkey))
print('main: spending by script path p2pk')
user_p2pk.transfer_all(mate.script)
assert user_p2tr.balance() == 0
print('main: spending by script path p2pk done')

# Spending by script path: pay to 2-of-2 multisig script.
mate.transfer(user_p2tr.script, 1 * btc.denomination.bitcoin)
assert user_p2tr.balance() == btc.denomination.bitcoin
user_p2ms = btc.wallet.Wallet(Tp2trp2ms(user_p2tr.signer.pubkey))
mate.transfer(user_p2tr.script, 1 * plbtc.denomination.bitcoin)
assert user_p2tr.balance() == plbtc.denomination.bitcoin
user_p2ms = plbtc.wallet.Wallet(Tp2trp2ms(user_p2tr.signer.pubkey))
print('main: spending by script path p2ms')
user_p2ms.transfer_all(mate.script)
assert user_p2tr.balance() == 0
Expand Down
20 changes: 10 additions & 10 deletions example/transfer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import argparse
import btc
import plbtc

# Transfer bitcoin to another account.

Expand All @@ -12,22 +12,22 @@
args = parser.parse_args()

if args.net == 'develop':
btc.config.current = btc.config.develop
plbtc.config.current = plbtc.config.develop
if args.net == 'mainnet':
btc.config.current = btc.config.mainnet
plbtc.config.current = plbtc.config.mainnet
if args.net == 'testnet':
btc.config.current = btc.config.testnet
plbtc.config.current = plbtc.config.testnet

accept_script = btc.core.script_pubkey(args.to)
accept_value = int(args.value * btc.denomination.bitcoin)
accept_script = plbtc.core.script_pubkey(args.to)
accept_value = int(args.value * plbtc.denomination.bitcoin)
prikey = int(args.prikey, 0)
if args.script_type == 'p2pkh':
wallet = btc.wallet.Wallet(btc.wallet.Tp2pkh(prikey))
wallet = plbtc.wallet.Wallet(plbtc.wallet.Tp2pkh(prikey))
if args.script_type == 'p2sh-p2wpkh':
wallet = btc.wallet.Wallet(btc.wallet.Tp2shp2wpkh(prikey))
wallet = plbtc.wallet.Wallet(plbtc.wallet.Tp2shp2wpkh(prikey))
if args.script_type == 'p2wpkh':
wallet = btc.wallet.Wallet(btc.wallet.Tp2wpkh(prikey))
wallet = plbtc.wallet.Wallet(plbtc.wallet.Tp2wpkh(prikey))
if args.script_type == 'p2tr':
wallet = btc.wallet.Wallet(btc.wallet.Tp2tr(prikey, bytearray()))
wallet = plbtc.wallet.Wallet(plbtc.wallet.Tp2tr(prikey, bytearray()))
txid = wallet.transfer(accept_script, accept_value)
print(f'0x{txid.hex()}')
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit d6b5c9f

Please sign in to comment.