Zaprogramuj Inteligentny Kontrakt

Przypomnij sobie , że inteligentne umowy Ethereum są napisane w języku programowania Solidity. Chociaż biblioteka JavaScript web3 pomoże nam wdrożyć naszą umowę na blockchain Ethereum, nadal będziemy musieli napisać i skompilować nasz inteligentny kontrakt w Solidity, zanim wyślemy go do sieci Ethereum za pomocą web3. Stwórzmy więc przykładową umowę za pomocą Solidity. Istnieje wiele narzędzi do kodowania w Solidity. Większość głównych IDE i edytorów kodu ma wtyczki Solidity do edycji i kompilacji inteligentnych umów. Istnieje również internetowy edytor Solidity o nazwie Remix. Jest dostępny do bezpłatnego użytku na https://remix.ethereum.org/. Remix zapewnia bardzo prosty interfejs do kodowania i kompilowania inteligentnych umów w przeglądarce. W tym ćwiczeniu będziemy używać Remiksu do kodowania i testowania naszej inteligentnej umowy, a następnie wyślemy tę samą umowę do sieci Ethereum za pomocą biblioteki JavaScript web3 i usługi API Infura. Poniższy fragment kodu został napisany w języku programowania Solidity i jest to prosty inteligentny kontrakt, który zwraca ciąg „Hello World” z funkcji Hello. Ma również konstruktor, który ustawia wartość zwracanej wiadomości.

pragma solidność ^ 0.4.0;

umowa HelloWorld {

wiadomość łańcuchowa;

funkcja HelloWorld () {

message = “Hello World!”;

}

funkcja Hello () stałe zwraca (ciąg) {

wiadomość zwrotna;

}

}

Przejdźmy do Remiksu i wklejmy ten kod w oknie edytora. Poniższe obrazy pokazują, jak wygląda nasz przykładowy inteligentny kontrakt w edytorze remiksów i jak wygląda wynik po kliknięciu przycisku Utwórz w menu po prawej stronie, na karcie Uruchom. Należy również pamiętać, że domyślnie edytor Remix jest ukierunkowany na środowisko VM VM JavaScript do inteligentnej kompilacji kontraktów i do celów testowych używa konta testowego z pewnym saldem ETH. Po kliknięciu przycisku Utwórz umowa zostaje utworzona przy użyciu wybranego konta w środowisku JavaScript VM.

Poniżej przedstawiono dane wyjściowe wygenerowane przez operację tworzenia i pokazuje nam, że umowa została utworzona, ponieważ ma adres umowy. Wartość „od” to adres konta, który został użyty do utworzenia umowy. Pokazuje nam również skrót transakcji tworzenia kontraktu.

status 0x1 Transaction mined and execution succeed

contractAddress 0x692a70d2e424a56d2c6c27aa97d1a86395877b3a

from 0xca35b7d915458ef540ade6068dfe2f44e8fa733c

to HelloWorld.(constructor)

gas 3000000 gas

transaction cost 205547 gas

execution cost 109539 gas

hash 0x9f3c21c21f263084b9f031966858a5d8e0648ed19c77d4d2291

875b01d89a141

input 0x6060604052341561000f57600080fd5b6040805190810160405

280600c81526020017f48656c6c6f20576f726c642100000000000000000

000000000000000000000008152506000908051906020019061005a92919

0610060565b50610105565b8280546001816001161561010002031660029

00490600052602060002090601f016020900481019282601f106100a1578

05160ff19168380011785556100cf565b828001600101855582156100cf5

79182015b828111156100ce5782518255916020019190600101906100b35

65b5b5090506100dc91906100e0565b5090565b61010291905b808211156

100fe5760008160009055506001016100e6565b5090565b90565b6101bc8

06101146000396000f300606060405260043610610041576000357c01000

00000000000000000000000000000000000000000000000000000900463f

fffffff168063bcdfe0d514610046575b600080fd5b34156100515760008

0fd5b6100596100d4565b604051808060200182810382528381815181526

0200191508051906020019080838360005b8381101561009957808201518

184015260208101905061007e565b50505050905090810190601f1680156

100c65780820380516001836020036101000a031916815260200191505b5

09250505060405180910390f35b6100dc61017c565b60008054600181600

116156101000203166002900480601f01602080910402602001604051908

101604052809291908181526020018280546001816001161561010002031

