Python create ethereum wallet

Сетевой протокол Ethereum с нуля. Часть первая. Соединение

В этой статье мы разберемся в основных концепциях работы сети Ethereum и напишем Python-скрипт для ее пингования.

Ethereum — это криптовалюта, где код может исполняться посредством блокчейна. Эта возможность позволяет создавать «умные контракты», которые будут выполняться автоматически. Давайте разберемся, как работают «умные контракты» и протокол Ethereum в целом.

Предполагается, что у читателя есть базовое понимание Python, Git и сетевых концепций, таких как TCP и UDP.

Концепция криптовалюты

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

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

Настройка среды разработки

Все нижеприведенные действия производились на Amazon Linux и должны быть осуществимы на OS X и большинстве дистрибудивов Linux.

Intel , Нижний Новгород, можно удалённо , По итогам собеседования

Давайте создадим виртуальную среду для этого проекта:

Виртуальная среда не позволит произойти конфликту модулей Python.

Для активации виртуального окружения запустите команду:

Это приведет к изменению некоторых переменных среды. Теперь Python будет использовать пакеты только из виртуальной среды, pip будет ставить пакеты только туда.

Вы можете убедиться, что все сработало, проверив путь к среде:

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

Это довольно удобно использовать при работе над проектом.

Примечание Используемая версия Python 2.7.12 не гарантирует, что все будет работать с другим версиями.

Версию можно проверить командой:

Последнее, что нужно сделать — создать пакетный скелет с библиотекой pipiecutter:

Будем использовать minimal skeleton , который позволяет производить публикацию в pip и выполнять тестирование:

Вам потребуется ответить на некоторые вопросы для настройки проекта. Назовем проект pyethtutorial . После этого вы можете настроить Git для его отслеживания.

Также давайте установим пакет nose . Он понадобится для тестирования:

Теперь давайте проверим, что все работает. В pyethtutorial/tests есть один тест, который поможет нам в этом убедиться:

Для запуска всех тестов используйте команду nosetests в каталоге проекта:

Все работает. Идем дальше.

Реализация

Нам нужно выяснить, как общаться с другими узлами сети.
Вот отрывок из документации по протоколу Ethereum:

Одноранговая связь между узлами, на которых запущенны клиенты Ethereum, выполняется с использованием протокола devp2p.

Узлы devp2p обмениваются сообщениями с использованием RLPx — транспортного протокола, использующего шифрование. Одноранговые узлы могут предлагать и принимать соединения на любых TCP-портах, однако по умолчанию порт, на котором может быть установлено соединение, будет 30303.

Узлы devp2p находят соседние узлы с помощью протокола обнаружения DHT.

Таким образом по умолчанию мы отправляем пакеты через порт 30303, используя протокол RLPx. Протокол devp2p имеет два разных режима: основной, который использует TCP, и режим обнаружения, который использует UDP. UDP работает таким образом: вы подключаетесь к определенным серверам, называемыми «узлами начальной загрузки» (для BitTorrent это router.bittorrent.com и router.utorrent.com), которые предоставляют вам небольшой список одноранговых узлов для подключения. После получения списка узлов вы можете подключиться к ним. Сервера в свою очередь будут делиться своими списками узлов с вами. Это будет продолжаться до тех пор, пока у вас не будет полного списка узлов в сети.

Звучит достаточно просто, но давайте сделаем это еще проще. В спецификации RLPx есть раздел «Обнаружение узла». В нем описано, как сообщения отправляются через UPD порт 30303, задавая следующую структуру пакетов:

Читайте также:  Для чайников с чего начать инвестировать

И различные типы пакетов:

Типы сообщений представлены C-подобными структурами данных. Самое простое, что мы можем сделать сейчас — это реализовать пакет PingNode , который состоит из объекта version , двух объектов EndPoint и timestamp . Объекты EndPoint состоят из IP-адреса и двух целых чисел, представляющих порты UDP и TCP соответственно.

Чтобы отправить пакеты на аппаратный интерфейс, они кодируются по стандарту RLP. В документации говорится:

Функция кодирования RLP принимает элемент. Элемент определяется следующим образом:
Строка (то есть массив байтов) является элементом.
Список элементов — это элемент.

