LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 新闻观点 > 使用Java与区块链智能合约进行交互

使用Java与区块链智能合约进行交互

2020-02-08 区块链研究实验室 来源:区块链网络

本文是一个非常实用的分步教程,其目的是向Java开发人员(特别是)展示一种非常简单的与区块链智能合约进行交互的方式。了解使用库与区块链进行交互的难易程度。

环境要求

我们将使用Tezos区块链。为了使我们的Java代码与现有的、部署的智能合同交互,我们需要来自TezosRio的TeZOSJ库。 该库有两个版本,一个是专门为Android应用程序开发编写的版本(TezosJ_SDK),另一个是为使用Eclipse IDE编写的通用Java应用程序(TezosJ_plainJava)编写的,我们将在这里使用。 无需下载整个库源代码。 仅v1.1.0 JAR文件就足够了。 作为我们的开发IDE,Eclipse将是首选。

文章目标

我们要调用的智能合约是一个简单的客户基本注册,可以在Tezos testnet上找到,地址如下:KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t

您可以通过Tezblock之类的Tezos区块浏览器之一轻松查看智能合约的详细信息。或通过使用Better-call.dev工具。 还有另一种选择是与SmartPy资源管理器检查智能合约。请记住,记住,要指定一个测试网服务器,例如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"});

上面的代码将一个新客户Bob的余额加为10?,其ID为123456789,电话号码为98769985,从而为该客户添加了一个新客户。这是通过调用callContractEntryPoint方法完成的,该方法基本上需要与普通的Tezos .send()方法相同的参数,但具有一些额外的功能:智能合约入口点名称和包含预期入口点参数的String Array

请一步一步来!

如果您还没有完成,请下载并安装Eclipse。打开它。第一步是创建一个新项目,选择File->new->project选项,如下所示:

下一步是选择项目类型:选择Gradle Project:

将新项目的名称设置为“ callSmartContract”,然后单击“完成”按钮。等待Eclipse构建项目文件结构。现在,我们将创建一个Main类,以便我们可以运行和测试项目。右键单击项目名称“ SmartContract”,然后选择New->Class:

然后,指定“Main”作为新类的名称,并确保选中“public void static Main(String args[])”创建框。然后单击“完成”按钮:

您会注意到Main类已创建。右键单击Main class,然后选择Run as-> Java Application。 这只是为了配置从现在开始单击play按钮时项目的运行方式:

在控制台中,您将看到项目已成功运行,但是当然还没有任何反应。因此,您将看到“terminated”消息:

现在我们将添加TezosJ库JAR文件。 转到Tezos.Rio github存储库并下载文件tezosj-sdk-plain-java-1.1.0.jar

在文件浏览器上,复制tezosj-sdk-plain-java-1.1.0.jar文件(CTRL + C)。

回到Eclipse,单击项目名称,然后使用CTRL + V粘贴。

该文件将显示为已添加到项目结构中:

下一步是将JAR添加到项目的构建路径中。右键单击项目浏览器中的库文件,然后选择选项 Build Path-> Add to Build Path (or Build Path -> Configure Build Path):

选择库文件,然后单击“应用并关闭”按钮:

现在我们已经准备好一切,让我们首先构建一个Tezos钱包:

上方(左侧)的红色“ X”提醒我们,需要导入类,才能使我们的代码了解什么是TezosWallet:

现在添加一些控制台输出,以检查是否成功创建了我们的钱包。 我们将打印有关此信息:钱包的公钥哈希(Tezos地址),其助记词和当前余额。 添加System.out.println命令后,运行项目,您将获得类似以下内容(检查控制台):

好! 我们有一个功能齐全的Tezos钱包。现在我们可以调用客户Tezos智能合约了。

关于智能合约的一点事....

我们将使用SmartPy.io在线IDE在Tezos区块链测试网上创建并部署了我们将要使用的客户智能合约。检查下面的智能合约源代码:

