Aplikacja kliencka

Tak jak  poprzednio, możemy użyć biblioteki web3 do wywołania funkcji w inteligentnym kontrakcie. Tu zrobiliśmy to za pomocą aplikacji node.js, a nie aplikacji przeglądarki. W tej sekcji będziemy używać web3 w aplikacji przeglądarki do wywoływania funkcji głosowania wdrożonej inteligentnej umowy. Najprostszą aplikacją internetową, którą możemy utworzyć dla tego DApp, jest pojedyncza strona internetowa z kilkoma kontrolkami tekstu i przycisków. W przypadku strony internetowej możemy użyć następującego kodu w pliku HTML, a następnie uruchomić go z lokalnego serwera. Należy pamiętać, że uruchamianie z lokalnego serwera i nie otwieranie bezpośrednio pliku z przeglądarki jest ważne, aby poprawnie załadować skrypty, bez problemów związanych z bezpieczeństwem przeglądarki.

<html>

<c>

<meta charset=”UTF-8″>

<title>Beginning Blockchain – DApp demo</title>

<script src=”<source of web3 library from any CDN or local

file>”></script>

</head>

<body>

<div>

<p>

<strong>Beginning Blockchain</strong>

</p>

<p>Hi, Welcome to the Polling DApp!</p>

<p>&nbsp;</p>

<p>Get latest poll:&nbsp;

<button onclick=”getPoll()”>Get Poll</button>

</p>

<p>

<div id=”pollSubject”></div>

</p>

<p>Vote: Yes:

<input type=”radio” id=”yes”> No:

<input type=”radio” id=”no”>

</p>

<p>Submit:&nbsp;

<button onclick=”submitVote()”>Submit Vote</button>

</p>

</p>

</div>

<script>

