主页 > 下载imtoken钱包地址 > java和android如何使用web3j开发以太坊智能合约并进行交易
java和android如何使用web3j开发以太坊智能合约并进行交易
从广义上讲,web3j 支持三种类型的以太坊交易:
为了进行这些交易以太坊怎么获取,交易发生的以太坊账户中必须存在以太币(以太坊区块链的代币)。 这是支付gas cost,也就是支付参与交易的以太坊客户端的交易执行成本。 支付这笔费用后,结果可以提交到以太坊区块链。 下文描述了获取以太币的说明。
此外,我们还可以查询智能合约的状态。
如何获得以太币
要获得以太币,您有两种选择:
在私有链或公共测试网 (testnet) 中挖矿非常简单明了。 但是在主公链(mainnet)中,需要大量的专用GPU时间,除非你已经有多个专用GPU矿机,否则基本上是行不通的。 如果你想使用私有链,这个官方文档中有一些指南。
要购买以太币,您需要通过交易所。 由于不同地区有不同的交易所,您还需要研究一下适合您的交易所。 官方文档包含了几个交流,是一个很好的参考。
以太坊测试链(测试网)
以太坊有许多专用的测试网或测试链,受到各种客户的支持。
对于开发,建议您使用 Rinkeby 或 KoVan 测试链。 这是因为他们使用工作量证明 POA 共识机制,确保交易和区块的创建一致且及时。 虽然 Ropsten 测试链是最接近公链(主网)的,但由于其使用的工作量证明共识机制,过去曾遭受过攻击,并且经常给以太坊开发者带来更多问题。
您可以通过 Rinkeby 测试链的 Rinkeby Crypto Fauce 请求以太坊硬币,如何操作可以在这里找到。
有关如何请求 Kovan 测试链的详细信息,请参见此处。
如果你需要在 Ropsten 上获得一些以太币,请将你的钱包地址发布到 web3j gitter 频道,一些将发送给你。
在测试网测试链或私有链上挖矿
在ethereum以太坊测试链testnet中,挖矿难度低于公链主网。 这意味着你可以用普通的 CPU 来挖掘新的以太币,比如你的笔记本电脑。 您需要做的是运行一个以太坊客户端,例如 geth 或 Parity,并开始进行一些储备。 更多信息可在其官方网站上找到。
一旦你开采了一些以太币,你就可以开始使用以太坊区块链了。
但是,如上所述,使用 Kovan 或 Rinkeby 测试网络更简单。
气体
当一笔交易发生在以太坊上时,必须为执行交易的客户端支付交易费用,并将交易的输出提交给以太坊区块链。
该成本以 gas 衡量,其中 gas 是用于在以太坊虚拟机中执行交易指令的量。 请参阅官方文档以获取更多信息。
当您使用以太坊客户端时,这意味着有两个参数指示您要花费多少以太币来完成转账:
这两个参数共同决定了您愿意在交易成本上花费的最大以太币数量。 也就是说,你花费的gas不会超过gas price * gas limit。 gas 价格也会影响交易发生的速度,这取决于其他交易是否为矿工提供更优惠的 gas 价格。
您可能需要调整这些参数以确保及时交易。
交易机制
当您使用一些 Ether 创建了一个有效帐户后,您可以使用两种机制与 Ethereum 进行交易。
Web3j 支持这两种机制。
通过以太坊客户端验证签名交易
为了与以太坊客户端进行交易,您首先需要确保您使用的客户端知道您的钱包地址。 最好运行自己的 ethereum 客户端,例如 geth/Parity,这样你可以更方便地执行此操作。 运行客户端后,您可以通过以下方式创建以太坊钱包:
通过创建你的钱包文件,你可以通过 web3j 开户,首先创建一个支持 geth/Parity 管理命令的 web3j 实例:
Admin web3j = Admin.build(new HttpService());
然后你可以解锁账户,如果成功,发送交易:
PersonalUnlockAccount personalUnlockAccount = web3j.personalUnlockAccount("0x000...", "a password").send();
if (personalUnlockAccount.accountUnlocked()) {
// send a transaction
}
以这种方式发送的交易应该通过 EthSendTransaction 创建以太坊怎么获取,使用交易类型:
Transaction transaction = Transaction.createContractTransaction(
,
,
BigInteger.valueOf(), // we use default gas limit
"0x..."
);
org.web3j.protocol.core.methods.response.EthSendTransaction
transactionResponse = parity.ethSendTransaction(ethSendTransaction)
.send();
String transactionHash = transactionResponse.getTransactionHash();
// poll for transaction response via org.web3j.protocol.Web3j.ethGetTransactionReceipt()
下面会提到获取nonce值的方法。
有关此交易工作流程的详细信息,请参阅 DeployContractIT 和场景。
web3j 支持的各种管理命令的更多详细信息在管理 API 中。
离线交易签名认证 Offline transaction signing
如果您不想管理自己的以太坊客户端,或者不想向以太坊客户端提供密码等钱包详细信息,则可以通过离线交易验证签名。
离线交易签名身份验证允许您使用 web3j 中的以太坊钱包签署交易,让您可以完全控制您的私人凭证。 然后,离线创建的交易可以发送到网络上的任何以太坊客户端,只要是有效交易,它就会将交易传播到其他节点。
如果需要,还可以执行进程外交易签名验证。 这可以通过覆盖 ECKeyPair 的签名方法来实现。
创建和使用以太坊钱包文件
为了离线交易,您需要有您的钱包文件或与您的私人钱包/账户相关联的公钥和私钥。
web3j 可以为您生成新的安全以太坊钱包文件,或使用私钥处理现有钱包文件。
创建一个新的钱包文件:
String fileName = WalletUtils.generateNewWalletFile(
"your password",
new File("/path/to/destination"));
从钱包文件加载凭证:
Credentials credentials = WalletUtils.loadCredentials(
"your password",
"/path/to/walletfile");
这些凭据然后用于签署交易,请参阅 Web3 秘密存储定义钱包文档规范 Web3 秘密存储定义
签署以太坊交易
要使离线签名交易被签名,需要设置一个 RawTransaction 类型。 RawTransaction 类似于前面提到的 Transaction 类型,但是不需要通过具体的账户地址来请求,因为可以从签名中推断出来。
为了创建和签署原生交易,交易顺序如下:
随机数是一个不断增加的数字,用于唯一标识交易。 在交易被挖掘之前,随机数只能使用一次。 可以使用相同的 nonce 发送多个版本的交易,但一旦其中一个被挖掘,其他后续提交将被拒绝。
一旦获得下一个可用的随机数,这个值就可以用来创建一个交易对象:
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
nonce, , , , );
然后可以对交易进行签名和编码:
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, );
String hexValue = Numeric.toHexString(signedMessage);
根据创建和使用钱包文件加载凭据的位置。
然后使用 eth_SendRawTransaction 发送交易:
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
String transactionHash = ethSendTransaction.getTransactionHash();
// poll for transaction response via org.web3j.protocol.Web3j.ethGetTransactionReceipt()
有关创建和发送原始交易的完整示例,请参阅 CreateRawTransactionIT。
交易随机数nonce
随机数是一个不断增加的数字,用于唯一标识交易。 在交易被挖掘之前,随机数只能使用一次。 可以使用相同的 nonce 发送多个版本的交易,但一旦其中一个被挖掘,其他后续提交将被拒绝。
下一个可用的nonce可以通过eth_getTransactionCount方法获取:
EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(
address, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
然后您可以使用随机数来创建您的交易对象:
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
nonce, , , , );
交易类型
web3j 中不同类型的事务使用 Transaction 和 RawTransaction 对象。 关键区别在于交易对象必须始终有一个地址,以便处理 eth_sendTransaction 请求的以太坊客户端知道使用哪个钱包来代表消息发送者并发送交易。 如上所述,对于通过离线签名认证签名的原始交易,这不是必需的。
接下来的部分概述了不同交易类型所需的关键交易属性。 以下属性对所有人都是不变的:
Transaction 和 RawTransaction 对象在所有后续示例中可以互换使用。
以太币从一方交易到另一方
在两方之间发送 Ether 需要有关交易对方的最少量信息:
BigInteger value = Convert.toWei("1.0", Convert.Unit.ETHER).toBigInteger();
RawTransaction rawTransaction = RawTransaction.createEtherTransaction(
, , , , value);
// send...
但是,建议您使用 TransferClass 发送 Ether,它负责 nonce 管理并通过不断轮询为您提供响应:
Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
Credentials credentials = WalletUtils.loadCredentials("password", "/path/to/walletfile");
TransactionReceipt transactionReceipt = Transfer.sendFunds(
web3, credentials, "0x|",
BigDecimal.valueOf(1.0), Convert.Unit.ETHER).send();
使用智能合约包装器
当使用下面列出的智能合约包装器时,所有从 Solidity 到原生 Java 类型的转换都必须手动执行。 使用 Solidity 智能合约包装器非常有效,它负责所有代码的生成和转换。
创建智能合约
要部署新的智能合约,需要提供以下属性:
// using a raw transaction
RawTransaction rawTransaction = RawTransaction.createContractTransaction(
,
,
,
,
"0x ");
// send...
// get contract address
EthGetTransactionReceipt transactionReceipt =
web3j.ethGetTransactionReceipt(transactionHash).send();
if (transactionReceipt.getTransactionReceipt.isPresent()) {
String contractAddress = transactionReceipt.get().getContractAddress();
} else {
// try again
}
如果智能合约包含构造函数,则必须对关联的构造函数字段值进行编码并将其附加到已编译的智能合约代码中:
String encodedConstructor =
FunctionEncoder.encodeConstructor(Arrays.asList(new Type(value), ...));
// using a regular transaction
Transaction transaction = Transaction.createContractTransaction(
,
,
,
,
,
"0x " + encodedConstructor);
// send...
使用智能合约进行交易
要与现有智能合约进行交易,需要提供以下属性:
web3j 负责函数编码,有关实现的更多详细信息,请参阅应用程序二进制接口部分应用程序二进制接口。
Function function = new Function<>(
"functionName", // function we're calling
Arrays.asList(new Type(value), ...), // Parameters to pass as Solidity Types
Arrays.asList(new TypeReference() {}, ...));
String encodedFunction = FunctionEncoder.encode(function)
Transaction transaction = Transaction.createFunctionCallTransaction(
, , , contractAddress, , encodedFunction);
org.web3j.protocol.core.methods.response.EthSendTransaction transactionResponse =
web3j.ethSendTransaction(transaction).sendAsync().get();
String transactionHash = transactionResponse.getTransactionHash();
// wait for response using EthGetTransactionReceipt...
无论消息签名的返回类型如何,都不可能从事务函数调用返回值。 但是,可以使用过滤器捕获函数返回的值。 有关详细信息,请参阅过滤器和事件部分。
查询智能合约状态
此功能由 eth_call 通过 JSON-RPC 调用实现。
eth_call 允许您调用智能合约上的方法来查询值。 这个函数没有相关的交易成本,因为它不会改变任何智能合约方法的状态,它只是返回它们的值:
Function function = new Function<>(
"functionName",
Arrays.asList(new Type(value)), // Solidity Types in smart contract functions
Arrays.asList(new TypeReference() {}, ...));
String encodedFunction = FunctionEncoder.encode(function)
org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall(
Transaction.createEthCallTransaction(, contractAddress, encodedFunction),
DefaultBlockParameterName.LATEST)
.sendAsync().get();
List someTypes = FunctionReturnDecoder.decode(
response.getValue(), function.getOutputParameters());
注意:如果执行了一个无效的函数调用,或者返回一个空的 null 结果,返回值将是一个 Collections.emptyList 实例。
汇智网原创翻译,原文访问这里