Кодирование RLP определяется следующим образом:
Для одного байта, значение которого находится в диапазоне [0x00, 0x7f], этот байт является его собственной RLP-кодировкой.
В противном случае, если длина строки составляет 0-55 байт, кодировка RLP состоит из одного байта со значением 0x80 плюс длина строки, за которой следует строка. Таким образом, диапазон первого байта [0x80, 0xb7].
Если длина строки больше 55 байтов, то RLP-кодировка состоит из одного байта со значением 0xb7 плюс длина в строки в двоичной форме, за которой следует длина строки, за которой следует строка. Например, строка длиной 1024 будет кодироваться как \ xb9 \ x04 \ x00, за которой следует строка. Таким образом, диапазон первого байта равен [0xb8, 0xbf].
Если общая полезная нагрузка списка (т. е. длина всех элементов) составляет 0-55 байт, то RLP-кодирование состоит из одного байта со значением 0xc0 плюс длина списка, за которым следует последовательность RLP-кодировок каждого элемента. Таким образом, диапазон первого байта [0xc0, 0xf7].
Если общая полезная нагрузка списка составляет более 55 байтов, то RLP-кодирование состоит из одного байта со значением 0xf7 плюс длина полезной нагрузки в двоичной форме, за которой следует длина полезной нагрузки, за которой следует последовательность RLP-кодировок объектов. Таким образом, диапазон первого байта [0xf8, 0xff].

Прежде чем что-либо можно будет закодировать в RLP, нужно преобразовать структуру в «элемент»: либо строку, либо список элементов (определение является рекурсивным). Как сказано в документации, RLP просто кодирует «структуру» и оставляет интерпретацию байтов содержимого протоколу более высокого порядка.

Начнем реализацию самого протокола. Будем использовать библиотеку rlp для RLP-кодирования и декодирования. Для установки используем pip install rlp .

У нас есть все необходимое для отправки пакета PingNode . Далее мы создадим PingNode , упакуем его и отправим. Чтобы упаковать данные, мы начнем с RLP-кодирования структуры, потом добавим байт, чтобы обозначить тип структуры, добавим криптографическую подпись и, наконец, добавим хеш для проверки целостности пакета. Приступим.

Первый класс — это класс EndPoint . Ожидается, что порты будут целыми числами и адрес будет находиться в формате 127.0.0.1. Адрес передается в библиотеку ipaddress , поэтому мы можем использовать его служебные функции, например, преобразование представления с точками в двоичный формат, что и происходит в методе pack . Для установки этого пакета используйте pip install ipaddress . Метод pack подготавливает объект, который будет использоваться rlp.encode , преобразуя его в список строк. Для портов на странице спецификации RLP сказано: «Целые числа Ethereum должны быть представлены в бинарной форме», а спецификация Endpoint перечисляет их типы данных как uint16_t или беззнаковые 16-битные целые числа. Таким образом, используется метод struck.pack с строкой формата >H , что означает «big-endian unsigned 16-bit integer».

Следующий класс — это PingNode . Вместо того, чтобы задавать значения позже, введем исходные байтовые значения для packet_type и version . Для метода pack мы можем использовать исходное значение версии, так как оно уже находится в байтах. Для адресов будем использовать struct.pack со строкой формата >I . Также добавим 60 к отметке времени, чтобы дать дополнительные 60 секунд и пакет успел прибыть в пункт назначения. (В документации сказано, что пакеты с устаревшей временной меткой не обрабатываются.)

Последний класс — PingServer . Этот класс открывает сокеты, подписывает, хеширует сообщения и отправляет их на другие серверы. Конструктор принимает объект EndPoint . Далее при создании сервера загружается секретный ключ, который мы должны инициализировать.

Ethreum использует систему асимметричного шифрования, основанную на эллиптических кривых secp256k1 . Для реализации понадобится библиотека secp256k1-py . Установим pip install secp256k1 .

Чтобы сгенерировать ключ, вызовем конструктор Private Key с None в качестве аргумента, а затем запишем вывод функции serialized() в файл:

Читайте также:  Тарков биткоин что делать

Помещаем файл в каталог с проектом. Не забудьте добавить его в .gitignore , если вы используете Git, чтобы случайно его не опубликовать.

Метод wrap_packet кодирует пакет: hash || signature || packet-type || packet-data

Первое, что нужно сделать, — добавить тип пакета в RLP-код пакетных данных. Затем хэшированная полезная нагрузка подписывается с помощью функции ecdsa_sign_recoverable и ключа. Параметр raw установлен в значение True , потому что мы сами сделали хеширование (иначе функция использовала бы собственную хеш-функцию). Затем мы обрабатываем подпись и добавляем ее перед полезной нагрузкой. Наконец, вся полезная нагрузка хэшируется, и этот хэш добавляется в пакет. Теперь пакет готов к отправке.

Возможно, вы заметили, что мы еще не определили функцию keccak256 . Ethereum использует нестандартный алгоритм sha3 , называемый keccak-256 . Библиотека pysha3 реализует ее. Используйте pip install pysha3 для установки.

В pyethtutorial/crypto.py мы определяем keccak256 :

Вернемся к PingServer . Следующая функция udp_listen обрабатывает входящие передачи. Она создает объект сокета, который привязывается к UDP-порту сервера. Затем определяется функция receive_ping , которая принимает входящие данные, выводит их и возвращает объект Thread , который будет запускать get_ping , поэтому мы можем отправлять пинги одновременно с приемом входящих данных.

Последний метод ping создает объект PingNode , формирует сообщение с помощью wrap_packet и отправляет его с использованием UDP.

Теперь мы можем настроить скрипт, который будет отправлять некоторые пакеты.

Запустим код и получим следующий вывод:

Мы успешно запинговали самих себя.

Пытаемся пинговать соседний узел

Хорошими кандидатами для приема наших сообщений будут те самые узлы начальной загрузки. В документации сказано:

Чтобы начать работу, geth использует узлы начальной загрузки, адреса которых записаны в исходном коде.

Geth — это Ethereum-клиент, реализованный на Go. В этом репозитории файл /bootnodes.go содержит списки узлов начальной загрузки в специальном формате:

Ниже перечислены основные узлы сети:

Для примера используется узел US-WEST, но вы можете использовать любой из этого списка. Например, ближайший к вам.

Сейчас send_ping.py выглядит так:

Давайте проверим, что выйдет:

Ждет ответа, но его нет. Разберемся, что пошло не так.

Решение

Оказывается, что Ethereum использует адрес возврата из заголовка UPD, а не тот, который мы ему передаем в PingNode .

53042 — это порт из заголовка UDP. Сокет отправляет пакет с этим заголовком, потому что он не привязан к какому-либо порту заранее. Ниже в комментариях отмечены проблемы с PingServer :

Проблема в том, что udp_listen и ping используют разные сокеты (созданные на строках 3 и 15), а тот, который используется ping , не привязан к порту 30303, поэтому он использует произвольный порт.

Чтобы исправить это, нужно переопределить порт в методе __init__ на сервере. Окончательный результат выглядит примерно так:

Сокет инициализирован в __init__ и указан в udp_listen и ping .

Теперь попробуем запустить send_ping.py :

Мы получили сообщение от узла начальной загрузки! Отлично.

Источник

Ethereum + Python = Brownie

Салют, дорогой криптоэнтузиаст!

Сегодня речь пойдёт о Brownie — аналоге фреймворка Truffle, который часто используется для разработки умных контрактов на Solidity, их тестирования и развёртывания (о чём можно почитать в цикле соответствующих статей здесь).

Так зачем же нужен ещё один фреймворк и в чём его ключевое отличие от Truffle?

  • Во-первых, в них используются разные языки — в то время, как Truffle опирается на JS, не все знают этот язык и не всем его комфортно использовать; в brownie же в используется Python 3.
  • Во-вторых, brownie за счёт интеграций различного софта делает разработку удобнее: тут и менеджер пакетов ethpm для умных контрактов, и ganache для развёртывания локальной тестовой цепочки, и тесты через pytest, и все версии компиляторов solc, и даже биндинги к MythX — инструменту для автоматического поиска ошибок в умных контрактах,- иначе говоря brownie предлагает инструменты для всего цикла разработки. Конечно Truffle тоже позволяет использовать все эти инструменты, однако они не встроены во фреймворк и их приходится устанавливать дополнительно.
  • В-третьих, brownie позволяет работать не только с умными контрактами на Solidity, но и на vyper — типизированном python-based для разработки умных контрактов.

Таким образом, если вы предпочитаете работать с пайтоном и хотите упростить себе разработку умных контрактов, то однозначно стоит попробовать brownie.

