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.rhkb.cn/news/17532.html

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

相关文章

RAGFlow和Dify对比

‌ RAGFlow和Dify都是基于大语言模型&#xff08;LLM&#xff09;的应用开发平台&#xff0c;具有相似的功能和应用场景&#xff0c;但它们在技术架构、部署要求和用户体验上存在一些差异。‌‌ RAGFlow和Dify对比 2025-02-13 22.08 RAGFlow‌ ‌技术栈‌&#xff1a;RAGFlow…

day9手机创意软件

趣味类 in:记录趣味生活&#xff08;通用&#xff09; 魔漫相机&#xff1a;真人变漫画&#xff08;通用&#xff09; 活照片&#xff1a;让照片活过来&#xff08;通用&#xff09; 画中画相机&#xff1a;与众不同的艺术 年龄检测仪&#xff1a;比一比谁更年轻&#xf…

Next.js 15【实用教程】2025最新版

官网 https://nextjs.org/docs/app/getting-started Next.js 简介 Next.js 由 Vercel 开发和维护&#xff0c;旨在解决单页应用&#xff08;SPA&#xff09;和多页应用&#xff08;MPA&#xff09;在性能和 SEO 上的不足。 核心特性 服务端渲染&#xff08;SSR&#xff09;--…

MySQL 联合索引的最左匹配原则

环境&#xff1a;MySQL 版本&#xff1a;8.0.27 执行计划基础知识 possible_keys&#xff1a;可能用到的索引 key&#xff1a;实际用到的索引 type: ref&#xff1a;当通过普通的二级索引列与常量进行等值匹配的方式 询某个表时const&#xff1a;当我们根据主键或者唯一得…

2025 西湖论剑wp

web Rank-l 打开题目环境&#xff1a; 发现一个输入框&#xff0c;看一下他是用上面语言写的 发现是python&#xff0c;很容易想到ssti 密码随便输&#xff0c;发现没有回显 但是输入其他字符会报错 确定为ssti注入 开始构造payload&#xff0c; {{(lipsum|attr(‘global…

【2024 CSDN博客之星】大学四年,我如何在CSDN实现学业与事业的“双逆袭”?

前言&#xff1a; Hello大家好&#xff0c;我是Dream。不知不觉2024年已经过去&#xff0c;自己也马上迈入23岁&#xff0c;感慨时间飞快&#xff0c;从19岁刚入大学加入CSDN&#xff0c;到现在大学毕业已经整整四年了。CSDN陪伴我走过了最青涩的四年大学时光&#xff0c;在这里…

RAG(检索增强生成)落地:基于阿里云opensearch视线智能问答机器人与企业知识库

文章目录 一、环境准备二、阿里云opensearch准备1、产品文档2、准备我们的数据3、上传文件 三、对接1、对接文本问答 一、环境准备 # 准备python环境 conda create -n opensearch conda activate opensearch# 安装必要的包 pip install alibabacloud_tea_util pip install ali…

Qt事件机制

目录 一、事件基本概念 1.1 事件基本概念和产生 1.2 事件类 1.3 事件发送 二、事件的捕获处理 2.1 事件处理流程 2.2事件分发&#xff08;event&#xff09;处捕获事件 2.3 事件过滤器 2.4 重新实现事件处理函数 三、 QEventLoop 3.1事件循环基本概念 3.2 QEventL…

20250212:sigmastar系列2-获取UUID进行授权

距离上一篇Sigmastar文章已经过去3年了。最近基于Sigmastar-330 开发人脸识别SDK,需要进行授权管理,所以需要获取UUID作为激活、授权的凭证。 本文记录2个事情:授权逻辑 + sigmastar获取UUID 1:授权流程 step1:算法SDK在设备上电,算法初始化环节,校验本地是否有加密存…

STM32F407通过FSMC扩展外部SRAM和NAND FLASH

1 扩展外部SRAM 1.1 地址情况 FSMC控制器的存储区分为4个区(Bank)&#xff0c;每个区256MB。其中&#xff0c;Bank1可以用于连接SRAM、NOR FLASH、PSRAM&#xff0c;还可以连接TFT LCD。Bank1的地址范围是0x60000000&#xff5e;0x6FFFFFFF。Bank1又分为4个子区&#xff0c;每…

MySQL Workbench工具 导出导入数据库

第一步 数据库导出 1、打开workbench->连接数据库->Server->Data Export 2、选择要导出的数据库&#xff0c;Export Self-Contained File ->更改导出位置和数据库名->Start Export 3、提示“sql has finished”&#xff0c;没有error表示导出成功 第二步 数据…

我用AI做数据分析之四种堆叠聚合模型的比较

我用AI做数据分析之四种堆叠聚合模型的比较 这里AI数据分析不仅仅是指AI生成代码的能力&#xff0c;我想是测试AI数据分析方面的四个能力&#xff0c;理解人类指令的能力、撰写代码的能力、执行代码的能力和解释结果的能力。如果这四个能力都达到了相当的水准&#xff0c;才可…

广告深度学习计算:阿里妈妈大模型服务框架HighService

一、背景 HighService(High-Performance Pythonic AI Service) 是在支持阿里妈妈业务过程中&#xff0c;不断提炼抽象出的高性能Python AI服务框架&#xff0c;支持视频、图文、LLM等多种模型&#xff0c;能够显著加快模型的推理速度&#xff0c;提高集群的资源利用效率。随着S…

深度学习框架探秘|TensorFlow vs PyTorch:AI 框架的巅峰对决

在深度学习框架中&#xff0c;TensorFlow 和 PyTorch 无疑是两大明星框架。前面两篇文章我们分别介绍了 TensorFlow&#xff08;点击查看&#xff09; 和 PyTorch&#xff08;点击查看&#xff09;。它们引领着 AI 开发的潮流&#xff0c;吸引着无数开发者投身其中。但这两大框…

企语企业管理系iFair(F23.2_a0)在Debian操作系统中的安装

起因&#xff1a;在安装了F24.8版本后&#xff0c;发现生产用环境和测试、开发用环境还是分开的好。 旧版的用来实验、测试&#xff0c;新版的一步一步小心的配置、使用是比较稳妥的操作。因此&#xff0c;决定在KVM虚拟机上搭建一个F23.2版本的企语系统。 一、 存在的问题 而…

Redis 数据类型 Hash 哈希

在 Redis 中&#xff0c;哈希类型是指值本⾝⼜是⼀个键值对结构&#xff0c;形如 key "key"&#xff0c;value { { field1, value1 }, ..., {fieldN, valueN } }&#xff0c;Redis String 和 Hash 类型⼆者的关系可以⽤下图来表⽰。 Hash 数据类型的特点 键值对集合…

Elasticsearch:15 年来致力于索引一切,找到重要内容

作者&#xff1a;来自 Elastic Shay Banon 及 Philipp Krenn Elasticsearch 刚刚 15 岁了&#xff01;回顾过去 15 年的索引和搜索&#xff0c;并展望未来 15 年的相关内容。 Elasticsearch 刚刚成立 15 周年。一切始于 2010 年 2 月的一篇公告博客文章&#xff08;带有标志性的…

EF Core中实现值对象

目录 值对象优点 值对象的需求 值类型的实现 值类型GEO的实现 值类型MultilingualString的实现 案例&#xff1a;构建表达式树&#xff0c;简化值对象的比较 值对象优点 把有紧密关系的属性打包为一个类型把领域知识放到类的定义中 class shangjia {long id;string nam…

ETHEREAL:使用压缩Tsetlin机器实现能效高吞吐量推理

论文标题 英文标题&#xff1a;ETHEREAL: Energy-efficient and High-throughput Inference using Compressed Tsetlin Machine 中文标题&#xff1a;ETHEREAL&#xff1a;使用压缩Tsetlin机器实现能效高吞吐量推理 作者信息 Shengyu Duan, Newcastle University, Newcastle…

PyCharm 批量替换

选择替换的内容 1. 打开全局替换窗口 有两种方式可以打开全局替换窗口&#xff1a; 快捷键方式&#xff1a; 在 Windows 或 Linux 系统下&#xff0c;按下 Ctrl Shift R。在 Mac 系统下&#xff0c;按下 Command Shift R。菜单操作方式&#xff1a;点击菜单栏中的 Edit&…