Что такое смарт-контракт мы рассмотрели на примере, который, возможно, поймет даже ребенок. Но как же создавать такие «умные» контракты? Многие думают, что это очень сложно. На самом деле это не так, и в данном примере мы рассмотрим создание смарт-контракта в сети Ethereum с помощью командной строки.

Смарт-контракты, по сути, это объекты, содержащие учетные записи в цепочке блоков (блокчейне). Они содержат функции кода и могут взаимодействовать с другими контрактами, принимать решения, хранить данные и отправлять эфир другим. Контракты определяются их создателями, но их исполнение, а также расширение услуг, которые они предлагают, обеспечивается самой сетью Ethereum. Они будут существовать и исполняться до тех пор, пока существует целая сеть, и исчезнут, только если они запрограммированы на самоуничтожение.
Что вы можете делать с такими контрактами? Ну, вы можете сделать практически все, что угодно, но в данном случае сделаем несколько простых вещей: для начала вы создадите классический контракт типа «Hello World», тогда вы сможете создать свой собственный криптографический токен, чтобы отправить кому бы то ни было. После того, как вы овладеете этим, вы сможете, например, собирать средства посредством ICO, который в случае успеха предоставит абсолютно прозрачную организацию.
Код простого смарт-контракта
Теперь, когда вы освоили основы Ethereum, давайте перейдем к созданию вашего первого смарт-контракта. Это будет приветственный смарт-контракт, который мы назовем Greeter. Greeter – интеллектуальная цифровая сущность, которая живет в блокчейне и способна вести беседы с любым, кто с ней взаимодействует, на основе ее интерфейса ввода. Возможно, это не болтун, но это отличный слушатель. Вот его код:
contract mortal {
/* Определение переменной owner типа address */
address owner;
/* Эта функция выполняется при инициализации и устанавливает владельца контракта */
function mortal() { owner = msg.sender; }
/* Функция возврата средств по контракту */
function kill() { if (msg.sender == owner) selfdestruct(owner); }
}
contract greeter is mortal {
/* Определение переменной greeting типа string */
string greeting;
/* Это запускается, когда контракт выполнен */
function greeter(string _greeting) public {
greeting = _greeting;
}
/* Основная функция */
function greet() constant returns (string) {
return greeting;
}
}
Вы заметите, что в этом коде есть два разных контракта: «mortal» и «greeter». Это связано с тем, что Solidity (язык высокого уровня для контрактов, который мы используем) имеет свойство наследования, что означает, что один контракт может наследовать характеристики другого. Это очень полезно для упрощения программирования, поскольку общие черты контрактов не нужно переписывать каждый раз, и все контракты могут быть записаны в меньших, более читаемых фрагментах. Таким образом, просто объявив, что greeter является mortal, вы унаследовали все характеристики от контракта mortal и сохранили код greeter простым и легким для чтения. Унаследованная характеристика mortal просто означает, что контракт greeter может быть уничтожен его владельцем, чтобы очистить цепочку блоков и вернуть средства, вложенные в нее, когда контракт больше не нужен. Контракты в ethereum по умолчанию бессмертны и не имеют владельца, а это означает, что после выпуска автор больше не имеет особых привилегий. Учтите это перед выпуском.
Компилятор Solc
Прежде чем вы сможете выпустить смарт-контракт, вам понадобятся две вещи: скомпилированный код и интерфейс Application Binary Interface, который является объектом javascript и определяет, как взаимодействовать с контрактом. У вас должен быть встроенный компилятор solidity, встроенный в вашу geth-консоль. Чтобы проверить это, используйте следующую команду:
eth.getCompilers()
Если вы его установили, должно появиться что-то вроде этого:
['Solidity' ]
Теперь вам нужно переформатировать свой контракт, удалив разрывы строк, чтобы он вписывался в строковую переменную (существуют некоторые онлайн-инструменты, которые сделают это):
var greeterSource = 'contract mortal { address owner; function mortal() { owner = msg.sender; } function kill() { if (msg.sender == owner) selfdestruct(owner); } } contract greeter is mortal { string greeting; function greeter(string _greeting) public { greeting = _greeting; } function greet() constant returns (string) { return greeting; } }'
var greeterCompiled = web3.eth.compile.solidity(greeterSource)
Теперь вы скомпилировали свой код. Затем вам нужно подготовить его к выпуску, включая настройку некоторых переменных, например, какое приветствие вы хотите использовать. Измените первую строку ниже на нечто более интересное, чем «Hello World!». и выполните следующие команды:
var _greeting = "Hello World!"
var greeterContract = web3.eth.contract(greeterCompiled.greeter.info.abiDefinition);
var greeter = greeterContract.new(_greeting,{from:web3.eth.accounts[0], data: greeterCompiled.greeter.code, gas: 300000}, function(e, contract){
if(!e) {
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
})
Использование онлайн-компилятора
Если у вас не установлен Solc, то вы можете воспользоваться онлайн-компилятором. Скопируйте исходный код выше в онлайн-компилятор solidity, а затем ваш скомпилированный код должен появиться на левой панели. Скопируйте код в поле с надписью Web3 deploy как для контракта greeter, так и для контракта mortal в один текстовый файл. Теперь в этом файле измените первую строку на ваше приветствие:
var _greeting = "Hello World!"
Теперь вы можете вставить полученный текст в окно geth или импортировать файл с помощью loadScript. Подождите до тридцати секунд, и вы увидите следующее сообщение:
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
Возможно, вам придется «разблокировать» учетную запись, которая отправляет транзакцию, используя пароль, который вы выбрали в начале, потому что вам нужно оплатить расходы на газ для выпуска вашего контракта, например:
personal.unlockAccount (web3.eth.accounts [0], "yourPassword")
По оценкам, для этого контракта требуется 180 тысяч единиц газа. Обратите внимание, что стоимость не выплачивается разработчикам Ethereum, вместо этого она переходит к майнерам, тем пользователям, компьютеры которых работают над поиском новых блоков и обеспечивают безопасность сети. Цена на газ устанавливается рынком текущего спроса и предложения. Если цены на газ слишком высоки, вы можете стать майнером и снизить цену. Менее чем за минуту у вас должен быть журнал с адресом контракта, это означает, что вы успешно выпустили свой контракт. Вы можете проверить развернутый код (который будет скомпилирован) с помощью этой команды:
eth.getCode(greeter.address)
Запуск смарт-контракта
Чтобы вызвать своего бота, просто введите в свой терминал следующую команду:
greeter.greet();
Поскольку этот вызов ничего не меняет в цепочке блоков, он мгновенно возвращается без каких-либо затрат на газ. Вы должны увидеть, как он вернет ваше приветствие:
'Hello World!'
Как другим пользователям взаимодействовать с вашим смарт-контрактом
Для того, чтобы другие люди могли запускать ваш контракт, им нужны две вещи: адрес, в котором находится контракт, и ABI (Application Binary Interface), который является своего рода руководством пользователя, описывающим имя его функций и как их вызывать с помощью консоли javascript. Для получения каждого из них запустите следующие команды:
greeterCompiled.greeter.info.abiDefinition;
greeter.address;
Если вы скомпилировали с помощью онлайн-инструмента, вы можете получить ABI из полей Interface для контрактов greeter и mortal. Затем вы можете создать экземпляр объекта javascript, который можно использовать для вызова контракта на любом компьютере, подключенном к сети. Замените «ABI» (массив) и «Адрес» (строка) для создания объекта контракта в javascript:
var greeter = eth.contract(ABI).at(Address);
Этот конкретный пример может быть инстанцирован кем-либо с помощью вызова следующего вида (замените greeterAddress адресом вашего контракта):
var greeter2 = eth.contract([{constant:false,inputs:[],name:'kill',outputs:[],type:'function'},{constant:true,inputs:[],name:'greet',outputs:[{name:'',type:'string'}],type:'function'},{inputs:[{name:'_greeting',type:'string'}],type:'constructor'}]).at('greeterAddress');
Удаляем смарт-контракт
Вы должны быть очень рады созданию и выпуску своего первого контракта в системе Ethereum, но следует помнить, что создавать лучше полезные контракты, а не «пустые». Когда владельцы продолжают писать бесполезные контракты, это приводит к неприятному виду заброшенных контрактов в блокчейне. Желательно такие смарт-контракты удалять. Необходимо отправить транзакцию в сеть и заплатить за изменения, внесенные в блокчейн после запуска приведенного ниже кода. Саморазрушение субсидируется сетью, поэтому стоимость будет намного меньше обычной транзакции.
greeter.kill.sendTransaction({from:eth.accounts[0]})
Это может быть вызвано только транзакцией, отправленной владельцем контракта. Вы можете проверить, что дело сделано, если следующая команда вернет 0:
eth.getCode(greeter.address)
Обратите внимание, что каждый контракт должен выполнить свою собственную инструкцию kill. В этом конкретном случае только учетная запись, которая создала контракт, может уничтожить его.