#?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.
[email protected]_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.
[email protected]_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.
[email protected]_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.
[email protected]_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.
[email protected]_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

现在我们拥有从Java调用合同所需的一切。首先我们将使用智能合约的“ addCustomer”入口点添加新客户。让我们考虑客户的名字“Bob”,他的ID将是“ 98765”,电话号码是“ 99876787”。 Bob的余额为10英镑(1000万个mutez)。 因此,我们的智能合约调用命令将如下所示:

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

首先,我们需要通知TezosJ我们将使用TezosTestNet(智能合约实际发布的地方)。我们还需要设定交易金额和费用。这是用下面的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");
?System.out.println("OpHash?:?"?+?opHash);

复制代码并将其粘贴到我们的Main类中,使其保持如下所示:

请注意,要使此调用正常工作,您首先需要注资并显示您的Tezos帐户。 否则,您可能会收到如下错误:

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

运行项目! 如果一切正常,您将获得控制台中显示的操作哈希:

这表明我们已成功将callContract事务发送到Tezos testnet区块链(因为我们有一个操作哈希)。 现在让我们检查交易是否被Tezos区块链接受。我们将使用TezBlock资源管理器执行此操作。在您喜欢的浏览器中打开https://tezblock.io,首先,在屏幕的右上角,将“ mainnet”更改为“ balylonnet”(与testnet相同)。 然后,将从Java执行中获得的操作哈希值粘贴到搜索框中,然后按“ enter”键:

这将显示我们智能合约的结果以及操作细节。通过单击“display”,您将能够检查从我们的Java代码传递到Tezos区块链的参数:

参数:

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

这是我们从Java应用程序调用生成的Micheline格式的参数。部署时,Tezos智能合约以Michelson 语言编写,它们期望以这种格式发送的输入参数。使用TezosJ库的好处之一是它可以实时生成Micheline格式的参数,而您不必担心它是如何完成的。

到目前为止,我们可以确保正确调用了智能合约,传递了参数并且操作已被Tezos区块链接受。现在我们要做的最后一件事是检查是否将新客户Bob插入了智能合约的存储中。为此,我们将使用Better-call.dev工具。 只需打开浏览器并将其指向https://better-call.dev。 在搜索字段中输入我们的客户智能合约的地址(KT18pK2MGrnTZqyTafUe1sWp2ubJ75eYT86t),将网络更改为babylonnet,然后按Enter:

果将是曾经发送到智能合约地址的所有操作的列表以及智能合约存储的当前状态。您将在此处检查从Java传递过来的参数,以及它们是否正确保存在存储器中:

更进一步

您可以尝试智能合约的其他入口点,例如removeCustomer,transfer和updateBalance。切记始终检查每个入口点所需的参数数量。

运行代码时,如果遇到Java错误,则表示未发送事务。在这种情况下,您必须重新检查参数,其顺序,帐户余额,费用以及您正在使用的网络(主网或测试网)。此外另一方面,如果您曾经获得过操作哈希,则意味着您的Java应用程序已成功将交易发送到了区块链。但是,您还必须检查可能的与区块链相关的错误。在这种情况下,当您使用TezBlock Explorer进行检查时,它将显示带有鲑鱼色背景的错误,这意味着在区块链上下文中发生了错误(例如,传递的参数数量错误,参数Micheline格式错误,甚至合同未接受的条件-例如:您调用了转移入口点,但“发件人”客户没有足够的资金可发送)。还要检查gasLimit和storageLimit参数。

结论

开发人员使用区块链智能合约从未如此简单。特别是Tezos,提供了许多出色的工具和无数的计算机语言库,可促进与大多数系统的集成。TezosJ库通过提供一种易于使用的callContractEntryPoint方法进行创新,该方法可以即时创建Micheline格式的参数。它具有Java开发人员在与区块链无缝交互的应用程序开发中蓬勃发展所需的所有工具。


—-

编译者/作者:区块链研究实验室

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...