66002900480156101725780601f106101475761010080835404028352916

0200191610172565b820191906000526020600020905b815481529060010

19060200180831161015557829003601f168201915b50505050509050905

65b6020604051908101604052806000815250905600a165627a7a7230582

0d6796e48540eced3646ea52c632364666e64094479451066317789a712

aef4da0029

decoded input {}

decoded output –

logs []

value 0 wei

W tym momencie przygotowaliśmy prosty inteligentny kontrakt „Hello World”, a teraz następnym krokiem jest wdrożenie go programowo do blockchaina Ethereum.

Wymagania wstępne

W tym ćwiczeniu dotyczącym kodu, aby stworzyć inteligentną umowę, będziemy kontynuować założenie, że biblioteka JavaScript web3 jest zainstalowana i utworzona w aplikacji node.js i zarejestrowaliśmy się w usłudze Infura, tak jak to zrobiliśmy w poprzedniej sekcji. Poniżej przedstawiono kroki, aby utworzyć inteligentną umowę na Ethereum przy użyciu JavaScript.

Programowa interakcja z Ethereum – tworzenie inteligentnego kontraktu

W tej sekcji będziemy kontynuować nasze ćwiczenia związane z programowaniem Ethereum i utworzymy prosty inteligentny kontrakt na blockchain Ethereum przy użyciu tej samej biblioteki JavaScript web3 i interfejsu API usługi Infura. Ponieważ żaden samouczek dla początkujących programistów komputerowych nie jest kompletny bez programu „Hello World”, inteligentny kontrakt, który stworzymy, będzie prostym inteligentnym kontraktem zwracającym ciąg „Hello World” po wywołaniu. Proces tworzenia umowy będzie specjalnym rodzajem transakcji wysyłanej do blockchain Ethereum, a tego rodzaju transakcje nazywane są „transakcjami tworzenia umowy”. Transakcje te nie wspominają o adresie „do”, a właścicielem inteligentnej umowy jest „ z ”adresu podanego w transakcji.

Wyślij transakcję do sieci Ethereum

Ostatnim krokiem jest wysłanie tej podpisanej surowej transakcji do opublikowanego testowego węzła sieci Ethereum, który został ustawiony jako dostawca naszego obiektu web3. Poniższy kod wywołuje funkcję sendSignedTransaction w celu wysłania surowej transakcji do sieci testowej Ethereum. Parametrem wejściowym jest wartość ciągu rawTransaction, który otrzymaliśmy w poprzednim kroku w ramach podpisywania transakcji.

web3.eth.sendSignedTransaction (podpisanyTx.rawTransaction).

następnie (console.log);

Zwróć uwagę na użycie słowa „then” we fragmencie kodu wstępnego. Jest to interesujące, ponieważ biblioteka web3 zapewnia różne poziomy ostateczności podczas pracy z transakcjami Ethereum, ponieważ transakcja Ethereum przechodzi przez kilka stanów po przesłaniu. W tej funkcji wywołanie wysyłania transakcji do sieci jest następnie trafiane po utworzeniu potwierdzenia transakcji i zakończeniu transakcji. Po kilku sekundach, gdy obietnica JavaScript zostanie rozwiązana, otrzymujemy następujące dane wyjściowe.

{

blockHash: ‘0x26f1e1374d11d4524f692cdf1ce3aa6e085dcc1810

84642293429eda3954d30e’,

blockNumber: 2514764,

contractAddress: null,

cumulativeGasUsed: 125030,

from: ‘0xaff9d328e8181ae831bc426347949eb7946a88da’,

gasUsed: 21000,

logs: [],

logsBloom: ‘0x0000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000

0000000000000′,

status: ‘0x1’,

to: ‘0x22013fff98c2909bbfccdabb411d3715fdb341ea’,

transactionHash: ‘0xd3f45394ac038c44c4fe6e0cdb7021fdbd

672eb1abaa93eb6a1828df5edb6253′,

transactionIndex: 3

}

Dane wyjściowe zawierają wiele informacji, jak widzimy. Najważniejsza jest transakcja hasłowa, która jest identyfikatorem transakcji w sieci. Daje nam także blockHash, który jest identyfikatorem bloku, w którym uwzględniono tę transakcję. Wraz z tym otrzymujemy również informacje o tym, ile gazu wykorzystano do tej transakcji, między innymi. Jeśli użyty gaz jest mniejszy niż maksymalny gaz określony podczas tworzenia transakcji, pozostały gaz jest odsyłany z powrotem na adres nadawcy. W tej sekcji wysłaliśmy prostą transakcję do blockchain Ethereum za pomocą JavaScript. Ale to dopiero początek programowania aplikacji Ethereum.

Zarejestruj transakcję

Teraz, gdy utworzyliśmy obiekt transakcji z wymaganymi polami i wartościami, musimy podpisać go za pomocą klucza prywatnego konta, które wysyła Ether. W tym przypadku nadawcą jest Alice, więc użyjemy prywatnego klucza Alice do podpisania transakcji. Ma to na celu kryptograficzne udowodnienie, że to właściwie Alice wydaje Ether na swoje konto.

var signTransaction = function () {

var tx = {

from: “0xAff9d328E8181aE831Bc426347949EB7946A88DA”,

gasPrice: “20000000000”,

gas: “42000”,

to: ‘0x22013fff98c2909bbFCcdABb411D3715fDB341eA’,

value: “1000000000000000000”,

data: “”

};

web3.eth.accounts.signTransaction(tx, ‘0x9fb71152b32cb

90982f95e2b1bf2a5b6b2a53855eacf59d132a2b7f043cfddf5′)

.then(function(signedTx){

console.log(signedTx.rawTransaction);

});

};

Poprzedni fragment kodu wywołuje funkcję signTransaction z obiektem transakcji, który utworzyliśmy w poprzednim kroku, oraz kluczem prywatnym Alicji, który otrzymaliśmy po wygenerowaniu konta Alice. Poniżej znajduje się wynik, który otrzymujemy po uruchomieniu fragmentu kodu wstępnego.

{

messageHash: ‘0x91b345a38dc728dc06a43c49b92a6ac1e0e6d

614c432a6dd37d809290a25aa6b’,

v: ‘0x2a’,

r: ‘0x14c20901a060834972a539d7b8ad1f23161

c2144a2b66fbf567e37e963d64537′,

s: ‘0x3d2a0a818633a11832a5c48708a198af909

eaf4884a7856c9ac9ed216d9b029c’,

rawTransaction: ‘0xf86c018504a817c80082a4109422013fff98c

2909bbfccdabb411d3715fdb341ea880de0b6b3a76400

00802aa014c20901a060834972a539d7b8ad1f23161c2144a2b66fbf5

67e37e963d64537a03d2a0a818633a11832a5c48708a198af909ea

f4884a7856c9ac9ed216d9b029c’

}

W danych wyjściowych funkcji signTransaction otrzymujemy Obiekt JSON z kilkoma właściwościami. Ważną dla nas wartością jest wartość rawTransaction, czyli szesnastkowy ciąg reprezentujący podpisaną transakcję. Jest to bardzo podobne do tego, jak stworzyliśmy ciąg szesnastkowy transakcji Bitcoin w sekcji Bitcoin.

Przygotuj transakcję Ethereum

Teraz, gdy mamy trochę testowego Etheru z Alicją, utwórzmy transakcję Ethereum, aby wysłać trochę tego Etheru do Boba. Przypomnijmy, że w przypadku Ethereum nie ma żadnych danych wejściowych i wyjściowych oraz zapytań UTXO, ponieważ wykorzystuje on system oparty na rachunkach i saldach. Tak więc wszystko, co musimy zrobić w transakcji, to między innymi podać adres „od” (adres nadawcy), adres „do” (adres odbiorcy) i ilość Etheru do wysłania . Pamiętaj również, że w przypadku transakcji Bitcoin nie musieliśmy określać opłaty transakcyjnej; jednak w przypadku transakcji Ethereum musimy określić dwa powiązane pola. Jeden to limit gazu, a drugi to cena gazu. Przypomnijmy, że gaz to jednostka opłaty transakcyjnej, którą musimy zapłacić sieci Ethereum, aby nasze transakcje zostały potwierdzone i dodane do bloków. cena gazu to ilość eteru (w gwei), którą chcemy zapłacić za jednostkę gazu. Maksymalna opłata, jaką zezwalamy na wykorzystanie w transakcji, jest iloczynem gazu i ceny gazu. Tak więc dla tej przykładowej transakcji definiujemy obiekt JSON za pomocą następujących pól. Tutaj „od” ma adres Alice, a „do” ma adres Boba, a wartość to jeden Eter na wei. Wybrana przez nas cena gazu wynosi 20 gwei, a maksymalna ilość gazu, jaką chcemy zapłacić za tę transakcję, wynosi 42 000. Pamiętaj też, że pozostawiliśmy puste pole danych. Wrócimy do tego później w części dotyczącej inteligentnych umów.