if (typeof web3 !== ‘undefined’) {

web3 = new Web3(web3.currentProvider);

} else {

web3 = new Web3(new Web3.providers.HttpProvider

(‘http://127.0.0.1:8507’));

}

function getPoll() {

var pollingContract = new web3.eth.Contract([{

“constant”: true,

“inputs”: [{

“name”: “”,

“type”: “address”

}],

“name”: “votes”,

“outputs”: [{

“name”: “”,

“type”: “uint256”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“constant”: true,

“inputs”: [],

“name”: “getPoll”,

“outputs”: [{

“name”: “”,

“type”: “string”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“anonymous”: false,

“inputs”: [{

“indexed”: false,

“name”: “_voter”,

“type”: “address”

},

{

“indexed”: false,

“name”: “_value”,

“type”: “uint256”

}

],

“name”: “Voted”,

“type”: “event”

},

{

“constant”: false,

“inputs”: [{

“name”: “selection”,

“type”: “uint256”

}],

“name”: “vote”,

“outputs”: [],

“payable”: false,

“stateMutability”: “nonpayable”,

“type”: “function”

}

], ‘0x59E7161646C3436DFdF5eBE617B4A172974B481e’);

pollingContract.methods.getPoll().call().

then(function (value) {

document.getElementById(‘pollSubject’).

textContent = value;

});

};

function submitVote() {

var value = 0

var yes = document.getElementById(‘yes’).checked;

var no = document.getElementById(‘no’).checked;

if (yes) {

value = 1

} else if (no) {

value = 2

} else {

return;

}

var pollingContract = new web3.eth.Contract([{

“constant”: true,

“inputs”: [{

“name”: “”,

“type”: “address”

}],

“name”: “votes”,

“outputs”: [{

“name”: “”,

“type”: “uint256”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“constant”: true,

“inputs”: [],

“name”: “getPoll”,

“outputs”: [{

“name”: “”,

“type”: “string”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“anonymous”: false,

“inputs”: [{

“indexed”: false,

“name”: “_voter”,

“type”: “address”

},

{

“indexed”: false,

“name”: “_value”,

“type”: “uint256”

}

],

“name”: “Voted”,

“type”: “event”

},

{

“constant”: false,

“inputs”: [{

“name”: “selection”,

“type”: “uint256”

}],

“name”: “vote”,

“outputs”: [],

“payable”: false,

“stateMutability”: “nonpayable”,

“type”: “function”

}

], ‘0x59E7161646C3436DFdF5eBE617B4A172974B481e’);

pollingContract.methods.vote(value).send({

from: ‘0xbaf735f889d603f0ec6b1030c91d9033e

60525c3′

}).then(function (result) {

console.log(result);

});

};

</script>

</body>

</html>

Przeanalizujmy teraz każdą sekcję tego pliku HTML. W sekcji nagłówka dokumentu HTML załadowaliśmy skrypt web3 ze źródła CDN lub źródła lokalnego. To tak, jakbyśmy odwoływali się do dowolnej innej biblioteki JavaScript stron trzecich na naszych stronach internetowych (JQuery itp.). Następnie w sekcji treści HTML mamy kontrolki do wyświetlania tematu ankiety i radia oraz przycisków do przechwytywania użytkownika. Ogólna strona wygląda tak

fig6-11

Ważna jest sekcja skryptu w ciele. Właśnie tam nazywamy kod interakcji inteligentnego kontraktu. Spójrzmy na to szczegółowo.

<script>

if (typeof web3 !== ‘undefined’) {

web3 = new Web3(web3.currentProvider);

} else {

web3 = new Web3(new Web3.providers.HttpProvider

(‘http://127.0.0.1:8507’));

}

function getPoll() {

var pollingContract = new web3.eth.Contract([{

“constant”: true,

“inputs”: [{

“name”: “”,

“type”: “address”

}],

“name”: “votes”,

“outputs”: [{

“name”: “”,

“type”: “uint256”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“constant”: true,

“inputs”: [],

“name”: “getPoll”,

“outputs”: [{

“name”: “”,

“type”: “string”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“anonymous”: false,

“inputs”: [{

“indexed”: false,

“name”: “_voter”,

“type”: “address”

},

{

“indexed”: false,

“name”: “_value”,

“type”: “uint256”

}

],

“name”: “Voted”,

“type”: “event”

},

{

“constant”: false,

“inputs”: [{

“name”: “selection”,

“type”: “uint256”

}],

“name”: “vote”,

“outputs”: [],

“payable”: false,

“stateMutability”: “nonpayable”,

“type”: “function”

}

], ‘0x59E7161646C3436DFdF5eBE617B4A172974B481e’);

pollingContract.methods.getPoll().call().

then(function (value) {

document.getElementById(‘pollSubject’).

textContent = value;

});

};

function submitVote() {

var value = 0

var yes = document.getElementById(‘yes’).checked;

var no = document.getElementById(‘no’).checked;

if (yes) {

value = 1

} else if (no) {

value = 2

} else {

return;

}

var pollingContract = new web3.eth.Contract([{

“constant”: true,

“inputs”: [{

“name”: “”,

“type”: “address”

}],

“name”: “votes”,

“outputs”: [{

“name”: “”,

“type”: “uint256”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“constant”: true,

“inputs”: [],

“name”: “getPoll”,

“outputs”: [{

“name”: “”,

“type”: “string”

}],

“payable”: false,

“stateMutability”: “view”,

“type”: “function”

},

{

“anonymous”: false,

“inputs”: [{

“indexed”: false,

“name”: “_voter”,

“type”: “address”

},

{

“indexed”: false,

“name”: “_value”,

“type”: “uint256”

}

],

“name”: “Voted”,

“type”: “event”

},

{

“constant”: false,

“inputs”: [{

“name”: “selection”,

“type”: “uint256”

}],

“name”: “vote”,

“outputs”: [],

“payable”: false,

“stateMutability”: “nonpayable”,

“type”: “function”

}

], ‘0x59E7161646C3436DFdF5eBE617B4A172974B481e’);

pollingContract.methods.vote(value).send({

from: ‘0xbaf735f889d603f0ec6b1030c91d9033

e60525c3′

}).then(function (result) {

console.log(result);

});

};

</script>

W poprzedniej sekcji skryptu najpierw inicjalizujemy obiekt web3 z dostawcą HTTP lokalnego węzła Ethereum (jeśli jeszcze nie jest zainicjowane). Następnie mamy dwie funkcje JavaScript. Jeden do pobierania wartości ciągu pollSubject z inteligentnego kontraktu, a drugi do wywoływania funkcji głosowania w kontrakcie. Wywołanie funkcji inteligentnego kontraktu jest dokładnie tak, jak to zrobiliśmy w poprzedniej sekcji, używając submoduła web3.eth.Contract biblioteki web3. Zauważ, że w pierwszej funkcji getPoll wywołujemy funkcję wywołania w instancji inteligentnej umowy, podczas gdy w drugiej funkcji submVote wywołujemy wysyłanie w instancji inteligentnej umowy. To przede wszystkim różnica w dwóch wywołaniach funkcji. Korzystając z wywołania funkcji getPoll inteligentnej umowy, otrzymujemy wartość zwrotną funkcji getPoll bez wysyłania żadnej transakcji do sieci. Następnie wyświetlamy tę wartość w interfejsie użytkownika, przypisując ją jako tekst elementu interfejsu użytkownika. Następnie, korzystając z funkcji wysyłania w głosowaniu, wysyłamy transakcję, aby wykonać tę funkcję w sieci, dlatego musimy również zdefiniować konto, które będzie używane do wykonania funkcji inteligentnego kontraktu. Poniżej przedstawiono dane wyjściowe uzyskane z przedstawionej wcześniej funkcji submVote, która jest w zasadzie pokwitowaniem transakcji.

{

blockHash: ‘0x04a02dd56c037569eb6abe25e003a65d3366407

134c90a056f64b62c2d23eb84′,

blockNumber: 4257,

contractAddress: null,

cumulativeGasUsed: 43463,

from: ‘0xbaf735f889d603f0ec6b1030c91d9033e60525c3’,

gasUsed: 43463,

logsBloom: ‘0x000000000000000000000000000000800000000

00000040000000000000000000200000000000000000000000000

00000000000000000000000000000000000000000000000000000

00000000000200000000002000000000000000000000000000000

00000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000002000000000000000

00000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000

0000000000000000000000000000000000000000000000000′,

root: ‘0x58bc4ee0a3025ca3f303df9bb243d052a123026519637

30c52c88aafe92ebeee’,

to: ‘0x59e7161646c3436dfdf5ebe617b4a172974b481e’,

transactionHash: ‘0x434aa9c0037af3367a0d3d92985781c50

774241ace1d382a8723985efcea73b3′,

transactionIndex: 0,

events: {

Voted: {

address: ‘0x59E7161646C3436DFdF5eBE617B4A17

2974B481e’,

blockNumber: 4257,

transactionHash: ‘0x434aa9c0037af3367a0d3d929

85781c50774241ace1d382a8723985efcea73b3′,

transactionIndex: 0,

blockHash: ‘0x04a02dd56c037569eb6abe25e003a65

d3366407134c90a056f64b62c2d23eb84′,

logIndex: 0,

removed: false,

id: ‘log_980a1744’,

returnValues: [Result],

event: ‘Voted’,

signature: ‘0x4d99b957a2bc29a30ebd96a7be8e68f

e50a3c701db28a91436490b7d53870ca4′,

raw: [Object]

}

}

}

Jeśli przyjrzymy się bliżej temu wynikowi, zobaczymy, że ma on również sekcję wydarzeń i pokazuje on wyzwalanie Głosowanego wydarzenia, które stworzyliśmy w naszej inteligentnej umowie.

events: {

Voted: {

address: ‘0x59E7161646C3436DFdF5eBE617B4A172

974B481e’,

blockNumber: 4257,

transactionHash: ‘0x434aa9c0037af3367a0d3d929

85781c50774241ace1d382a8723985efcea73b3′,

transactionIndex: 0,

blockHash: ‘0x04a02dd56c037569eb6abe25e003a6

5d3366407134c90a056f64b62c2d23eb84′,

logIndex: 0,

removed: false,

id: ‘log_980a1744’,

returnValues: [Result],

event: ‘Voted’,

signature: ‘0x4d99b957a2bc29a30ebd96a7be8e68fe

50a3c701db28a91436490b7d53870ca4′,

raw: [Object]

}

}

W poprzednim fragmencie kodu wyodrębniliśmy sekcję wydarzeń od otrzymania transakcji, którą otrzymaliśmy w odpowiedzi na przesłaną transakcję, na funkcję głosowania naszej inteligentnej umowy. Jak widzimy, sekcja zdarzeń pokazuje również wartości zwracane i wartości pierwotne z wywołania funkcji. Doszliśmy do końca naszego ćwiczenia programowania DApp. W poprzednich sekcjach tego rozdziału opracowaliśmy kompleksową zdecentralizowaną aplikację w łańcuchu bloków Ethereum, a także wdrożyliśmy prywatny łańcuch bloków dla naszego DApp. Z DApp można także korzystać w publicznej sieci Ethereum – wyborca musi hostować węzeł i może głosować przy użyciu istniejących kont Ethereum w publicznej (głównej) sieci. Istnieje kilka sposobów na ulepszenie logiki biznesowej w inteligentnej umowie przy użyciu różnych kontroli i reguł. To ćwiczenie programowania daje nam podstawową wiedzę na temat tego, jak podejść do rozwoju zdecentralizowanych aplikacji i komponentów, które pojawiają się na obrazie podczas procesu. Ćwiczenie to można potraktować jako punkt wyjścia do opracowania aplikacji Ethereum, a czytelnika zachęca się do zapoznania się z najlepszymi praktykami i bardziej złożonymi scenariuszami na ten temat.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *