Przejdź do głównej zawartości

Python Bitcoin bsv-sdk: pierwsza transakcja

Bitcoin SV w Pythonie

W poprzednich wpisach (1, 2) wygenerowaliśmy klucz prywatny, poznaliśmy adres testnet, mainnet, sprawdziliśmy saldo i pobraliśmy niewydane transakcje. Teraz nauczymy się, jak przy pomocy oficjalnego bsv-sdk dla Pythona zbudować prostą transakcję, którą wyślemy na swój własny adres testnetowy. Jak to w ogóle możliwe, że możesz wysłać Bitcoina… samemu sobie? 
W Bitcoinie nikt nie wie, kim jesteś - sieć tylko sprawdza, czy umiesz wydać monety zgodnie z zasadami a skoro umiesz, to możesz je wysłać.. nawet z powrotem do siebie i sieci jest to kompletnie obojętne :)

Bitcoin SV: Python bsv-sdk

UTXO: Bitcoin SV

W tradycyjnym banku masz konto i tutaj wszystko ląduje do jednego wora:

Bitcoin SV: Python bsv-sdk
W Bitcoinie działa model UTXO (Unspent Transaction Output), który można sobie wyobrazić tak, że każda transakcja tworzy nowy wiersz i każdy ten wiersz:

  •         ma konkretną kwotę,
  •         ma "kłódkę" - skrypt, który mówi: kto i na jakich warunkach może je wydać.

Twoje "saldo" to tak naprawdę zbiór wszystkich wierszy, a każdy z tych wierszy potrafisz otworzyć swoim kluczem prywatnym.

Bitcoin SV: Python bsv-sdk

I teraz chcesz wydać 50zł w sklepie. Musisz wydać/zużyć jeden z wierszy (wydajemy 100zł), a Twoja reszta (50zł) wracając, utworzy nowy wiersz. 

Bitcoin SV: Python bsv-sdk

 Proste? :) No to przechodzimy do kodu.

Tworzenie i Rozgłaszanie Transakcji BSV

Pamiętaj, że cały czas pracujemy na kodzie z poprzednich wpisów, a to jest jego kontynuacja:

Krok 0: Ile będziemy wysyłać :) 

Zadeklaruj zmienną do_wyslania i wpisz jakąś wartość.

do_wyslania = 222 

Krok 1: Zadeklaruj funkcję asynchroniczną

async def create_and_broadcast_transaction():

Na początek zadeklaruj asynchroniczną funkcję o nazwie create_and_broadcast_transaction. Słowo kluczowe async jest ważne - dzięki niemu będziesz mógł czekać na odpowiedzi z sieci bez zawieszania całego programu.

Krok 2: Załaduj poprzednią transakcję

Poprzedni wpis, zakończyliśmy wypisaniem niewydanej transakcji w hex (tx_hex); musisz ją teraz przekazać:
 
source_tx = Transaction.from_hex(tx_hex)

Krok 3: Przygotuj input - określ źródło pieniędzy

  1. Stwórz nowy obiekt TransactionInput.
  2. Przypisz poprzednią transakcję (source_tx) jako źródło. Ten parametr mówi: "pieniądze biorę z tej transakcji"
  3. Wyciągnij i przypisz ID źródłowej transakcji. source_tx.txid() to metoda, która generuje unikalny identyfikator tej transakcji. ID jednoznacznie identyfikuje transakcję na blockchainie - bez niego sieć nie wiedziałaby, którą transakcję masz na myśli. 
  4. Określ, który output ze źródłowej transakcji chcesz wydać. 0 oznacza pierwszy output (liczymy od zera). Transakcja może mieć wiele wyjść, ale Ty bierzesz tylko jedno - pierwsze.
  5. Przygotuj szablon skryptu odblokowania. .unlock(klucz_prywatny) - generuje skrypt, który będzie podpisany Twoim kluczem prywatnym Ten skrypt będzie dowodem, że jesteś właścicielem tych pieniędzy i masz prawo je wydać.

tx_input = TransactionInput( # (1)
    source_transaction=source_tx, # (2)
    source_txid=source_tx.txid(), # (3)
    source_output_index=0, # (4)
    unlocking_script_template=P2PKH().unlock(klucz_prywatny),) # (5)

Zamknij konfigurację input-u.

