蚂蚁区块链投票案例(二)---投票合约设计开发

这篇具有很好参考价值的文章主要介绍了蚂蚁区块链投票案例(二)---投票合约设计开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

摘要

计划用三篇文章,一个月左右的时间来实现一个蚂蚁开放联盟链上的区块链投票案例,本文是系列第二篇。

  1. 蚂蚁区块链投票案例(一)—蚂蚁链简介
  2. 蚂蚁区块链投票案例(二)—投票合约设计开发
  3. 蚂蚁区块链投票案例(三)—Java调用部分实现(整理中)

背景

本文将结合具体的投票案例,设计一组区块链投票合约,并将合约部署到蚂蚁开放联盟链进行测试。重点在于结合工具展示蚂蚁链solidity合约的开发、升级、调用的过程,业务流程尽量简单,不会涉及投票的匿名性、抗胁迫性等指标。


案例场景

本案例虚构了一个业主投票的场景,小区议事过程中,一般需要有业主提出议案事项,如“小区是否允许外卖小哥进入?”,议案交到业主大会,由业主大会整理并发起业主投票,计票规则一般是一户一票,权重按照房屋面积计算,如果超过一半面积的业主同意,议案则获得通过。因为投票的前后组织工作非常复杂繁重,可能需要线下扫楼等,所以一般一次投票不会只针对一个议案。每个议案下通常固定有三个选项,“同意”、“不同意”、“弃权”。因为是演示项目,流程和业务逻辑都尽量简单,例如我们在计票时不回采用面积权重的方法,只是简单的超过半数即可,不同意、弃权、未参与投票几种情况也不会做特殊处理(实际投票中,未参与投票可能会被记入同意)。


用例分析

通过案例场景分析,系统中存在系统管理员、业主两种角色,每种角色又对应不同操作,本案例演示重点在合约的设计开发,所以不会区分系统的管理端和业主端,也不会做对应的鉴权等操作,统一配置一个swagger方便测试。一个完备的系统中应该将信息同时写到数据库中和数据合约中,但简单起见,本案例只向合约中写入数据,不涉及到Mysql等DB操作。下图为本案例中涉及到的用例。

简单投票合约 结果,区块链,区块链

接下来逐个分析:

系统管理员注册

系统管理员承担了系统基础信息的维护工作,其所进行的操作需要上到区块链留痕,这里的注册我们简化为系统账户与蚂蚁链的链上账户地址绑定。

添加小区、添加房屋

系统管理员通过该功能向系统中添加小区和房屋信息,准备投票的基本信息。

编辑房屋

主要用来演示如何对合约中数据进行编辑。

发起投票

系统管理员组织并发起一次投票。需要初始化的内容包括投票起止时间、议案、可投票房屋地址等。

统计投票

在投票结束后,调用合约对投票进行计票。

业主注册

任何一个新业主账号在系统注册时,都会生成一个唯一业主数据合约与其对应。在系列上一篇中讲过,国内区块链应用实际是中介化,具体到这个用例,业主并不能用他的链上钱包地址直接对链上合约进行操作,总是要通过投票系统这个“中介”,所以业主也没必要具备自己的钱包地址,要完成数据上链,只要存到业主数据合约就可以了。

业主实名认证

业主信息注册后需要业主进行人脸识别或者提交身份证正反面信息进行实名认证。业主合约这里做的主要是认证信息固化存证,可包括身份证号、照片哈希等。

客房关系认证

业主实名认证后可像自己名下添加房屋,同样客房关系的证明,如房产证照片Hash等可以上链存证。

投票

业主对管理员发起的议案进行投票。这里需要对业主身份进行判断,对重复投票进行检测等。


合约设计

设计原则

开始合约设计前,我们先明确下合约的设计原则。

智能合约的生命周期主要有设计、开发、部署、运行、升级、销毁。其中的设计和升级阶段是核心,相对于非区块链项目,区块链多了一个不可篡改的特性,升级时合约需要做到向下兼容。从业务视角来看,智能合约只需要做两件事,其一是如何定义数据的结构和读写方式,其二是如何处理数据并对外提供服务接口。这两件事有点类似于MVC中M和C的关系。

为了更好的做模型抽象和合约分层,也方便合约升级、回滚、兼容,将业务控制和数据从合约代码层面就做好分离,这样的处理在复杂业务逻辑场景中经过实践是当前被认为最佳的模式。这个模式简称为CD(Controller-Data)模式,将合约分为两类:控制器合约(Controller Contract)与数据合约(Data Contract)。