{

from: “0xAff9d328E8181aE831Bc426347949EB7946A88DA”,

gasPrice: “20000000000”,

gas: “42000”,

to: ‘0x22013fff98c2909bbFCcdABb411D3715fDB341eA’,

value: “1000000000000000000”,

data: “”

}

Uzyskaj testowy eter na koncie nadawcy

Teraz, aby utworzyć transakcję Ethereum, która przenosi Ether z jednego konta na drugie, najpierw potrzebujemy trochę Etheru na jednym z kont. Przypomnijmy z sekcji programowania Bitcoin, że użyliśmy kranów testnet, aby uzyskać testowe Bitcoiny na adres, który wygenerowaliśmy. Zrobimy to samo dla Ethereum. Pamiętaj, że naszym celem jest sieć testowa Ropsten dla Ethereum, dlatego będziemy szukać kranu Ropsten w Internecie. W tym przykładzie podaliśmy adres Alicji, który wygenerowaliśmy w poprzednim fragmencie kodu, do kranu testowego sieci Ethereum Ropsten, a my

otrzymał trzy etery pod tym adresem. Po otrzymaniu Ether na adres Alice sprawdźmy saldo tego adresu, aby potwierdzić, czy naprawdę mamy Ether, czy nie. Chociaż możemy sprawdzić saldo tego adresu za pomocą dowolnego z eksploratorów Ethereum online, zróbmy to za pomocą kodu. Poniższy fragment kodu wywołuje funkcję getBalance, przekazując adres Alice jako parametr wejściowy.

var getBalance = function () {

web3.eth.getBalance („0xAff9d328E8181aE831Bc426347949

EB7946A88DA ‘). Następnie (console.log);

};

Otrzymujemy następujący wynik jako saldo adresu Alice. To ogromna liczba, ale tak naprawdę jest to wartość salda wei. Wei jest najmniejszą jednostką eteru. Jeden eter równa się 10 ^ 18 wei. Zatem następująca wartość jest równa trzem Etherowi, co otrzymaliśmy z kranu sieci testowej.

3000000000000000000

Skonfiguruj konta Ethereum

Teraz, gdy wszyscy jesteśmy skonfigurowani, wyślijmy transakcję do łańcucha bloków Ethereum. W tej transakcji wyślemy część Etheru z jednego konta na drugie. Przypomnijmy, że Ethereum nie korzysta z modelu UTXO, ale korzysta z modelu konta i sald. Zasadniczo blockchain Ethereum zarządza stanem i aktywami w zakresie kont i sald, tak jak robią to banki. Nie ma tu żadnych wejść i wyjść. Możesz po prostu wysłać Ether z jednego konta na drugie, a Ethereum upewni się, że stany zostaną zaktualizowane dla tych kont we wszystkich węzłach. Aby wysłać transakcję do Ethereum, która przenosi Ether z jednego konta na inne, najpierw potrzebujemy kilku kont Ethereum. Zacznijmy od utworzenia dwóch kont dla Alicji i Boba. Poniższy fragment kodu wywołuje funkcję tworzenia konta w bibliotece web3 i tworzy dwa konta.

var createAccounts = function () {

var aliceKeys = web3.eth.accounts.create();

console.log(aliceKeys);

var bobKeys = web3.eth.accounts.create();

console.log(bobKeys);

};

A oto dane wyjściowe, które otrzymujemy w oknie konsoli po uruchomieniu poprzedniego fragmentu.

{

address: ‘0xAff9d328E8181aE831Bc426347949EB7946A88DA’,

privateKey: ‘0x9fb71152b32cb90982f95e2b1bf2a5b6b2a5385

5eacf59d132a2b7f043cfddf5′,

signTransaction: [Function: signTransaction],

sign: [Function: sign],

encrypt: [Function: encrypt]

}