Krok 4: Przygotuj output - określ cel pieniędzy

  1. Stwórz nowy obiekt TransactionOutput - to będzie wyjście Twojej transakcji :)
  2. Stwórz skrypt blokujący pieniądze - to blokuje satoshi na Twoim adresie testnet. Ten fragment .lock(address_testnet) wpisujemy zmienną naszego adresu lub możesz wpisać swój adres jako string .lock("xxxxxxxxxxx")
  3. Określ ilość satoshi w tym outputcie."satoshis" to zmienna przechowująca konkretną liczbę (np. 222 - u nas to zmienna do_wyslania)
  4. Oznacz ten output jako zmianę (resztę).  Jeśli ustawisz change=True - biblioteka automatycznie wyśle resztę pieniędzy (różnicę między inputem a outputem) z powrotem na Twój adres. Jeśli ustawisz change=False - reszta pieniędzy zostanie zmarnowana.

tx_output = TransactionOutput( # (1)
    locking_script=P2PKH().lock(address_testnet), # (2)
    satoshis=do_wyslania, # (3)
    change=True) # (4)


Zamknij konfigurację output-u. Teraz output jest gotowy.

Krok 5: Połącz input i output w transakcję


    tx = Transaction([tx_input], [tx_output], version=1)
  • [tx_input] - lista inputów (tutaj jeden, w nawiasach kwadratowych)
  • [tx_output] - lista outputów (tutaj jeden)
  • version=1 - określa wersję transakcji (1 to oryginalna wersja)
Teraz masz kompletną strukturę transakcji: pieniądze wchodzą (input), pieniądze wychodzą (output).

Krok 6: Wyświetl informacje

Wydrukuj na ekran informacyjny komunikat.

print(f"{address_testnet} wysyła {do_wyslania} satoshi")


Krok 7: Oblicz opłatę  i podpisz transakcję


Oblicz i ustaw automatyczną opłatę. Metoda fee() analizuje rozmiar transakcji (w bajtach) i wylicza odpowiednią opłatę sieciową. Opłata automatycznie zostanie odliczona z outputu. Podpisz całą transakcję Twoim kluczem prywatnym.

tx.fee()
tx.sign()

Krok 9: Przygotuj klucz API

api_key = 'testnet_73657152612......'

Zadeklaruj swój klucz API w zmiennej. Ten klucz identyfikuje Cię wobec usługi Taal ARC i pozwala na rozgłaszanie transakcji. 

Krok 10: Rozgłoś transakcję do sieci


Wyślij podpisaną transakcję do sieci Bitcoin SV

response = await tx.broadcast(ARC('https://api.taal.com/arc', api_key))
  1. tx.broadcast() - wysyła transakcję
  2. ARC(...) - tworzy klienta ARC z endpointem serwera i Twoim kluczem API
  3. await - czeka na odpowiedź z serwera
  4. response - przechowuje odpowiedź - informacje o tym, czy rozgłoszenie się powiodło

Krok 11: Wyświetl status rozgłoszenia


Wydrukuj status odpowiedzi serwera.
 
print(f"Status rozgłoszenia: {response.status}")


Krok 12: Wyświetl ID transakcji

Wydrukuj unikalny identyfikator Twojej nowej transakcji, którą będziesz mógł zobaczyć w blockchain --> https://test.whatsonchain.com/

print(f"ID transakcji: {tx.txid()}")

Krok 13: Uruchom funkcję

if __name__ == "__main__":
    asyncio.run(create_and_broadcast_transaction()) 



Zapisz skrypt i uruchom :) 
 
Powinno pojawić się coś takiego:
 
Transakcja bsv-sdk-python

 a teraz możemy sprawdzić naszą transakcję w blockchain: TUTAJ 
 

Kosmetyka:

Teraz nieco zmodyfikujmy nasz kod, żeby nie trzeba było za każdym razem "z palca" wpisywać numeru indeksu z niewydanym UTXO.
Zadeklaruj zmienną tx_pos, która poprzez API sama sprawdzi o który indeks chodzi:

