Хорошо, не стесняйтесь привлекать меня к ответственности за шокирующий выбор слова painless. Я до сих пор помню боль, когда узнал свои первые Dapps. Именно поэтому я сделаю все возможное, чтобы снять с вас всю боль.

Без лишних слов, приступим!

Начиная

Чтобы получить полный и наиболее реалистичный опыт, я думаю, было бы полезно запустить первый смарт-контракт в реальной тестовой сети Ethereum. А это значит, что нам нужен эфир для тестирования Dapps. Давай попробуем достать!

Скачать эти

Сделай это

  • Открыть кошелек Ethereum
  • Выберите сеть Rinkeby

  • Создайте учетную запись Ethereum в кошельке Ethereum. В результате адрес учетной записи выглядит так 0x248A3d277B38E1125b87931Ad52f57b52c45208B
  • Запомните адрес учетной записи и закройте кошелек Ethereum.
  • Перейдите на https://faucet.rinkeby.io/ и следуйте инструкциям. Дело в том, чтобы получить немного бесплатного эфира для развлечения Dapps.
  • Запустите эту команду и дождитесь синхронизации блокчейна.
geth --rinkeby --syncmode "fast" --rpc --rpcapi db,eth,net,web3,personal --cache=1024 --rpcport 8545 --rpcaddr 127.0.0.1 --rpccorsdomain "*" --bootnodes="enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@52.169.42.101:30303"

Это займет некоторое время, особенно если у вас медленный Интернет. Подождите от 30 до 60 минут для синхронизации. Я знаю, это отстой. Но начинается самое интересное! Вы увидите кучу этих вещей, так что не волнуйтесь, расслабьтесь!

Давайте повеселимся (серверная часть)

Я хочу поблагодарить Махеша Мурти за его запись в блоге, которая действительно привела меня к моему первому успеху. Я буду использовать материалы из его поста. Ура, дружище!

$ mkdir voting $ cd voting $ npm install -g webpack $ truffle init webpack

Хорошо, штука под названием трюфель только что установила кучу файлов, которые вам понадобятся для первого смарт-контракта. Это чертовски чудесно.

Теперь скопируйте эти строки в файл Voting.sol и поместите его в каталог contracts/, созданный трюфелем.

pragma solidity ^0.4.11; // We have to specify what version of compiler this code will compile with contract Voting { /* mapping field below is equivalent to an associative array or hash. The key of the mapping is candidate name stored as type bytes32 and value is an unsigned integer to store the vote count */ mapping (bytes32 => uint8) public votesReceived; /* Solidity doesn't let you pass in an array of strings in the constructor (yet). We will use an array of bytes32 instead to store the list of candidates */ bytes32[] public candidateList; /* This is the constructor which will be called once when you deploy the contract to the blockchain. When we deploy the contract, we will pass an array of candidates who will be contesting in the election */ function Voting(bytes32[] candidateNames) { candidateList = candidateNames; } // This function returns the total votes a candidate has received so far function totalVotesFor(bytes32 candidate) returns (uint8) { if (validCandidate(candidate) == false) throw; return votesReceived[candidate]; } // This function increments the vote count for the specified candidate. This // is equivalent to casting a vote function voteForCandidate(bytes32 candidate) { if (validCandidate(candidate) == false) throw; votesReceived[candidate] += 1; } function validCandidate(bytes32 candidate) returns (bool) { for(uint i = 0; i < candidateList.length; i++) { if (candidateList[i] == candidate) { return true; } } return false; } }

Пока все в порядке, да? Поскольку мы хотим использовать наш собственный смарт-контракт голосования вместо примера, созданного трюфелем, нам нужно будет изменить ссылку во время развертывания, управляемую сценарием 2_deploy_contracts в каталоге migrastions/. Замените содержимое внутри 2_deploy_contracts на

var Voting = artifacts.require("./Voting.sol"); module.exports = function(deployer) { deployer.deploy(Voting, ['Rama', 'Nick', 'Jose'], {gas: 290000}); };

Теперь вы написали свой первый смарт-контракт, но это только половина дела. Чтобы сделать его полезным, нам понадобится веб-интерфейс для взаимодействия с ним.

Давайте повеселимся (внешний интерфейс)

Здесь начинается самое интересное. Опять же, все кредиты принадлежат Махешу Мурти. Я понятия не имею, как он это понял, когда документации не так много.

Замените app/javascripts/app.js содержимым

// Import the page's CSS. Webpack will know what to do with it. import "../stylesheets/app.css"; // Import libraries we need. import { default as Web3} from 'web3'; import { default as contract } from 'truffle-contract' /* * When you compile and deploy your Voting contract, * truffle stores the abi and deployed address in a json * file in the build directory. We will use this information * to setup a Voting abstraction. We will use this abstraction * later to create an instance of the Voting contract. * Compare this against the index.js from our previous tutorial to see the difference * https://gist.github.com/maheshmurthy/f6e96d6b3fff4cd4fa7f892de8a1a1b4#file-index-js */ import voting_artifacts from '../../build/contracts/Voting.json' var Voting = contract(voting_artifacts); let candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"} window.voteForCandidate = function(candidate) { let candidateName = $("#candidate").val(); try { $("#msg").html("Vote has been submitted. The vote count will increment as soon as the vote is recorded on the blockchain. Please wait.") $("#candidate").val(""); /* Voting.deployed() returns an instance of the contract. Every call * in Truffle returns a promise which is why we have used then() * everywhere we have a transaction call */ Voting.deployed().then(function(contractInstance) { contractInstance.voteForCandidate(candidateName, {gas: 140000, from: web3.eth.accounts[0]}).then(function() { let div_id = candidates[candidateName]; return contractInstance.totalVotesFor.call(candidateName).then(function(v) { $("#" + div_id).html(v.toString()); $("#msg").html(""); }); }); }); } catch (err) { console.log(err); } } $( document ).ready(function() { if (typeof web3 !== 'undefined') { console.warn("Using web3 detected from external source like Metamask") // Use Mist/MetaMask's provider window.web3 = new Web3(web3.currentProvider); } else { console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask"); // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail) window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); } Voting.setProvider(web3.currentProvider); let candidateNames = Object.keys(candidates); for (var i = 0; i < candidateNames.length; i++) { let name = candidateNames[i]; Voting.deployed().then(function(contractInstance) { contractInstance.totalVotesFor.call(name).then(function(v) { $("#" + candidates[name]).html(v.toString()); }); }) } });

Заменить app/index.html на

<!DOCTYPE html> <html> <head> <title>Hello World DApp</title> <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'> <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'> </head> <body class="container"> <h1>A Simple Hello World Voting Application</h1> <div id="address"></div> <div class="table-responsive"> <table class="table table-bordered"> <thead> <tr> <th>Candidate</th> <th>Votes</th> </tr> </thead> <tbody> <tr> <td>Rama</td> <td id="candidate-1"></td> </tr> <tr> <td>Nick</td> <td id="candidate-2"></td> </tr> <tr> <td>Jose</td> <td id="candidate-3"></td> </tr> </tbody> </table> <div id="msg"></div> </div> <input type="text" id="candidate" /> <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a> </body> <script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script> <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script> <script src="app.js"></script> </html>

Ты все еще со мной? Мы почти на месте!

Давайте развернем это

Я надеюсь, что у вас уже есть немного эфира, с которым можно поиграть в тестовой сети Rinkeby. Давайте теперь разблокируем ваш аккаунт с трюфелем.

$ truffle console truffle(development)> web3.personal.unlockAccount('0x248A3d277B38E1125b87931Ad52f57b52c45208B', 'mysuperstrongpassword', 15000)

Теперь ваша учетная запись должна быть разблокирована для развертывания. Все еще внутри трюфельной консоли. Делать

truffle(development)> migrate

Видишь это? Это похоже на успех

Сбор урожая

Пора поговорить со Smart Contract и почувствовать себя полезным, woot: D

Давайте запустим локальный веб-сервер, который общается с только что развернутым смарт-контрактом.

$ npm run dev

Теперь перейдите на http: // localhost: 8080 / и вуаля!

Не стесняйтесь поиграть с ним. Ты заслуживаешь это! Вся логика этого приложения реализована на Ethereum EVM. Как это круто! Хотя очень медленно.

Это оно!

Следующее? Напишите смарт-контракт, проведите роуд-шоу и отправляйтесь на ICO. Не говори, что я не говорил тебе, где деньги.

Не стесняйтесь обращаться ко мне, чтобы спросить что-нибудь в Твиттере. Мне также любопытно, какие эксперименты вы хотите проводить со мной. Напиши мне в Твиттере: D

Ваше здоровье!

Первоначально опубликовано на steven.news 21 сентября 2017 г.