控制器合约通过入参和访问数据合约获得数据,并对数据做逻辑处理,然后写回数据合约。它专注于对数据的逻辑处理和对外提供服务。根据处理逻辑的不同,常见的有命名空间控制器合约、代理控制器合约、业务控制器合约、工厂控制器合约等。一般情况下,控制器合约不需要存储任何数据,它完全依赖外部的输入来决定对数据合约的访问。特殊情况下,控制器合约可以存储某个固定的数据合约的地址或者命名空间(通过命名空间在运行时获得合约地址)。

数据合约专注于数据结构定义与所存储数据的读写裸接口。为了达到数据统一访问管理和数据访问权限控制的目的,最好是将数据读写接口只暴露给对应的控制器合约。禁止其他方式的读写访问。

基于这个模式,遵循从上至下的分析方式,从对外提供的服务接口开始设计各类控制器合约,再逐步过渡到服务接口所需要的数据模型和存储方式,进而设计各类数据合约,可以较为快速的完成合约架构的设计。

下图是一个最基础的控制合约和数据合约示意图。合约的部署和升级过程会在后文实际操作中演示。

简单投票合约 结果,区块链,区块链

合约设计

根据以上案例场景和用例的分析,我们可以抽象出以下几个对象:管理员、小区、房屋、业主、投票、议案。其中管理员被简化为一个线上账户,投票和议案简化为投票,我们可以得到4个合约对象:小区、房屋、业主、投票。按照CD模式,可拆分为四组共8个合约。如下图。
简单投票合约 结果,区块链,区块链

图中列出了各个合约的字段和方法。可以看到除了4组合约外还多出来一个代理控制合约,这里主要是方便对合约进行统一管理,方便升级和回滚。

补充说明:
代理设计模式在区块链中,一般用于控制合约的升级,比如在以太链中,合约的升级实际上是部署了一份新的合约,旧合约的内容无法被改写,升级会导致合约地址的改变。在DApp(Decentralized Application的缩写,中文直译为去中心化应用)中,后端建立在链上,没有像web应用一样的中心化后台,所以在DApp端的合约地址并不方便更新,为解决这一问题才设计了代理模式,但是在蚂蚁链上,因为国内政策原因,并不存在客户钱包这种真正去中心化的设计,蚂蚁链的中介化导致了中介后端的存在,中介后端可代替代理合约,所以本案例中我们不设置代理合约。


合约开发

命名规则

因为蚂蚁开放联盟链没有提供测试链,生产和测试的数据都放在同一条链上。防止测试和生产环境相互干扰,合约部署时需要在名称上加以区分。为方便区分版本,合约名称上需要带上版本号。我们定义的各个合约的版本号命名方式如下:

[package]_[env]_[name]_[yyyyMMdd]_[version]
  • package
    项目标识,如VoteDemo
  • env
    环境标识,如Dev对应开发环境,Online对应线上
  • name
    合约名称,如小区控制合约名称是ProjectContral
  • yyyyMMdd
    部署日期
  • version
    当天的第几次部署,如1就是当天的第一次,每日重新计数
例:

开发环境:
	小区控制合约命名
	VoteDemo_Dev_ProjectContral_20221101_1
	四季花城小区数据合约命名
	VoteDemo_Dev_Project_44030013_20221101_1
生产环境:
	小区控制合约命名
	VoteDemo_Online_ProjectContral_20221101_1
	四季花城小区数据合约命名
	VoteDemo_Online_Project_44030013_20221101_1

工具

蚂蚁提供了在线和离线的开发工具,我们选用在线的Cloud IDE。合约工程的创建以及Cloud IDE的使用请参考蚂蚁的官方文档蚂蚁开放联盟链文档。

这里要说一个Cloud IDE的小问题

  • 首次编译报错
    每次刷新编译器页面后点击编译,第一次都是失败的,第二次会成功。如下图。

简单投票合约 结果,区块链,区块链

  • 单文件部署后再拆分文件,无法触发右侧的升级按钮
    在Cloud IDE中,如果将合约写在一个sol文件中,首次部署后再拆分合约到多个sol文件,会导致升级按钮不可用。如下图,将项目代码拆分成两个sol文件时,编译后右侧的升级按钮灰掉了。简单起见,这里我们直接就将合约写在同一文件,防止后面升级操作编译器抽风。

