首页 > 其他分享 >Solidity智能合约例子:存证合约

Solidity智能合约例子:存证合约

时间:2023-12-13 17:56:03浏览次数:27  
标签:存证 hash name type Solidity bytes32 address 合约

一、合约编写

感谢b站上的UP老哥冲少,这里参考了他的视频。一共是4个合约,1个是权限控制,1个存证、1个存证申请(是否可以存证有投票机制)、还一个入口合约。

Authentication.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

contract Authentication {
    address public _owner;
    mapping (address => bool) private _acl;

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == _owner, "Not Admin");
        _;
    }

    modifier auth(){
        require(msg.sender==_owner || _acl[msg.sender]==true, "Not Authenticated");
        _;
    }

    function allow(address addr) public onlyOwner{
        _acl[addr] = true;
    }

    function deny(address addr) public onlyOwner{
        _acl[addr] = false;
    }
}

EvidenceRepository.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "./Authentication.sol";

contract EvidenceRepository is Authentication{

    struct EvidenceData{
        bytes32 hash;
        address owner;
        uint timestamp;
    }

    mapping(bytes32=>EvidenceData) private _evidences; //所有存证数据,用data hash进行索引

    function setData(bytes32 hash, address owner, uint timestamp) public auth{
        _evidences[hash].hash = hash;
        _evidences[hash].owner = owner;
        _evidences[hash].timestamp = timestamp;
    }

    function getData(bytes32 hash) public view returns(bytes32, address, uint) {
        EvidenceData storage evidence = _evidences[hash];
        require(evidence.hash == hash, "Evidence not exist");
        return (evidence.hash, evidence.owner, evidence.timestamp);
    }
}

RequestRepository.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "./Authentication.sol";

contract RequestRepository is Authentication {
    struct SaveRequest{
        bytes32 hash;    //data hash
        address creator; //存证创建人
        uint8 voted; //投了多少票了
        bytes desc;
        mapping(address=>bool) status;  //投票人是否针对可以存证进行了投票
    }
    uint8 public _threshold;    //达到多少票算通过,可以存证
    mapping(bytes32=>SaveRequest) private _saveRequests;
    mapping(address=>bool) private _voters;

    constructor(uint8 threshold, address[] memory voterArray) {
        _threshold = threshold;
        for(uint i=0; i<voterArray.length; i++){
            _voters[voterArray[i]] = true;
        }
    }

    function createSaveRequest(bytes32 hash, address owner, bytes memory desc) public auth{
        require(_saveRequests[hash].hash == 0, "request already existed");
        _saveRequests[hash].hash = hash;
        _saveRequests[hash].creator = owner;
        _saveRequests[hash].desc = desc;
    }

    function voteSaveRequest(bytes32 hash, address voter) public auth returns (bool) {
        require(_voters[voter] == true, "Not allowed to vote");
        require(_saveRequests[hash].hash == hash, "request not found");
        SaveRequest storage request = _saveRequests[hash];
        require(request.status[voter] == false, "Voter already voted");
        request.status[voter] = true;
        request.voted++;
        return true;
    }

    function getRequestData(bytes32 hash) public view 
        returns(bytes32, address creator, bytes memory desc, uint8 voted, uint8 threshold) {   
        SaveRequest storage request = _saveRequests[hash];
        require(_saveRequests[hash].hash==hash, "request not found");
        return (hash, request.creator, request.desc, request.voted, _threshold);
    }

    function deleteSaveRequest(bytes32 hash) public auth{
        require(_saveRequests[hash].hash==hash, "request not found");
        delete _saveRequests[hash];
    }
}

EvidenceController.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "./EvidenceRepository.sol";
import "./RequestRepository.sol";

contract EvidenceController {
    EvidenceRepository public _evidenceRepo;
    RequestRepository public _requestRepo;

    event CreateSaveRequestEvent(bytes32 indexed hash, address creator);
    event VoteSaveRequestEvent(bytes32 indexed hash, address voter, bool complete);
    event EvidenceSavedEvent(bytes32 indexed hash);

    constructor(uint8 threshold, address[] memory voterArray)  {
        _evidenceRepo = new EvidenceRepository();
        _requestRepo = new RequestRepository(threshold, voterArray);
    }

    modifier validDataHash(bytes32 hash){
        require(hash != 0, "Not valid hash");
        _;
    }

    function createSaveRequest(bytes32 hash, bytes memory ext) public validDataHash(hash) {
        _requestRepo.createSaveRequest(hash, msg.sender, ext);
        emit CreateSaveRequestEvent(hash, msg.sender);
    }

    function voteSaveRequest(bytes32 hash) public validDataHash(hash) returns (bool) {
        bool b = _requestRepo.voteSaveRequest(hash, msg.sender);
        if(!b){
            return false;
        }
        (bytes32 h, address creator, bytes memory ext, uint8 voted, uint8 threshold) 
            = _requestRepo.getRequestData(hash);
        bool passed = voted >= threshold;
        emit VoteSaveRequestEvent(hash, msg.sender, passed);
        if(passed){
            _evidenceRepo.setData(hash, creator, block.timestamp);
            _requestRepo.deleteSaveRequest(hash);
            emit EvidenceSavedEvent(hash);
        }
        return true;
    }

    function getRequestData(bytes32 hash) public view 
    returns (bytes32, address creator, bytes memory ext, uint8 voted, uint8 threshold) {
        return _requestRepo.getRequestData(hash);
    }

    function getEvidence(bytes32 hash) public view returns (bytes32, address, uint) {
        return _evidenceRepo.getData(hash);
    }
}

