GVKun编程网logo

【Solidity】2.合约的结构体 - 深入理解Solidity(solidity new 合约)

34

在本文中,我们将带你了解【Solidity】2.合约的结构体-深入理解Solidity在这篇文章中,我们将为您详细介绍【Solidity】2.合约的结构体-深入理解Solidity的方方面面,并解答s

在本文中,我们将带你了解【Solidity】2.合约的结构体 - 深入理解Solidity在这篇文章中,我们将为您详细介绍【Solidity】2.合约的结构体 - 深入理解Solidity的方方面面,并解答solidity new 合约常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的深入理解Solidity之二---Solidity源代码文件结构、fisco bcos solidity销毁合约,删除合约的方法、Solidity 官方文档中文版 3_安装Solidity、Solidity 官方文档中文版 4_Solidity 编程实例

本文目录一览:

【Solidity】2.合约的结构体 - 深入理解Solidity(solidity new 合约)

【Solidity】2.合约的结构体 - 深入理解Solidity(solidity new 合约)

2 合约的结构体

solidity的合约类似于面向对象语言的类。 每个合同都可以包含State Variables,Functions,Function Modifiers,Events,Structs TypesEnum Types的声明。 此外,合约可以继承其他合约。

状态变量

状态变量是永久存储在合约存储中的值。

pragma solidity ^0.4.0;

contract SimpleStorage {
    uint storedData; // 状态变量
    // ...
}

请参阅有关状态变量类型的“类型”部分,“可见性”和“获取器”,以获取可见性的可能选择。

函数 Functions

函数是一个代码合同中的可执行单元。

pragma solidity ^0.4.0;

contract SimpleAuction {
    function bid() payable { // 函数
        // ...
    }
}

函数调用可以内部或外部发生,均有不同程度的知名度对其他合同(可见性和getter)的。

函数修饰符 Function Modifiers

函数修饰符可用于以声明方式修改函数的语义(参见“契约”部分中的函数修饰符)。

pragma solidity ^0.4.11;

contract Purchase {
    address public seller;

    modifier onlySeller() { // Modifier
        require(msg.sender == seller);
        _;
    }

    function abort() onlySeller { // 调用Modifier
        // ...
    }
}

事件

事件是与EVM日志工具便捷接口。

pragma solidity ^0.4.0;

contract SimpleAuction {
    event HighestBidIncreased(address bidder,uint amount); // 事件

    function bid() payable {
        // ...
        HighestBidIncreased(msg.sender,msg.value); // 触发事件
    }
}

请参阅合约中的事件部分,了解有关事件如何声明和可以在dapp内使用的信息。

结构类型

Structs是可以分组几个变量的自定义类型(请参阅类型部分中的结构体)。

pragma solidity ^0.4.0;

contract Ballot {
    struct Voter { // 结构体
        uint weight;
        bool Voted;
        address delegate;
        uint Vote;
    }
}

枚举类型

枚举可用于创建具有有限值集的自定义类型(请参阅类型部分中的枚举)。

pragma solidity ^0.4.0;

contract Purchase {
    enum State { Created,Locked,Inactive } // 枚举
}

<Solidity学习系列二>深入理解Solidity之二---Solidity源代码文件结构

深入理解Solidity之二---Solidity源代码文件结构

Solidity源代码文件结构

源文件可以包含任意数量的合约定义,包括指令和编译指示。

版本Pragma
源文件可以(也应该)用所谓的版本注释来注释,以拒绝被编译为未来可能引入不兼容更改的编译器版本。 我们试图将这种变化保持在绝对最低限度,特别是引入变化的方式是语义的变化也需要语法的变化,但这当然不总是可能的。 因此,至少对于包含重大更改的版本,通读更新日志总是一个好主意,这些版本始终具有0.x.0或x.0.0格式的版本。

版本附注使用如下:

pragma solidity ^0.4.0;

这样的源代码文件不会使用早于版本0.4.0的编译器进行编译,并且它也不适用于从版本0.5.0开始的编译器(第二个条件是使用^添加的)。 这背后的想法是,在版本0.5.0之前不会有任何重大更改,所以我们始终可以确定我们的代码将按照我们打算的方式进行编译。 我们不修复编译器的确切版本,因此bug修复版本仍然有可能。
可以为编译器版本指定更复杂的规则,表达式遵循npm使用的规则。

