51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring Boot集成BlockChain快速入门Demo

1.什么是区块链?

区块链定义:区块链是一个共享的、不可篡改的账本,旨在促进业务网络中的交易记录和资产跟踪流程。 资产 可以是有形的(如房屋、汽车、现金、土地),也可以是无形的(如知识产权、专利、版权、品牌)。几乎任何有价值的东西都可以在区块链网络上跟踪和交易,从而降低各方面的风险和成本。 为什么区块链很重要:业务运营依靠信息。信息接收速度越快,内容越准确,越有利于业务运营。区块链是用于传递这些信息的理想之选,因为它可提供即时、共享和完全透明的信息,这些信息存储在不可篡改的账本上,只能由获得许可的网络成员访问。区块链网络可跟踪订单、付款、帐户、生产等信息。由于成员之间共享单一可信视图,因此,您可采取端到端方式查看交易的所有细节,从而增强信心,提高效率并获得更多的新机会。

区块链的关键元素

  1. 分布式分类账技术:所有网络参与者都可以访问分布式分类账及其不可篡改的交易记录。借助这种共享分类账,交易只记录一次,可消除传统业务网络典型的重复工作。

  2. 不可篡改记录:交易记录至共享分类账后,任何参与者都不能更改或篡改交易。如果交易记录中包含错误,则必须添加新交易来撤销错误,然后两笔交易均可见。

  3. 智能合约:为了加快交易速度,区块链上存储并自动运行了一组称为智能合约的规则。智能合约可定义企业债券转让的条件,包括支付旅行保险的条款等等。

区块链如何运作

  • 每笔交易发生时,都会记录为一个数据"区块"

    这些交易表明资产的流动,资产可以是有形的(产品),也可以是无形的(知识)。数据区块可以记录您选择的信息:人物、事件、时间、地点、价格。它甚至可以记录条件,例如食品运输温度。

  • 每个区块都与其前后的区块相连

    随着资产从一地转移至另一地,或所有权易手,这些区块会形成数据链。区块可确认交易的准确时间和顺序,并且区块之间安全地链接在一起,以防止任何区块遭到篡改,或在两个现有区块之间插入一个其他区块。

  • 交易以区块形式组合在一条不可逆的链中:区块链

    每添加一个区块都会加强对前一个区块的验证,从而加强整条区块链的验证。区块链篡改会变得容易发现,这就是不可篡改性的关键优势。这可以消除恶意行为者进行篡改的可能性,并建立您预其他网络成员可以信任的交易分类账。

2.环境搭建

Deploy a Custom Ethereum Network

docker run -d --name ethereum -p 8545:8545 -p 30303:30303 ethereum/client-go --http --http.addr="0.0.0.0" --http.api="db,eth,net,web3,personal" --http.corsdomain="*" --dev

view logs

docker logs -f ethereum

Create Account

docker exec -it ethereum geth attach ipc:/tmp/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.10.15-unstable-356bbe34/linux-amd64/go1.17.5coinbase: 0x40f074a6c0e40f7c5167718355375c6f2c509690at block: 0 (Thu Jan 01 1970 00:00:00 GMT+0000 (UTC)) datadir: modules: admin:1.0 clique:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit> personal.newAccount('ABC')"0x9b418710ce8438e5fe585b519e8d709e1ea77aca"> eth.accounts["0x40f074a6c0e40f7c5167718355375c6f2c509690", "0x9b418710ce8438e5fe585b519e8d709e1ea77aca"]

Send Ethers to Accounts

> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(100000, 'ether')})"0x48fe4bd2d6db424ecc1f3713809d53e103fa7fc63646f4051a6a280d5f7080ea"> eth.getBalance(eth.accounts[1])

3.代码工程

实验目标

使用Java对接ethereum网络

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <parent>        <artifactId>springboot-demo</artifactId>        <groupId>com.et</groupId>        <version>1.0-SNAPSHOT</version>    </parent>    <modelVersion>4.0.0</modelVersion>
    <artifactId>Blockchain</artifactId>
    <properties>        <maven.compiler.source>8</maven.compiler.source>        <maven.compiler.target>8</maven.compiler.target>    </properties>    <dependencies>
        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>
        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-autoconfigure</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>        <dependency>            <groupId>org.web3j</groupId>            <artifactId>core</artifactId>            <version>4.0.1</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-databind</artifactId>            <version>2.9.4</version>        </dependency>        <dependency>            <groupId>org.ethereum</groupId>            <artifactId>solcJ-all</artifactId>            <version>0.4.25</version>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <version>1.18.2</version>            <scope>provided</scope>        </dependency>    </dependencies>    <build>    <plugins>        <plugin>            <groupId>org.web3j</groupId>            <artifactId>web3j-maven-plugin</artifactId>            <version>0.3.7</version>            <configuration>                <packageName>org.sgitario.lottery.blockchain.model</packageName>                <nativeJavaType>true</nativeJavaType>                <outputFormat>java,bin,abi</outputFormat>                <soliditySourceFiles>                    <directory>src/main/resources/contracts</directory>                    <includes>                        <include>*.sol</include>                    </includes>                </soliditySourceFiles>                <outputDirectory>                    <java>src/main/java</java>                    <bin>src/main/resources/bin/generated</bin>                    <abi>src/main/resources/abi/generated</abi>                </outputDirectory>            </configuration>        </plugin>    </plugins>    </build>    <repositories>
        <repository>            <id>nexus-ethereum</id>            <name>Nexus ethereum</name>            <layout>default</layout>            <url>https://dl.bintray.com/ethereum/maven/</url>            <snapshots>                <enabled>false</enabled>            </snapshots>            <releases>                <enabled>true</enabled>            </releases>        </repository>    </repositories></project>

controller

package com.et.bc.controller;
import com.et.bc.model.Balance;import com.et.bc.service.LotteryService;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import org.web3j.protocol.Web3j;import org.web3j.protocol.core.DefaultBlockParameterName;import org.web3j.protocol.core.methods.response.EthGetBalance;
import java.io.IOException;import java.util.List;
@RestControllerpublic class OwnerController {
    @Value("${lottery.contract.owner-address}")    private String ownerAddress;
    @Autowired    private Web3j web3j;
    @Autowired    private LotteryService lotteryService;
    @GetMapping("/owner")    public String getAddress() {        return ownerAddress;    }
    @GetMapping("/owner/balance")    public Balance getBalance() throws IOException {        EthGetBalance wei = web3j.ethGetBalance(ownerAddress, DefaultBlockParameterName.LATEST).send();
        return new Balance(wei.getBalance());    }
    @GetMapping("/owner/lottery/players")    public List<String> getPlayers() throws Exception {        return lotteryService.getPlayers(ownerAddress);    }
    @GetMapping("/owner/lottery/pickWinner")    public void pickWinner() throws Exception {        lotteryService.pickWinner(ownerAddress);    }}

service

package com.et.bc.service;
import com.et.bc.model.Lottery;import com.et.bc.model.Player;import com.et.bc.properties.LotteryProperties;import org.web3j.protocol.Web3j;import org.web3j.protocol.core.DefaultBlockParameterName;import org.web3j.tx.ClientTransactionManager;import org.web3j.tx.TransactionManager;import org.web3j.utils.Convert;import org.web3j.utils.Convert.Unit;
import java.io.IOException;import java.math.BigInteger;import java.util.List;
public class LotteryService {
    private final String contractAddress;    private final Web3j web3j;    private final LotteryProperties config;
    public LotteryService(String contractAddress, Web3j web3j, LotteryProperties config) {        this.contractAddress = contractAddress;        this.web3j = web3j;        this.config = config;    }
    public BigInteger getBalance() throws IOException {        return web3j.ethGetBalance(contractAddress, DefaultBlockParameterName.LATEST).send().getBalance();    }
    public void join(Player player) throws Exception {        Lottery lottery = loadContract(player.getAddress());        lottery.enter(Convert.toWei(player.getEthers(), Unit.ETHER).toBigInteger()).send();    }
    @SuppressWarnings("unchecked")    public List<String> getPlayers(String ownerAddress) throws Exception {        Lottery lottery = loadContract(ownerAddress);        return lottery.getPlayers().send();    }
    public void pickWinner(String ownerAddress) throws Exception {        Lottery lottery = loadContract(ownerAddress);        lottery.pickWinner().send();    }
    private Lottery loadContract(String accountAddress) {        return Lottery.load(contractAddress, web3j, txManager(accountAddress), config.gas());    }
    private TransactionManager txManager(String accountAddress) {        return new ClientTransactionManager(web3j, accountAddress);    }}

转换器

package com.et.bc.utils;
import org.web3j.utils.Convert;import org.web3j.utils.Convert.Unit;
import java.math.BigDecimal;import java.math.BigInteger;
public class ConvertUtils {    public static BigDecimal toEther(BigInteger wei) {        return Convert.fromWei(new BigDecimal(wei), Unit.ETHER);    }}

注入的属性文件

package com.et.bc.properties;
import lombok.Getter;import lombok.Setter;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Configuration;import org.web3j.tx.gas.StaticGasProvider;
import java.math.BigInteger;
@Configuration@ConfigurationProperties(prefix = "lottery.contract")@Getter@Setterpublic class LotteryProperties {    private BigInteger gasPrice;    private BigInteger gasLimit;
    public StaticGasProvider gas() {        return new StaticGasProvider(gasPrice, gasLimit);    }}

配置类

package com.et.bc.config;
import com.et.bc.model.Lottery;import com.et.bc.properties.LotteryProperties;import com.et.bc.service.LotteryService;import okhttp3.OkHttpClient;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.util.StringUtils;import org.web3j.protocol.Web3j;import org.web3j.protocol.http.HttpService;import org.web3j.tx.ClientTransactionManager;import org.web3j.tx.TransactionManager;
@Configurationpublic class LotteryConfiguration {
    private static final Logger LOG = LoggerFactory.getLogger(LotteryConfiguration.class);
    @Value("${lottery.contract.owner-address}")    private String ownerAddress;
    @Value("${web3j.client-address}")    private String clientAddress;
    @Autowired    private LotteryProperties config;
    @Bean    public Web3j web3j() {        return Web3j.build(new HttpService(clientAddress, new OkHttpClient.Builder().build()));    }
    @Bean    public LotteryService contract(Web3j web3j, @Value("${lottery.contract.address:}") String contractAddress)            throws Exception {        if (StringUtils.isEmpty(contractAddress)) {            Lottery lottery = deployContract(web3j);            return initLotteryService(lottery.getContractAddress(), web3j);        }
        return initLotteryService(contractAddress, web3j);    }
    private LotteryService initLotteryService(String contractAddress, Web3j web3j) {        return new LotteryService(contractAddress, web3j, config);    }
    private Lottery deployContract(Web3j web3j) throws Exception {        LOG.info("About to deploy new contract...");        Lottery contract = Lottery.deploy(web3j, txManager(web3j), config.gas()).send();        LOG.info("Deployed new contract with address '{}'", contract.getContractAddress());        return contract;    }
    private TransactionManager txManager(Web3j web3j) {        return new ClientTransactionManager(web3j, ownerAddress);    }
}

application.properties

web3j.client-address=http://localhost:8545
lottery.contract.owner-address=0x9b418710ce8438e5fe585b519e8d709e1ea77aca
lottery.contract.gas-price=1lottery.contract.gas-limit=2000000lottery.contract.address=0x1c0fe20304e76882fe7ce7bb3e2e63dc92ce64de

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

  • https://github.com/Harries/springboot-demo

4.测试

  • 启动Spring Boot应用

  • 访问接口http://127.0.0.1:8080/owner

  • 访问接口http://127.0.0.1:8080/owner/balance

5.引用

  • https://www.ibm.com/cn-zh/topics/blockchain

  • http://www.liuhaihua.cn/archives/710788.html

赞(4)
未经允许不得转载:工具盒子 » Spring Boot集成BlockChain快速入门Demo