java每日精进 2.13 Ganache(区块链本地私有化部署)

需求:使用区块链实现数据村存储,记录一些不可篡改的交互信息,网络环境为内外网均需要部署;

1.准备工作(软件安装)


1.1 安装 Node.js 和 npm

1.2 安装 Ganache

地址如下:windows有可视化界面 ,本文章使用windows版

Ganache - Truffle Suite

点击“Quickstart”创建一个本地以太坊区块链网络

1.3 安装 Truffle

打开命令提示符(CMD)或 PowerShell,运行以下命令安装 Truffle:

npm install -g truffle

安装后验证

truffle version

类似如下则安装成功:

1.4 安装 Web3.js(前端和ganache连接需要,后端的话直接跳过即可)
npm install web3

2. 创建和配置区块链项目

2.1 初始化 Truffle 项目

打开命令提示符(CMD)或 PowerShell

找到合适的文件夹 下运行以下命令创建一个新目录并初始化 Truffle 项目:

mkdir my-blockchain-project
cd my-blockchain-project
truffle init
2.2 配置 Truffle
  • 在项目目录中找到 truffle-config.js 文件,用文本编辑器(如 Notepad++ 或 VSCode)打开。

  • 修改配置文件,配置 Ganache 作为开发网络:

module.exports = {networks: {development: {host: "127.0.0.1", // Ganache 的默认地址port: 7545,        // Ganache 的默认端口network_id: "*",   // 匹配任何网络ID},},compilers: {solc: {version: "0.8.0",  // 使用合适的 Solidity 版本},},
};

3. 编写和部署智能合约

3.1 编写智能合约

创建 Solidity 合约文件:

  • 在 contracts 目录下创建一个新的 Solidity 合约文件,例如 DataStorage.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;contract DataStorage {struct Data {string jsonData;}mapping(uint256 => Data) public dataMap;uint256 public dataCount;function storeData(string memory _jsonData) public {dataMap[dataCount] = Data(_jsonData);dataCount++;}function getData(uint256 _id) public view returns (string memory) {return dataMap[_id].jsonData;}
}

Solidity 合约定义了一个简单的数据存储和检索机制

**合约声明
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
  • // SPDX-License-Identifier: UNLICENSED: 这是一个 SPDX 声明,用于指明代码的许可证类型。UNLICENSED 表示该代码没有许可条款。
  • pragma solidity ^0.8.0(一定要和truffle-config.js 文件中的compilers的version相同,不然会报错): 指定该合约使用的 Solidity 编译器版本是 0.8.0 或更高版本。^ 表示向上兼容。
**合约定义
contract DataStorage {
  • contract DataStorage {: 定义了一个名为 DataStorage 的合约,所有的存储和检索功能都将在这个合约内实现。
**数据结构定义struct Data {string jsonData;}
  • struct Data: 定义了一个名为 Data 的结构体,它包含一个字段 jsonData,该字段是一个 string 类型,用来存储 JSON 格式的数据,表示使用此合约存储的是json类数据;
**状态变量mapping(uint256 => Data) public dataMap;uint256 public dataCount;
  • mapping(uint256 => Data) public dataMap;: 定义了一个 mapping,它将一个 uint256 类型的键映射到一个 Data 结构体。public 关键字使得该映射可以通过合约外部访问(自动生成 getter 函数)。dataMap 用来存储每个数据条目,数据是通过 dataCount 作为键存储的。
  • uint256 public dataCount;: 定义了一个计数器 dataCount,用来记录当前存储的 Data 的数量。每当存储新数据时,dataCount 会自增,用于将来遍历查询数据。
**存储函数function storeData(string memory _jsonData) public {dataMap[dataCount] = Data(_jsonData);dataCount++;}
  • function storeData(string memory _jsonData) public: 定义了一个公开函数 storeData,它接受一个 string 类型的参数 _jsonData,用于存储数据。
    • string memory _jsonData: 这是函数的输入参数,表示传入的 JSON 数据。
  • dataMap[dataCount] = Data(_jsonData);: 将传入的 JSON 数据 _jsonData 存储在 dataMap 中,以 dataCount 作为键,值是一个包含该 JSON 数据的 Data 结构体。
  • dataCount++;: 每次调用 storeData 函数时,dataCount 计数器会增加 1,确保下一个数据存储使用新的键。
  • 将来每次取值都是通过健访问dataMap的值,得以拿到数据;
**获取函数function getData(uint256 _id) public view returns (string memory) {return dataMap[_id].jsonData;}

这个合约实现了以下功能:

  • storeData 函数允许将 JSON 格式的数据存储到区块链中。
  • getData 函数允许根据存储时生成的 id(由 dataCount 自动递增)获取对应的 JSON 数据。
  • dataMap 是一个映射,它将数据的 id 映射到存储的数据 jsonData
  • dataCount 记录了当前存储的数据数量,并且用于为每个数据条目生成唯一的 id
3.2 编译智能合约

接下来命令都是在项目根目录下运行 , 运行以下命令编译合约:

truffle compile
3.3 部署智能合约

在 migrations 目录下创建一个新的迁移文件,例如 2_deploy_contracts.js

const DataStorage = artifacts.require("DataStorage");module.exports = function (deployer) {deployer.deploy(DataStorage);
};

运行以下命令部署合约:

truffle migrate --network development
  • 部署成功后,控制台输出如下,记下合约地址(在终端输出中查找 contract address)。

Starting migrations...
======================
> Network name:    'development'
> Network id:      5777
> Block gas limit: 6721975 (0x6691b7)


2_deploy_contracts.js
=====================

   Deploying 'DataStorage'
   -----------------------
   > transaction hash:    0x779d63bdaa8e9afb1ce4ff56751a923f861ce006d03028183570e1130a326dca
   > Blocks: 0            Seconds: 0
   > contract address:    0x9E6954C2B46ae3B7C1e6676964a2Cc5e4477Fedf
   > block number:        1
   > block timestamp:     1739346849
   > account:             0xEF8625527393F19118803b027631F215a6eE10c8
   > balance:             99.99854643475
   > gas used:            430686 (0x6925e)
   > gas price:           3.375 gwei
   > value sent:          0 ETH
   > total cost:          0.00145356525 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:       0.00145356525 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.00145356525 ETH

4. 使用 Java 与区块链交互

4.1 安装 Web3j

下载 Web3j:github中其地址如下

Releases · hyperledger-web3j/web3j (github.com)

下载.zip版本并解压

解压后目录如下:

在本文件夹下使用powershell

.\gradlew build
4.2. 生成 Java 合约文件

已经有了 Solidity 合约文件(.sol 文件),可以使用 Web3j 提供的工具来生成 Java 类。
在 PowerShell 中执行以下命令来安装 Web3j CLI 工具:

Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/hyperledger/web3j-installer/main/installer.ps1'))

执行以下命令检查是否安装成功:

web3j --version

在项目目录下运行以下命令生成 Java 合约包装器

web3j generate truffle --truffle-json ./build/contracts/DataStorage.json -o ./src/main/java -p com.example.contract
  • 生成的 Java 文件将位于 src/main/java/com/example/contract 目录下。

4.3 编写 Java 程序

创建项目,将生成的合约包装器文件复制到项目的 src/main/java/com/example/contract 目录下

添加 Web3j 依赖

<dependency><groupId>org.web3j</groupId><artifactId>core</artifactId><version>4.9.4</version>
</dependency>

编写java程序:

@RestController
@RequestMapping("/myBlockChain")
public class BlockChainController {@AutowiredDataStorageExample dataStorageExample;@PostMapping("/storeData")public String addMsg(@RequestBody Transaction  transaction) throws Exception {// 将接收到的消息对象转化为 JSON 字符串String jsonData = String.format("{\"tid\":\"%s\",\"data\":%s}", transaction.getTid(), transaction.getData());String msg = DataStorageExample.storeData(jsonData);return msg;}@PostMapping("/getAllData")public String getMsg() throws Exception {// 将接收到的消息对象转化为 JSON 字符串String msg = DataStorageExample.getData();return msg;}
}
/*** 数据存储示例*/
@Service
public class DataStorageExample {private static final String NODE_URL = "http://localhost:7545";private static final String PRIVATE_KEY = "******************************";private static Web3j web3j;private static Credentials credentials;private static DataStorage dataStorage;// 静态代码块初始化 Web3j 和 Credentialsstatic {web3j = Web3j.build(new HttpService(NODE_URL));credentials = Credentials.create(PRIVATE_KEY);}/*** 获取单一的 DataStorage 合约实例* @return DataStorage* @throws Exception*/public static DataStorage getDataStorage() throws Exception {if (dataStorage == null) {// 如果合约尚未部署,则进行部署,确保单例,不然不同合约下的数据不互通dataStorage = deployContract(web3j, credentials);}return dataStorage;}/*** 部署合约* @param web3j* @param credentials* @return* @throws Exception*/private static DataStorage deployContract(Web3j web3j, Credentials credentials) throws Exception {System.out.println("正在部署合约...");DataStorage dataStorage = DataStorage.deploy(web3j, credentials, new DefaultGasProvider()).send();System.out.println("合约部署在地址: " + dataStorage.getContractAddress());return dataStorage;}/*** 存储JSON数据* @param jsonData* @throws Exception*/public static String storeData(String jsonData) throws Exception {if (dataStorage == null) {getDataStorage(); // 确保合约已部署}System.out.println("存储的数据: " + jsonData);TransactionReceipt receipt = dataStorage.storeData(jsonData).send();System.out.println("交易收据: " + receipt.getTransactionHash());return receipt.getTransactionHash();}/*** 获取数据* @return String* @throws Exception*/public static String getData() throws Exception {if (dataStorage == null) {getDataStorage(); // 确保合约已部署}BigInteger dataCount = dataStorage.dataCount().send(); // 获取数据的总条目数Map<BigInteger, String> allData = new HashMap<>();// 遍历所有数据,按照ID获取并存储for (BigInteger i = BigInteger.ZERO; i.compareTo(dataCount) < 0; i = i.add(BigInteger.ONE)) {String data = dataStorage.getData(i).send(); // 获取每条数据allData.put(i, data); // 将数据存入Map}return allData.toString();}
}

PRIVATE_KEY的值为任意ACCOUNT的 PRIVATE_KEY的值,表示哪个账户发起交易

每次交易都会生成一个新的Block存储数据

点击Transactions可查看每次交易的相关数据

运行示例:

至此,实现本地Ganache区块链私有化部署并使json数据上链

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

w206基于Spring Boot的农商对接系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

chrome://version/

浏览器输入&#xff1a; chrome://version/ Google浏览器版本号以及安装路径 Google Chrome131.0.6778.205 (正式版本) &#xff08;64 位&#xff09; (cohort: Stable) 修订版本81b36b9535e3e3b610a52df3da48cd81362ec860-refs/branch-heads/6778_155{#8}操作系统Windows…

哈希槽算法与一致性哈希算法比较

Redis 集群模式使用的 哈希槽&#xff08;Hash Slot&#xff09; 算法与传统的 一致性哈希&#xff08;Consistent Hashing&#xff09; 算法在数据分布和节点管理上有显著的区别。以下是两者的详细比较&#xff1a; 1. Redis 哈希槽算法 1.1 基本原理 Redis 集群将整个数据集…

【BUUCTF逆向题】[WUSTCTF2020]level3(魔改base64)

一.[WUSTCTF2020]level3 打开IDA反汇编&#xff0c;发现就是base64加密 这里rand就是与&搭配设置奇偶数2分随机 但是根据提示不是标准base64加密 首先想到魔改密码表&#xff0c;追踪进去&#xff0c;发现没有什么变化啊 尝试对Base64字符串解码也不对 追踪密码表CtrlX发…

有关Java中的接口

学习目标 掌握接口语法理解接口多态熟练使用接口了解接口新特性掌握final关键字了解lambda语法 1.接口语法 1.1 接口概念 从功能上看, 实现接口就意味着扩展了某些功能 接口与类之间不必满足is-a的关系结构 从抽象上看, 接口是特殊的抽象父类 从规则上看, 接口定义者和实…

鸿蒙(openharmony) 5.0 光感接口崩溃

目录 1.背景 2.解决方案 1.背景 使用OpenHarmony 5.0调用光感接口崩溃,返回的值是undefined,接口如下: sensor.on(sensor.SensorId.AMBIENT_LIGHT, (data) => {if (data == null || data == undefined || data.intensity == null || data.intensity == undefined) {ret…

git用法(简易版)

介绍 git是一个版本管理工具 使用方法 建立仓库 第一步 git init&#xff1a;初始化仓库 第二步 git add .&#xff1a;将代码添加到暂存区 第三步 git commit -m "first"&#xff1a;为修改添加备注 第四步 git remote add origin 你的url 第五步 git pus…

【C++八股】内存泄漏

内存泄漏&#xff08;Memory Leak&#xff09;是指程序在动态分配内存后&#xff0c;未能及时释放已分配的内存&#xff0c;导致这些内存无法被再次使用&#xff0c;从而造成系统内存的浪费。随着时间的推移&#xff0c;内存泄漏可能导致程序性能下降&#xff0c;甚至系统崩溃。…

sqli-labs时间盲注和布尔盲注

1、时间盲注和布尔盲注 在SQL注入攻击中&#xff0c;时间盲注&#xff08;Time-Based Blind SQL Injection&#xff09;和布尔盲注&#xff08;Boolean-Based Blind SQL Injection&#xff09;是两种常见的技术&#xff0c;用于在无法直接获取数据的情况下推断数据库信息。 2…

数据库脚本MySQL8转MySQL5

由于生产服务器版本上部署的是MySQL5&#xff0c;而开发手里的脚本代码是MySQL8。所以只能降版本了… 升级版本与降级版本脚本转换逻辑一样 MySQL5与MySQL8版本SQL脚本区别 大多数无需调整、主要是字符集与排序规则 MySQL5与MySQL8版本SQL字符集与排序规则 主要操作&…

Flutter 双屏双引擎通信插件加入 GitCode:解锁双屏开发新潜能

在双屏设备应用场景日益丰富的当下&#xff0c;移动应用开发领域迎来了新的机遇与挑战。如何高效利用双屏设备优势&#xff0c;为用户打造更优质的交互体验&#xff0c;成为开发者们关注的焦点。近日&#xff0c;一款名为 Flutter 双屏双引擎通信插件的创新项目正式入驻 GitCod…

Mysql进阶篇(mysqlcheck - 表维护程序)

mysqlcheck的作用 mysqlcheck客户端用于执行表维护&#xff0c;可以对表进行&#xff1a;分析、检查、优化或修复操作。 &#xff08;1&#xff09;分析的作用是查看表的关键字分布&#xff0c;能够让 sql 生成正确的执行计划&#xff08;支持 InnoDB&#xff0c;MyISAM&#x…

如何使用qt开发一个xml发票浏览器,实现按发票样式显示

使用Qt开发一个按发票样式显示的XML发票浏览器&#xff0c;如下图所示样式&#xff1a; 一、需求&#xff1a; 1、按税务发票样式显示。 2、拖入即可显示。 3、正确解析xml文件。 二、实现 可以按照以下步骤进行&#xff1a; 1. 创建Qt项目 打开Qt Creator&#xff0c;创…

Docker上安装Zabbix-server-mysql报错

创建新的zabbix server &#xff08;mysql&#xff09;容易&#xff0c;最后一条日志报错 cannot usedatabase"zabbix": its "users" table is empty (is this the Zabbix proxy database?) 往前还有一条关键报错信息 ERROR 1153 (08S01): Got a packe…

树和二叉树_13

树和二叉树_13 一、HZOJ-245二、题解1.引库2.代码 一、HZOJ-245 货仓选址 ​ 在一条数轴上有 N 家商店&#xff0c;他们的坐标分别为 A[1]−A[N]。现在需要在数轴上建立一家货仓&#xff0c;每天清晨&#xff0c;从货仓到每家商店都要运送一车商品。为了提高效率&#xff0c;求…

AI Agent有哪些痛点问题

AI Agent有哪些痛点问题 AI Agent领域有哪些知名的论文 目录 AI Agent有哪些痛点问题AI Agent领域有哪些知名的论文难以将自然语言与程序语言结合,跨平台兼容性差,缺乏有效的生产级干预机制具身 AI 在实现快速知识传播方面存在困难,难以从人类和 AI 专家中快速学习并实时模…

c++TinML转html

cTinML转html 前言解析解释转译html类定义开头html 结果这是最终效果&#xff08;部分&#xff09;&#xff1a; ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6cf6c3e3c821446a84ae542bcc2652d4.png) 前言 在python.tkinter设计标记语言(转译2-html)中提到了将Ti…

阿里云OSS创建,及修改读写权限为公共读。

1、创建Bucket 2、创建时需要注意点 〇 名字区域等略过不讲 ①默认为同城冗余&#xff0c;但计费标准更高&#xff0c;如果对数据安全性要求不严格&#xff0c;可以改为本地。 ②如果想开启公共读&#xff0c;会发现创建时改不了&#xff0c;暂时先不改&#xff0c;完成创建…

深入解析A2DP v1.4协议:蓝牙高质量音频传输的技术与实现

1. A2DP概述 A2DP&#xff08;Advanced Audio Distribution Profile&#xff09;是一种高质量音频流媒体协议&#xff0c;旨在实现高质量音频内容的分发&#xff0c;通常用于通过蓝牙设备传输音频数据&#xff0c;例如将音乐从便携式播放器传输到耳机或扬声器。与传统的蓝牙语…

Vulhub靶机 ActiveMQ 反序列化漏洞(CVE-2015-5254)(渗透测试详解)

一、开启vulhub环境 docker-compose up -d 启动 docker ps 查看开放的端口 漏洞版本&#xff1a;Apache ActiveMQ 5.x ~ Apache ActiveMQ 5.13.0 二、访问靶机IP 8161端口 默认账户密码 admin/admin&#xff0c;登录 此时qucues事件为空 1、使用jmet-0.1.0-all.jar工具将…