Fisco-Bcos智能合约开发案例----多签存证合约

多签存证合约功能在这里插入图片描述

1. 编写多签存证接口和存证合约

pragma solidity^0.8.7;

interface IEvidence{
    //验证某个人是否具有签名资格
   function verify(address _signer) external view returns(bool);
   //根据编号查看某个人的具体签名信息
   function getSigner(uint256 _index)external view returns(address);
   //查看所有人的签名信息
   function getAllSigner()external view returns(address[] memory);
   //查看需要签名的用户数量
   function getSignersSize()external view returns(uint256);
}
contract Evidence{
    //数据定义
    string evidence;
    address[] signers;//已签过名列表
    address public factoryAddr;//工厂合约接口地址

    event NewSignaturesEvidence(string _evi,address _sender);
    event AddRepeatSignatureEvidence(string _evi,address _sender);
    event AddSignatureEvidence(string _evi,address _sender);
    
    //验证调用合约的人是否具有签名的资格
    function callVerify(address _signer) public view returns(bool){
        return IEvidence(factoryAddr).verify(_signer);
    }

    //function
    constructor(string memory _evi,address _factory){
        factoryAddr=_factory;
        //此处不能使用msg.sender,因为A合约调用B合约,B合约中的msg.sender是A合约的地址,而不是调用合约的账户地址,tx.origin交易的原始发起者
        require(callVerify(tx.origin),"_signer is not valid!");
        //记录存证信息
        evidence=_evi;
        //存入签名列表中
        signers.push(tx.origin);

        emit NewSignaturesEvidence(_evi,tx.origin);
    }

    //查看某个存证信息,具体包括存证数据,待签名列表,已签名列表
    function getEvidence() public view returns(string memory,address[] memory,address[] memory){
        uint256 isize = IEvidence(factoryAddr).getSignersSize();
        address[] memory signerList= new address[](isize);
        for(uint256 i=0;i<isize;i++){
            signerList[i]=IEvidence(factoryAddr).getSigner(i);
        }
        return(evidence,signerList,signers);
    }
    //查看所有存证信息,具体包括存证数据,待签名列表,已签名列表
    function getAllEvidence() public view returns(string memory,address[] memory,address[] memory){
        uint256 isize = IEvidence(factoryAddr).getSignersSize();
        address[] memory signerList= new address[](isize);
        for(uint256 i=0;i<isize;i++){
            signerList[i]=IEvidence(factoryAddr).getSigner(i);
        }
        return(evidence,signerList,signers);
    }

    //签名
    function sign()public returns(bool){
        //判断该人是否有签名资格
         require(callVerify(tx.origin),"_signer is not valid!");
         //该人是否已经签过名
         if(isSigned(tx.origin)){
             emit  AddRepeatSignatureEvidence(evidence,tx.origin);
             return true;
         }
         signers.push(tx.origin);
         emit  AddSignatureEvidence(evidence,tx.origin);
         return true;

    }
    //验证是否已经签过名
    function isSigned(address _signer)internal  view returns(bool){
        for(uint256 i=0;i<signers.length;i++){
            if(signers[i]==_signer){
                return true;
            }
        }
        return  false;
    } 
    //是否所有人都已签过名
    function isAllSigned()public view returns(bool,string memory){
         uint256 isize = IEvidence(factoryAddr).getSignersSize();
         for(uint256 i=0;i<isize;i++){
             if(!isSigned(IEvidence(factoryAddr).getSigner(i))){
                 return(false,"");
             }
         }
         return(true,evidence);
    }
}

2. 编写工厂合约

pragma solidity^0.8.7;

import "./Evidence.sol";

contract EvidenceFactory is IEvidence{

    mapping(string=>address) evi_keys; //记录若干个存证合约信息
    address[] signers; //签名列表
   //记录存证合约信息,存证合约的创建者,存证合约地址
    event NewEvidence(string  _evi,address _sender,address _eviAddr);

    constructor(address[]memory _signers){
        for(uint256 i=0;i<_signers.length;i++){
            signers.push(_signers[i]);
        }
    }

     //验证某个人是否具有签名资格
   function verify(address _signer)override external view returns(bool){
      for(uint256 i=0;i<signers.length;i++){
          if(signers[i]==_signer){
              return true;
          }
      }
      return false;
   }
   //根据编号查看某个人的具体签名信息
   function getSigner(uint256 _index) override external view returns(address){
       if(_index<signers.length){
           return signers[_index];
       }else{
           return address(0);
       }
   }
    //查看所有人的签名信息
   function getAllSigner() override external view returns(address[] memory){
       return signers;
   }
   //查看需要签名的用户数量
   function getSignersSize() override external view returns(uint256){
       return signers.length;
   }

   //创建存证 ,第二个参数是为了记录存证合约地址,有了地址,才可以进行后续操作
   function newEvidence(string memory _evi,string memory _key)public returns(address){
        Evidence evidence = new Evidence(_evi,address(this));
        evi_keys[_key] = address(evidence); //强制类型转换
        emit NewEvidence(_evi,msg.sender, address(evidence));
        return address(evidence);
   }
   //查询存证
   function getEvidence(string memory _key)public view returns(string memory,address[] memory,address[] memory){
       address addr = evi_keys[_key];
       return Evidence(addr).getEvidence();
   }
   //签名方法
   function sign(string memory _key)public returns(bool){
           address addr = evi_keys[_key];
           return Evidence(addr).sign();
   }
   //是否所有都签名
   function isAllSigned(string memory _key) public view returns(bool,string memory){
          address addr = evi_keys[_key];
           return Evidence(addr).isAllSigned();
   }

}