二、部署与测试

部署脚本deploy.js

const { ethers } = require("hardhat");

async function main() {
  const [deployer] = await ethers.getSigners();
 
  console.log("Deploying contracts with the Account:", deployer.address);

  const votersWhiteList = ["0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A",
                                  "0x72BbA0fE9D0dA19b27705BCdDAb783BeED24bbDb",
                                  "0x5e4105b9d7C6a5D7a9ce282F36018E95e76Cf95C"];

  const EvidenceController = await ethers.deployContract("EvidenceController" , [2, votersWhiteList] );
 
  console.log("EvidenceController Address:", await EvidenceController.getAddress());
}
 
main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

部署到ganache:

>npx hardhat run scripts/deploy.js --network ganache
Deploying contracts with the Account: 0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A
EvidenceController Address: 0xCC6075edc208F8531BbE62751590C48390B65e18

测试脚本call.js

const { ethers } = require("hardhat");

const contractABI = [
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "threshold",
          "type": "uint8"
        },
        {
          "internalType": "address[]",
          "name": "voterArray",
          "type": "address[]"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "bytes32",
          "name": "hash",
          "type": "bytes32"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "creator",
          "type": "address"
        }
      ],
      "name": "CreateSaveRequestEvent",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "bytes32",
          "name": "hash",
          "type": "bytes32"
        }
      ],
      "name": "EvidenceSavedEvent",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "bytes32",
          "name": "hash",
          "type": "bytes32"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "voter",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "bool",
          "name": "complete",
          "type": "bool"
        }
      ],
      "name": "VoteSaveRequestEvent",
      "type": "event"
    },
    {
      "inputs": [],
      "name": "_evidenceRepo",
      "outputs": [
        {
          "internalType": "contract EvidenceRepository",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "_requestRepo",
      "outputs": [
        {
          "internalType": "contract RequestRepository",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "bytes32",
          "name": "hash",
          "type": "bytes32"
        },
        {
          "internalType": "bytes",
          "name": "ext",
          "type": "bytes"
        }
      ],
      "name": "createSaveRequest",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "bytes32",
          "name": "hash",
          "type": "bytes32"
        }
      ],
      "name": "getEvidence",
      "outputs": [
        {
          "internalType": "bytes32",
          "name": "",
          "type": "bytes32"
        },
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "bytes32",
          "name": "hash",
          "type": "bytes32"
        }
      ],
      "name": "getRequestData",
      "outputs": [
        {
          "internalType": "bytes32",
          "name": "",
          "type": "bytes32"
        },
        {
          "internalType": "address",
          "name": "creator",
          "type": "address"
        },
        {
          "internalType": "bytes",
          "name": "ext",
          "type": "bytes"
        },
        {
          "internalType": "uint8",
          "name": "voted",
          "type": "uint8"
        },
        {
          "internalType": "uint8",
          "name": "threshold",
          "type": "uint8"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "bytes32",
          "name": "hash",
          "type": "bytes32"
        }
      ],
      "name": "voteSaveRequest",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ];