{

address: ‘0x22013fff98c2909bbFCcdABb411D3715fDB341eA’,

privateKey: ‘0xc6676b7262dab1a3a28a781c77110b63ab8cd5

eae2a5a828ba3b1ad28e9f5a9b’,

signTransaction: [Function: signTransaction],

sign: [Function: sign],

encrypt: [Function: encrypt]

}

Jak widać, wraz z adresami i kluczami prywatnymi dane wyjściowe dla każdego wywołania funkcji tworzenia konta zawierają również kilka funkcji. Na razie skupimy się na adresie i kluczu prywatnym zwracanych obiektów. Adres to skrót Keccak-256 klucza publicznego ECDSA wygenerowanego klucza prywatnego. Ta kombinacja adresu i klucza prywatnego reprezentuje konto w łańcuchu bloków Ethereum. Możesz wysłać Ether na adres i wydać go za pomocą klucza prywatnego odpowiedniego adresu.

Skonfiguruj bibliotekę i połączenie

Najpierw instalujemy bibliotekę web3 w naszej aplikacji node.js. Zwróć uwagę na konkretną wersję biblioteki wymienioną w poleceniu instalacji. Wynika to z faktu, że wersja 1.0.0 biblioteki ma więcej dostępnych interfejsów API i funkcji, a także zmniejszają zależność od innych zewnętrznych pakietów.

npm install web3@1.0.0-beta.28

Następnie inicjalizujemy bibliotekę w naszym module nodejs Ethereum przy użyciu słowa kluczowego require,

var Web3 = require(‘web3’);

Teraz mamy odniesienie do biblioteki web3, ale musimy utwórz go, zanim będziemy mogli go użyć. Poniższy wiersz kodu tworzy nową instancję obiektu Web3 i ustawia testowany węzeł sieci Ethereum Ropsten hostowany przez Infura jako dostawca dla tej instancji Web3.

var web3 = new Web3(new Web3.providers.HttpProvider(‘https://ropsten.infura.io/<your Infura API key>’));

Programowa interakcja z Ethereum – wysyłanie transakcji

Blockchain Ethereum ma znacznie więcej do zaoferowania pod względem rozwoju aplikacji blockchain w porównaniu z blockchainem Bitcoin. Zdolność do wykonywania logiki na blockchainie za pomocą inteligentnych kontraktów jest kluczową cechą blockchain Ethereum, która pozwala programistom tworzyć zdecentralizowane aplikacje. W tej sekcji nauczymy się programowo współdziałać z blockchainem Ethereum za pomocą JavaScript. Przyjrzymy się głównym aspektom programowania aplikacji Ethereum, od prostych transakcji po tworzenie i wywoływanie inteligentnych umów. Podobnie jak w przypadku interakcji z łańcuchem bloków Bitcoin w poprzedniej sekcji, będziemy używać biblioteki JavaScript i sieci testowej również do interakcji z Ethereum. Użyjemy biblioteki JavaScript web3 dla Ethereum. Ta biblioteka zawiera wiele interfejsów API Ethereum JSON RPC i zapewnia łatwe w użyciu funkcje do tworzenia Ethereum DApps przy użyciu JavaScript. W chwili pisania tego tekstu korzystamy z wersji wyższej niż i kompatybilnej z wersją 1.0.0-beta.28 biblioteki JavaScript web3. W przypadku sieci testowej będziemy używać sieci testowej Ropsten dla blockchaina Ethereum. Dla uproszczenia ponownie użyjemy testowanego węzła sieciowego hostowanego publicznie dla Ethereum, abyśmy nie musieli hostować węzła lokalnego podczas uruchamiania tych fragmentów kodu. Jednak wszystkie fragmenty powinny działać z hostowanym lokalnie węzeł również. Korzystamy z interfejsów API Ethereum dostarczanych przez usługę Infura. Infura to usługa udostępniająca hostowane publicznie węzły Ethereum, dzięki czemu programiści mogą łatwo przetestować swoje aplikacje Ethereum. Aby móc korzystać z interfejsu API Infury, potrzebny jest mały i bezpłatny krok rejestracji, dlatego przejdziemy na stronę https://infura.io i dokonamy rejestracji. Po rejestracji otrzymamy klucz API. Za pomocą tego klucza API możemy teraz wywołać interfejs API Infura. Poniżej pokazano, jak ten kod współdziała z łańcuchem bloków Ethereum. Uwaga: rysunek jest tylko przybliżonym szkicem i nie pokazuje szczegółowo architektury usług Infura.