3.测试

部署工厂合约,初始化需要签名的列表
在这里插入图片描述
在这里插入图片描述

1. 查看需要签名的人数

在这里插入图片描述

2. 查看某个签名信息

在这里插入图片描述

3. 查看所有签名信息

在这里插入图片描述

4.创建存证

在这里插入图片描述

5.查询存证信息

包含存证信息,待签名列表,已签名列表,创建存证的人默认已经签名
在这里插入图片描述

6.签名

使用未在签名列表的账户进行签名

在这里插入图片描述
在这里插入图片描述

出现以下错误
在这里插入图片描述
使用正确的账户进行签名
在这里插入图片描述
查询存证信息,已经2人签名
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.查看是否全部签名

在这里插入图片描述

注意

//此处不能使用msg.sender,因为A合约调用B合约,B合约中的msg.sender是A合约的地址,而不是调用合约的账户地址,tx.origin交易的原始发起者
        require(callVerify(tx.origin),"_signer is not valid!");
  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
FISCO-BCOS智能合约支持使用C++编写智能合约,因此可以在智能合约中使用SM4算法的C++源码实现。以下是一个简单的示例: ```cpp #include <openssl/evp.h> #include <string.h> extern "C" { #include "sm4.h" } // 使用OpenSSL库实现SM4算法加密 std::string sm4_encrypt_openssl(const std::string& key, const std::string& iv, const std::string& data) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); // 设置加密算法和模式 EVP_EncryptInit_ex(ctx, EVP_sms4_cbc(), NULL, (const unsigned char*)key.c_str(), (const unsigned char*)iv.c_str()); // 执行加密操作并获取加密后的数据 int len = data.length(); int ciphertext_len = len + EVP_MAX_BLOCK_LENGTH; unsigned char* ciphertext = new unsigned char[ciphertext_len]; int outlen; EVP_EncryptUpdate(ctx, ciphertext, &outlen, (const unsigned char*)data.c_str(), len); ciphertext_len = outlen; EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &outlen); ciphertext_len += outlen; // 转换为十六进制字符串返回 std::string result; for (int i=0; i<ciphertext_len; i++) { char buf[3]; snprintf(buf, sizeof(buf), "%02x", ciphertext[i]); result.append(buf); } delete[] ciphertext; return result; } // 使用国密SM4算法加密 std::string sm4_encrypt_sm(const std::string& key, const std::string& iv, const std::string& data) { unsigned char* plaintext = new unsigned char[data.length() + 1]; strcpy((char*)plaintext, data.c_str()); // 加密 unsigned char* ciphertext = new unsigned char[data.length() + 1]; memset(ciphertext, 0, data.length() + 1); unsigned char* tmp_key = new unsigned char[key.length() + 1]; strcpy((char*)tmp_key, key.c_str()); unsigned char* tmp_iv = new unsigned char[iv.length() + 1]; strcpy((char*)tmp_iv, iv.c_str()); sm4_context ctx; sm4_setkey_enc(&ctx, tmp_key); sm4_crypt_cbc(&ctx, SM4_ENCRYPT, data.length(), tmp_iv, plaintext, ciphertext); // 转换为十六进制字符串返回 std::string result; for (int i=0; i<data.length(); i++) { char buf[3]; snprintf(buf, sizeof(buf), "%02x", ciphertext[i]); result.append(buf); } delete[] plaintext; delete[] ciphertext; delete[] tmp_key; delete[] tmp_iv; return result; } ``` 其中,`sm4_encrypt_openssl`使用OpenSSL库实现SM4算法加密,`sm4_encrypt_sm`使用国密SM4算法加密。在使用国密SM4算法加密时,需要包含国密SM4算法的头文件,并调用其API实现加密操作。 请注意,由于国密SM4算法的限制,其密钥长度必须为16个字节,IV长度必须为16个字节。在实际使用时,需要根据实际情况生成合适的密钥和IV。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟逆袭之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值