简单投票合约 结果,区块链,区块链
简单投票合约 结果,区块链,区块链

代码

建立合约文件如下图。
简单投票合约 结果,区块链,区块链

编译部署

编译很简单,只要点击编译器左上角编译按钮即可。如下图,编译成功后点击左侧的部署按钮,再点击部署记录,可以看到合约之前的部署记录,因为我之前是用合并单文件编译发布过,所以右侧部署记录中的合约升级按钮是灰掉的。

蚂蚁链是支持通过api来部署合约的,api调用的方式会在下一节讲。先部署project_data合约,点击左侧文件下的部署合约按钮。按照前面讲到的合约命名方式,填写好对应的参数,
简单投票合约 结果,区块链,区块链

测试

在本测试中,按照约定的命名规则,我部署了以下几个合约:

  • 项目数据合约 VoteDemo_Dev_ProjectData_20221222_2
  • 房屋数据合约 VoteDemo_Dev_HouseData_20221222_2
  • 业主数据合约 VoteDemo_Dev_OwnerData_20221222_2
  • 投票数据合约 VoteDemo_Dev_VoteData_20221222_2
  • 业主控制合约 VoteDemo_Dev_OwnerControl_20221230_1
  • 投票控制合约 VoteDemo_Dev_VoteControl_20221230_1

下图示意了构建测试合约数据的过程,因为蚂蚁链不允许在合约中创建合约,且还没有开发合约的调用后台,所以这里的测试合约全部是通过蚂蚁链CloudIDE手动部署。

简单投票合约 结果,区块链,区块链
附构建测试用数据步骤:

  1. 创建项目数据合约
  2. 创建房屋数据合约
  3. 创建业主数据合约
  4. 创建投票数据合约
  5. 创建业主控制合约
  6. 调用业主控制合约模拟业主认证
  7. 调用业主数据合约验证认证结果
  8. 部署投票控制合约
  9. 调用投票控制合约模拟投票
  10. 调用投票数据合约验证投票结果

升级实验

蚂蚁链的升级是替换了原合约的代码,修改代码,编译后,可在编译器右侧对应合约的后面看到升级按钮,点击可对合约进行升级。升级后、合约地址、ID都不会改变,这一点是与以太链等公链最大不同的地方。
简单投票合约 结果,区块链,区块链

存在的问题

  1. 数据合约升级时,旧的数据合约可能需要大面积缓慢升级。
    虽然合约的升级不会引起ID,名称等的变化,但是数据合约的结构变化同样需要对历史合约逐个升级,会较为耗时且消耗较多燃料。

疑问

  • 智能合约的销毁是干啥的?

代码

先将合约代码附在这里,待下一篇和后端代码整理好一起放到git上文章来源地址https://www.toymoban.com/news/detail-766424.html

pragma solidity ^0.4.20;


/*****************************************************************************************
 * 小区控制合约
 *****************************************************************************************/

contract ProjectControl {
    //版本
    uint8 public version = 1;

    /**
     *修改小区名称
     */
    function modifyProject(identity _pdIdentity, bytes32 _code, string _name) {
        ProjectData _data = ProjectData(_pdIdentity);
        require(_data.code() == _code, "小区Code不相等");
        _data.setName(_name);
    }

    /**
     *添加房屋
     */
    function addHouse(identity _pdIdentity, bytes32 _houseCode, identity _houseIdentity) {
        ProjectData _data = ProjectData(_pdIdentity);
        _data.addHouse(_houseCode,_houseIdentity);
    }
}

/*****************************************************************************************
 * 小区数据合约
 *****************************************************************************************/

contract ProjectData {  
    //版本
    uint8 public version = 1;
    
    /**
     *构造函数
     */
    constructor(bytes32 _code, string _name) {
        code = _code;
        name = _name;
    }

    //小区在系统中的唯一编码
    bytes32 public code;
    //小区名称
    string public name;
    //小区房屋数据(系统中ID到链上地址的映射,防止系统问题导致房屋Code重复)
    mapping(bytes32 => identity) public houses;

    /**
     *修改小区名称
     */
    function setName(string _name) {
        name = _name;
    }

    /**
     *添加房屋
     */
    function addHouse(bytes32 _houseCode, identity _houseIdentity) {
        houses[_houseCode] = _houseIdentity;
    }

    /**
     *查找房屋
     */
    function houseExists(bytes32 _houseCode, identity _houseIdentity) view returns(bool) {
        if (_houseIdentity == houses[_houseCode]) {
            return true;
        }
        return false;
    }
}


