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 {
    @Autowired
    DataStorageExample 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 和 Credentials
    static {
        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数据上链

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

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

相关文章

【深度学习】多目标融合算法(四):多门混合专家网络MMOE(Multi-gate Mixture-of-Experts)

目录 一、引言 二、MMoE&#xff08;Multi-gate Mixture-of-Experts&#xff0c;多门混合专家网络&#xff09; 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 2.3.1 业务场景与建模 2.3.2 模型代码实现 2.3.3 模型训练与推理测试 2.3.4 打印模型结构 三、总结 一、…

sqli-labs靶场实录(四): Challenges

sqli-labs靶场实录: Challenges Less54确定字段数获取数据库名获取表名获取列名提取密钥值 Less55Less56Less57Less58爆库构造爆表构造爆列构造密钥提取构造 Less59Less60Less61Less62爆库构造 Less63Less64Less65免责声明&#xff1a; Less54 本关开始上难度了 可以看到此关仅…

使用Redis实现分布式锁,基于原本单体系统进行业务改造

一、单体系统下&#xff0c;使用锁机制实现秒杀功能&#xff0c;并限制一人一单功能 1.流程图&#xff1a; 2.代码实现&#xff1a; Service public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderSe…

Python + WhisperX:解锁语音识别的高效新姿势

大家好&#xff0c;我是烤鸭&#xff1a; 最近在尝试做视频的质量分析&#xff0c;打算利用asr针对声音判断是否有人声&#xff0c;以及识别出来的文本进行进一步操作。asr看了几个开源的&#xff0c;最终选择了openai的whisper&#xff0c;后来发现性能不行&#xff0c;又换了…

【Linux】Ubuntu Linux 系统——Node.js 开发环境

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天星期五了&#xff0c;同时也是2025年的情人节&#xff0c;今晚又是一个人的举个爪子&#xff01;&#xff01; &#x1f642; 本文是有关Linux 操作系统中 Node.js 开发环境基础知识&#xff0c;后续我将添加更多相关知识噢&a…

Oracle查看执行计划

方式一&#xff08;查看的真实的使用到的索引&#xff09; 1.执行解释计划 2.查看结果 可以看到使用了RANGE SCAN范围扫描的索引 方式二&#xff08;查看的是预测的可能会用到的索引&#xff09; 1.执行解释计划sql explain plan for select * from COURSE where COURSE_…

百度 AI开源!将在6月30日开源文心大模型4.5系列

【大力财经】直击互联网最前线&#xff1a;百度近期动作频频&#xff0c;先是宣布将在未来数月陆续推出文心大模型4.5系列&#xff0c;并于6月30日正式开源。 据大力财经了解&#xff0c;自DeepSeek开源之风盛行全球后&#xff0c;开源闭源路径的选择就成为AI领域的热门话题&a…

【DDD系列-2】风暴出的领域模型

为什么使用DDD​ 三个问题​ 1.为什么我们的系统越做越多&#xff0c;越来越庞大&#xff0c;还需要不断的重构&#xff1f;​ 2.为什么我们的系统业务越来越复杂&#xff0c;服务层的代码越来越多难以维护&#xff0c;不敢维护&#xff1f;​ 3.为什么一旦业务变化或者数据…

基于YALMIP和cplex工具箱的微电网最优调度算法matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 系统建模 4.2 YALMIP工具箱 4.3 CPLEX工具箱 5.完整工程文件 1.课题概述 基于YALMIP和cplex工具箱的微电网最优调度算法matlab仿真。通过YALMIP和cplex这两个工具箱&#xff0c;完成微电网的最优调…

visual studio导入cmake项目后打开无法删除和回车

通过Cmakelists.txt导入的项目做删除和回车无法响应&#xff0c;需要点击项目&#xff0c;然后选择配置项目就可以了

npm安装时无法访问github域名的解决方法

个人博客地址&#xff1a;npm安装时无法访问github域名的解决方法 | 一张假钞的真实世界 今天在用npm install的时候出现了github项目访问不了的异常&#xff1a; npm ERR! Error while executing: npm ERR! /bin/git ls-remote -h -t https://github.com/nhn/raphael.git np…

解锁豆瓣高清海报(三)从深度爬虫到URL构造,实现极速下载

脚本地址: 项目地址: Gazer PosterBandit_v2.py 前瞻 之前的 PosterBandit.py 是按照深度爬虫的思路一步步进入海报界面来爬取, 是个值得学习的思路, 但缺点是它爬取慢, 仍然容易碰到豆瓣的 418 错误, 本文也会指出彻底解决旧版 418 错误的方法并提高爬取速度. 现在我将介绍…

一维差分算法篇:高效处理区间加减

那么在正式介绍我们的一维差分的原理前&#xff0c;我们先来看一下一维差分所应用的一个场景&#xff0c;那么假设我们现在有一个区间为[L,R]的一个数组&#xff0c;那么我要在这个数组中的某个子区间比如[i,m] (L<i<m<R)进行一个加k值或者减去k值的一个操作&#xff…

信息收集-Web应用JS架构URL提取数据匹配Fuzz接口WebPack分析自动化

知识点&#xff1a; 1、信息收集-Web应用-JS提取分析-人工&插件&项目 2、信息收集-Web应用-JS提取分析-URL&配置&逻辑 FUZZ测试 ffuf https://github.com/ffuf/ffuf 匹配插件 Hae https://github.com/gh0stkey/HaE JS提取 JSFinder https://github.com/Threez…

Python基础语法精要

文章目录 一、Python的起源二、Python的用途三、Python的优缺点优点缺点 四、基础语法&#xff08;1&#xff09;常量和表达式&#xff08;2&#xff09;变量变量的语法&#xff08;i&#xff09;定义变量&#xff08;ii&#xff09;变量命名的规则 &#xff08;3&#xff09;变…

测试方案整理

搜索引擎放在那里&#xff1f;研发 查看问题样本或者在提取再批量入录等情况&#xff0c;一旦我没有勾选或者全选中已经批量入录的样本&#xff0c;那么在直接点击批量提取或查看问题样本的后&#xff0c;会自动默认为选择全选样本还是按照输入错误处理&#xff1f; 批量查看返…

开启对话式智能分析新纪元——Wyn商业智能 BI 携手Deepseek 驱动数据分析变革

2月18号&#xff0c;Wyn 商业智能 V8.0Update1 版本将重磅推出对话式智能分析&#xff0c;集成Deepseek R1大模型&#xff0c;通过AI技术的深度融合&#xff0c;致力于打造"会思考的BI系统"&#xff0c;让数据价值触手可及&#xff0c;助力企业实现从数据洞察到决策执…

政策赋能科技服务,CES Asia 2025将展北京科技新貌

近日&#xff0c;《北京市支持科技服务业高质量发展若干措施》正式印发&#xff0c;为首都科技服务业的腾飞注入了强大动力。 该《若干措施》提出了三方面14条政策措施。在壮大科技服务业市场主体方面&#xff0c;不仅支持科技服务业企业向平台化和综合性服务机构发展&#xf…

2024春秋杯网络安全联赛冬季赛wp

web flask 根据题目描述&#xff0c;很容易想到ssti注入 测试一下 确实存在 直接打payload {{lipsum.globals[‘os’].popen(‘cat f*’).read()}} file_copy 看到题目名字为file_copy&#xff0c; 当输入路径时会返回目标文件的大小&#xff0c; 通过返回包&#xff0c…

Mac os部署本地deepseek+open UI界面

一.部署本地deepseek 使用ollama部署&#xff0c;方便快捷。 ollama介绍&#xff1a;Ollama 是一个高效、便捷的人工智能模型服务平台&#xff0c;提供多样化的预训练模型&#xff0c;涵盖自然语言处理、计算机视觉、语音识别等领域&#xff0c;并支持模型定制和微调。其简洁…