java使用spring boot和web3j开发以太坊应用。
朋友一起走
发表于 2022-11-13 23:50:49
100
1
0
于是以太坊来了。这是一个Vitarik Buterin提供的去中心化的平台,可以通过脚本语言创建开发应用。它的想法是从比特币获得的,并由新的叫Ether即以太坊币的加密数字币驱动。今天,以太币是继比特币之后的第二大加密数字货币。以太坊技术的核心是EVM(以太坊虚拟机),它可以被视为类似于Java虚拟机,而且用一种完全去中心化的节点网络。基于java世界实现以太坊交易我们使用web3j库。这是一个轻量级的、响应式、类型安全的java和Android库结合了以太坊区块链节点。更多的细节可以在这里找到web3j.io中文版。7 r" M* t C7 v* ]" i R" {
1.本地运行: C j% b. j" e+ J+ ^" I0 P
虽然有许多针对区块链文章,但以太坊相关的网络内容中不容易找到一个解决方案描述如何准备在本地机器使用实例运行以太坊。值得一提的是,一般有两种最基本的客户端可以使用:Geth和Parity。原来,我们可以很容易地在本地使用Docker容器运行节点。默认情况下,连接节点的以太坊主网络(公有链)。或者,你可以将它连接到测试网络或Rinkeby网络。但开始最好的选择就是运行在设置了开发参数(–dev)的开发模式下,并在Docker容器中运行命令。
下面的命令启动Docker容器开发模式在端口8545调用以太坊RPC API。# c# X# Q" {2 |! i1 D/ ?5 K, i# e
$ docker run -d --name ethereum -p 8545:8545 -p 30303:30303 ethereum/client-go --rpc --rpcaddr "0.0.0.0" --rpcapi="db,eth,net,web3,personal" --rpccorsdomain "*" --dev
在开发模式中运行该容器时,一个非常好的消息是,在默认的测试帐户上有大量的Ether。在这种情况下,你不必挖掘任何Ether,便能够开始测试。超级棒!现在,让我们创建一些其他的测试帐号,并做一些检查。为了实现这一点,我们需要在容器内部运行Geth的交互式JavaScript控制台。" B& t0 I4 f+ { Z
$ docker exec -it ethereum geth attach ipc:/tmp/geth.ipc: j9 X. d7 a9 f, p/ m" ~' b2 _
2.以太坊节点使用JavaScript控制台管理% x1 x+ b. N- A! p8 C& @: c
运行JavaScript控制台可以方便显示默认帐户(Coinbase),所有可用的账户及其余额清单。这里的屏幕显示我的以太坊结果。
现在,我们必须创建一些测试帐号。我们可以通过调用personal.newAccount(password)函数来实现这一点。在创建必需的帐户之后,我们可以使用JavaScript控制台执行一些测试交易,并将一些资金从基础帐户转移到新创建的帐户。下面是用于创建帐户和执行交易的命令。
$ H! T% L: L; }; B
3.系统体系结构6 a `! b- N* {! E# E i2 y, J% J
我们的demo系统的体系结构非常简单。不用想复杂的事情,只是告诉大家如何发送交易到geth节点和接收交易收据。而transaction-service发送新交易到以太坊节点,bonus-service节点监听传入的交易。然后每10笔交易发送者的帐户收到一次奖金(bonus)。这里的图表说明了一个我们的demo的系统架构。
$ I& s8 `; {. c: q# t& X( c
4.spring boot应用程序使用web3j
我想现在我们清楚了我们到底想做什么。所以,让我们来进行实施。首先,我们应该包括所有必需的依赖项,以便能够在Spring boot应用程序中使用web3j库。幸运的是,有一个starter可以使用。
org.web3j, {" @( A. J9 y r& U
web3j-spring-boot-starter
1.6.0
因为我们在Docker容器运行以太坊客户端需要改变客户端的自动默认配置的web3j的调用地址。
spring:
application:7 W E# l3 [0 z" k
name: transaction-service* v0 w: ^* U ]6 t) U
server: S6 I2 y7 }. R3 j6 c
port: ${PORT:8090}
web3j:- p2 Q. }1 G* l4 t3 @2 t
client-address: http://192.168.99.100:8545
5.构建应用2 j8 x! u1 A) |2 g
如果我们将web3j starter包含到项目依赖项中,需要的是自动装载web3j bean。web3j负责向Geth客户端节点发送交易。它用交易哈希接收响应,不管是节点接受或由于错误被拒绝。在创建交易对象时,重要的是将gas限制最小值设置为21000。如果发送较低的值,则可能会收到错误信息:intrinsic gas too low。: ?+ Y |( Y! B- z" J7 j
@Service
public class BlockchainService {
7 H3 w- l8 U( U9 d2 a& a. Y
private static final Logger LOGGER = LoggerFactory.getLogger(BlockchainService.class);5 O& y; J5 W) y6 g, x
7 l$ Y \/ N" A6 ^0 M7 C
@Autowired1 D* F$ O# J& N8 i& l
Web3j web3j;# D3 n8 @* u: E3 v d
public BlockchainTransaction process(BlockchainTransaction trx) throws IOException {6 [. X3 M( n2 u$ g- i/ w; m
EthAccounts accounts = web3j.ethAccounts().send();
EthGetTransactionCount transactionCount = web3j.ethGetTransactionCount(accounts.getAccounts().get(trx.getFromId()), DefaultBlockParameterName.LATEST).send();' L& s Z& S. P
Transaction transaction = Transaction.createEtherTransaction(accounts.getAccounts().get(trx.getFromId()), transactionCount.getTransactionCount(), BigInteger.valueOf(trx.getValue()), BigInteger.valueOf(21_000), accounts.getAccounts().get(trx.getToId()),BigInteger.valueOf(trx.getValue()));/ l/ V m8 y* A7 i5 K; [; z# @( T
EthSendTransaction response = web3j.ethSendTransaction(transaction).send();
if (response.getError() != null) {
trx.setAccepted(false);2 U2 [: _' _! T
return trx;1 Y* z. Q/ a+ E8 g
}( t& D& \& }: M# Z4 U+ q
trx.setAccepted(true);7 j5 W! D# ]/ l+ ?5 J# p
String txHash = response.getTransactionHash();. T, L0 {# f# `% C
LOGGER.info("Tx hash: {}", txHash);4 s! o% o/ v6 s" D3 N D4 o6 q5 e
trx.setId(txHash);2 ?0 M4 ^+ S& P' |2 O0 E/ l& C' O3 x
EthGetTransactionReceipt receipt = web3j.ethGetTransactionReceipt(txHash).send();2 _& \2 I$ V% @8 c; ~
if (receipt.getTransactionReceipt().isPresent()) {3 R% p- R! T2 T: w5 H) }
LOGGER.info("Tx receipt: {}", receipt.getTransactionReceipt().get().getCumulativeGasUsed().intValue());
}) Q9 `. v0 _7 E4 I
return trx;
}
0 ?6 G8 \+ `4 X/ W0 M+ p+ Z
}
@Service从上面的代码看由控制器调用。POST方法的需要BlockchainTransaction对象作为参数。你可以发送发件人ID,接收人ID和交易金额。发送者和接收者ID是通过eth.account[index]可查询的。1 F6 M% z2 t' K1 h
@RestController% o7 m8 |/ O+ N5 I
public class BlockchainController {
8 Y) o1 P7 m' J! \
@Autowired: U4 a3 _; M+ U7 N
BlockchainService service;
+ h) d& `: g# r5 B& ]4 D
@PostMapping("/transaction")
public BlockchainTransaction execute(@RequestBody BlockchainTransaction transaction) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, CipherException, IOException {
return service.process(transaction);
}1 z* H2 B8 q4 @1 l
: z0 D- ? ]. B# M1 x N5 o
}
你可以用下面的命令调用POST方法发送测试交易。' M) z3 _2 s, O7 a7 X9 q* F0 U; `6 ~% i
在发送任何交易之前,你应该解锁发送人帐户。
$ curl --header "Content-Type: application/json" --request POST --data '{"fromId":2,"toId":1,"value":3}' http://localhost:8090/transaction; M* Z! K5 b1 _6 j1 W
应用程序bonus-service监听由以太坊节点处理的交易。它通过调用web3j.transactionObservable().subscribe(...)方法从web3j库订阅通知消息。它将从该地址每10个交易返回后,发送一次到发送者的帐户。下面是bonus-service中可监听方法的实现。; y5 k. `( h- w
@Autowired+ F" \, Q0 Y1 F7 C" q
Web3j web3j;
@PostConstruct6 o+ S4 h$ Y8 W: A% A% q. |- I
public void listen() {
Subscription subscription = web3j.transactionObservable().subscribe(tx -> {
LOGGER.info("New tx: id={}, block={}, from={}, to={}, value={}", tx.getHash(), tx.getBlockHash(), tx.getFrom(), tx.getTo(), tx.getValue().intValue());
try {
EthCoinbase coinbase = web3j.ethCoinbase().send();) ]$ s5 w# F! E, W: J X
EthGetTransactionCount transactionCount = web3j.ethGetTransactionCount(tx.getFrom(), DefaultBlockParameterName.LATEST).send();
LOGGER.info("Tx count: {}", transactionCount.getTransactionCount().intValue());* V" { Z* S* a% V$ Z! O' L
if (transactionCount.getTransactionCount().intValue() % 10 == 0) {1 x: i* x' @- H/ L
EthGetTransactionCount tc = web3j.ethGetTransactionCount(coinbase.getAddress(), DefaultBlockParameterName.LATEST).send();$ T8 k. l! x5 N R1 {6 X9 q X
Transaction transaction = Transaction.createEtherTransaction(coinbase.getAddress(), tc.getTransactionCount(), tx.getValue(), BigInteger.valueOf(21_000), tx.getFrom(), tx.getValue());
web3j.ethSendTransaction(transaction).send();0 ~ N- G# }- N9 \/ l$ ?
}
} catch (IOException e) {
LOGGER.error("Error getting transactions", e);. O: L9 A+ I/ n I% ]) B4 M1 |
}
});2 Z5 ?) h* `4 j/ p! b) q+ B' q
LOGGER.info("Subscribed"); D+ r& `/ [. E- h. ?8 d ?
总结: r& D5 Y. k3 [# `$ {: Y6 n# c
区块链和数字货币不是容易开始的话题。通过提供完整的脚本语言,以太坊简化了使用区块链进行应用程序开发的难度。使用web3j、spring boot和以太坊geth客户端的docker容器镜像,可以快速启动解决方案,实现区块链技术的本地开发。
如果你想进行本地开发时clone我的库,可以在github上下载源代码。
如果希望快速进行web3j、java、以太坊开发,那请看我们精心打造的教程:
web3j教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
成为第一个吐槽的人