async function main(){
    const contractAddress = "0xCC6075edc208F8531BbE62751590C48390B65e18";
    const provider = ethers.getDefaultProvider("http://localhost:7545/");

    //获取地址有多少ETH,获取当前区块高度
    const queryAddress = "0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A";
    let ethBalance = await provider.getBalance(queryAddress);
    console.log("地址%s有%s个ETH", queryAddress, ethBalance);
    let blockNumber = await provider.getBlockNumber();
    console.log("当前链上区块高度%s", blockNumber);

    //调用合约方法
    //查询
    let evidenceContract = await new ethers.Contract(contractAddress, contractABI, provider);
    
    
    //写(调用合约新建存证方法)
    const sha256hash = "0x4d633e712a045622a49398476ddd54ee0ffdb7e8881757724918b795fc5ea06c";

    let signer = await new ethers.Wallet("0x624cfb2cb9b9c3212abfa2800fd8de8e2501c84500336007f4459c50198c69f7", provider);
    let evidenceContractConnected = await evidenceContract.connect(signer);

    //创建一个存证请求
    console.log("==================>新建存证请求");
    const ext = ethers.toUtf8Bytes("feituzi ai douchuzi");
    let txn = await evidenceContractConnected.createSaveRequest(sha256hash, ext);
    console.log("创建存证请求, 交易结果: %s", txn);

    console.log("==================>查询存证请求");
    let request = await evidenceContractConnected.getRequestData(sha256hash);
    //bytes32, address creator, bytes memory ext, uint8 voted, uint8 threshold
    console.log("存证请求内容, datahash:%s, 创建人:%s, 附加信息:%s, 已投票:%s, 共需投票:%s", 
        request[0], request[1], request[2], request[3], request[4]);

    //存证请求需要两个以上地址vote,第一个投票
    console.log("==================>存证请求需要两个以上地址vote");
    let result = await evidenceContractConnected.voteSaveRequest(sha256hash);
    console.log("%s对存证请求的投票结果%s", await signer.getAddress(), result);
    //第二个投票
    signer = await new ethers.Wallet("0x68ef8f95e6c8bc2411a6f4ca995d5ffbe73d146a43f829c40002f1fe57fe305d", provider);
    evidenceContractConnected = await evidenceContract.connect(signer);
    result = await evidenceContractConnected.voteSaveRequest(sha256hash);
    console.log("%s对存证请求的投票结果%s", await signer.getAddress(), result);

    console.log("==================>查询存证结果");
    let evidence = await evidenceContractConnected.getEvidence(sha256hash);
    console.log("存证内容DataHash:%s, 存证人Address:%s, 存证时间戳:%s", evidence[0], evidence[1], evidence[2]);

    

}

main()
.then(() => {
    process.exit(0);
})
.catch((error) => {
    console.error(error);
    process.exit(1);
});

输出:

>npx hardhat run scripts/call.js --network ganache
地址0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A有99979908610956548638n个ETH
当前链上区块高度16
==================>新建存证请求
创建存证请求, 交易结果: ContractTransactionResponse {
  provider: JsonRpcProvider {},
  blockNumber: null,
  blockHash: null,
  index: undefined,
  hash: '0x4878174613c432e93ee101a4537c4e06de250cc77fa788ef6a574e2b0b904a0b',
  type: 2,
  to: '0xCC6075edc208F8531BbE62751590C48390B65e18',
  from: '0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A',
  nonce: 15,
  gasLimit: 101692n,
  gasPrice: undefined,
  maxPriorityFeePerGas: 1000000000n,
  maxFeePerGas: 1420328120n,
  data: '0x8c7536af4d633e712a045622a49398476ddd54ee0ffdb7e8881757724918b795fc5ea06c0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001366656974757a6920616920646f756368757a6900000000000000000000000000',
  value: 0n,
  chainId: 1337n,
  signature: Signature { r: "0xa7ee9a9892bcb9d3e84336bfcd435c7bb5aa7462c5f96c1475fbca01e3a13c40", s: "0x6077dba0e1554f172a7f38ac7c4e0db54b792c8c2a4ef740870be77becb5b3ed", yParity: 1, networkV: null },
  accessList: []
}
==================>查询存证请求
存证请求内容, datahash:0x4d633e712a045622a49398476ddd54ee0ffdb7e8881757724918b795fc5ea06c, 创建人:0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A, 附加信息:0x66656974757a6920616920646f756368757a69, 已投票:0n, 共需投票:2n
==================>存证请求需要两个以上地址vote
0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A对存证请求的投票结果ContractTransactionResponse {
  provider: JsonRpcProvider {},
  blockNumber: null,
  blockHash: null,
  index: undefined,
  hash: '0xbb8a1acf8993ff091a8fed2304086b478af3321441936d934d7eee11d9bdfee0',
  type: 2,
  to: '0xCC6075edc208F8531BbE62751590C48390B65e18',
  from: '0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A',
  nonce: 16,
  gasLimit: 74712n,
  gasPrice: undefined,
  maxPriorityFeePerGas: 1000000000n,
  maxFeePerGas: 1369376818n,
  data: '0xab9beda74d633e712a045622a49398476ddd54ee0ffdb7e8881757724918b795fc5ea06c',
  value: 0n,
  chainId: 1337n,
  signature: Signature { r: "0xdf53f19910951b0e909dcdd0019fc0be14c593559225fbdd80b0474cb3927135", s: "0x29e7c9ec820132a504978e3a3f2634c307332768d6bb8f2df6a5cc43fa6d2b08", yParity: 1, networkV: null },
  accessList: []
}
0x5e4105b9d7C6a5D7a9ce282F36018E95e76Cf95C对存证请求的投票结果ContractTransactionResponse {
  provider: JsonRpcProvider {},
  blockNumber: null,
  blockHash: null,
  index: undefined,
  hash: '0x53445ece5e25cc99557b169274f6f45a1b2705dee1c735e28934ecb700aa1251',
  type: 2,
  to: '0xCC6075edc208F8531BbE62751590C48390B65e18',
  from: '0x5e4105b9d7C6a5D7a9ce282F36018E95e76Cf95C',
  nonce: 1,
  gasLimit: 159052n,
  gasPrice: undefined,
  maxPriorityFeePerGas: 1000000000n,
  maxFeePerGas: 1324601728n,
  data: '0xab9beda74d633e712a045622a49398476ddd54ee0ffdb7e8881757724918b795fc5ea06c',
  value: 0n,
  chainId: 1337n,
  signature: Signature { r: "0xd48914d918cb84f5ef267ede0eda21ba4212928b4c9bc07411e8dc5faf22f14e", s: "0x6965f60c9d2858c091be6a028d942fd6b66e9e1271ec47757e99581ea2a4564d", yParity: 1, networkV: null },
  accessList: []
}
==================>查询存证结果
存证内容DataHash:0x4d633e712a045622a49398476ddd54ee0ffdb7e8881757724918b795fc5ea06c, 存证人Address:0xF7A1938Fecc594aaF126d46fd173cE74A659ad9A, 存证时间戳:1702459055n