导入其他源文件
语法和语义

Solidity支持非常类似于JavaScript中可用的导入语句(来自ES6),尽管Solidity不知道“默认导出”的概念。

在全局范围内,您可以使用以下格式的导入语句:

import "filename";

该语句从“文件名”(及其导入的符号)中导入所有全局符号到当前全局作用域(与ES6不同,但向后兼容Solidity)。

import * as symbolName from "filename";

...创建一个新的全局符号symbolName,其成员全部来自“filename”的全局符号。

import {symbol1 as alias, symbol2} from "filename";

...分别创建新的全局符号aliassymbol2,它们分别从“filename”引用symbol1symbol2

另一种语法不是ES6的一部分,但可能很方便:

import "filename" as symbolName;

这相当于从import * as symbolName from "filename";

Paths

在上面,filename总是被视为一个路径,其中/作为目录分隔符。.作为当前和..作为父目录。 什么时候 ...后跟一个除/以外的字符,它不被视为当前或父目录。 所有路径名都被视为绝对路径,除非它们以当前的.或父目录开头..

要从与当前文件相同的目录中导入文件x,请使用import "./x" as x;. 如果使用import "x" as x; 则可以引用不同的文件(在全局“包含目录”中)。

它取决于编译器(见下文)如何实际解析路径。 通常,目录层次不需要严格映射到你的本地文件系统,它也可以映射到通过例如发现的资源。 ipfs,http或者git。

在实际编译器中使用

调用编译器时,不仅可以指定如何发现路径的第一个元素,但可以指定路径前缀重新映射,以便例如 github.com/ethereum/dapp-bin/library被重新映射到/usr/local/dapp-bin/library,编译器将从那里读取文件。 如果可以应用多重重映射,则首先尝试使用最长密钥的那个。 这允许用例如fallback-remapping ""映射到/usr/local/include/solidity

(原文:This allows for a "fallback-remapping" with e.g. "" maps to
> "/usr/local/include/solidity") 翻译的不太通顺。

。 此外,这些重新映射可能取决于上下文,从而允许您配置要导入的包。 不同版本的同名图书馆。

solc:
对于solc(命令行编译器),这些重新映射是作为context:prefix = target参数提供的,其中context:= target部分都是可选的(在这种情况下目标缺省为前缀)。 所有重映射值都是常规文件(包括它们的依赖关系)。 这种机制是完全向后兼容的(只要没有文件名包含=或:),因此不是一个突破性的改变。 在导入以prefix开头的文件的context目录下的文件中的所有导入都将通过将prefix替换为target进行重定向。
例如,如果您将github.com/ethereum/dapp-bin/本地克隆到/usr/local/dapp-bin,则可以在源文件中使用以下内容:

import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;

然后运行编译器

solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol

作为一个更复杂的例子,假设你依赖于一些使用非常旧版本的dapp-bin的模块。 dapp-bin的旧版本在/usr/local/dapp-bin_old处检出,然后您可以使用:

solc module1:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ \
     module2:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin_old/ \
     source.sol
     

以便module2中的所有导入都指向旧版本,但module1中的导入将获得新版本。

请注意,solc仅允许您包含来自特定目录的文件:它们必须位于某个明确指定的源文件的目录(或子目录)中,或位于重新映射目标的目录(或子目录)中。 如果你想允许直接绝对包含,只需添加重新映射=/

如果存在多个导致有效文件的重映射,则选择具有最长公共前缀的重映射。

Remix:

Remix为github提供了一个自动重新映射,并且还会自动通过网络检索文件:您可以通过导入可迭代映射例如:

import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;

未来可能会添加其他源代码提供者。

