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):\n0}\n", bitcoinadresaprivatnimain); Parametr Network: - v testovací síti: Network.TestNet - v hlavní síti: Network.Main obrázek č. 3 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íč:\n0}\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):\n0}\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):\n0}\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):\n0}\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:\n0}\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()); d) Celkový počet transakcí v bloku obrázek č. 10 /* 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:\t0}", pocet); Console.WriteLine("\t- o celkove hodnote:\t0} 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) }); 5. Částka k převodu: obrázek č. 13 prázdná transakce 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
7. Podepsání transakce privátním klíčem: obrázek č. 14 připravená transakce bez podpisu platba.inputs[0].scriptsig = bitcoinadresaprivatni.scriptpubkey; platba.sign(bitcoinadresaprivatni, false); 8. Síťové spojení vykonání transakce obrázek č. 15 připravená transakce s podpisem 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