标签:存证,hash,name,type,Solidity,bytes32,address,合约
From: https://www.cnblogs.com/lyhero11/p/17899616.html

相关文章

  • 使用hardhat + ganache进行本地solidity开发
    hardhat是有本地开发网络的,但ganache是个有界面的程序,也是在本地模拟一个以太坊链,但是界面比较漂亮一些。hardhat.config.jsrequire("@nomicfoundation/hardhat-toolbox");/**@typeimport('hardhat/config').HardhatUserConfig*/module.exports={solidity:"0.8.19",......
  • Solidity基本语法学习4
    文档:https://solidity-by-example.org/视频教程:https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p说明:本文内容:FunctionModifier,Events,Constructor,Inheritance,ShadowingInheritedStateVariables,CallingParentCon......
  • Solidity基本语法学习3
    文档:https://solidity-by-example.org/视频教程:https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p说明:本文内容:Enum,struct,datalocation,function,ViewandPureFunction,ErrorEnum(枚举)Solidity支持枚举,这对modelch......
  • Solidity基本概念学习2
    文档:https://solidity-by-example.org/视频教程:https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p说明看视频没注意有文档,前面写了一篇好多废话,之后结合文档+视频去做笔记和写代码,做记录...常量(constant)常量是不能修改的......
  • 基于truffle进行合约部署
    1.Truffle简介1.1.什么是Truffle?Truffle是一个世界级的开发环境,测试框架,以太坊的资源管理通道,致力于让以太坊上的开发变得简单。Truffle有以下特性:内置的智能合约编译,链接,部署和二进制文件的管理;快速开发下的自动合约测试;脚本化的,可扩展的部署与发布框架;部署到不管多......
  • Solidity初学
    https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-phelloworld//SPDX-License-Identifier:MIT//如果没有上面的license就会出现黄色warning,挺难看的..pragmasolidity^0.8;//指定solidity编译版本,带了^号说明要在该版本(0.8)......
  • java版本的智能合约部署到fabric区块链测试网络
    开发智能合约并进行部署和更新操作在之前的文章中我们可以成功启动测试网络并进行了相关测试,现在我们需要进行智能合约的编写操作,并将其部署到测试网络中进行相关测试。本节智能合约代码采取Java语言进行编写,代码及相关部署参考(https://www.bilibili.com/video/BV1DR4y1M74B/?spm......
  • solidity--time
    1//SPDX-License-Identifier:GPL-3.0-or-later23pragmasolidity>=0.8.0;45contractdatetime{67constructor(){89}101112functiongetBlockTime()publicviewreturns(uint256){1314returnbl......
  • 把bsc的合约代码部署到opbnb
    1.找到bsc已经正式部署的合约https://bscscan.com/ 2.拷贝ContractSourceCode把文件导出为xxx.sol 3.把导出的sol文件导入remix编辑器打开remix编辑器https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+com......
  • 合约量化交易系统APP开发案例
    项目背景:该案例软件的开发是一款针对市场交易员而设计的软件系统,它能帮助交易者实现高效率的合约交易。我们目的是以用户的需求为主进行开发,应对市场上未知的风险和把控。开发过程:软件在开发过程中,采用了多种的开发按技术,软件工具包,开发框架,数据库技术,移动端的开发。在开发前先......