Przejdź do głównej zawartości

Python 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

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