/*****************************************************************************************
 * 房屋控制合约
 *****************************************************************************************/

contract HouseControl {
    //版本
    uint public version = 1;
    /**
     *增加业主
     */
    function addOwner(identity _houseIdentity, bytes32 _ownerCode, identity _ownerIdentity) {
        HouseData h = HouseData(_houseIdentity);
        h.addOwner(_ownerCode, _ownerIdentity);
    }

    /**
     *删除业主
     */
    function removeOwner(identity _houseIdentity, bytes32 _ownerCode) {
        HouseData h = HouseData(_houseIdentity);
        h.removeOwner(_ownerCode);
    }

    /**
     *修改房屋信息
     */
    function modifyHouse(identity _houseIdentity, string _name) {
        HouseData h = HouseData(_houseIdentity);
        h.setName(_name);
    }
}

/*****************************************************************************************
 * 房屋数据合约
 *****************************************************************************************/

contract HouseData {
    //版本
    uint public version = 1;
    //项目合约地址
    identity public projectIdentity;
    //房屋Code
    bytes32 public code;
    //房屋名称
    string public name;
    //房屋业主数据(系统中ID到链上地址的映射,防止系统问题导致业主Code重复)
    mapping(bytes32 => identity) public owners;

    /**
     *构造函数
     */
    constructor(bytes32 _code, string _name, identity _projectIdentity) {
        code = _code;
        name = _name;
        projectIdentity = _projectIdentity;
    }

    /**
     *修改房屋名称
     */
    function setName(string _name) {
        name = _name;
    }

    /**
     *设置房屋code
     */
    function setCode(bytes32 _code) {
        code = _code;
    }

    /**
     *添加业主
     */
    function addOwner(bytes32 _ownerCode, identity _ownerIdentity) {
        owners[_ownerCode] = _ownerIdentity;
    }

    /**
     *删除业主
     */
    function removeOwner(bytes32 _ownerCode) {
        delete owners[_ownerCode];
    }
}

/*****************************************************************************************
 * 业主控制合约
 *****************************************************************************************/

contract OwnerControl {
    //版本
    uint public version = 1;

    /**
     *业主身份认证
     */
    function auth(identity _ownerIdentity, bytes32 _code, string _authFileHash) {
        //设置认证标记位
        OwnerData owner = OwnerData(_ownerIdentity);
        owner.setAuthFileHash(_authFileHash);
        owner.setAuthed(true);
    }   

    /**
     *添加房屋(房客关系认证)
     */
    function addHouse(identity _ownerIdentity, identity _houseIdentity, bytes32 _houseCode, string _authFileHash, bool _authed){
        OwnerData owner = OwnerData(_ownerIdentity);
        owner.addHouse(_houseIdentity, _houseCode, _authFileHash, _authed);
    }

    /**
     *删除房屋
     */
    function removeHouse(identity _ownerIdentity, bytes32 _houseCode) {
        OwnerData o = OwnerData(_ownerIdentity);
        o.removeHouse(_houseCode);
    }
}


/*****************************************************************************************
 * 业主数据合约
 *****************************************************************************************/

contract OwnerData {
    //版本
    uint public version = 1;
    
    /**
     *构造函数
     */
    constructor(bytes32 _code, bytes32 _ID, string _name) {
        ID = _ID;
        code = _code;
        name = _name;
        authed = false;
    }
    
    //身份证号
    bytes32 public ID;
    //业主code
    bytes32 public code;
    //小区名称
    string public name;
    //是否认证
    bool public authed;
    //认证文件hash
    string public authFileHash;
    //房屋code到房屋的映射
    mapping(bytes32 => House) houses;

    struct House {
        identity houseIdentity;
        string authFileHash;
        bool authed;
    }

    /**
     *设置业主是否认证标记
     */
    function setAuthed(bool _authed) {
        authed = _authed;
    }

    /**
     *设置业主认证文件Hash
     */
    function setAuthFileHash(string _authFileHash) {
        authFileHash = _authFileHash;
    }

    /**
     *添加房屋
     *
     *此处房屋的认证标记,与业主身份认证标记不同,是指房屋与业主关系是否认证
     */
    function addHouse(identity _houseIdentity, bytes32 _houseCode, string _authFileHash, bool _authed) {
        houses[_houseCode] = House({
            houseIdentity: _houseIdentity,
            authFileHash: _authFileHash,
            authed: _authed
        });
    }

    /**
     *删除房屋
     */
    function removeHouse(bytes32 _houseCode) {
        delete houses[_houseCode];
    }
}