Читайте также:  Биржа криптовалют binance как работает

Что же ещё умеет brownie?
Как сказано в самом репозитории brownie — это фреймворк разработки полного цикла умных контрактов для Ethereum-based платформ, поддерживающий:

  • Несколько языков программирования умных контрактов: Solidity и Vyper.
  • Сборку контрактов.
  • Интерактивное взаимодействие с контрактами.
  • Тестирование умных контрактов с помощью pytest.
  • Скрипты для взаимодействия с умными контрактами.
  • Работу с шаблонами умных контрактов.

Рассмотрим все эти возможности и организацию проекта на brownie подробнее, для чего установим brownie себе на машину. Сделать это проще всего можно с помощью pip:

pip install eth-brownie

Теперь brownie доступен как консольная утилита.

Проект brownie

Проект brownie представляет из себя определённую структуру директорий и конфигурационный файл brownie-config.yaml . Создать проект можно либо с помощью команды brownie init

либо можно создать проект на основе шаблона с помощью команды brownie bake template_name

Далее я рассмотрю второй вариант на основе шаблона для ERC-20 токена (шаблон token).
Рассмотрим структуру проекта:

Стоит отметить, что помимо перечисленных директорий brownie имеет конфигурационный файл, который находится в корне проекта и называется brownie-config.yaml — в нём можно указать опции компилятора, данные для подключения к ноде или параметры тестирования.

Команды brownie

brownie даже в базовой комплектации имеет множество команд, но я рассмотрю четыре из них, которые значительно чаще прочих используются в производственном цикле: compile , console , test и run .

brownie compile

Данная команда используется для компиляции умных контрактов, которые расположены в директории проекта contracts или её поддиректориях. Если необходимо, чтобы часть контрактов не компилировалась как самостоятельные единицы, то к названию файла или директории стоит приписать слева символ нижнего подчёркивания «_»,- в таком случае компилятор brownie будет их игнорировать (это полезно при подключении библиотек к проекту).

Собранные контракты помещаются в ./build/contracts/ в виде одноимённых json-файлов, которые содержат ABI контрактов, их байт-код и дополнительную мета-информацию.

При компиляции brownie запоминает, какие контракты были скомпилированы, а какие ещё нет и компилирует только их. Но если нужно перекомпилировать все контракты, то можно сделать это добавив флаг -all .

Параметры компиляции, такие как версия компилятора или оптимизация кода, задаются в файле brownie-config.yaml

brownie test

Этой командой запускаются тесты в проекте с использованием pytest, однако стоит заметить, что команда не возвращает никакое значение, поэтому есть трудности с интеграцией тестов в CI/CD.

Тесты в проекте хранятся в директории tests/

brownie run

С помощью данной команды осуществляется запуск скриптов из директории scripts. Однако передача параметров в них поддерживается только с версии brownie 2.x, но даже без них удобно использовать данный функционал для интеграции с CI/CD (например для деплоя контрактов).

brownie console

Запускает интерактивный режим brownie: по сути он является интерпретатором установленной версии питона, но с заранее импортированными пространствами имён для проекта. Например для проекта токена мы имеем следующие переменные сразу после запуска:

Информацию о их назначении можно найти в документации brownie, однако подавляющая часть имён имеет то же предназначение, что и в web3py.

Работа с майнетом/тестнетами

Во всех примерах выше brownie поднимал ganache (локальное тестовое окружение Ethereum) и работал с ним, однако есть возможность работы с произвольной выбранной сетью (в том числе с приватным тестнетом и даже с Quorum!). Для этого используется параметр —network network_name при выполнении команд console и run, где network_name должна быть описана в brownie-config.yaml. По умолчанию там уже заданы майнеты ETH и ETC, а также локальный и публичные тестнеты. Однако можно добавлять свои сети в том числе добавляя в их свойства свои собственные параметры, если yaml позволяет это сделать. Обычно я при работе создаю дополнительно сети develop, test и master (по названиям веток в гите), а их блокчейны разворачиваю в Azure с помощью специальной службы.

Подводя итог можно сказать, что brownie на текущий момент уже достаточно зрелое Enterpise-ready решение для разработки под Ethereum и способен удовлетворить практически все возникающие в её процессе потребности. Питонистам и не только однозначно стоит попробовать сделать на нём свой следующий проект.

Источник

Оцените статью