tx_pos = data['result'][0]['tx_pos'

Wypisz numer indeksu:
 
print(f"Indeks transakcji: {tx_pos}\n")

Zmodyfikuj zmienną source_output:

source_output_index=tx_pos,

Pełny kod:

import nest_asyncio
nest_asyncio.apply()
import asyncio
from bsv import PrivateKey, P2PKH, ARC, Transaction, TransactionInput, TransactionOutput
import requests
import json


moj_klucz = "KwVs88aLx6ZuZmphr........................."
klucz_prywatny = PrivateKey(moj_klucz)
address_testnet = klucz_prywatny.address(network = "testnet")

url = f"https://api.whatsonchain.com/v1/bsv/test/address/{address_testnet}/confirmed/balance"
response = requests.get(url)
data = response.json()
saldo = data['confirmed']

print(f"Adres testnet : {address_testnet}")
print(f"Saldo : {saldo} satoshi / {saldo / 100000000} BSV")


url = f"https://api.whatsonchain.com/v1/bsv/test/address/{address_testnet}/unspent/all"
response = requests.get(url)
data = response.json()
txid = data['result'][0]['tx_hash']
tx_pos = data['result'][0]['tx_pos']
print(f"\nTransakcja z niewydanym UTXO: {txid}")
print(f"Indeks transakcji: {tx_pos}\n")

url = f"https://api.whatsonchain.com/v1/bsv/test/tx/{txid}/hex"
response = requests.get(url)
tx_hex = response.text
print(f"HEX : {tx_hex}\n")

do_wyslania = 333

input("Naciśnij Enter by kontynuować..")

async def create_and_broadcast_transaction():

    source_tx = Transaction.from_hex(tx_hex)

    tx_input = TransactionInput(
        source_transaction=source_tx,
        source_txid=source_tx.txid(),
        source_output_index=tx_pos, 
        unlocking_script_template=P2PKH().unlock(klucz_prywatny),
    )

    tx_output = TransactionOutput(
        locking_script=P2PKH().lock(address_testnet),
        satoshis=do_wyslania,
        change=True 
    )

    tx = Transaction([tx_input], [tx_output], version=1)
    print(f"{address_testnet} wysyła {do_wyslania} satoshi")

    tx.fee()
    tx.sign()

    api_key = 'testnet_2d8a5a0745..........'
    response = await tx.broadcast(ARC('https://api.taal.com/arc', api_key))
    print(f"Status rozgłoszenia: {response.status}")
    print(f"ID transakcji: {tx.txid()}")

    
if __name__ == "__main__":
    asyncio.run(create_and_broadcast_transaction())

input("Koniec")
 
Ok, to co już mamy?
  • wygenerowany klucz prywatny,
  • uzupełnione saldo za pomocą kranu testnet,
  • sprawdzone saldo z poziomu kodu (a nie poprzez explorer bloków na stronie www),
  • ustalone niewydane UTXO
  • pobrany hex z powyższego UTXO 
  • ustalony indeks z UTXO
  • zbudowaną funkcję do zbudowania wejść i wyjść
  • rozgłoszenie transakcji 
  • pobranie hasha transakcji

Wysłaliśmy sami sobie Bitcoin'a :)  

Co dalej?

W kolejnym wpisie, dalej będziemy pracować na dotychczasowym kodzie. Zbudujemy transakcję w której wyślemy środki na jakiś inny adres a reszta będzie wracała na nasz adres. Pokażę też, dwie metody na zbudowanie takiej transakcji :) Jeśli masz jakieś pytania, nie zawahaj się ich zadać w komentarzach.

Cześć!

 


Jeśli moje wpisy przypadły Ci do gustu i chcesz wesprzeć rozwój bloga, możesz postawić mi wirtualną kawę (GGwallet czeka!) albo wrzucić coś na adres BSV. Oczywiście, to całkowicie dobrowolne - blog i tak zawsze będzie dostępny za darmo. Dzięki za każde wsparcie, nawet to w formie dobrej energii! ☕😊



 **Gwarantuję Ci niezmienność moich treści**

Hash artykułu:

ID transakcji: sprawdź OP_RETURN i porównaj jego hash

Komentarze

  1. Anonimowy8/12/25 22:02

    hmm w realnej app jak bezpiecznie podstawić priv key ? ;)

    OdpowiedzUsuń
    Odpowiedzi
    1. relax40009/12/25 10:53

      W realnej APP musiałbyś mieć zaszyfrowany klucz prywatny i odszyfrować go "na chwilę" w pamięci RAM.

      Usuń
    2. Hmm fakt w secure ram ten zwykły przeczesują często wajrusy, thx!

      Usuń
    3. To prawda. No chyba że chcemy mieć Uber Turbo Secure App, wtedy trzeba myśleć tak jakby "wajrus" był na naszym komputerze. Czyli (tak podejrzewam) tutaj nic nie może wykonać się na naszym PC. Moja odpowiedź jest do "real app" - z czego korzysta 90% popularnych portfeli. Ty masz na myśli portfel "premium" a ja nie posiadam takiej wiedzy jak to najbezpieczniej wykonać ale jeśli będzie trzeba to poszukam informacji o tym i możemy gdzieś to przedyskutować. Pozdrawiam!

      Usuń

Prześlij komentarz

Popularne posty

Discord kontra Forum – dlaczego Twój mózg tęskni za phpBB

Cyfrowy minimalizm - mniej pingów, więcej spokoju

Not Your Keys? – Krypto, Prawo i Wielkie Nieporozumienie