/*****************************************************************************************
 * 投票控制合约
 *****************************************************************************************/

contract VoteControl {
    //版本
    uint public version = 1;

    /**
     *投票
     */
    function vote(identity _voteIdentity, identity _houseIdentity, identity _ownerIdentity, uint _proposalID, uint _optionID) {
        VoteData v = VoteData(_voteIdentity);
        v.vote(_houseIdentity, _ownerIdentity, _proposalID, _optionID);
    }

    /**
     *添加房屋
     */
    function addHouse(identity _voteIdentity, identity _houseIdentity) {
        VoteData v = VoteData(_voteIdentity);
        v.addHouse(_houseIdentity);
    }

    /**
     *删除房屋
     */
    function removeHouse(identity _voteIdentity, identity _houseIdentity) {
        VoteData v = VoteData(_voteIdentity);
        v.removeHouse(_houseIdentity);
    }

    /**
     *添加议题
     */
    function addProposal(identity _voteIdentity, uint _ID, string _content) {
        VoteData v = VoteData(_voteIdentity);
        v.addProposal(_ID, _content);
    }

    /**
     *删除议题
     */
    function removeProposal(identity _voteIdentity, uint _ID) {
        VoteData v = VoteData(_voteIdentity);
        v.removeProposal(_ID);
    }
}

/*****************************************************************************************
 * 投票数据合约
 *****************************************************************************************/

contract VoteData {
    //版本
    uint public version = 1;

    /**
     *构造函数
     */
    constructor(bytes32 _code, string _content, uint _startTime, uint _endTime) {
        code = _code;
        content = _content;
        startTime = _startTime;
        endTime = _endTime;
        started = false;
    }

    //投票code
    bytes32 public code;
    //投票内容
    string public content;
    //投票开始时间(时间戳 10位)
    uint public startTime;
    //投票结束时间(时间戳 10位)
    uint public endTime;
    //投票是否开始?开始后不允许更改,这个判断应该放在控制合约中处理
    bool public started;
    //房屋地址到投票标记位的映射
    mapping(identity => House) public houses;
    //议案ID到议案的映射
    mapping(uint => Proposal) public proposals;

    
    struct Proposal {
        uint ID;
        string content;
        mapping(uint => Option) options;
    }

    struct Option {
        uint ID;
        string content;
        uint totalVotes;
    }

    struct House {
        identity houseIdentity;
        identity ownerIdentity;
        bool hasVote;
    }

    /**
     * 投票
     */
    function vote(identity _houseIdentity, identity _ownerIdentity, uint _proposalID, uint _optionID){
        House house = houses[_houseIdentity];
        proposals[_proposalID].options[_optionID].totalVotes += 1;    
        house.ownerIdentity = _ownerIdentity;
        house.hasVote = true;
    }

    /**
     * 获取选项内容
     */
    function getPOptions(uint _proposalID, uint _optionID) returns(string){
        return proposals[_proposalID].options[_optionID].content;
    }

    /**
     * 获取选项票数
     */
    function getPOptionsVote(uint _proposalID, uint _optionID) returns(uint){
        return proposals[_proposalID].options[_optionID].totalVotes;
    }

    /**
     *添加议题
     */
    function addProposal(uint _ID, string _content) {
        proposals[_ID] = Proposal({
            ID: _ID,
            content: _content
        });
    }

    /**
     *删除议题
     */
    function removeProposal(uint _ID) {
        delete proposals[_ID];
    }

    /**
     *添加议案选项
     */
    function addOption(uint _proposalID, uint _optionID, string _content) {
        proposals[_proposalID].options[_optionID] = Option({
            ID: _optionID,
            content: _content,
            totalVotes: 0
        });
    }

    /**
     *添加可投票的房屋地址
     */
    function addHouse(identity _houseIdentity) {
        houses[_houseIdentity] = House({
            houseIdentity: _houseIdentity,
            ownerIdentity: 0x0,
            hasVote: false
        });
    }

    /**
     *删除房屋
     */
    function removeHouse(identity _houseIdentity) {
        delete houses[_houseIdentity];
    }
}

