Jump to content
Sign in to follow this  
mr.save

Ставим Ethereum на Raspberry Pi, чтобы связать умные вещи контрактами

Recommended Posts

На пересечении двух ультрамодных тем, криптовалют и интернета вещей, возможно, лежит золотая жила. Представь: умные предметы в будущем смогут общаться друг с другом при помощи неразрывных контрактов. А посмотреть, как это будет работать, можно уже сегодня. В этой статье я расскажу тебе, как установить Ethereum на Raspberry Pi и запустить умный контракт, взаимодействующий с реальным миром.

Введение

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

Сейчас же мы находимся в самой начальной точке развития будущей экосистемы, но с появлением Ethereum у нас уже есть нецензурируемая децентрализованная и автономная среда, которая позволяет налаживать экономическое взаимодействие между девайсами. А раз есть, значит, можно экспериментировать!

Итак, тебе понадобятся:

  • Raspberry Pi 2 или 3 или BeagleBone Black. Мы тестировали это руководство с RPi 3, но все должно работать и на RPi 2 и BBB. Нюансы могут быть только с установкой пакетов — в этом случае тебя спасет Google и смекалка.
  • Карта на 64 Гбайт. Большой объем понадобится для хранения блокчейна Ethereum, который к тому же постоянно растет.
  • Все, что ты хочешь подключить к порту GPIO Raspberry Pi.

Мы напишем умный контракт и загрузим его в сеть с помощью браузера Mist. Далее поднимем ноду на Raspberry Pi, развернем на ней небольшое приложение, которое будет слушать события от определенного контракта в сети и управлять GPIO по наступлении этого события.

 

Подготовка

  • Для начала подготовим Raspberry Pi к работе.
  • Форматируем карту и скачиваем Ubuntu Mate для Raspberry Pi (можно выбрать и Raspbian).
  • Записываем образ на флеш-карту. Для этого можно воспользоваться консолью или Pi Filler.
  • Вставляем карту и устанавливаем систему. После установки ресайзим карту, перезагружаемся и можем подключаться к RPi через Wi-Fi по SSH.
  • Устанавливаем клиент сети Ethereum. Сейчас самый популярный из них — это Geth, он написан на Go. Можно собрать его из исходников, но этот процесс имеет некоторые особенности, поэтому более быстрый путь — скачать и установить уже собранную версию.
  • Приложение у нас будет на Node.js, поэтому скачиваем версию для ARMv7 и устанавливаем
 $ wget https://nodejs.org/dist/v4.4.5/node-v4.4.5-linux-armv7l.tar.xz
 $ tar -xvf node-v4.4.5-linux-armv7l.tar.xz
 $ cd node-v4.4.5-linux-armv7l
 $ sudo cp -R * /usr/local/

Убеждаемся, что все в порядке:

$ node -v
v4.4.5
$ npm -v
2.15.5

Теперь нам нужно поставить два пакета npm: web3 и onoff. Для этого, в свою очередь, понадобится Git, а также g++ 4.7 (для корректной установки onoff):

 $ sudo apt-get install g++-4.7 git
 $ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6
 $ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.7
 $ sudo update-alternatives --config gcc

Ставим пакеты:

$ sudo npm install -g onoff web3

Синхронизация

Для начала работы нужно синхронизировать блокчейн. Иногда это может занять несколько дней. «Легких» клиентов Ethereum пока что нет, и на твоем девайсе должна храниться вся информация о транзакциях с начала летописи. Сейчас архив занимает около 20 Гбайт.

Клиенты бывают разные. Parity, к примеру, очень многообещающий, но для наших целей мы возьмем проверенный Geth. Есть много способов синхронизировать блокчейн.

  • Самый долгий способ — просто запустить ./geth в фоне и оставить работать. Периодически придется проверять, не прервалась ли синхронизация.
  • Используя опцию ./geth --fast. В таком случае будут проверяться только заголовки блоков и процесс пойдет чуть быстрее, да и сам блокчейн будет занимать поменьше места.
  • Если на основной машине уже стоит клиент той же версии, то можешь просто скопировать папку chaindata (на «Маке» это ~/Library/Ethereum/chaindata) при помощи rsync.
  • Экспортировать данные с основного компьютера можно и при помощи Geth: geth export blockchain_backup. Копируем бэкап на Raspberry Pi и разворачиваем там: geth export blockchain_backup. Как ни странно, процесс тоже очень долгий.
  • Последний вариант — это не совсем о синхронизации, но если хочешь побыстрее начать экспериментировать, подойдет и он. Тебе понадобится открытая для запросов нода — своя или сторонняя в паблике. К примеру, можно взять инстанс на Digital Ocean, развернуть клиент там и синхронизировать блокчейн, как описано выше. Потом запускаешь его с открытым портом и можешь коннектиться к нему из приложения. Можно обойтись и без Digital Ocean и сделать то же самое на своей машине. Если Raspberry Pi находится в той же подсети, то процесс аналогичен:
$ screen -dmS eth geth --testnet --rpc --rpcaddr "localhost" --rpcport "8545" --rpcapi "eth,net,web3"

1469091364_9b59_ethereum-rpi.thumb.png.00bcb7006284dfd8e85a241c07aad5af.png

Контракт

Итак, все готово: клиент установлен, нода синхронизирована и работает, можно приступать к самому интересному. Для начала накидаем простейший контракт.

contract EthThing {
  uint state;
  address owner;

  event stateChanged(uint _state);
  event eithersRecieved(uint _amount);

  function EthThing() {
      owner = msg.sender;
  }

  function setState(uint _state) {
      state = _state;
      stateChanged(state);
  }

  function getState() constant returns (uint _state) {
      return  state;
  }

  function() {
      eithersRecieved(msg.value);
  }

  function kill() {
      if (msg.sender == owner) suicide(owner);
  }
}

Он хранит в блокчейне две переменные: адрес создателя контракта и состояние, которое мы можем устанавливать и получать с помощью функций setState(uint _state) и getState().

Я добавил kill() и функцию без названия, а также событие eithersRecieved с целью показать, куда писать код, чтобы наладить экономическое взаимодействие с нашим устройством. К примеру, можно будет предоставлять какую-нибудь услугу и принимать оплату в эфирах по адресу контракта. Он сразу пришлет сообщение о принятой транзакции на твое устройство (или даже на несколько).

У нас есть два ивента, которые мы хотим бродкастить в сеть, — stateChanged и eithersRecieved. Первый ивент сообщает всем о том, что кто-то изменил значение переменной state, сделав транзакцию с вызовом функции setState. Второй ивент сообщает, что кто-то послал эфир на адрес контракта.

В конструкторе EthThing(), который вызывается при загрузке контракта в сеть, мы запоминаем владельца — создателя контракта.

С помощью setState(uint _state) любой желающий может установить значение переменной state, что станет известно всем, кто следит за контрактом. Функция getState() возвращает текущее значение переменной state, а constant позволяет вызывать эту функцию локально (значение не вычисляется, и не нужно платить за газ).

Функция без имени — это транзакция без параметров с переводом ETH. Она используется в качестве колбэка и позволяет с помощью события отслеживать перевод средств на адрес контракта. А функция kill() позволяет создателю контракта уничтожить его и вернуть средства на свой адрес.

 

Фронтенд

Напишем небольшое приложение на Node.js, которое будет коннектиться к локальной или удаленной ноде и слушать указанные события. Начать лучше всего с интерфейса контракта. Чтобы создать его, можно воспользоваться онлайновым компилятором Solidity или установить браузер Mist на своей рабочей машине.

1469091384_ddf2_deploy-contract.thumb.png.a2950f40ec050ea4a0ea9b839d771b7c.png

Мы будем ждать передачи средств и в случае поступления мигать светодиодом (или трещать реле — зависит от того, что у тебя есть) в течение восьми секунд с периодом, который будет передан в state.

// Объект web3 должен указывать на локальную или удаленную ноду
var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

// Тут нужно вписать номер порта GPIO, который ты используешь
var Gpio = require('onoff').Gpio;
var port = new Gpio(18,'out');
port.writeSync(1);

// Пишем в лог некоторые свойства объекта web3, чтобы проверить соединение
console.log(web3.version.api);
console.log(web3.isConnected());
console.log(web3.version.node);

// ABI — Application Binary Interface Definition для нашего контракта
var ABIString = 'enter contract interface here';
var ABI = JSON.parse(ABIString);

// Подсоединяемся к контракту
var ContractAddress = 'enter contract address here';
var contract = web3.eth.contract(ABI).at(ContractAddress);

var portDriver = function(time) {
  portSync = setInterval(function(){
      port.writeSync(port.readSync() === 0 ? 1 : 0);
  }, time);

  setTimeout(function() {
        clearInterval(portSync);
        port.writeSync(1);
  }, 8000);
};

// Бесконечный цикл, который читает ивент 'stateChanged'
var event = contract.stateChanged( {}, function(error, result) {
  if (!error) {
    var msg = "\n***********";
    msg += "State changed: " + result.args.state + " (block:" + result.blockNumber + ")";
    msg += "***********";
    console.log(msg);
    portDriver(result.args.state);
  }
});

// Отслеживаем транзакцию
var event = contract.eithersRecieved( {}, function(error, result) {
  if (!error) {
    var msg = "\n***********";
    msg += "Eithers received: " + result.args.amount + "wei" + " (block:" + result.blockNumber + ")";
    msg += "***********";
    console.log(msg);
    portDriver(500);
  }
});

Чтобы задеплоить контракт, открываем Contact → Deploy New Contract. Вставляем код, жмем Execute, оплачиваем газ и немного ждем, пока операция завершится.

1469091401_eddc_create-contract.thumb.png.fd7954f9e155f583285f44ad84618d00.png

Теперь нам нужен адрес контракта и интерфейс. Ими мы проинициализируем переменные в коде приложения, которое крутится на Raspberry Pi.

1469091481_152f_json-interface.thumb.png.6af6b8df2ee7b31f5e0bd596ed8fc60c.png

Теперь в созданном контракте ты можешь изменять значение переменной state и пересылать на его адрес эфир, а «Малинка» будет за этим следить и реагировать так, как ты ее запрограммировал.

1469091493_11e6_eth-thing.thumb.png.5f122029caef0119dbde3ca9a87d8500.png

На этом все. Как видишь, перед тобой теперь огромное поле для экспериментов!

 

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...