智能合约_智能合约开发 - CSDN
智能合约 订阅
智能合约(英语:Smart contract )是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于1995年由Nick Szabo首次提出。智能合约的目的是提供优于传统合约的安全方法,并减少与合约相关的其他交易成本。 展开全文
智能合约(英语:Smart contract )是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于1995年由Nick Szabo首次提出。智能合约的目的是提供优于传统合约的安全方法,并减少与合约相关的其他交易成本。
信息
外文名
Smart contract
提出者
尼克·萨博(Nick Szabo)
中文名
智能合约
出现时间
1995年
智能合约术语简介
“智能合约”(Smart contract)这个术语至少可以追溯到1995年,是由多产的跨领域法律学者尼克·萨博(Nick Szabo)提出来的。他在发表于自己的网站的几篇文章中提到了智能合约的理念,定义如下:“一个智能合约是一套以数字形式定义的承诺(commitment),包括合约参与方可以在上面执行这些承诺的协议。” [1] 
收起全文
精华内容
参与话题
  • 什么是智能合约

    千次阅读 2018-05-07 21:11:05
    智能合约介绍一个简单的智能合约先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节。Storagecontract SimpleStorage { uint storedData; function set(uint x) { ...

    智能合约介绍

    一个简单的智能合约

    先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节。

    Storage

    contract SimpleStorage {
        uint storedData;
    
        function set(uint x) {
            storedData = x;
        }
    
        function get() constant returns (uint retVal) {
            return storedData;
        }
    }

    在Solidity中,一个合约由一组代码(合约的函数)和数据(合约的状态)组成。合约位于以太坊区块链上的一个特殊地址。*uint storedData*; 这行代码声明了一个状态变量,变量名为storedData,类型为 uint (256bits无符号整数)。你可以认为它就像数据库里面的一个存储单元,跟管理数据库一样,可以通过调用函数查询和修改它。在以太坊中,通常只有合约的拥有者才能这样做。在这个例子中,函数 set 和 get 分别用于修改和查询变量的值。

    跟很多其他语言一样,访问状态变量时,不需要在前面增加 this. 这样的前缀。

    这个合约还无法做很多事情(受限于以太坊的基础设施),仅仅是允许任何人储存一个数字。而且世界上任何一个人都可以来存取这个数字,缺少一个(可靠的)方式来保护你发布的数字。任何人都可以调用set方法设置一个不同的数字覆盖你发布的数字。但是你的数字将会留存在区块链的历史上。稍后我们会学习如何增加一个存取限制,使得只有你才能修改这个数字。

    代币的例子

    接下来的合约将实现一个形式最简单的加密货币。空中取币不再是一个魔术,当然只有创建合约的人才能做这件事情(想用其他货币发行模式也很简单,只是实现细节上的差异)。而且任何人都可以发送货币给其他人,不需要注册用户名和密码,只要有一对以太坊的公私钥即可。

    Note

    对于在线solidity环境来说,这不是一个好的例子。如果你使用在线solidity环境 来尝试这个例子。调用函数时,将无法改变from的地址。所以你只能扮演铸币者的角色,可以铸造货币并发送给其他人,而无法扮演其他人的角色。这点在线solidity环境将来会做改进。

    contract Coin {
    //关键字“public”使变量能从合约外部访问。
        address public minter;
        mapping (address => uint) public balances;
    
    //事件让轻客户端能高效的对变化做出反应。
        event Sent(address from, address to, uint amount);
    
    //这个构造函数的代码仅仅只在合约创建的时候被运行。
        function Coin() {
            minter = msg.sender;
        }
        function mint(address receiver, uint amount) {
            if (msg.sender != minter) return;
            balances[receiver] += amount;
        }
        function send(address receiver, uint amount) {
            if (balances[msg.sender] < amount) return;
            balances[msg.sender] -= amount;
            balances[receiver] += amount;
            Sent(msg.sender, receiver, amount);
        }
    }

    这个合约引入了一些新的概念,让我们一个一个来看一下。

    address public minter; 这行代码声明了一个可公开访问的状态变量,类型为address。address类型的值大小为160 bits,不支持任何算术操作。适用于存储合约的地址或其他人的公私钥。public关键字会自动为其修饰的状态变量生成访问函数。没有public关键字的变量将无法被其他合约访问。另外只有本合约内的代码才能写入。自动生成的函数如下:

    function minter() returns (address) { return minter; }

    当然我们自己增加一个这样的访问函数是行不通的。编译器会报错,指出这个函数与一个状态变量重名。

    下一行代码 mapping (address => uint) public balances; 创建了一个public的状态变量,但是其类型更加的复杂。该类型将一些address映射到无符号整数。mapping可以被认为是一个哈希表,每一个可能的key对应的value被虚拟的初始化为全0.这个类比不是很严谨,对于一个mapping,无法获取一个包含其所有key或者value的链表。所以我们得自己记着添加了哪些东西到mapping中。更好的方式是维护一个这样的链表,或者使用其他更高级的数据类型。或者只在不受这个缺陷影响的场景中使用mapping,就像这个例子。在这个例子中由public关键字生成的访问函数将会更加复杂,其代码大致如下:

    function balances(address _account) returns (uint balance) {
        return balances[_account];
    }

    我们可以很方便的通过这个函数查询某个特定账号的余额。

    event Sent(address from, address to, uint value); 这行代码声明了一个“事件”。由send函数的最后一行代码触发。客户端(服务端应用也适用)可以以很低的开销来监听这些由区块链触发的事件。事件触发时,监听者会同时接收到from,to,value这些参数值,可以方便的用于跟踪交易。为了监听这个事件,你可以使用如下代码:

    Coin.Sent().watch({}, '', function(error, result) {
        if (!error) {
            console.log("Coin transfer: " + result.args.amount +
                " coins were sent from " + result.args.from +
                " to " + result.args.to + ".");
            console.log("Balances now:\n" +
                "Sender: " + Coin.balances.call(result.args.from) +
                "Receiver: " + Coin.balances.call(result.args.to));
        }
    }

    注意在客户端中是如何调用自动生成的 balances 函数的。

    这里有个比较特殊的函数 Coin。它是一个构造函数,会在合约创建的时候运行,之后就无法被调用。它会永久得存储合约创建者的地址。msg(以及tx和block)是一个神奇的全局变量,它包含了一些可以被合约代码访问的属于区块链的属性。msg.sender 总是存放着当前函数的外部调用者的地址。

    最后,真正被用户或者其他合约调用,用来完成本合约功能的函数是mint和send。如果合约创建者之外的其他人调用mint,什么都不会发生。而send可以被任何人(拥有一定数量的代币)调用,发送一些币给其他人。注意,当你通过该合约发送一些代币到某个地址,在区块链浏览器中查询该地址将什么也看不到。因为发送代币导致的余额变化只存储在该代币合约的数据存储中。通过事件我们可以很容易创建一个可以追踪你的新币交易和余额的“区块链浏览器”。

    区块链基础

    对于程序员来说,区块链这个概念其实不难理解。因为最难懂的一些东西(挖矿,哈希,椭圆曲线加密,点对点网络等等)只是为了提供一系列的特性和保障。你只需要接受这些既有的特性,不需要关心其底层的技术。就像你如果仅仅是为了使用亚马逊的AWS,并不需要了解其内部工作原理。

    交易/事务

    区块链是一个全局共享的,事务性的数据库。这意味着参与这个网络的每一个人都可以读取其中的记录。如果你想修改这个数据库中的东西,就必须创建一个事务,并得到其他所有人的确认。事务这个词意味着你要做的修改(假如你想同时修改两个值)只能被完完全全的实施或者一点都没有进行。

    此外,当你的事务被应用到这个数据库的时候,其他事务不能修改该数据库。

    举个例子,想象一张表,里面列出了某个电子货币所有账号的余额。当从一个账户到另外一个账户的转账请求发生时,这个数据库的事务特性确保从一个账户中减掉的金额会被加到另一个账户上。如果因为某种原因,往目标账户上增加金额无法进行,那么源账户的金额也不会发生任何变化。

    此外,一个事务会被发送者(创建者)进行密码学签名。这项措施非常直观的为数据库的特定修改增加了访问保护。在电子货币的例子中,一个简单的检查就可以确保只有持有账户密钥的人,才能从该账户向外转账。

    区块

    区块链要解决的一个主要难题,在比特币中被称为“双花攻击”。当网络上出现了两笔交易,都要花光一个账户中的钱时,会发生什么?一个冲突?

    简单的回答是你不需要关心这个问题。这些交易会被排序并打包成“区块”,然后被所有参与的节点执行和分发。如果两笔交易相互冲突,排序靠后的交易会被拒绝并剔除出区块。

    这些区块按时间排成一个线性序列。这也正是“区块链”这个词的由来。区块以一个相当规律的时间间隔加入到链上。对于以太坊,这个间隔大致是17秒。

    作为“顺序选择机制”(通常称为“挖矿”)的一部分,一段区块链可能会时不时被回滚。但这种情况只会发生在整条链的末端。回滚涉及的区块越多,其发生的概率越小。所以你的交易可能会被回滚,甚至会被从区块链中删除。但是你等待的越久,这种情况发生的概率就越小。

    以太坊虚拟机

    总览

    以太坊虚拟机(EVM)是以太坊中智能合约的运行环境。它不仅被沙箱封装起来,事实上它被完全隔离,也就是说运行在EVM内部的代码不能接触到网络、文件系统或者其它进程。甚至智能合约与其它智能合约只有有限的接触。

    账户

    以太坊中有两类账户,它们共用同一个地址空间。外部账户,该类账户被公钥-私钥对控制(人类)。合约账户,该类账户被存储在账户中的代码控制。

    外部账户的地址是由公钥决定的,合约账户的地址是在创建该合约时确定的(这个地址由合约创建者的地址和该地址发出过的交易数量计算得到,地址发出过的交易数量也被称作"nonce")

    合约账户存储了代码,外部账户则没有,除了这点以外,这两类账户对于EVM来说是一样的。

    每个账户有一个key-value形式的持久化存储。其中key和value的长度都是256比特,名字叫做storage.

    另外,每个账户都有一个以太币余额(单位是“Wei"),该账户余额可以通过向它发送带有以太币的交易来改变。

    交易

    一笔交易是一条消息,从一个账户发送到另一个账户(可能是相同的账户或者零账户,见下文)。交易可以包含二进制数据(payload)和以太币。

    如果目标账户包含代码,该代码会执行,payload就是输入数据。

    如果目标账户是零账户(账户地址是0),交易将创建一个新合约。正如上文所讲,这个合约地址不是零地址,而是由合约创建者的地址和该地址发出过的交易数量(被称为nonce)计算得到。创建合约交易的payload被当作EVM字节码执行。执行的输出做为合约代码被永久存储。这意味着,为了创建一个合约,你不需要向合约发送真正的合约代码,而是发送能够返回真正代码的代码。

    Gas

    以太坊上的每笔交易都会被收取一定数量的gas,gas的目的是限制执行交易所需的工作量,同时为执行支付费用。当EVM执行交易时,gas将按照特定规则被逐渐消耗。

    gas price(以太币计)是由交易创建者设置的,发送账户需要预付的交易费用 = gas price * gas amount。 如果执行结束还有gas剩余,这些gas将被返还给发送账户。

    无论执行到什么位置,一旦gas被耗尽(比如降为负值),将会触发一个out-of-gas异常。当前调用帧所做的所有状态修改都将被回滚。

    存储,主存和栈

    每个账户有一块持久化内存区域被称为存储。其形式为key-value,key和value的长度均为256比特。在合约里,不能遍历账户的存储。相对于另外两种,存储的读操作相对来说开销较大,修改存储更甚。一个合约只能对它自己的存储进行读写。

    第二个内存区被称为主存。合约执行每次消息调用时,都有一块新的,被清除过的主存。主存可以以字节粒度寻址,但是读写粒度为32字节(256比特)。操作主存的开销随着其增长而变大(平方级别)。

    EVM不是基于寄存器,而是基于栈的虚拟机。因此所有的计算都在一个被称为栈的区域执行。栈最大有1024个元素,每个元素256比特。对栈的访问只限于其顶端,方式为:允许拷贝最顶端的16个元素中的一个到栈顶,或者是交换栈顶元素和下面16个元素中的一个。所有其他操作都只能取最顶的两个(或一个,或更多,取决于具体的操作)元素,并把结果压在栈顶。当然可以把栈上的元素放到存储或者主存中。但是无法只访问栈上指定深度的那个元素,在那之前必须要把指定深度之上的所有元素都从栈中移除才行。

    指令集

    EVM的指令集被刻意保持在最小规模,以尽可能避免可能导致共识问题的错误实现。所有的指令都是针对256比特这个基本的数据类型的操作。具备常用的算术,位,逻辑和比较操作。也可以做到条件和无条件跳转。此外,合约可以访问当前区块的相关属性,比如它的编号和时间戳。

    消息调用

    合约可以通过消息调用的方式来调用其它合约或者发送以太币到非合约账户。消息调用和交易非常类似,它们都有一个源,一个目标,数据负载,以太币,gas和返回数据。事实上每个交易都可以被认为是一个顶层消息调用,这个消息调用会依次产生更多的消息调用。

    一个合约可以决定剩余gas的分配。比如内部消息调用时使用多少gas,或者期望保留多少gas。如果在内部消息调用时发生了out-of-gas异常(或者其他异常),合约将会得到通知,一个错误码被压在栈上。这种情况只是内部消息调用的gas耗尽。在solidity中,这种情况下发起调用的合约默认会触发一个人工异常。这个异常会打印出调用栈。就像之前说过的,被调用的合约(发起调用的合约也一样)会拥有崭新的主存并能够访问调用的负载。调用负载被存储在一个单独的被称为calldata的区域。调用执行结束后,返回数据将被存放在调用方预先分配好的一块内存中。

    调用层数被限制为1024,因此对于更加复杂的操作,我们应该使用循环而不是递归。

    代码调用和库

    存在一种特殊类型的消息调用,被称为callcode。它跟消息调用几乎完全一样,只是加载自目标地址的代码将在发起调用的合约上下文中运行。

    这意味着一个合约可以在运行时从另外一个地址动态加载代码。存储,当前地址和余额都指向发起调用的合约,只有代码是从被调用地址获取的。

    这使得Solidity可以实现”库“。可复用的库代码可以应用在一个合约的存储上,可以用来实现复杂的数据结构。

    日志

    在区块层面,可以用一种特殊的可索引的数据结构来存储数据。这个特性被称为日志,Solidity用它来实现事件。合约创建之后就无法访问日志数据,但是这些数据可以从区块链外高效的访问。因为部分日志数据被存储在布隆过滤器(Bloom filter) 中,我们可以高效并且安全的搜索日志,所以那些没有下载整个区块链的网络节点(轻客户端)也可以找到这些日志。

    创建

    合约甚至可以通过一个特殊的指令来创建其他合约(不是简单的向零地址发起调用)。创建合约的调用跟普通的消息调用的区别在于,负载数据执行的结果被当作代码,调用者/创建者在栈上得到新合约的地址。

    自毁

    只有在某个地址上的合约执行自毁操作时,合约代码才会从区块链上移除。合约地址上剩余的以太币会发送给指定的目标,然后其存储和代码被移除。

    注意,即使一个合约的代码不包含自毁指令,依然可以通过代码调用(callcode)来执行这个操作。

    -----------------------------------------------------------------------------------------------------

    如果你希望高效的学习以太坊DApp开发,可以访问汇智网提供的最热门在线互动教程:

    1. 适合区块链新手的以太坊DApp智能合约实战入门教程
    2. 区块链+IPFS+Node.js+MongoDB+Express去中心化以太坊电商应用开发实战

    3. 其他更多内容也可以访问这个以太坊博客

    展开全文
  • 智能合约从入门到精通:完整范例

    千次阅读 2018-07-06 15:56:01
    简介:前几篇文章我们一直在讨论Solidity语言的相关语法,从本文开始,我们将介绍智能合约开发。今天我们将介绍一个完整范例。此章节将介绍一个完整案例来帮助开发者快速了解合约的开发规范及流程。注意:在进行案例...

    简介:前几篇文章我们一直在讨论Solidity语言的相关语法,从本文开始,我们将介绍智能合约开发。今天我们将介绍一个完整范例。

    此章节将介绍一个完整案例来帮助开发者快速了解合约的开发规范及流程。

    注意:

    在进行案例编写前,请先前往JUICE开放服务平台,完成用户注册,JUICE区块链账户创建;并下载、安装、配置好JUICE客户端。https://open.juzix.net/

    场景描述

    在案例实践前请确保已拥有可用的JUICE区块链平台环境!!!

    现假设一个场景,编写一个顾客管理合约。主要实现以下功能:

    • 提供增加顾客信息功能,手机号作为唯一KEY
    • 提供根据手机号删除顾客信息的功能;
    • 提供输出所有顾客信息的功能;

    接口定义

    说明:此接口定义了顾客管理合约的基本操作,接口的定义可以开放给三方进行调用而不暴露源码;

    文件目录:${workspace}/contracts/interfaces 用于存放抽象合约目录

    pragma solidity ^0.4.2;
    
    contract IConsumerManager {
    
        function add(string _mobile, string _name, string _account, string _remark) public returns(uint);
    
        function deleteByMobile(string _mobile) public returns(uint);
    
        function listAll() constant public returns (string _json);
    
    }

    • add(string _mobile, string _name, string _account, string _remark) 新增一个顾客信息
    • deleteByMobile(string_mobile) 根据手机号删除顾客信息
    • listAll() 输出所有顾客信息,此方法不影响变量状态,因此使用constant修饰;

    数据结构定义

    说明:当接口中的输入输出数据项比较多,或者存储在链上的数据项比较多时,开发者可以定义一个结构化数据,来简化数据项的声明。并且在这个结构化数据,还可以封装对数据的序列化操作,主要包括通过将json格式转为结构化数据 反序列化为json格式。

    可以把结构化数据,看成面向对象编程中的对象。

    文件目录:${workspace}/contracts/librarys 用于存放数据结构的定义

    pragma solidity ^0.4.2;
    
    import "../utillib/LibInt.sol";
    import "../utillib/LibString.sol";
    import "../utillib/LibStack.sol";
    import "../utillib/LibJson.sol";
    
    library LibConsumer {
    
        using LibInt for *;
        using LibString for *;
        using LibJson for *;
        using LibConsumer for *;
    
    
        struct Consumer {
            string mobile;
            string name;
            string account;
            string remark;
        }
    
        /**
        *@desc fromJson for Consumer
        *      Generated by juzhen SolidityStructTool automatically.
        *      Not to edit this code manually.
        */
        function fromJson(Consumer storage _self, string _json) internal returns(bool succ) {
            _self.reset();
    
            if (!_json.isJson())
                return false;
    
            _self.mobile = _json.jsonRead("mobile");
            _self.name = _json.jsonRead("name");
            _self.account = _json.jsonRead("account");
            _self.remark = _json.jsonRead("remark");
    
            return true;
        }
    
        /**
        *@desc toJson for Consumer
        *      Generated by juzhen SolidityStructTool automatically.
        *      Not to edit this code manually.
        */
        function toJson(Consumer storage _self) internal constant returns (string _json) {
            LibStack.push("{");
            LibStack.appendKeyValue("mobile", _self.mobile);
            LibStack.appendKeyValue("name", _self.name);
            LibStack.appendKeyValue("account", _self.account);
            LibStack.appendKeyValue("remark", _self.remark);
            LibStack.append("}");
            _json = LibStack.pop();
        }
    
        /**
        *@desc fromJsonArray for Consumer
        *      Generated by juzhen SolidityStructTool automatically.
        *      Not to edit this code manually.
        */
        function fromJsonArray(Consumer[] storage _self, string _json) internal returns(bool succ) {
            _self.length = 0;
    
            if (!_json.isJson())
                return false;
    
            while (true) {
                string memory key = "[".concat(_self.length.toString(), "]");
                if (!_json.jsonKeyExists(key))
                    break;
    
                _self.length++;
                _self[_self.length-1].fromJson(_json.jsonRead(key));
            }
    
            return true;
        }
    
        /**
        *@desc toJsonArray for Consumer
        *      Generated by juzhen SolidityStructTool automatically.
        *      Not to edit this code manually.
        */
        function toJsonArray(Consumer[] storage _self) internal constant returns(string _json) {
            _json = _json.concat("[");
            for (uint i=0; i<_self.length; ++i) {
                if (i == 0)
                    _json = _json.concat(_self[i].toJson());
                else
                    _json = _json.concat(",", _self[i].toJson());
            }
            _json = _json.concat("]");
        }
    
        /**
        *@desc update for Consumer
        *      Generated by juzhen SolidityStructTool automatically.
        *      Not to edit this code manually.
        */
        function update(Consumer storage _self, string _json) internal returns(bool succ) {
            if (!_json.isJson())
                return false;
    
            if (_json.jsonKeyExists("mobile"))
                _self.mobile = _json.jsonRead("mobile");
            if (_json.jsonKeyExists("name"))
                _self.name = _json.jsonRead("name");
            if (_json.jsonKeyExists("account"))
                _self.account = _json.jsonRead("account");
            if (_json.jsonKeyExists("remark"))
                _self.remark = _json.jsonRead("remark");
    
            return true;
        }
    
        /**
        *@desc reset for Consumer
        *      Generated by juzhen SolidityStructTool automatically.
        *      Not to edit this code manually.
        */
        function reset(Consumer storage _self) internal {
            delete _self.mobile;
            delete _self.name;
            delete _self.account;
            delete _self.remark;
        }
    
    
    }

    • toJson(Consumer storage _self) 将struct结构序列化为JSON格式:{"mobile":"xxx",...}.
    • fromJson(Consumer storage _self, string _json) 将一个JSON串反序列为struct结构.
    • fromJsonArray(Consumer[] storage _self, string _json),将一个数组形式的JSON串转为数据struct结构
    • toJsonArray(Consumer[] storage _self) 数组结构反序列化,eg.[{"mobile":"xxx",...},...]
    • reset(Consumer _self) 重置struct中为默认值.

    业务合约编写

    说明:顾客管理合约的主要业务逻辑,即合约接口的实现类. ConsumerManager.sol,该合约继承了基础合约OwnerNamed以及抽象合约IConsumerManager

    • OwnerNamed 主要提供一些基础操作,主要包含模块注册、合约注册、数据写入DB等操作,所有业务合约需按规定继承该合约。

    文件目录:${workspace}/contracts 用于存放业务合约主体逻辑

    pragma solidity ^0.4.2;
    
    import "./library/LibConsumer.sol";
    import "./sysbase/OwnerNamed.sol";
    import "./interfaces/IConsumerManager.sol";
    import "./interfaces/IUserManager.sol";
    import "./utillib/LibLog.sol";
    
    contract ConsumerManager is OwnerNamed, IConsumerManager {
    
        using LibConsumer
        for * ;
        using LibString
        for * ;
        using LibInt
        for * ;
        using LibLog
        for * ;
    
        event Notify(uint _errno, string _info);
    
        LibConsumer.Consumer[] consumerList;
        mapping(string => uint) keyMap;
    
    
        //定义错误信息
        enum ErrorNo {
            NO_ERROR,
            BAD_PARAMETER,
            MOBILE_EMPTY,
            USER_NOT_EXISTS,
            MOBILE_ALREADY_EXISTS,
            ACCOUNT_ALREDY_EXISTS,
            NO_PERMISSION
        }
    
        // 构造函数,在合约发布时会被触发调用
        function ConsumerManager() {
            LibLog.log("deploy ConsumerModule....");
    
            //把合约注册到JUICE链上, 参数必须和ConsumerModule.sol中的保持一致
            register("ConsumerModule", "0.0.1.0", "ConsumerManager", "0.0.1.0");
    
            //或者注册到特殊的模块"juzix.io.debugModule",这样用户就不需要编写模块合约了
            //register("juzix.io.debugModule", "0.0.1.0", "ConsumerManager", "0.0.1.0");
        }
    
    
        function add(string _mobile, string _name, string _account, string _remark) public returns(uint) {
            LibLog.log("into add..", "ConsumerManager");
            LibLog.log("ConsumerManager into add..");
    
            if (_mobile.equals("")) {
                LibLog.log("Invalid mobile.", "ConsumerManager");
                errno = 15200 + uint(ErrorNo.MOBILE_EMPTY);
                Notify(errno, "顾客手机号为空,插入失败.");
                return errno;
            }
    
            if (keyMap[_mobile] == 0) {
                if (consumerList.length > 0) {
                    if (_mobile.equals(consumerList[0].mobile)) {
                        LibLog.log("mobile aready exists", "ConsumerManager");
                        errno = 15200 + uint(ErrorNo.MOBILE_ALREADY_EXISTS);
                        Notify(errno, "顾客手机号已存在,插入失败.");
                        return errno;
                    }
                }
            } else {
                LibLog.log("mobile aready exists", "ConsumerManager");
                errno = 15200 + uint(ErrorNo.MOBILE_ALREADY_EXISTS);
                Notify(errno, "顾客手机号已存在,插入失败.");
                return errno;
            }
    
            uint idx = consumerList.length;
            consumerList.push(LibConsumer.Consumer(_mobile, _name, _account, _remark));
    
            keyMap[_mobile] = idx;
    
            errno = uint(ErrorNo.NO_ERROR);
    
            LibLog.log("add a consumer success", "ConsumerManager");
            Notify(errno, "add a consumer success");
            return errno;
        }
    
        function deleteByMobile(string _mobile) public returns(uint) {
            LibLog.log("into delete..", "ConsumerManager");
    
            //合约拥有者,才能删除顾客信息
            if (tx.origin != owner) {
                LibLog.log("msg.sender is not owner", "ConsumerManager");
                LibLog.log("operator no permission");
                errno = 15200 + uint(ErrorNo.NO_PERMISSION);
                Notify(errno, "无操作权限,非管理员");
                return;
            }
    
            //顾客列表不为空
            if (consumerList.length > 0) {
                if (keyMap[_mobile] == 0) {
                    //_mobile不存在,或者是数组第一个元素
                    if (!_mobile.equals(consumerList[0].mobile)) {
                        LibLog.log("consumer not exists: ", _mobile);
                        errno = 15200 + uint(ErrorNo.USER_NOT_EXISTS);
                        Notify(errno, "顾客手机号不存在,删除失败.");
                        return;
                    }
                }
            } else {
                LibLog.log("consumer list is empty: ", _mobile);
                errno = 15200 + uint(ErrorNo.USER_NOT_EXISTS);
                Notify(errno, "顾客列表为空,删除失败.");
                return;
            }
    
            //数组总长度
            uint len = consumerList.length;
    
            //此用户在数组中的序号
            uint idx = keyMap[_mobile];
    
            if (idx >= len) return;
            for (uint i = idx; i < len - 1; i++) {
                //从待删除的数组element开始,把后一个element移动到前一个位置
                consumerList[i] = consumerList[i + 1];
                //同时修改keyMap中,对应key的在数组中的序号
                keyMap[consumerList[i].mobile] = i;
            }
            //删除数组最后一个元素(和倒数第二个重复了)
            delete consumerList[len - 1];
            //删除mapping中元素,实际上是设置value为0
            delete keyMap[_mobile];
    
            //数组总长度-1
            consumerList.length--;
    
    
            LibLog.log("delete user success.", "ConsumerManager");
            errno = uint(ErrorNo.NO_ERROR);
    
            Notify(errno, "删除顾客成功.");
        }
    
        function listAll() constant public returns(string _json) {
            uint len = 0;
            uint counter = 0;
            len = LibStack.push("");
            for (uint i = 0; i < consumerList.length; i++) {
                if (counter > 0) {
                    len = LibStack.append(",");
                }
                len = LibStack.append(consumerList[i].toJson());
                counter++;
            }
            len = itemsStackPush(LibStack.popex(len), counter);
            _json = LibStack.popex(len);
        }
    
        function itemsStackPush(string _items, uint _total) constant private returns(uint len) {
            len = 0;
            len = LibStack.push("{");
            len = LibStack.appendKeyValue("result", uint(0));
            len = LibStack.appendKeyValue("total", _total);
            len = LibStack.append(",\"data\":[");
            len = LibStack.append(_items);
            len = LibStack.append("]");
            len = LibStack.append("}");
            return len;
        }
    }

    模块合约

    说明:模块合约是JUICE区块链中,为了管理用户的业务合约,以及为了管理DAPP和业务的关系而引入的。开发者在实现业务合约后,必须编写一个或多个模块合约,并在模块合约中说明本模块中用到的业务合约。从DAPP的角度来理解,就是一个DAPP必须对应一个模块,一个DAPP能调用的业务合约,必须在DAPP对应的模块合约中说明。

    模块合约继承了基础模块合约BaseModule

    • BaseModule 主要提供一些基础操作,主要包含:模块新增、合约新增、角色新增等操作.

    文件目录:${workspace}/contracts 用于存放业务模块合约主体逻辑

    /**
     * @file      ConsumerModule.sol
     * @author    JUZIX.IO
     * @time      2017-12-11
     * @desc      给用户展示如何编写一个自己的模块。
     *            ConsumerModule本身也是一个合约,它需要部署到链上;同时,它又负责管理用户的合约。只有添加到模块中的用户合约,用户才能在dapp中调用这些合约
     */
    pragma solidity ^ 0.4 .2;
    
    //juice的管理库,必须引入
    import "./sysbase/OwnerNamed.sol";
    import "./sysbase/BaseModule.sol";
    
    //juice提供的模块库,必须引入
    import "./library/LibModule.sol";
    
    //juice提供的合约库,必须引入
    import "./library/LibContract.sol";
    
    //juice提供的string库
    import "./utillib/LibString.sol";
    
    //juice提供的log库
    import "./utillib/LibLog.sol";
    
    contract ConsumerModule is BaseModule {
    
        using LibModule
        for * ;
        using LibContract
        for * ;
        using LibString
        for * ;
        using LibInt
        for * ;
        using LibLog
        for * ;
    
        LibModule.Module tmpModule;
        LibContract.Contract tmpContract;
    
        //定义Demo模块中的错误信息
        enum MODULE_ERROR {
            NO_ERROR
        }
    
        //定义Demo模块中用的事件,可以用于返回错误信息,也可以返回其他信息
        event Notify(uint _code, string _info);
    
        // module : predefined data
        function ConsumerModule() {
    
            //定义模块合约名称
            string memory moduleName = "ConsumerModule";
    
            //定义模块合约名称
            string memory moduleDesc = "顾客模块";
    
            //定义模块合约版本号
            string memory moduleVersion = "0.0.1.0";
    
            //指定模块合约ID
            //moduleId = moduleName.concat("_", moduleVersion);
            string memory moduleId = moduleName.concat("_", moduleVersion);
    
            //把合约注册到JUICE链上
            LibLog.log("register DemoModule");
            register(moduleName, moduleVersion);
    
            //模块名称,只是JUICE区块链内部管理模块使用,和moduleText有区别
            tmpModule.moduleName = moduleName;
            tmpModule.moduleVersion = moduleVersion;
            tmpModule.moduleEnable = 0;
            tmpModule.moduleDescription = moduleDesc;
            //显示JUICE开放平台,我的应用列表中的DAPP名字
            tmpModule.moduleText = moduleDesc;
    
            uint nowTime = now * 1000;
            tmpModule.moduleCreateTime = nowTime;
            tmpModule.moduleUpdateTime = nowTime;
    
            tmpModule.moduleCreator = msg.sender;
    
            //这里设置用户DAPP的连接地址(目前DAPP需要有用户自己发布、部署到公网上)
            tmpModule.moduleUrl = "http://host.domain.com/youDapp/";
    
    
    
            tmpModule.icon = "";
            tmpModule.publishTime = nowTime;
    
            //把模块合约本身添加到系统的模块管理合约中。这一步是必须的,只有这样,用户的dapp才能调用添加到此模块合约的相关合约。
            //并在用户的“我的应用”中展示出来
            LibLog.log("add ConsumerModule to SysModule");
            uint ret = addModule(tmpModule.toJson());
    
            if (ret != 0) {
                LibLog.log("add ConsumerModule to SysModule failed");
                return;
            }
    
            //添加用户合约到模块合约中
            LibLog.log("add ConsumerManager to ConsumerModule");
            ret = initContract(moduleName, moduleVersion, "ConsumerManager", "顾客管理合约", "0.0.1.0");
            if (ret != 0) {
                LibLog.log("add ConsumerManager to ConsumerModule failed");
                return;
            }
    
    
            //返回消息,以便控制台能看到是否部署成功
            Notify(1, "deploy ConsumerModule success");
        }
    
        /**
         * 初始化用户自定义合约。
         * 如果用户有多个合约文件,则需要多次调用此方法。
         * @param moduleName        约合所属模块名
         * @param moduleVersion     约合所属模块版本
         * @param contractName      约合名
         * @param contractDesc      约合描述
         * @param contractVersion   约合版本
         * @return return 0 if success;
         */
        function initContract(string moduleName, string moduleVersion, string contractName, string contractDesc, string contractVersion) private returns(uint) {
            tmpContract.moduleName = moduleName;
            tmpContract.moduleVersion = moduleVersion;
    
            //合约名称
            tmpContract.cctName = contractName;
            //合约描述
            tmpContract.description = contractDesc;
            //合约版本
            tmpContract.cctVersion = contractVersion;
    
            //保持false
            tmpContract.deleted = false;
            //保持0
            tmpContract.enable = 0;
    
            uint nowTime = now * 1000;
            //合约创建时间
            tmpContract.createTime = nowTime;
            //合约修改时间
            tmpContract.updateTime = nowTime;
    
            //合约创建人
            tmpContract.creator = msg.sender;
            //预约块高
            tmpContract.blockNum = block.number;
    
            uint ret = addContract(tmpContract.toJson());
            return ret;
        }
    
    }

    • 模块合约作用:当进行一个新的DAPP开发时会伴随着一些合约的业务服务的编写,即,合约为DAPP应用提供业务逻辑的服务,我们将这一类(或一组)合约统一归属到一个模块中(eg:HelloWorldModuleMgr)。在JUICE区块链平台上有一套鉴权体系,一个合约要被成功调用需要经过多层鉴权:

      校验模块开关,开:继续鉴权,关:直接通过

      校验合约开关,开:继续鉴权,关:直接通过

      检验函数开关,开:继续鉴权,关:直接通过

      校验用户是否存在,存在则访问通过,不存在则鉴权失败

      注意:如果是合约发布者owner(超级管理员)则不需要鉴权可直接通过。

    • HelloWorldModuleMgr该合约的主要功能就是做数据的初始化操作,当合约被发布时触发构造函数的调用。

      添加一个新的模块到角色过滤器(默认过滤器)

      添加绑定合约与模块的关系

      添加菜单(新的DAPP如果需要菜单-如:用户管理)

      添加权限,合约中的每个函数操作都是一个Action,如果需要访问就需要进行配置;

      添加角色,初始化某些角色到模块中,并绑定对应的权限到角色上;

    编译部署、测试

    编译部署

    业务合约,模块合约编写完成后

    • 首先,处理业务合约

    1.编译业务合约,编译成功后,在控制台分别复制出ABIBIN,并分别保存到contracts/ConsumerManager.abicontracts/

    ConsumerManager.bin文本文件中。这两个文件,可以用web3j生成调用业务合约的JAVA代理类,这个在编写DAPP时有用,因此在编译阶段就先保存这两个文件。(注:JUICE客户端的后续版本中,将在编译业务合约时,直接生成JAVA代理类,开发者不用再手工保存bin/abi,再手工生成JAVA代理类)

    2.部署业务合约

    • 然后,处理模块合约

    1.编译模块合约。编译成功后的的bin/abi,不需要保存。

    2.部署模块合约

    测试

    JUICE客户端中,选择需要测试的业务合约,以及相应的业务方法,然后填写输入参数,即可运行。用户可观察控制台的日志输出,来判断业务方法是否执行成功。

    参考内容:https://open.juzix.net/doc

    智能合约开发教程视频:区块链系列视频课程之智能合约简介

    展开全文
  • 智能合约简介

    2019-07-19 11:23:37
    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许...用户的应用直接和智能合约打交道,智能合约直接和Fabric账本进行交互。 一个完整的Fabric区块链应用包含两部分,一部分是用户的应用程序,...

    链客,专为开发者而生,有问必答!

    此文章来自区块链技术社区,未经允许拒绝转载。

    在这里插入图片描述

    在Fabric中,chaincode(链码)也称为智能合约,是用高级语言编写的一段代码。代码主要是读取和操作账本上的数据。 智能合约是一座连接用户应用和Fabric账本的桥梁。用户的应用直接和智能合约打交道,智能合约直接和Fabric账本进行交互。

    一个完整的Fabric区块链应用包含两部分,一部分是用户的应用程序,一部分是用户编写的智能合约。下图展示了用户智能合约和用户的应用程序以及账本交互的过程。用户的应用程序通过区块链网络的Peer节点,调用智能合约。用户智能合约通过区块链网络的Peer节点操作账本数据。整体架构中,用户的应用程序负责以下两部分职责。第一,用户的应用程序根据业务逻辑负责生成需要存储在区块链网络上的数据。第二,用户的应用程序根据业务逻辑,从区块链网络上获取到相关数据,进行业务操作。总体来说,用户应用程序更关注业务本身。智能合约主要是负责封装与账本直接交互的过程,包括按照用户指定的逻辑存储与查询账本数据,供用户应用程序调用。

    Fabric中用户编写的智能合约是运行在隔离的沙盒环境中,目前主要展现形态是独立的docker容器。智能合约安装在区块链网络中的Peer节点上,运行时Peer节点会启动单独的docker容器来运行智能合约。智能合约以容器启动后,会与启动智能合约容器的Peer节点建立交互,从而实现对对应Peer节点上账本相关数据的操作。智能合约在运行的过程中,会在对应的Peer节点账本上创建独立的命名空间,命名空间是智能合约的名字,然后在此命名空间中完成键值对的操作。不同智能合约的命名空间不一样,互相之间的数据是独立的,一般情况下智能合约只能访问到属于自己命名空间的键值对。如果一个智能合约想访问另外智能合约的数据,可以通过在智能合约内部调用其他智能合约来实现。

    Fabric中的Peer节点提供了调用智能合约相关服务的接口。用户的应用程序可以通过使用此类型服务和Fabric Peer进行交互,Fabric Peer在与智能合约容器进行交互,从而完成应用程序和智能合约之间的交互。用户的应用程序可以通过以下两种方式使用Fabric Peer提供的服务。第一,用户的应用程序直接利用Fabric提供的SDK与Fabric Peer进行交互,具体参看Fabric SDK。第二,用户可以使用腾讯云SDK调用相关的TBaaS云API接口与TBaaS中的Fabric Peer进行交互。

    展开全文
  • 智能合约是什么?

    千次阅读 2018-05-07 21:10:34
    Peter Todd–比特币核心(Bitcoin Core)的开发者之一–非常准确地总结了智能合约的现状:“从智能合约讨论中得到的结论:没有人理解智能合约究竟是什么,如果我们要实施智能合约,应该需要预言机(oracles)。...

    通过谷歌的关键词搜索趋势图可以看出,智能合约正在受到越来越多的关注,从而我们需要一个更加清晰的定义。目前,与人们对智能合约的兴奋相伴的还有对这一术语含义的困惑。Peter Todd–比特币核心(Bitcoin Core)的开发者之一–非常准确地总结了智能合约的现状:

    无标题1

    “从智能合约讨论中得到的结论:没有人理解智能合约究竟是什么,如果我们要实施智能合约,应该需要预言机(oracles)。”

    在本文中,我尽力进一步阐明智能合约的本质。我的首要目标是,使得隐藏在智能合约背后的假设明确化,并澄清人们对与法律系统相关的神秘现象的误解。然而,这只是我我第一次尝试找到一种方式,将智能合约的理念系统化。我希望得到社区的反馈,从而我们能够得到比现在更加清晰的理解。

    声明

    说到法律术语,我要指出,虽然我是一名律师,但是我并不熟悉英语世界的法律术语,也不熟悉英美普通法(common law)系统。我是一名德国法律系统的学者,我学习德国法律和在法律领域工作将近十年了(译者注:英语世界法律大部分属于英美普通法,德国属于大陆法系,故作者特别强调)。虽然,我借助谷歌搜索的能力,选择我所知的最好词汇,但是不精确是在所难免的。如果你有能力,请指出我对术语的误用。从积极的角度看,德语对法律术语的严苛,在这里也许有些帮助。

    另外,我不是一名计算机科学家,虽然我个人写代码的时间长达12年了。如果你发现计算机领域的错误,请指出来。谢谢!

    溯源

    “智能合约”(smart contract)这个术语至少可以追溯到1995年,是由多产的跨领域法律学者尼克·萨博(Nick Szabo)提出来的。他在发表在自己的网站的几篇文章中提到了智能合约的理念。他的定义如下:

    “一个智能合约是一套以数字形式定义的承诺(promises) ,包括合约参与方可以在上面执行这些承诺的协议。”

    让我们更加详细地探讨他的定义的意思。

    承诺

    一套承诺指的是合约参与方同意的(经常是相互的)权利和义务。这些承诺定义了合约的本质和目的。以一个销售合约为典型例子。卖家承诺发送货物,买家承诺支付合理的货款。

    数字形式

    数字形式意味着合约不得不写入计算机可读的代码中。这是必须的,因为只要参与方达成协定,智能合约建立的权利和义务,是由一台计算机或者计算机网络执行的。

    更进一步地说明:

    (1)达成协定

    智能合约的参与方什么时候达成协定呢?答案取决于特定的智能合约实施。一般而言,当参与方通过在合约宿主平台上安装合约,致力于合约的执行时,合约就被发现了。

    (2)合约执行

    “执行”的真正意思也依赖于实施。一般而言,执行意味着通过技术手段积极实施。

    (3)计算机可读的代码

    另外,合约需要的特定“数字形式”非常依赖于参与方同意使用的协议。

    协议

    协议是技术实现(technical implementation),在这个基础上,合约承诺被实现,或者合约承诺实现被记录下来。选择哪个协议取决于许多因素,最重要的因素是在合约履行期间,被交易资产的本质。

    再次以销售合约为例。假设,参与方同意货款以比特币支付。选择的协议很明显将会是比特币协议,在此协议上,智能合约被实施。因此,合约必须要用到的“数字形式”就是比特币脚本语言。比特币脚本语言是一种非图灵完备的、命令式的、基于栈的编程语言,类似于Forth。

    从理论到实践

    剧透:如果你了解比特币协议、比特币货币和智能财产的概念,你可以跳过这一章节。

    当萨博在近二十年以前,在网络提出了智能合约理论时,实践一直严重地落后于理论。一直没有如何将这个理念转变现实的清晰路径。

    现在,技术已经赶上萨博富有远见的头脑,智能合约开始变得可行。在这二十年中发生了什么事情呢?

    简而言之,萨博在他的智能合约定义中建立的协议,已经被进一步开发。它们已经以比特币协议的形式出现,或者更加一般地说,这些协议能够实现中本聪共识(Nakamoto consensus)。

    在这些协议被开发的同时,我们获得了另一个必需的构件:第一种真正的、原生的数字资产,即作为货币的比特币。没有这种资产,智能合约也将不可行,因为金融部门在过去的几十年中,一直对任何创新抱有极端的敌意。

    最后,另一个还没有结出果实的概念是智能财产。我们正在进入一个计算和连接无所不在的时代,通俗地讲,就是物联网。物理实体能够从互联网中检索信息和向互联网发送信息,它们也能够通过软件控制它们自身的使用(想想数字版权管理吧),这使得我们能够建立萨博所指的嵌入式合约(embedded contracts)。

    “智能合约的基本理念是,许多合约条款能够嵌入到硬件和软件中。”

    萨博认为嵌入式合约最初的应用实例是自动贩卖机、销售点终端、大公司间的电子数据交换和银行间用于转移和清算的支付网络SWIFT、ACH、FedWire。另一个嵌入式合约的例子是数字内容消费–例如音乐、电影和电子书–领域的数字版权管理机制。

    从这个意义上理解,智能合约是赛博空间(虚拟空间)和物理空间(实体空间)之间的桥梁。

    智能VS法律

    人们对智能合约概念的最多的困惑,源于它的名字和用于描述它的语言。人们似乎从“合约”这一术语中,推断出智能合约一定与法律概念中的合约有某种联系。那么,根据这个逻辑,智能合约是有法律约束力的协定加上其它因素(X),X使得协定变得“智能”。

    从法律的角度,这一推测是错误的。根据参与方选择的智能合约实施,参与双方或者多方完全可能进入一个不满足合法的合约所必需条件的“智能合约”。

    然而,不可否认的是,智能合约必须被归类为与法律相关的行为。我们生活在一个被法律管理和控制的世界,所有可能的经济交易也被法律管理和控制。合约法只是组织经济交易的一种可能的工具。原理图如下:

     1-WWtCLYSV4T5ml_L-gn-aIA

    Legally relevant behaviour :与法律相关的行为;  contract law:合约法;  smart contracts:智能合约


    让我们看一下合约法和智能合约的交集部分。我们能否发现一个能够描述这两个系统的合约行为的概括呢?引用萨博的论文:

    “合约–一套达成共识的协定–是形成关系的传统方式。”

    萨博告诉我们的是,“合约”的抽象概念是在个人、机构和他们拥有的东西(财产)之间形成关系的一种公认的工具。然而,上面的引用并不清晰,参与方如何达成协定,如何形成协定,没有讲到。

    我建议下面这个普遍的合约模型:

    1-wdlFcTIAuYElZkRGupEb0g 

    Agreement:协定; Formalization:形式化 ;Execution/Enforcement:执行

    如果这个模型应用到智能合约和法律意义上的合约中,让我们看看它怎么起作用。

    协定

    协定是一个完全的理想情况,从它在正式系统中的实施中抽象而来。当然,事实上这是一个脆弱的抽象。在法律系统中,在许多情况下,具有法律约束力,不要求形成一个协议。与此相反,对智能合约来说,在许多情况下,在形式化以前,没有事前协定。

    形式化

    形式化在这里的意思是,在一个正式系统实施理想的协定的行为。有两个相关的正式系统。一个是合约法,另一个是你选择的智能合约系统。这两个系统都服务于相同的目的:当违约行为发生时,使得协定能够执行。

    从一般角度理解,对于合约是怎么形式化的这一问题,有人认为它只是实施细节。然而,事实证明,合约的实施的确事关重大。

    现在有两种本质上不同的、形成一种合约关系的方式。这两种方式是截然不同的,因为它们需要不同的执行方式。


    执行

    因为一图顶千言,所以来看下面这张我从Lawrence Lessig那里“剽窃”来的信息图,出于本文的需要,我对图片做了轻微的修改。

    1-Qr6DFyNGAH0Cf3t-1PC8lg

    Market:市场 ; contract:合约  ;Norms:惯例、常规 ; Architecture :架构 ; law:法律; ex ante:事前;  ex post:事后

    在Lessig的最初版本中,是一个人位于信息图的中间,不是一个合约。这位了不起的思考者用他的信息图,努力教给我们这些凡人的是,有四种最基本的约束影响着一个人的一生。这四个约束本质上截然不同的,但是以复杂的方式交织在一起。

    我对原版的信息图做出了修改,用合约取代了人,这里的合约是指双方或者多方之间达成的协定。有趣的是,做出修改以后,这个信息图仍然有效。这四个约束就像管理着人一样,管理着合约关系。

    另外,我着重强调这四个约束中的两个约束,即架构和法律。这两个约束是合约能够被执行的两个最基本的动力。根据参与方选择的协定实施的系统,合约将通过法律系统执行,或者通过架构执行。这两种合约执行模式显著不同。

    Lessig认识到合约执行的两个特征,可以帮助我们谈论两种合约执行模式的不同。一个是代理(agency),另一个是时间性(temporality)。在法律意义上,合约的执行,只有当一些人选择这样做时,才会发生。此外,执行只发生在违约以后,例如事后。

    智能合约的执行在这两个方面,本质上不同于传统合约。为了理解是如何不同的,我们需要首先理解Lessig所指的架构是什么意思。

    Lessig在他的《代码:网络空间的法律》一书中,为了解释代码在赛博空间中的作用,引入了架构的概念。物理空间的形状,就是你的身体穿梭其中的空间,是由它的架构决定的,例如建筑环境(建筑物、街道等)。如此类似,赛博空间的形状是由代码决定的,人们使用的应用和协议就是建立在这些代码上面的。因此,代码是赛博空间的架构。

    法律和架构都有方法管理参与方的行为。法律依赖于个人将规则内化,个人据此调整自己的行为,或者该系统允许法律追索权(例如法庭)。然而,架构通过塑造空间本身管理行为。架构不是关于允许什么,而是什么是可能的。架构既不依靠个人将规则内化,也不依靠起诉系统。

    根据我们衡量合约执行的质量的标准,例如代理和时间性,因此架构明显地不同于法律。架构执行合约时,不需要任何个人或者组织(代理,agency)决定如何执行合约,你可以称架构执行为自我执行(self-enforcing),虽然我不喜欢这种叫法。另外,架构事前执行,违约甚至不可能发生。

    未来展望

    有一件事确定无疑:智能合约已经扎下根了。它们是真正的全球经济的基本构件,任何人都可以接入到这一全球经济,不需要事前审查和高昂的预付成本。它们从许多经济交易中,移除了对第三方的信任必要,在其它情况下,将信任转移到可以信任的人和机构。

    我在这篇博客中尽力想说明的理念是,智能合约怎样与合约法共存。本质上,它们是解决相同问题–以一种方式形成一种关系,使得承诺可以执行–的两种不同方法。就这一点而言,智能合约似乎是更好的解决方案:智能合约事前执行,不像法律系统一样,事后执行。然而,这是一种谬误。最后一次引用全能的萨博:

    “合约法的成功和取代合约法所需的高额成本,使得保存和利用合适的原则,仍然很有价值。但是,数字革命正在剧烈地改变我们能够拥有的各种关系。在这个赛博时代,我们来之不易的法律传统中的哪一部分,将仍然具有价值?将这些法律原则应用到我们的线上关系设计,最好的方式是什么?”

    在合约法中,有许多已建立的原则,仍值得保存。其中包括法律默认规则,我将在另一篇博客中写这个问题。

    因此,为了实现最优的结果,同时利用合约法和智能合约,好像是有利的行为。我将在另一篇博客中,告诉你怎么实现这一点。

    如果你觉得这篇文章给你带来启迪,欢迎给作者(1HT7q3HtDYLSeMTkMcsjsRcExBAjsnKHws )和译者(1JtgQcqAoU65VY2NZy25FT9dAcuXrUKhfG)打赏。

    ----

    ----

    如果你希望高效的学习以太坊DApp开发,可以访问汇智网提供的最热门在线互动教程:

    1. 适合区块链新手的以太坊DApp智能合约实战入门教程
    2. 区块链+IPFS+Node.js+MongoDB+Express去中心化以太坊电商应用开发实战

    3. 其他更多内容也可以访问这个以太坊博客

    展开全文
  • 以太坊智能合约项目实战

    万人学习 2019-06-28 14:16:14
    通过这个课程的学习,我们可以了解以太坊发展的轨迹,学会洞察智能合约的漏洞,学会如何发币以及具备一定的智能合约开发技能,让学习者在区块链的大潮中立于不败之地。 本科主要介绍5个智能合约项目,包括1.奖金...
  • 智能合约

    千次阅读 2018-12-28 11:00:49
    什么是智能合约智能合约的目的是提供优于传统合约的安全方法,并减少与合约相关的其他交易成本
  • 什么是智能合约?

    千次阅读 2018-08-21 10:53:10
    温馨提示:阅读本文需要...广义来讲,区块链技术是利用块链式数据结构来验证与存储数据、利用分布式节点共识算法来生成和更新数据、利用密码学的方式保证数据传输和访问的安全、利用由自动化脚本代码组成的智能合...
  • 智能合约开发简介

    千次阅读 2018-04-24 19:02:31
    原文: https://ethfans.org/posts/introduction-smart-contract-development我最近在 Blockgeeks 上读...当然这里边有很多要素可以讨论,我会详细阐述其中的一些工具,以及它们是如何用于智能合约开发的。这一系列...
  • 智能合约入门

    2019-10-27 11:32:55
    智能合约也称为”自执行和约“,或者叫“代码化的合约”。这个小节里面我们不聊智能合约的社会意义,而是假设你是一位开发者,准备上手智能合约的开发,那么动手之前都有哪些基础知识是必备的呢?本文为你呈现。 一....
  • 哈希算法

    万次阅读 多人点赞 2019-01-21 14:51:16
    对于哈希算法,在我们平时的开发中,都是基本上拿来就用就行了,所以这节我们将重点放在如何使用,并不进行哈希算法的原理剖析和如何设计一个哈希算法的讲解. 什么是哈希算法? 将任意长度的二进制值串映射为固定...
  • 区块链开发(二)部署并运行第一个以太坊智能合约 李赫2016年8月10日  网络上不少部署智能合约的文章,但是都有一个共同的特点,就是采用命令行的方式来部署,先是建立SOLC的编译环境,然后部署Geth或者Eth节点,...
  • Nick Szabo提出了“智能合约”的概念,其目的是将POS(销售点)等电子交易方式的功能...智能合约:它的复杂程度和案例有关智能合约案例:医疗行业智能合约案例:物业转让智能合约的优势编写智能合约的区块链平台编写...
  • BC之SC:区块链之智能合约——与传统合约的比较以及智能合约模型部署原理、运行原理相关配图 目录 SC与传统合约的比较 SC模型部署原理、运行原理 SC与传统合约的比较 1、传统合约VS智能合约 特点...
  • 区块链实现智能合约

    千次阅读 2018-07-03 11:45:57
    区块链实现智能合约一、制定生成智能合约1、首先参与智能合约的用户必须先注册成为区块链的用户,区块链返回给用户一对公钥和私钥。公钥做为用户在区块链上的账户地址,私钥做为操作该账户的唯一钥匙。2、两个以两个...
  • 2.solidity智能合约开发时使用 以下是具体实现 1.web3.js在DAPP应用开发时使用 web3.eth.getCode()方法返回指定地址上代码的16进制字符串,由于普通账户地址处没有代码,因此将仅返回16进制前缀0x。利用这个我们...
  • 智能合约应用案列及相关法律问题

    万次阅读 2019-04-08 09:24:33
    区块链中的合约或者说智能合约意味着区块链交易远不止买卖比特币这些简单的交易,将会有广泛的指令嵌入到区块链中。 传统合约是双方或者多方共同协议做或不做某事来换取某些东西,前提是互相要信任彼此会履行义务。...
  • 什么是智能合约(Smart Contract)?

    千次阅读 2017-09-18 19:06:45
    智能合约是什么?在区块链上运行的程序,通常称为智能合约(Smart Contract)��。所以通常会把写区块链程序改称写智能合约。虽然比特币(Bitcoin)上也能写智能合约,但是比特币所支持的语法仅与交易有关,能做的...
  • 智能合约图形化部署和运行原理

    千次阅读 2018-01-23 10:10:26
    网络上不少部署智能合约的文章,但是都有一个共同的特点,就是采用命令行的方式来部署,先是建立SOLC的编译环境,然后部署Geth或者Eth节点,然后一步一步生成钱包、ABI、合约地址进行部署,对初学者来说晦涩难懂而且...
  • Fabric 智能合约具体代码模板分析

    万次阅读 2017-07-19 21:31:53
    Fabric的智能合约称为链码(chaincode),分为系统链码和用户链码。系统链码用来实现系统层面的功能,用户链码实现用户的应用功能。链码被编译成一个独立的应用程序,运行于隔离的Docker容器中。
1 2 3 4 5 ... 20
收藏数 40,646
精华内容 16,258
关键字:

智能合约