Pierwszy kontrakt na Ethereum

Pierwszy kontrakt na Ethereum

Czas rozpocząć prawdziwą przygodę z blockchain, zbudujmy nasz pierwszy kontrakt na Ethereum.

Przed kodowaniem, zachęcam do zapoznania się z Wstęp do Ethereum.

Przygotowanie środowiska

node.js

Instalujemy środowisko uruchomieniowe node.js – skorzystamy z managerem pakietów npm.

testrpc

Za pomocą npm instalujemy testrpc – dzięki niemu stworzymy wirtualne środowisko Ethereum do testowania naszej aplikacji. Czemu wirtualne? Bo lepiej przetestować swoje rozwiązanie, zanim je umieścimy w sieci i nasz kontrakt pochłonie ogromne ilości Ethereum. Jak jest dostępne środowisko testowe, to trzeba korzystać!

npm install -g ethereumjs-testrpc
testrpc

Po wpisaniu testrpc, nasza wirtualna sieć do testów powinna się uruchomić i nasłuchiwać na jakimś porcie. Aplikację testrpc zostawiamy uruchomioną w tle i spróbujemy podłączyć się do naszej wirtualnej sieci.

truffle

Bardzo popularny framework do pisania własnych aplikacji na Ethereum. Instalujemy go za pomocą npm (otwieramy drugie okno Node.js, nasz serwer testrpc niech sobie chodzi):

 
npm install -g truffle

Po instalacji przygotujmy nasz pierwszy projekt:

 
mkdir pierwszy-kontrakt
cd pierwszy-kontrakt
truffle init

Sprawdźmy, co dla nasz przygotował truffle w katalogu pierwszy-kontrakt:

  • katalog contracts – nasze kontrakty napisane w języku Solidity
  • katalog migrations – skrypty do deploya naszych kontraktów
  • katalog test – nasze scenariusze testowe napisane w języku Solidity lub Javascript
  • pliki truffle.js/truffle-config.js – pliki konfiguracyjne

 

Przygotujmy plik konfiguracyjny truffle.js (przede wszystkim musimy mu wskazać adres naszej testowej sieci Ethereum):

 
module.exports = {
 networks: {
 development: {
 host: "localhost",
 port: 8545, //mój testrpc działa na tym porcie
 network_id: "*"
 }
}
};

Spróbujmy skompilować nasz pusty projekt:

 truffle.cmd compile 

Projekt się zbudował i odpowiednie pliki JSON pojawiły się w katalogu build. Czemu użyłem truffle.cmd? Używam Windowsowego Command Prompt i pliki z rozszerzenie .JS są traktowane jako plik wykonywalny (dokładny opis problemu tutaj).

Pierwszy kontrakt na Ethereum

Środowisko przygotowane, stwórzmy nasz pierwszy projekt oparty o Proof of Existence. Będziemy potwierdzali autentyczność dokumentów (podobny koncept jaki jest wdrażany w PKO BP przez firmę Coinfirm).

Tworzymy nasz pierwszy kontrakt:

 truffle.cmd create contract ProofOfExistence1 

Otwieramy plik ProofOfExistence1.sol, który został stworzony w katalogu contracts (ja na razie używam Notepad++). Zabieramy się do pisania naszego pierwszego kontraktu.

 
pragma solidity ^0.4.4;

// Proof of Existence contract, version 1
contract ProofOfExistence1 {
// state
bytes32 public proof;

// calculate and store the proof for a document
// transactional function
function notarize(string document) public {
proof = proofFor(document);
}
// helper function to get a document's sha256
// read-only function
function proofFor(string document) public constant returns (bytes32) {
return sha256(document);
}
}

Kod zaczerpnięty od Manuel Araoz.

Słowo kluczowe contract możemy porównać do class znanych z innych języków obiektowych. Mamy naszą definicję obiektu ProofOfExistence1, a w nim:

  • proof – state, przechowujemy w tej zmiennej skrót sha256 naszego dokumentu (nasz stan obiektu)
  • notarize – transactional function, wyliczamy skrót dla naszego dokumentu i zapisujemy go w zmiennej (funkcja zmieniająca stan naszego obiektu)
  • proofFor – read-only function, funkcja wykonująca wbudowaną kryptograficzną funkcje sha256 (funkcja skrótu) i zwracająca wynik (zwróćcie uwagę że funkcja nie zmienia stanu naszego obiektu)

Czas wrzucić nasz kod do blockchaina. Przygotujmy plik migracyjny, który przeniesie nasz kontrakt do wirtualnej sieci (tworzymy plik 2_deploy_contracts.js w katalogu migrations):

 
var ProofOfExistence1 = artifacts.require("./ProofOfExistence1.sol");

module.exports = function(deployer) {
  deployer.deploy(ProofOfExistence1);
};

Zobaczmy nasz kontrakt w akcji:

 
truffle.cmd migrate 

Migracja wykonała za nas kompilację i użyła plików migracyjnych do przeniesienia naszego kontraktu do wirtualnej sieci (więcej o migracji).

Spójrzmy na naszą wirtualną sieć:

W naszym prywatnym blockchainie powstały trzy transakcje:

  • block 1 – stworzenie kontraktu Migrations (wygenerowany przez framework truffle)
  • block 2 – wywołanie funkcji setCompleted i zapisanie informacji w kontrakcie Migrationslast_completed_migration
  • block 3 – stworzenie naszego kontraktu ProofOfExistence1

Interakcja z pierwszym kontraktem

Nasz kod trafił do sieci blockchain, sprawdźmy go w akcji! Do tego celu użyjemy konsoli dostarczonej przez Truffle:

 
truffle.cmd console

// pobieramy nasz kontrakt
truffle(development)> var poe = 
ProofOfExistence1.at(ProofOfExistence1.address)

// sprawdzamy adres naszego kontraktu
truffle(development)> poe.address
0x216eb7977e390409e1ceb78f33b889c8cd0d108f
// taki adres przypisała nam sieć podczas tworzenia kontraktu (trzeci block)

// zarejestrujemy pierwszy dokument
truffle(development)> poe.notarize('Kopalnia Programisty')
{ tx: '0x30f...106',
  receipt:
   { transactionHash: '0x30f...106',
     transactionIndex: 0,
     blockHash: '0x17a...12a',
     blockNumber: 5,
     gasUsed: 44545,
     cumulativeGasUsed: 44545,
     contractAddress: null,
     logs: [],
     status: 1 },
  logs: [] }
// ta funkcja zmienia stan naszego kontraktu (state)
// za zmianę zapłaciliśmy gas

// sprawdźmy jaki skrót powinien powstać dla naszego dokumentu
truffle(development)> poe.proofFor('Kopalnia Programisty')
0x847b5ffe880c7dacc37fe5c2273530b83e4f410248fb852829a8c6d7b9e42f6a
// darmowa funkcja (nie zmieniamy stanu kontraktu)

// sprawdźmy jaki skrót został zapisany w naszym kontrakcie (state)
truffle(development)> poe.proof()
0x847b5ffe880c7dacc37fe5c2273530b83e4f410248fb852829a8c6d7b9e42f6a
// mamy taki sam wynik, sukces!

Nasz prosty kontrakt działa! W następnym kroku ulepszymy jego działanie oraz zautomatyzujemy testy.

Przydatne materiały: