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.5
coinbase: 0x40f074a6c0e40f7c5167718355375c6f2c509690
at 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;

@RestController
public 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
@Setter
public 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;

@Configuration
public 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=1
lottery.contract.gas-limit=2000000
lottery.contract.address=0x1c0fe20304e76882fe7ce7bb3e2e63dc92ce64de

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

代码仓库

  • GitHub - Harries/springboot-demo: a simple springboot demo with some components for example: redis,solr,rockmq and so on.

4.测试

  • 启动Spring Boot应用
  • 访问接口http://127.0.0.1:8080/owner
  • 访问接口http://127.0.0.1:8080/owner/balance

5.引用

  • 什么是区块链?| IBM
  • Spring Boot集成BlockChain快速入门Demo | Harries Blog™

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/755496.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数组】- 螺旋矩阵 II

1. 对应力扣题目连接 螺旋矩阵 II 题目简述&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。如图&#xff1a; 2. 实现案例代码 public class SpiralMatrix {public static…

重磅更新-UniApp自定义字体可视化设计

重磅更新-UniApp自定义字体可视化设计。 DIY可视化为了适配不同APP需要&#xff0c;支持用户自定义字体&#xff0c;自定义字体后&#xff0c;设计出来的界面更多样化&#xff0c;不再是单一字体效果。用户可以使用第三方字体加入设计&#xff0c;在设计的时候选择上自己的字体…

MyBatis第一节

目录 1. 简介2. 配置3. doing3.1 创建一个表3.2 打开IDEA&#xff0c;创建一个maven项目3.3 导入依赖的jar包3.4 创建entity3.5 编写mapper映射文件(编写SQL)3.6 编写主配置文件3.7 编写接口3.8 测试 参考链接 1. 简介 它是一款半自动的ORM持久层框架&#xff0c;具有较高的SQ…

【技术指南】稳压器(电压调节器):原理、类型及其实际用用案例

电压调节器&#xff08;稳压器&#xff09;是一种电子器件或电路&#xff0c;用于控制电路中的电压水平&#xff0c;以确保在电源电压波动或负载变化时&#xff0c;输出电压能够保持在设定的稳定水平。它们通常用于各种电子设备和电源系统中&#xff0c;以提供稳定的电压供应。…

AI绘画 Stable Diffusion【特效文字】:火焰特效艺术字,轻松搞定特效生成!

大家好&#xff0c;我是画画的小强 今天我们继续艺术字系列的分享&#xff0c;艺术字的玩法很多&#xff0c;今天给大家带来的是火焰特效艺术字的制作。我们先来看火焰特效艺术字的效果图。 一. 火焰特效文字的制作方法 【第一步】&#xff1a;制作底图 这里制作底图使用白底…

HarmonyOS Next开发学习手册——通过startAbilityByType拉起垂类应用

使用场景 开发者可通过特定的业务类型如导航、金融等&#xff0c;调用startAbilityByType接口拉起对应的垂域面板&#xff0c;该面板将展示目标方接入的垂域应用&#xff0c;由用户选择打开指定应用以实现相应的垂类意图。垂域面板为调用方提供统一的安全、可信的目标方应用&a…

数据结构与算法笔记:高级篇 - 搜索:如何用 A* 搜索算法实现游戏中的寻路功能?

概述 魔兽世界、仙剑奇侠传这类 MMRPG 游戏&#xff0c;不知道你玩过没有&#xff1f;在这些游戏中&#xff0c;有一个非常重要的功能&#xff0c;那就是任务角色自动寻路。当任务处于游戏地图中的某个位置时&#xff0c;我们用鼠标点击另外一个相对较远的位置&#xff0c;任务…

Flutter循序渐进==>Dart之类型、控制流和循环

导言 磨刀不误砍柴工&#xff0c;想搞好Flutter&#xff0c;先学好Flutter&#xff0c;还是本着我学Python的方法&#xff0c;先从数据类型、控制流和循环开始&#xff0c;这是每一种编程语言必用的。编程语言是相通的&#xff0c;基本精通一种后&#xff0c;学其它的就变得很…

网络配置(IP、NETMASK、GATEWAY、DNS、DHCP) <持续更新中>

参考&#xff1a; 初学Linux之网络配置(IP、NETMASK、GATEWAY、DNS、DHCP)-CSDN博客【学习笔记】网关 & 路由_网关和路由-CSDN博客【学习笔记】计算机网络 IP地址与MAC地址_根据mac分配ip-CSDN博客【学习笔记】TCP 和 UDP 协议_tcp 发送 syn 应答没有syn ack-CSDN博客 一…

Kafka 位移

Consumer位移管理机制 将Consumer的位移数据作为一条条普通的Kafka消息&#xff0c;提交到__consumer_offsets中。可以这么说&#xff0c;__consumer_offsets的主要作用是保存Kafka消费者的位移信息。使用Kafka主题来保存位移。 消息格式 位移主题就是普通的Kafka主题。也是…

计算机组成原理:海明校验

在上图中&#xff0c;对绿色的7比特数据进行海明校验&#xff0c;需要添加紫色的4比特校验位&#xff0c;总共是蓝色的11比特。紫色的校验位pi分布于蓝色的hi的1, 2, 4, 8, 16, 32, 64位&#xff0c;是2i-1位。绿色的数据位bi分布于剩下的位。 在下图中&#xff0c;b1位于h3&a…

高频面试题基本总结回顾2(含笔试高频算法整理)

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

kubernetes给指定用户分配调用k8s的api权限

文章目录 概要利用RBAC添加角色权限使用shell命令创建角色权限使用配置文件创建角色权限 调用k8s的api获取k8s账户的token 小结 概要 使用kubernetes部署项目时&#xff0c;有些特殊场景&#xff0c;我们需要在自己创建的pod里面调用k8s的api来管理k8s&#xff0c;但是需要使用…

论文笔记:Spatial-Temporal Interval Aware Sequential POI Recommendation

ICDE 2022 1 intro 1.1 背景 空间&#xff08;Spatial&#xff09;和时间&#xff08;Temporal&#xff09;信息是序列 POI 推荐中两个重要且相辅相成的因素。 空间因素&#xff08;如地理距离间隔&#xff09;可以在用户的历史轨迹呈现空间分簇现象时&#xff0c;细粒度刻画…

Elasticsearch 聚合查询简介

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

Pytest集成Allure生成测试报告

# 运行并输出报告在Report文件夹下 查看生成的allure报告 1. 生成allure报告&#xff1a;pycharm terminal中输入命令&#xff1a;产生报告文件夹 pytest -s --alluredir../report 2. pycharm terminal中输入命令&#xff1a;查看生成的allure报告 allure serve ../report …

[数据集][目标检测]婴儿状态睡觉哭泣检测数据集VOC+YOLO格式7109张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;7109 标注数量(xml文件个数)&#xff1a;7109 标注数量(txt文件个数)&#xff1a;7109 标注…

abap 类封装Excel转换到内表

文章目录 1.封装思路2.参数2.1.参数解析3.代码4.调用案例5.该类中的其他方法截图1.封装思路 直接复制粘贴激活直接用 首先,需要你在SE11中创建一个和你Excel中的字段相同的结构,然后把这个结构名字以字符串的形式传给方法.几乎可以实现任意扁平结构的Excel转到内表. 2.参数 2…

港科夜闻 | 香港科大学者戴希教授荣获陈嘉庚科学奖及国家自然科学奖一等奖,李卫平教授荣获国家自然科学奖二等奖...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大学者戴希教授荣获「陈嘉庚科学奖」及「国家自然科学奖」一等奖&#xff0c;李卫平教授荣获「国家自然科学奖」二等奖。香港科大蒙民伟博士纳米科学教授兼物理系讲座教授戴希及其团队&#xff0c;具有开创性的研究…

Stylized Modular Character (Female)(程式化的模块化角色(女性)“运动型”)

一套程式化的角色模块化部件。 在这样的插槽中定制&#xff1a; 头 躯干 手 裤子 靴子 头发 每个插槽都有 2 到 5 个在 URP 中工作的 PBR 材料的选项。 该项目基于官方 Unity Standard Assets 包中的 Ethan 默认角色。 不包含动画。 皮肤网格的 SSS 是由自发光贴图伪造的。 如果…