参考资料

  • 浅谈以太坊智能合约的设计模式与升级方法

到了这里,关于蚂蚁区块链投票案例(二)---投票合约设计开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 案例005:基于小程序的电子点菜系统开发设计与实现

    文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序运行软件:微信开发者 目录 前言 系统展示 用户注册用户功能实现 管理员功能实现 代码实现 登录功能实现

    2024年02月04日
    浏览(28)
  • <Spring Boot>开发基于三层架构设计:Dao层、Service层、Controller层及案例一

    三层架构设计:基于Spring Boot开发要使用三层架构: 数据访问层(Dao)、业务逻辑层(Service)、控制层(Control-ler) (1)数据访问层(Dao):Dao层是最底层的设计,用户操作数据库。通过MyBatis持久化实现接口开发,XML文件。Dao层的设计步骤:1、在数据库中生成数据库表 2通

    2024年02月15日
    浏览(32)
  • 以太坊区块链之使用truffle框架完成简单投票Dapp开发

    编写环境 remix 话不多说,直接上代码 1、启动ganache 2、在 /contracts 目录下加入新建一个.sol文件,将之前编写的智能合约代码加入该文件中,博主新建的是一个 Voting.sol 的文件 !!!该文件目录一定要与智能合约代码名字相对应 3、修改truffle-config.js 将development内的host、port改

    2024年02月09日
    浏览(40)
  • 基于Fisco-Bcos的区块链智能合约-简单案例实践

    智能合约是指把合同/协议条款以代码的形式电子化地放到区块链网络上。FISCO BCOS平台支持两种智能合约类型:Solidity智能合约与预编译智能合约 Solidity与Java类似。代码写好后,都需要通过编译器将代码转换成二进制,在Java中,编译器是Javac,而对于Solidity,是solc。生成后的

    2024年02月09日
    浏览(38)
  • 区块链智能合约开发学习

    最近正在肝区块链知识学习,入手学习智能合约的开发,由于网上资料实在是太少了,好不容易东拼西凑完成了智能合约的开发、编译、部署、web3js调用(网页页面)和web3j调用(java调用),赶紧趁热把重点提炼出来。 先上图,是我最近学习知识点的一个概括总结,此外还包

    2023年04月18日
    浏览(30)
  • 【蚂蚁链学习4】授予勋章(蚂蚁链智能合约+函数部分应用+事件event)

    第一章 modifier函数修饰符 函数修饰符看起来跟函数没什么不同,不过 modifier 告诉编译器,这是个 modifier (修饰符),而不是个function(函数)。它不能像函数那样被直接调用,只能被添加到函数定义的末尾,用以改变函数的行为。函数修饰符也可以带参数。就像函数那样使

    2024年02月12日
    浏览(25)
  • 区块链2——Solidity智能合约开发

    区块链 索引目录 智能合约是一种以代码形式编写的自动执行合约,它们运行在区块链上。这些合约定义了在特定条件下发生的事件以及相应的行为。 1.1 智能合约结构 版本声明(Version Declaration): 智能合约通常以声明版本开始,指定合约应该使用的Solidity编译器版本。例如

    2024年02月05日
    浏览(52)
  • 区块链java开发智能合约nf(部署第一个NFT智能合约)

    手把手教你区块链java开发智能合约nft-第二篇(部署第一个NFT智能合约) 刚搞区块链开发真的是太累了,自己摸石头过河,动不动就报错,网上搜索错误,一律看不出什么问题,或者报错的信息太少,问同事同事不鸟,问领导,领导也烦,无奈,对于英文不好的我,只能被迫

    2024年02月12日
    浏览(40)
  • 华为区块链开发,处方流转合约Java代码示例

    https://wheart.cn/

    2024年02月03日
    浏览(32)
  • 区块链DAPP开发 以太坊智能合约框架有哪些

    Truffle 是一个在以太坊进行 DApp 开发的世界级开发环境、测试框架。 使用 Truffle 开发有一以下优点: 内置智能合约编译,链接,部署和二进制(文件)管理。 可快速开发自动化智能合约测试框架。 可脚本化、可扩展的部署和迁移框架。 可管理多个不同的以太坊网络,可部署

    2024年02月02日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包