zápočtová práce Základy implementace měny BITCOIN v programovacím jazyku C# N_TK – Technologie krypto-měn
Tomáš Pekárek 25387 listopad 2015
1
Obsah 1. Zadání .............................................................................................................................................................2 2. Vývojové prostředí .........................................................................................................................................2 3. Bitcoin – adresy ..............................................................................................................................................3 4. Transakce........................................................................................................................................................6
1. Zadání ze dne 2. 11. 2015 v rámci předmětu: „Technologie krypto-měn“ bych chtěl pro získání zápočtu, vypracovat následují seminární práci: -
manuál pro implementaci krypto-měny Bitcon v programovacím jazyku C# - při využití knihovny NBitcoin (popis tříd, metod, událostí včetně jednoduchých ukázek)
Poznatky získané v rámci seminární práce umožní tvorbu jednoduché aplikace využívající měnu Bitcon (např. peněženka, e-shop, finanční mechanizmus počítačové hry apod.).
2. Vývojové prostředí a) Určeno pro Visual Studio 2013, 2015 Community Programovací jazyk .NET C# Technologie krypto-měny Bitcoin, které popisuje tato zápočtová práce, je možné implementovat pro desktopové, webové a mobilní aplikace. b) Zavedení knihovny – NBitcoin
obrázek č. 1
2
1. Visual Studio -> Nástroje -> Správa balíčků, knihovny -> Spravovat balíčky NuGet pro řešení 2. Vyhledat: „NBitcoin“ 3. Nainstalovat 4. Zavedení direktivy v programu using NBitcoin;
3. Bitcoin – adresy Základní schéma adres a klíčů v síti Bitcoin
obrázek č. 2
a) Soukromý klíč (private key) vygenerujeme pomocí třídy Key. Key privatniKlic = new Key();
3
b) Bitcoin adresa privátní (Bitcoin secret) je reprezentována třídou BitcoinSecret. Vlastní adresu získáme použitím metody GetBitcoinSecret z třídy Key. Adresu je možné vygenerovat pro veřejnou nebo vlastní testovací Bitcoinovou síť. Stačí u metody GetBitcoinSecret nastavit parametr Network. /* Třída "BitcoinSecret" */ /* Využití metody "GetBitcoinSecret" z třídy "Key" */ BitcoinSecret bitcoinAdresaPrivatniMain=privatniKlic.GetBitcoinSecret(Network.Main); /* Network.Main - pro využití adresy v hlavní síti */ Console.WriteLine("Bitcoin adresa - privátní (v hlavní síti):\n{0}\n", bitcoinAdresaPrivatniMain);
obrázek č. 3
Parametr Network: - v testovací síti: Network.TestNet
-
v hlavní síti: Network.Main
c) Veřejný klíč (public key) je reprezentován třídou PubKey. Vlastní klíč získáme použitím metody PubKey z třídy Key. /* Třída "PubKey" */ /* Využití metody "PubKey" z třídy "Key" */ PubKey verejnyKlic = privatniKlic.PubKey; Console.WriteLine("Veřejný klíč:\n{0}\n", verejnyKlic);
obrázek č. 4
d) Bitcoin adresa veřejná (bitcoin address) je reprezentována třídou BitcoinAdress. Vlastní adresu získáme použitím metody GetAdress z třídy PubKey. Adresu je možné vygenerovat pro veřejnou nebo vlastní testovací Bitcoinovou síť. Stačí u metody GetAdress nastavit parametr Network. /* Třída "BitcoinAddress" */ /* Využití metody "GetAddress" z třídy "PubKey" */ BitcoinAddress bitcoinAdresaMain = verejnyKlic.GetAddress(Network.Main); Console.WriteLine("Bitcoin adresa (v hlavní síti):\n{0}\n", bitcoinAdresaMain);
4
obrázek č. 5
Parametr Network: - v testovací síti: Network.TestNet
-
v hlavní síti: Network.Main
e) Skript veřejného klíče (script pub key) je reprezentován třídou Script. Vlastní skript získáme z veřejné Bitcoin adresy (třída BitcoinAdress) při použití metody ScriptPubKey. /* Třída "Script" */ /* Využití metody "ScriptPubKey" z třídy "BitcoinAddress" */ Script skriptVerejnehoKlice = bitcoinAdresaMain.ScriptPubKey; Console.WriteLine("Skript veřejného klíče (z Bitcoin adresy):\n{0}\n", skriptVerejnehoKlice);
obrázek č. 6
f) Bitcoin adresa veřejná (bitcoin address) ze skriptu veřejného klíče Použitím metody GetDestinationAddress ze třídy Script můžeme zpětně ze skriptu veřejného klíče získat naší veřejnou Bitcoin adresu. /* Využití metody "GetDestinationAddress" z třídy "Script" */ Script skriptVerejnehoKlice = new Script(skriptVerejnehoKliceString); BitcoinAddress bitcoinAdresaMain = skriptVerejnehoKlice.GetDestinationAddress(Network.Main); Console.WriteLine("Bitcoin adresa (v hlavní síti):\n{0}\n", bitcoinAdresaMain);
g) Hash z veřejného klíče je reprezentován třídou KeyId. Hash získáme použitím metody Hash ze třídy PubKey. /* Třída "KeyId" */ /* Využití metody "Hash" z třídy "PubKey" */ KeyId hashVerejnyKlic = verejnyKlic.Hash; Console.WriteLine("Hash z veřejného klíče:\n{0}\n", hashVerejnyKlic);
5
obrázek č. 7
4. Transakce a) ID transakce – bloku Každá dílčí transakce je uložená v bloku. Při znalosti identifikačního čísla bloku (ID transakce) můžeme prohlížet veškerý obsah bloku, vyhledávat konkrétní transakce, spočítat celkový objem transakcí v bloku apod. Na obrázku č. 7 je ukázka detailu transakce z peněženky Bitcoin Core včetně čísla bloku (ID transakce) – „64c68bc2edca4807e0a1b94288845a9847b3782beb715f6fa8f1b966028c54c2“.
obrázek č. 8
b) Vypsání obsahu bloku nám umožňují třídy Transaction a BlockrTransactionRepository a metoda Get z třídy Transaction. Parametrem metody je číslo bloku (ID transakce). /* Třídy "BlockrTransactionRepository" a "Transaction" */ /* Využití metody "Get" z třídy "Transaction" */ Console.WriteLine("Vypsani transakcniho bloku:"); var blok = new BlockrTransactionRepository(); Transaction transakce = blok.Get("64c68bc2edca4807e0a1b94288845a9847b3782beb715f6fa8f1b966028c54c2"); Console.WriteLine(transakce.ToString());
obrázek č. 9
6
c) Celkový objem transakcí v bloku získáme pomocí tříd popsaných v bodě b). Pro výpočet celkové hodnoty bloku použijeme metodu TotalOut, /* Třídy "BlockrTransactionRepository" a "Transaction" */ /* Využití metod "Get" a "TotalOut" z třídy "Transaction" */ var blok = new BlockrTransactionRepository(); Transaction transakce = blok.Get("64c68bc2edca4807e0a1b94288845a9847b3782beb715f6fa8f1b966028c54c2"); Console.WriteLine("Celkove hodnota transakci v bloku: {0} satoshi", transakce.TotalOut.Satoshi.ToString());
obrázek č. 10
d) Celkový počet transakcí v bloku /* Třída "Transaction" */ int pocetTransakci = transakce.Outputs.Count; Console.WriteLine("Celkovy pocet transakci v bloku: {0}", pocetTransakci);
obrázek č. 11
e) Postupný průchod transakčním blokem a vyhledání konkrétní transakce při použití veřejné Bitcoinové adresy V transakčním bloku jsou jednotlivé operace implementovány do datové struktury pole. Průchod je možný realizovat pomocí FOR nebo WHILE cyklu. 1. Transakci budu vyhledávat v transakčním bloku ID: 64c68bc2edca4807e0a1b94288845a9847b3782beb715f6fa8f1b966028c54c2 var blok = new BlockrTransactionRepository(); Transaction transakce = blok.Get("64c68bc2edca4807e0a1b94288845a9847b3782beb715f6fa8f1b966028c54c2");
2. Budou mě zajímat transakce zaslané na veřejnou Bitcoinovou adresu: 1DhSD71uzM6NdwvLesTx69YsivkmHac8qE BitcoinAddress bitcoinAdresa = new BitcoinAddress("1DhSD71uzM6NdwvLesTx69YsivkmHac8qE");
3. Z Bitcoinové adresy musím vygenerovat skript veřejného klíče: Script skriptVerejnehoKlice = bitcoinAdresa.ScriptPubKey;
4. Vlastní průchod polem a vyhledávání požadovaných transakcí: double celkem = 0; int pocet = 0; for (int i = 0; i < transakce.Outputs.Count; i++) {
7
pocet++; if (skriptVerejnehoKlice == transakce.Outputs[i].ScriptPubKey) { Console.WriteLine("{0}. nalezena transakce\n------------------------", pocet); Console.WriteLine(transakce.Outputs[i].ScriptPubKey); Console.WriteLine("{0} satoshi\n", transakce.Outputs[i].Value); celkem = celkem + Convert.ToDouble(transakce.Outputs[i].Value); } } Console.WriteLine("Zaverecne hodnoceni\n------------------------"); Console.WriteLine("Pro verejnou Bitcoinovou adresu: {0}", bitcoinAdresa); Console.WriteLine("Bylo nalezeno:"); Console.WriteLine("\t- pocet transakci:\t{0}", pocet); Console.WriteLine("\t- o celkove hodnote:\t{0} satoshi", celkem);
obrázek č. 12
f) Postupný průchod transakčním blokem a vyhledání konkrétní transakce při použití privátní Bitcoinové adresy Princip je stejný jako u bodu „e“. Odlišnosti: 2. Budou mě zajímat transakce zaslané na privátní Bitcoinovou adresu: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX BitcoinSecret bitcoinAdresaPrivatni = new BitcoinSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
3. Z Bitcoinové adresy musím vygenerovat skript privátního klíče: Script skriptPrivatnihoKlice = bitcoinAdresaPrivatni.ScriptPubKey;
Ostatní body jsou beze změny. g) Založení nové transakce a odeslání Tento bod popisuje mechanizmus založen a odeslání nové transakce platby (z peněženky odesílatele do peněženky příjemce). 1. Uživatel, který platbu odesílá, musí zadat svou privátní Bitcoinovou adresu: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX BitcoinSecret bitcoinAdresaPrivatni = new BitcoinSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
2. Definujeme veřejnou Bitcoinovou adresu příjemce: 16DX9KxJYbiZrbgBjbqt7v1A4tfL9wfkxr
8
BitcoinAddress bitcoinAdresaVerejna = new BitcoinAddress("16DX9KxJYbiZrbgBjbqt7v1A4tfL9wfkxr");
3. Prostředky pro převod budou použity z transakčního bloku ID: 64c68bc2edca4807e0a1b94288845a9847b3782beb715f6fa8f1b966028c54c2 var blok = new BlockrTransactionRepository(); Transaction transakce = blok.Get("64c68bc2edca4807e0a1b94288845a9847b3782beb715f6fa8f1b966028c54c2");
4. Zadání nové platby: Transaction platba = new Transaction(); platba.Inputs.Add(new TxIn() { PrevOut = new OutPoint(transakce.GetHash(), 1) });
obrázek č. 13 – prázdná transakce
5. Částka k převodu: platba.Outputs.Add(new TxOut() { Value = Money.Coins(0.00005m), ScriptPubKey = bitcoinAdresaVerejna.ScriptPubKey });
6. Přidání zprávy k transakci (převod 0,0000 satoshi): var zprava = "Splatka pro Toma"; var bytes = Encoding.UTF8.GetBytes(zprava); platba.Outputs.Add(new TxOut() { Value = Money.Zero, ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(bytes) });
9
obrázek č. 14 – připravená transakce bez podpisu
7. Podepsání transakce privátním klíčem: platba.Inputs[0].ScriptSig = bitcoinAdresaPrivatni.ScriptPubKey; platba.Sign(bitcoinAdresaPrivatni, false);
obrázek č. 15 – připravená transakce s podpisem
8. Síťové spojení – vykonání transakce using (var node = Node.ConnectToLocal(Network.Main)) { node.VersionHandshake();
10
node.SendMessage(new InvPayload(InventoryType.MSG_TX, platba.GetHash())); node.SendMessage(new TxPayload(platba)); }
11