Узнайте, насколько легко можно взаимодействовать с блокчейном с помощью библиотеки.

Вступление

В своей прошлой статье я писал о вызове смарт-контракта, развернутого на блокчейне, из Java с помощью Eclipse. Пришло время перейти на мобильные устройства! В этом руководстве показано, как вызывать смарт-контракты прямо из среды разработки Android - Android Studio.

Требования

Мы собираемся использовать блокчейн Tezos. А чтобы заставить наш код Android Java взаимодействовать с существующим развернутым смарт-контрактом, нам понадобится библиотека TezosJ от TezosRio . Существует две версии этой библиотеки: одна написана специально для общих приложений Java, созданных с помощью Eclipse IDE (TezosJ_plainJava), а другая предназначена для разработки приложений для Android (TezosJ_SDK), которые мы собираемся использовать. здесь. Нет необходимости загружать весь исходный код библиотеки. Нам просто нужно вставить одну строку в раздел dependencies нашего файла build.gradle и voilà, мы готовы к работе. В качестве нашей IDE для разработки лучшим выбором будет Android Studio.

Цель

Контракт, который мы собираемся назвать, представляет собой простой реестр базы клиентов, который можно найти в тестовой сети Tezos по следующему адресу:

KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t

Вы можете легко проверить детали контракта через один из обозревателей блоков Tezos, например, Tezblock. Или с помощью инструмента better-call.dev. Еще один вариант - проверить договор с SmartPy explorer. Не забудьте указать сервер testnet, например https://tezos-dev.cryptonomic-infra.tech.

Наш смарт-контракт называется «Клиенты» и имеет четыре точки входа (или метода): addCustomer, removeCustomer, transfer и updateBalance. В основном вставляйте, удаляйте, переводите средства и обновляйте. Ничего особенного. Это было создано только в образовательных целях. Что он делает, так это поддерживает список «клиентов» в хранилище блокчейна Tezos.

Звонок

TezosJ, вероятно, является одним из самых простых способов вызова смарт-контракта Tezos, доступных в настоящее время. По сути, наш вызов может быть выполнен с помощью одной команды:

JSONObject jsonObject = wallet.callContractEntryPoint(wallet.getPublicKeyHash(), "KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t", amount, fee, "", "", "addCustomer", new String[]{"1000000", "123456789","Bob","98769985"});

Приведенный выше код добавляет нового клиента в базу, Боба, с балансом 10 центов, 123456789 в качестве идентификатора и 98769985 в качестве номера телефона. Это делается путем вызова метода callContractEntryPoint, который в основном требует тех же параметров, что и обычный метод Tezos .send (), но имеет некоторые дополнения: имя точки входа в контракт и String Массив, содержащий параметры ожидаемой точки входа (которые должны быть известны перед вызовом).

Пожалуйста, пошагово!

Если вы еще этого не сделали, скачайте и установите Android Studio. Открой это. Первый шаг - создать новый проект Android Studio, например:

Выберите Телефон и планшет в качестве типа проекта, затем нажмите Пустое действие:

Назовите свой проект smartContractCall и измените Язык на Java. Затем нажмите Готово:

Первое, что нам нужно сделать, это удалить android: allowBackup = ”true” из тега приложения в файле AndroidManifest.xml. Это очень важно, и если мы пропустим этот шаг, TezosJ_SDK не будет работать:

Пришло время добавить TezosJ_SDK в наш проект. Откройте файл build.gradle (Module: app). Перейдите в раздел зависимости и добавьте: реализацию ‘com.milfont.tezos: tezosj_android: 0.9.998’. Затем нажмите Синхронизировать сейчас (в правом верхнем углу окна):

Что касается конфигурации, мы почти закончили. Последний шаг - изменить minSdkVersion на 26 в том же файле. Затем снова Sync:

Все сделано! А теперь, когда у нас все подготовлено, давайте сначала создадим кошелек Tezos. В файле MainActivity метод onCreate поместите объявление, как показано ниже (не забудьте блок try-catch):

Теперь добавьте вывод Logcat, чтобы проверить, успешно ли создается наш кошелек. Мы собираемся распечатать некоторую информацию о нем: хэш открытого ключа кошелька (адрес Tezos), его мнемонические слова и текущий баланс:

После добавления команд Log.i () запустите проект, и вы получите что-то вроде этого (проверьте Logcat):

Мы смогли сгенерировать новый кошелек и получить его мнемонические слова. Но у нас произошла ошибка при попытке получить баланс кошелька из блокчейна. Это потому, что мы пытались получить доступ к Интернету напрямую в классе MainActivity, что запрещено в среде Android. Для этого урока давайте просто воспользуемся небольшим обходным путем. Поместите метод ниже в свой класс MainActivity:

public void enableStrictMode()
{
   StrictMode.ThreadPolicy policy = new     
   StrictMode.ThreadPolicy.Builder().permitAll().build();
   StrictMode.setThreadPolicy(policy);
}

И вызовите его из метода onCreate:

enableStrictMode();

Здесь строгий режим используется только в иллюстративных целях. Не рекомендуется напрямую выходить в Интернет через класс MainActivity (сделайте это в новом потоке):

Запустите проект еще раз, и теперь все будет работать правильно, и вы сможете правильно увидеть баланс кошелька в Logcat:

Ok! Теперь у нас есть работающий кошелек Tezos, и мы можем выполнять вызов смарт-контракта клиентов Tezos.

Немного о контракте

Смарт-контракт Клиенты, который мы собираемся использовать, был создан и развернут в тестовой сети блокчейна Tezos с использованием онлайн-среды IDE SmartPy.io. Проверьте исходный код контракта ниже:

# Imports the SmartPy library.
import smartpy as sp# Defines the Customer class and its constructor.
class Customer(sp.Contract):
    def __init__(self):
        self.init(customers = sp.map())
        
    # Defines the addCustomer entry point.
    @sp.entry_point
    def addCustomer(self, params):
        # Verifies if mandatory fields have values. 
        sp.verify(params.id != "")
        sp.verify(params.name != "")
        sp.verify(params.phoneNumber > 0)
        # Declare the parameter types.
        sp.set_type(params.id, sp.TString)
        sp.set_type(params.name, sp.TString)
        sp.set_type(params.phoneNumber, sp.TNat)
        sp.set_type(params.balance, sp.TMutez)
        
        # Defines a customer record, so we can add to a Map.
        customer = sp.record(name=params.name, phoneNumber=params.phoneNumber, balance=params.balance)
        
        # Adds the new customer record to a Map (that will reside in the contract's storage).
        self.data.customers[params.id] = customer
    # Defines the removeCustomer entry point.
    @sp.entry_point
    def removeCustomer(self, params):
        # Verifies if mandatory fields have values. 
        sp.verify(params.id != "")
        # Declare the parameter types.
        sp.set_type(params.id, sp.TString)
        # Remove the customer from the Map.
        del self.data.customers[params.id]
    # Defines the updateBalance entry point.
    @sp.entry_point
    def updateBalance(self, params):
        # Verifies if mandatory fields have values. 
        sp.verify(params.id != "")
        # Declare the parameter types.
        sp.set_type(params.id, sp.TString)
        sp.set_type(params.amount, sp.TMutez)
        # Updates the balance.
        self.data.customers[params.id].balance = params.amount
    
    # Defines the transfer entry point.
    @sp.entry_point
    def transfer(self, params):
        # Verifies if mandatory fields have values. 
        sp.verify(params.idFrom != "")
        sp.verify(params.idTo != "")
        sp.verify(params.amount > sp.mutez(0) )
        # Verifies if customer has enough funds to be transfered.
        sp.verify(params.amount <= self.data.customers[params.idFrom].balance )
        # Declare the parameter types.
        sp.set_type(params.idFrom, sp.TString)
        sp.set_type(params.idTo, sp.TString)
        sp.set_type(params.amount, sp.TMutez)
        # Updates the balance.
        self.data.customers[params.idFrom].balance = self.data.customers[params.idFrom].balance - params.amount
        self.data.customers[params.idTo].balance = self.data.customers[params.idTo].balance + params.amount
# Creates the test scenario, to simulate a contract call in SmartPy.io IDE.
    @sp.add_test(name = "Customers")
    def test():
        # Instantiate a contract inherited from the Customer Class.
        myCustomersContract = Customer()
        
        # Defines a test scenario.
        scenario = sp.test_scenario()
        
        # Adds the contract to the test scenario.
        scenario += myCustomersContract
        
        # Inserts the customers, calling the contract's addCustomer entry point.
        # This customers will reside in the contract's storage.
        scenario += myCustomersContract.addCustomer(id="123456",name="Daniel",phoneNumber=99984537,balance=sp.mutez(0))
        scenario += myCustomersContract.addCustomer(id="345678",name="Eleonor",phoneNumber=85375677,balance=sp.mutez(0))
        scenario += myCustomersContract.addCustomer(id="678905",name="Fabian",phoneNumber=78655567,balance=sp.mutez(0))
        # Removes a customer through its id number.
        scenario += myCustomersContract.removeCustomer(id="678905")
        
        # Updates a customer's balance.
        scenario += myCustomersContract.updateBalance(id="123456",amount=sp.mutez(10000000))
        # Transfers funds from a customer to another.
        scenario += myCustomersContract.transfer(idFrom="123456", idTo="345678", amount=sp.mutez(5000000))

Исходный код контракта SmartPy был показан здесь только в иллюстративных целях, и нам не нужно компилировать и развертывать его снова. Он уже находится в тестовой сети блокчейна Tezos по адресу:

KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t

И… Действие!

Теперь у нас есть все, что нужно для вызова контракта с Android. Во-первых, мы собираемся добавить нового клиента, используя точку входа «addCustomer» в контракте. Давайте рассмотрим имя клиента «Боб», его идентификатор «98765» и номер телефона «99876787». У Боба будет баланс 10ꜩ (10.000.000 мутезов). Итак, наша команда вызова контракта будет такой:

JSONObject jsonObject = wallet.callContractEntryPoint(wallet.getPublicKeyHash(), "KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t", amount, fee, "", "", "addCustomer", new String[]{"1000000", "98765","Bob","99876787"});

Прежде всего, нам нужно сообщить TezosJ, что мы будем использовать тестовую сеть Tezos (где фактически публикуется контракт). Также нам нужно указать сумму транзакции и комиссию. Это делается с помощью кода Java ниже:

// Change wallet provider to use testnet.
 wallet.setProvider(“https://tezos-dev.cryptonomic-infra.tech"); 
 
 // Sets amount and fee for the transaction.
 BigDecimal amount = new BigDecimal(“0”);
 BigDecimal fee = new BigDecimal(“0.1”);
 
 // Calls the contract entry point.
 JSONObject jsonObject = wallet.callContractEntryPoint(wallet.getPublicKeyHash(), “KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t”, amount, fee, “”, “”, “addCustomer”, new String[]{“1000000”, “98765”,”Bob”,”99876787"}); 
 // Prints the operation hash in the console.
 String opHash = (String) jsonObject.get("result");
 Log.i("output", "OpHash : " + opHash);

Скопируйте код и вставьте его в наш класс MainActivity, чтобы он оставался таким:

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

There were errors: kind ‘branch’ id ‘proto.005-PsBabyM1.implicit.empty_implicit_contract’

Запускаем проект! Если все было настроено нормально, в результате вы получите хэш транзакции (здесь onuvzSRu9GiUBtPxEVf958jPUkG8NTxo7UHCYvFXKB8Chtci3Jm), показанный в LogCat:

Это означает, что мы успешно отправили транзакцию callContract в блокчейн тестовой сети Tezos (поскольку у нас есть хэш операции). Теперь давайте проверим, была ли транзакция принята блокчейном Tezos. Для этого мы воспользуемся проводником TezBlock. Откройте https://tezblock.io в предпочитаемом вами браузере и, прежде всего, в правом верхнем углу экрана смените mainnet на balylonnet (то же самое с тестовой сетью). Затем вставьте хэш операции, полученный в результате выполнения Java, в поле поиска и нажмите клавишу Ввод:

Это покажет результаты нашего вызова контракта с деталями операции. Нажав «показать», вы сможете проверить параметры, которые были переданы из нашего кода Java в цепочку блоков Tezos:

Параметры:

Left (Left (Left (Pair (Pair (Pair 1000000 "98765") "Bob") 99876787)))

Это параметры в формате Micheline, которые сгенерировал наш вызов из приложения Android. Смарт-контракты Tezos при развертывании написаны на языке Майкельсона, и они ожидают, что параметры ввода будут отправлены в этом формате. Одним из преимуществ использования библиотеки TezosJ является то, что она генерирует параметры в формате Micheline на лету, и вам не нужно беспокоиться о том, как это делается.

Le Grand Finale

Теперь мы можем гарантировать, что контракт был правильно вызван, параметры были переданы и операция была принята блокчейном Tezos. Теперь последнее, что нам нужно сделать, это проверить, был ли новый клиент, Боб, помещен в хранилище контракта. Для этого воспользуемся инструментом better-call.dev. Просто откройте свой браузер и укажите его на https://better-call.dev. Введите адрес нашего клиентского договора (KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t) в поле поиска, измените сеть на babylonnet и нажмите ввод:

Результатом будет список всех операций, когда-либо отправленных на адрес контракта, а также текущее состояние хранилища контракта. Здесь вы сможете проверить параметры, которые вы передали с Java, и правильно ли они сохранены в хранилище:

Идти дальше

Вы можете попробовать другие точки входа в контракт, такие как removeCustomer, transfer и updateBalance. Не забывайте всегда проверять количество параметров, необходимых для каждой точки входа.

Если при запуске кода вы получите ошибку Java, это означает, что транзакция не была отправлена. В этом случае вам необходимо повторно проверить свои параметры, порядок, баланс вашего счета, комиссию и сеть (основная или тестовая), в которой вы работаете. Также проверьте параметры gasLimit и storageLimit.

С другой стороны, если вы когда-нибудь получите хэш операции, это означает, что ваше приложение Android успешно отправило транзакцию в цепочку блоков. Но, тем не менее, вы должны проверить возможные ошибки, связанные с блокчейном. В этом случае, когда вы проверяете с помощью TezBlock explorer, он покажет ошибки с фоном цвета лосося, что означает, что в контексте блокчейна произошло что-то не так (например, неправильное количество переданных параметров, неправильное форматирование параметра Micheline или даже контракт неприемлемых условий - например, : вы позвонили в точку входа перевода, но у «от» клиента недостаточно средств для отправки).

Заключение

Разработчикам еще никогда не было так просто работать со смарт-контрактами на блокчейне. Tezos, в частности, предлагает множество отличных инструментов и огромное количество библиотек компьютерных языков, которые облегчают интеграцию с большинством систем. Библиотека TezosJ является новаторской, предлагая простой в использовании метод callContractEntryPoint, который на лету создает параметры в формате Micheline. В нем есть все инструменты, необходимые разработчикам Android для успешной разработки приложений, которые беспрепятственно взаимодействуют с блокчейном.

Скачать полный код

Вы можете скачать здесь полный проект Android Studio, представленный в этой статье.