Comments
单行注释(//)和多行注释(/*...*/)是可用的。

// This is a single-line comment.

/*
This is a
multi-line comment.
*/

此外,还有另一种类型的注释称为natspec注释,对此文档尚未编写。 它们用三斜杠(///)或双星号块(/ ** ... * /)编写,它们应该直接用在函数声明或语句之上。 您可以在这些注释中使用Doxygen风格的标签来记录函数,为形式验证注释条件,并提供确认文本,当用户尝试调用函数时向用户显示。

在下面的例子中,我们记录了合同的标题,两个输入参数和两个返回值的解释。

    pragma solidity ^0.4.0;

/** @title Shape calculator. */
contract shapeCalculator {
    /** @dev Calculates a rectangle''s surface and perimeter.
      * @param w Width of the rectangle.
      * @param h Height of the rectangle.
      * @return s The calculated surface.
      * @return p The calculated perimeter.
      */
    function rectangle(uint w, uint h) returns (uint s, uint p) {
        s = w * h;
        p = 2 * (w + h);
    }
}

fisco bcos solidity销毁合约,删除合约的方法

fisco bcos solidity销毁合约,删除合约的方法

1.字节码中有一个selfdestruct指令,用于销毁合约。所以只需要暴露出自毁接口即可:

contract Mortal{
 //自毁 
function destroy() public{
 selfdestruct(msg.sender);
 } 
}

2.Automatic Deprecation - 允许合约自动停止服务

如果你希望一个合约在指定期限后停止服务,而不需要人工介入,可以使用Automatic Deprecation模式。

contract AutoDeprecated{

    uint private _deadline;

    function setDeadline(uint time) public {
        _deadline = time;
    }

    modifier notExpired(){
        require(now <= _deadline);
        _;
    }

    function service() public notExpired{ 
        //some code    
    } 
}

当用户调用service,notExpired修饰符会先进行日期检测,这样,一旦过了特定时间,调用就会因过期而被拦截在notExpired层。

ps: 合约部署前只能是内置了上述的函数,才能手动触发或者定时触发销毁。否则部署的合约会永久性的运行在系统之中。

Solidity 官方文档中文版 3_安装Solidity

Solidity 官方文档中文版 3_安装Solidity

基于浏览器的Solidity

如果你只是想尝试一个使用Solidity的小合约,你不需要安装任何东西,只要访问 基于浏览器的Solidity http://remix.ethereum.org/。

如果你想离线使用,你可以保存页面到本地,或者从 http://github.com/chriseth/browser-solidity 克隆一个。

NPM / node.js

这可能安装Solidity到本地最轻便最省事的方法。

在基于浏览器的Solidity上,Emscripten提供了一个跨平台JavaScript库,把C++源码编译为JavaScript,同时也提供NPM安装包。

去安装它就可以简单使用。,

npm install solc

如何使用nodejs包的详细信息可以在代码库中找到.

二进制安装包

Ethereum.

包括Mix IDE的二进制Solidity安装包在Ethereum网站C++ bundle中下载。 

从源码构建

在MacOS X、Ubuntu和其它类Unix系统中编译安装Solidity非常相似。这个指南开始讲解如何在每个平台下安装相关的依赖软件,然后构建Solidity。

MacOS X

系统需求:

  • OS X Yosemite (10.10.5)

  • Homebrew

  • Xcode

安装Homebrew:

  brew update
    brew install boost --c++11             # 这需要等待一段时间
    brew install cmake cryptopp miniupnpc leveldb gmp libmicrohttpd libjson-rpc-cpp 
    # 仅仅安装Mix IDE和Alethzero
    brew install xz d-bus
    brew install llvm --HEAD --with-clang 
    brew install qt5 --with-d-bus          # 如果长时间的等待让你发疯,那么添加--verbose输出信息会让你感觉更好。

Ubuntu 系统

下面是在最新版Ubuntu系统上编译安装Solidity的指南。最佳的支持平台是2014年11月发布的64位Ubuntu 14.04,至少需要2GB内存。我们所有的测试都是基于此版本,当然我们也欢迎其它版本的测试贡献者。

安装依赖软件:

在你从源码编译之前,你需要准备一些工具和依赖软件。

首先,升级你的代码库。Ubuntu主代码库不提供所有的包,你需要从Ethereum PPA和LLVM获取。

注意

Ubuntu 14.04的用户需要使用:sudo apt-add-repository ppa:george-edison55/cmake-3.x获取最新版本的cmake。

现在加入其它的包:

    sudo apt-get -y update
    sudo apt-get -y install language-pack-en-base
    sudo dpkg-reconfigure locales
    sudo apt-get -y install software-properties-common
    sudo add-apt-repository -y ppa:ethereum/ethereum
    sudo add-apt-repository -y ppa:ethereum/ethereum-dev
    sudo apt-get -y update
    sudo apt-get -y upgrade

对于Ubbuntu 15.04(Vivid Vervet)或者更老版本,使用下面的命令获取开发相关的包:

sudo apt-get -y install build-essential git cmake libboost-all-dev libgmp-dev libleveldb-dev libminiupnpc-dev libreadline-dev libncurses5-dev libcurl4-openssl-dev libcryptopp-dev libjson-rpc-cpp-dev libmicrohttpd-dev libjsoncpp-dev libedit-dev libz-dev

对于Ubbuntu 15.10(Wily Werewolf)或者更新版本,使用下面的命令获取开发相关的包:

sudo apt-get -y install build-essential git cmake libboost-all-dev libgmp-dev libleveldb-dev libminiupnpc-dev libreadline-dev libncurses5-dev libcurl4-openssl-dev libcryptopp-dev libjsonrpccpp-dev libmicrohttpd-dev libjsoncpp-dev libedit-dev libz-dev

不同版本使用不同获取命令的原因是,libjsonrpccpp-dev已经在最新版的Ubuntu的通用代码仓库中。

编译

如果你只准备安装solidity,忽略末尾Alethzero和Mix的错误。

    git clone --recursive https://github.com/ethereum/webthree-umbrella.git
    cd webthree-umbrella
    ./webthree-helpers/scripts/ethupdate.sh --no-push --simple-pull --project solidity 
    # 更新Solidity库
    ./webthree-helpers/scripts/ethbuild.sh --no-git --project solidity --all --cores 4 -DEVMJIT=0 
    # 编译Solidity及其它
    # 在OS X系统加上DEVMJIT将不能编译,在Linux系统上则没问题  

如果你选择安装Alethzero和Mix:

git clone --recursive https://github.com/ethereum/webthree-umbrella.git
    cd webthree-umbrella && mkdir -p build && cd build
    cmake ..

如果你想帮助Solidity的开发,你需要分支(fork)Solidity并添加到你的私人远端分支:

    cd webthree-umbrella/solidity
    git remote add personal git@github.com:username/solidity.git

注意webthree-umbrella使用的子模块,所以solidity是其自己的git代码库,但是他的设置不是保存在 .git/config, 而是在webthree-umbrella/.git/modules/solidity/config.

Solidity 官方文档中文版 4_Solidity 编程实例

Solidity 官方文档中文版 4_Solidity 编程实例

Voting 投票

接下来的合约非常复杂,但展示了很多Solidity的特性。它实现了一个投票合约。当然,电子选举的主要问题是如何赋予投票权给准确的人,并防止操纵。我们不能解决所有的问题,但至少我们会展示如何委托投票可以同时做到投票统计是自动和完全透明。

思路是为每张选票创建一个合约,每个投票选项提供一个短名称。合约创建者作为会长将会给每个投票参与人各自的地址投票权。

地址后面的人们可以选择自己投票或者委托信任的代表人替他们投票。在投票结束后,winningProposal()将会返回获得票数最多的提案。

 /// @title Voting with delegation.
 /// @title 授权投票
    contract Ballot
    {
       // 这里声明了复杂类型
         // 将会在被后面的参数使用
           // 代表一个独立的投票人。
        struct Voter
        {
            uint weight; // 累积的权重。
            bool voted;  // 如果为真,则表示该投票人已经投票。
            address delegate; // 委托的投票代表
            uint vote;   // 投票选择的提案索引号
        }

       // 这是一个独立提案的类型
        struct Proposal
        {
            bytes32 name;   // 短名称(32字节)
            uint voteCount; // 累计获得的票数
        }
    address public chairperson;
  //这里声明一个状态变量,保存每个独立地址的`Voter` 结构
    mapping(address => Voter) public voters;
    //一个存储`Proposal`结构的动态数组
    Proposal[] public proposals;

    // 创建一个新的投票用于选出一个提案名`proposalNames`.
    function Ballot(bytes32[] proposalNames)
    {
        chairperson = msg.sender;
        voters[chairperson].weight = 1;

        //对提供的每一个提案名称,创建一个新的提案
        //对象添加到数组末尾
        for (uint i = 0; i < proposalNames.length; i++)
            //`Proposal({...})` 创建了一个临时的提案对象,
            //`proposal.push(...)`添加到了提案数组`proposals`末尾。
            proposals.push(Proposal({
                name: proposalNames[i],
                voteCount: 0
            }));
    }

     //给投票人`voter`参加投票的投票权,
    //只能由投票主持人`chairperson`调用。
    function giveRightToVote(address voter)
    {
        if (msg.sender != chairperson || voters[voter].voted)
            //`throw`会终止和撤销所有的状态和以太改变。
           //如果函数调用无效,这通常是一个好的选择。
           //但是需要注意,这会消耗提供的所有gas。
            throw;
        voters[voter].weight = 1;
    }

    // 委托你的投票权到一个投票代表 `to`。
    function delegate(address to)
    {
        // 指定引用
        Voter sender = voters[msg.sender];
        if (sender.voted)
            throw;

        //当投票代表`to`也委托给别人时,寻找到最终的投票代表
        while (voters[to].delegate != address(0) &&
               voters[to].delegate != msg.sender)
            to = voters[to].delegate;
        // 当最终投票代表等于调用者,是不被允许的。
        if (to == msg.sender)
            throw;
        //因为`sender`是一个引用,
        //这里实际修改了`voters[msg.sender].voted`
        sender.voted = true;
        sender.delegate = to;
        Voter delegate = voters[to];
        if (delegate.voted)
            //如果委托的投票代表已经投票了,直接修改票数
            proposals[delegate.vote].voteCount += sender.weight;
        else
            //如果投票代表还没有投票,则修改其投票权重。
            delegate.weight += sender.weight;
    }

    ///投出你的选票(包括委托给你的选票)
    ///给 `proposals[proposal].name`。
    function vote(uint proposal)
    {
        Voter sender = voters[msg.sender];
        if (sender.voted) throw;
        sender.voted = true;
        sender.vote = proposal;
        //如果`proposal`索引超出了给定的提案数组范围
        //将会自动抛出异常,并撤销所有的改变。
        proposals[proposal].voteCount += sender.weight;
    }

   ///@dev 根据当前所有的投票计算出当前的胜出提案
    function winningProposal() constant
            returns (uint winningProposal)
    {
        uint winningVoteCount = 0;
        for (uint p = 0; p < proposals.length; p++)
        {
            if (proposals[p].voteCount > winningVoteCount)
            {
                winningVoteCount = proposals[p].voteCount;
                winningProposal = p;
            }
        }
    }
}

可能的改进

现在,指派投票权到所有的投票参加者需要许多的交易。你能想出更好的方法么?

盲拍

这一节,我们将展示在以太上创建一个完整的盲拍合约是多么简单。我们从一个所有人都能看到出价的公开拍卖开始,接着扩展合约成为一个在拍卖结束以前不能看到实际出价的盲拍。

简单的公开拍卖

通常简单的公开拍卖合约,是每个人可以在拍卖期间发送他们的竞拍出价。为了实现绑定竞拍人的到他们的拍卖,竞拍包括发送金额/ether。如果产生了新的最高竞拍价,前一个最高价竞拍人将会拿回他的钱。在竞拍阶段结束后,受益人人需要手动调用合约收取他的钱 — — 合约不会激活自己。

contract SimpleAuction {
    // 拍卖的参数。
   // 时间要么为unix绝对时间戳(自1970-01-01以来的秒数),
   // 或者是以秒为单位的出块时间
    address public beneficiary;
    uint public auctionStart;
    uint public biddingTime;

    //当前的拍卖状态
    address public highestBidder;
    uint public highestBid;

   //在结束时设置为true来拒绝任何改变
    bool ended;

   //当改变时将会触发的Event
    event HighestBidIncreased(address bidder, uint amount);
    event AuctionEnded(address winner, uint amount);

    //下面是一个叫做natspec的特殊注释,
    //由3个连续的斜杠标记,当询问用户确认交易事务时将显示。

    ///创建一个简单的合约使用`_biddingTime`表示的竞拍时间,
   /// 地址`_beneficiary`.代表实际的拍卖者
    function SimpleAuction(uint _biddingTime,
                           address _beneficiary) {
        beneficiary = _beneficiary;
        auctionStart = now;
        biddingTime = _biddingTime;
    }

    ///对拍卖的竞拍保证金会随着交易事务一起发送,
   ///只有在竞拍失败的时候才会退回
    function bid() {

       //不需要任何参数,所有的信息已经是交易事务的一部分
        if (now > auctionStart + biddingTime)
           //当竞拍结束时撤销此调用
            throw;
        if (msg.value <= highestBid)
           //如果出价不是最高的,发回竞拍保证金。
            throw;
        if (highestBidder != 0)
            highestBidder.send(highestBid);
        highestBidder = msg.sender;
        highestBid = msg.value;
        HighestBidIncreased(msg.sender, msg.value);
    }

   ///拍卖结束后发送最高的竞价到拍卖人
    function auctionEnd() {
        if (now <= auctionStart + biddingTime)
            throw; 
            //拍卖还没有结束
        if (ended)
            throw; 
     //这个收款函数已经被调用了
        AuctionEnded(highestBidder, highestBid);
        //发送合约拥有所有的钱,因为有一些保证金可能退回失败了。

        beneficiary.send(this.balance);
        ended = true;
    }

    function () {
        //这个函数将会在发送到合约的交易事务包含无效数据
        //或无数据的时执行,这里撤销所有的发送,
        //所以没有人会在使用合约时因为意外而丢钱。
        throw;
    }
}

Blind Auction 盲拍

接下来扩展前面的公开拍卖成为一个盲拍。盲拍的特点是拍卖结束以前没有时间压力。在一个透明的计算平台上创建盲拍系统听起来可能有些矛盾,但是加密算法能让你脱离困境。

在拍卖阶段, 竞拍人不需要发送实际的出价,仅仅只需要发送一个它的散列值。因为目前几乎不可能找到两个值(足够长)的散列值相等,竞拍者提交他们的出价散列值。在拍卖结束后,竞拍人重新发送未加密的竞拍出价,合约将检查其散列值是否和拍卖阶段发送的一样。 另一个挑战是如何让拍卖同时实现绑定和致盲 :防止竞拍人竞拍成功后不付钱的唯一的办法是,在竞拍出价的同时发送保证金。但是在Ethereum上发送保证金是无法致盲,所有人都能看到保证金。下面的合约通过接受任何尽量大的出价来解决这个问题。当然这可以在最后的揭拍阶段进行复核,一些竞拍出价可能是无效的,这样做的目的是(它提供一个显式的标志指出是无效的竞拍,同时包含高额保证金):竞拍人可以通过放置几个无效的高价和低价竞拍来混淆竞争对手。

contract BlindAuction
{
    struct Bid
    {
        bytes32 blindedBid;
        uint deposit;
    }
    address public beneficiary;
    uint public auctionStart;
    uint public biddingEnd;
    uint public revealEnd;
    bool public ended;

    mapping(address => Bid[]) public bids;

    address public highestBidder;
    uint public highestBid;

    event AuctionEnded(address winner, uint highestBid);

   ///修饰器(Modifier)是一个简便的途径用来验证函数输入的有效性。
   ///`onlyBefore` 应用于下面的 `bid`函数,其旧的函数体替换修饰器主体中 `_`后就是其新的函数体
    modifier onlyBefore(uint _time) { if (now >= _time) throw; _ }
    modifier onlyAfter(uint _time) { if (now <= _time) throw; _ }

    function BlindAuction(uint _biddingTime,
                            uint _revealTime,
                            address _beneficiary)
    {
        beneficiary = _beneficiary;
        auctionStart = now;
        biddingEnd = now + _biddingTime;
        revealEnd = biddingEnd + _revealTime;
    }

   ///放置一个盲拍出价使用`_blindedBid`=sha3(value,fake,secret).
   ///仅仅在竞拍结束正常揭拍后退还发送的以太。当随同发送的以太至少
   ///等于 "value"指定的保证金并且 "fake"不为true的时候才是有效的竞拍
   ///出价。设置 "fake"为true或发送不合适的金额将会掩没真正的竞拍出
   ///价,但是仍然需要抵押保证金。同一个地址可以放置多个竞拍。
    function bid(bytes32 _blindedBid)
        onlyBefore(biddingEnd)
    {
        bids[msg.sender].push(Bid({
            blindedBid: _blindedBid,
            deposit: msg.value
        }));
    }

   ///揭开你的盲拍竞价。你将会拿回除了最高出价外的所有竞拍保证金
   ///以及正常的无效盲拍保证金。
    function reveal(uint[] _values, bool[] _fake,
                    bytes32[] _secret)
        onlyAfter(biddingEnd)
        onlyBefore(revealEnd)
    {
        uint length = bids[msg.sender].length;
        if (_values.length != length || _fake.length != length ||
                    _secret.length != length)
            throw;
        uint refund;
        for (uint i = 0; i < length; i++)
        {
            var bid = bids[msg.sender][i];
            var (value, fake, secret) =
                    (_values[i], _fake[i], _secret[i]);
            if (bid.blindedBid != sha3(value, fake, secret))
                //出价未被正常揭拍,不能取回保证金。
                continue;
            refund += bid.deposit;
            if (!fake && bid.deposit >= value)
                if (placeBid(msg.sender, value))
                    refund -= value;
            //保证发送者绝不可能重复取回保证金
            bid.blindedBid = 0;
        }
        msg.sender.send(refund);
    }

    //这是一个内部 (internal)函数,
   //意味着仅仅只有合约(或者从其继承的合约)可以调用
    function placeBid(address bidder, uint value) internal
            returns (bool success)
    {
        if (value <= highestBid)
            return false;
        if (highestBidder != 0)
            //退还前一个最高竞拍出价
            highestBidder.send(highestBid);
        highestBid = value;
        highestBidder = bidder;
        return true;
    }

   ///竞拍结束后发送最高出价到竞拍人
    function auctionEnd()
        onlyAfter(revealEnd)
    {
        if (ended) throw;
        AuctionEnded(highestBidder, highestBid);
        //发送合约拥有所有的钱,因为有一些保证金退回可能失败了。
        beneficiary.send(this.balance);
        ended = true;
    }

    function () { throw; }
}
Safe Remote Purchase 安全的远程购物

contract Purchase
{
    uint public value;
    address public seller;
    address public buyer;
    enum State { Created, Locked, Inactive }
    State public state;
    function Purchase()
    {
        seller = msg.sender;
        value = msg.value / 2;
        if (2 * value != msg.value) throw;
    }
    modifier require(bool _condition)
    {
        if (!_condition) throw;
        _
    }
    modifier onlyBuyer()
    {
        if (msg.sender != buyer) throw;
        _
    }
    modifier onlySeller()
    {
        if (msg.sender != seller) throw;
        _
    }
    modifier inState(State _state)
    {
        if (state != _state) throw;
        _
    }
    event aborted();
    event purchaseConfirmed();
    event itemReceived();

   ///终止购物并收回以太。仅仅可以在合约未锁定时被卖家调用。
    function abort()
        onlySeller
        inState(State.Created)
    {
        aborted();
        seller.send(this.balance);
        state = State.Inactive;
    }

   ///买家确认购买。交易包含两倍价值的(`2 * value`)以太。
   ///这些以太会一直锁定到收货确认(confirmReceived)被调用。
    function confirmPurchase()
        inState(State.Created)
        require(msg.value == 2 * value)
    {
        purchaseConfirmed();
        buyer = msg.sender;
        state = State.Locked;
    }

    ///确认你(买家)收到了货物,这将释放锁定的以太。
    function confirmReceived()
        onlyBuyer
        inState(State.Locked)
    {
        itemReceived();
        buyer.send(value);//我们有意忽略了返回值。
        seller.send(this.balance);
        state = State.Inactive;
    }
    function() { throw; }
}

小额支付通道

我们今天的关于【Solidity】2.合约的结构体 - 深入理解Soliditysolidity new 合约的分享已经告一段落,感谢您的关注,如果您想了解更多关于深入理解Solidity之二---Solidity源代码文件结构、fisco bcos solidity销毁合约,删除合约的方法、Solidity 官方文档中文版 3_安装Solidity、Solidity 官方文档中文版 4_Solidity 编程实例的相关信息,请在本站查询。

本文标签: