根据例子学习Solidity-Solidity官方文档(3)

论坛 期权论坛 区块链     
宇宙永恒   2018-11-20 23:42   5076   0
            
image写在前面:HiBlock区块链社区成立了翻译小组(以太坊中文社区),翻译区块链相关的技术文档及资料,本文为Solidity官方文档翻译的第三部分《根据例子学习Solidity》,特发布出来邀请solidity爱好者、开发者做公开的审校,您可以添加微信baobaotalk_com,验证输入“solidity”,然后将您的意见和建议发送给我们,也可以在文末“留言”区留言,有效的建议我们会采纳及合并进下一版本,同时将送一份小礼物给您以示感谢。
1投  票以下的合约相当复杂,但展示了很多Solidity的功能。它实现了一个投票合约。 当然,电子投票的主要问题是如何将投票权分配给正确的人员以及如何防止被操纵。 我们不会在这里解决所有的问题,但至少我们会展示如何进行委托投票,同时,计票又是自动和完全透明的
我们的想法是为每个(投票)表决创建一份合约,为每个选项提供简称。 然后作为合约的创造者——即主席,将给予每个独立的地址以投票权。
地址后面的人可以选择自己投票,或者委托给他们信任的人来投票。
在投票时间结束时,winningProposal() 将返回获得最多投票的提案。
pragma solidity ^0.4.16;
///@title 委托投票
contract Ballot {
  • // 这里声明了一个新的复合类型用于稍后的变量*
  • // 它用来表示一个选民*
    ** struct** Voter {
    uint weight;* // 计票的权重*
    ** bool** voted;  // 若为真,代表该人已投票
    address delegate; // 被委托人
    ** uint** vote;   // 投票提案的索引
    }
  • // 提案的类型*
    struct Proposal {
    bytes32 name;   // 简称(最长32个字节)
    **  uint** voteCount; // 得票数
    }
**  address**public chairperson;
  • // 这声明了一个状态变量,为每个可能的地址存储一个
    1. Voter
    复制代码
    。*
    mapping(address=> Voter)public voters;
  • // 一个
    1. Proposal
    复制代码
    结构类型的动态数组*
    Proposal[]public proposals;
/// 为
  1. proposalNames
复制代码
中的每个提案,创建一个新的(投票)表决

function Ballot(bytes32[] proposalNames)public {
chairperson= msg.sender;
voters[chairperson].weight= 1;
* //对于提供的每个提案名称,*
* //创建一个新的 Proposal 对象并把它添加到数组的末尾。*
** for** (uint i= 0; iuint) pendingReturns;
  • // 拍卖结束后设为 true,将禁止所有的变更*
    bool ended;
  • // 变更触发的事件*
    **  event** HighestBidIncreased(address bidder,uint amount);
    event AuctionEnded(address winner,uint amount);
// 以下是所谓的 natspec 注释,可以通过三个斜杠来识别。
// 当用户被要求确认交易时将显示。

  • /// 以受益者地址
    1. _beneficiary
    复制代码
    的名义,
    /// 创建一个简单的拍卖,拍卖时间为
    1. _biddingTime
    复制代码
    秒。*
    ** function** SimpleAuction(
    ** uint** _biddingTime,
    address _beneficiary
    )public {
    beneficiary= _beneficiary;
    auctionEnd **= **now+ _biddingTime;
    }
/// 对拍卖进行出价,具体的出价随交易一起发送。
/// 如果没有在拍卖中胜出,则返还出价。

** function** bid()publicpayable {
* // 参数不是必要的。因为所有的信息已经包含在了交易中。
// 对于能接收以太币的函数,关键字 payable 是必须的。
  1.    // 如果拍卖已结束,撤销函数的调用。*   require(now **** highestBid);  ** if** (highestBid **!=** 0) {      * // 返还出价时,简单地直接调用 highestBidder.send(highestBid) 函数,       // 是有安全风险的,因为它有可能执行一个非信任合约。       // 更为安全的做法是让接收方自己提取金钱。*       pendingReturns[highestBidder] **+=** highestBid;   }   highestBidder **=** msg.sender;   highestBid **=** msg.value;   emit HighestBidIncreased(msg.sender, msg.value);
复制代码
}
  • /// 取回出价(当该出价已被超越)*
    ** function** withdraw()public returns (bool) {
    uint amount = pendingReturns[msg.sender];
    **  if **(amount **> *0) {
    * // 这里很重要,首先要设零值。
    // 因为,作为接收调用的一部分,
    // 接收者可以在
    1. send
    复制代码
    返回之前,重新调用该函数。

    pendingReturns[msg.sender]= 0;
    1.   ** if** (**!**msg.sender.send(amount)) {      * // 这里不需抛出异常,只需重置未付款*       pendingReturns[msg.sender] **=** amount;       **return false;**   }
    复制代码
    }
    ** return true;**
    }
  • /// 结束拍卖,并把最高的出价发送给受益人*
    **  function** auctionEnd()public {
      // 对于可与其他合约交互的函数(意味着它会调用其他函数或发送以太币),
      // 一个好的指导方针是将其结构分为三个阶段:
      // 1. 检查条件
      // 2. 执行动作 (可能会改变条件)
      // 3. 与其他合约交互
      // 如果这些阶段相混合,其他的合约可能会回调当前合约并修改状态,
      // 或者导致某些效果(比如支付以太币)多次生效。
      // 如果合约内调用的函数包含了与外部合约的交互,
      // 则它也会被认为是与外部合约有交互的。
    // 1. 条件*
    require(now>= auctionEnd); // 拍卖尚未结束
    require(!ended); // 该函数已被调用
    • // 2. 生效*
      ended= true;
      emit AuctionEnded(highestBidder, highestBid);
    1.   // 3\. 交互* beneficiary.transfer(highestBid);
    复制代码
    }
}
秘密竞拍(盲拍)
之前的公开拍卖接下来将被扩展为一个秘密竞拍。 秘密竞拍的好处是在投标结束前不会有时间压力。 在一个透明的计算平台上进行秘密竞拍听起来像是自相矛盾,但密码学可以实现它。
投标期间 ,投标人实际上并没有发送她的出价,而只是发送一个哈希版本的出价。 由于目前几乎不可能找到两个(足够长的)值,其哈希值是相等的,因此投标人可通过该方式提交报价。 在投标结束后,投标人必须公开他们的出价:他们不加密的发送他们的出价,合约检查出价的哈希值是否与投标期间提供的相同。
另一个挑战是如何使拍卖同时做到绑定和秘密 : 唯一能阻止投标者在她赢得拍卖后不付款的方式是,让她将钱连同出价一起发出。 但由于资金转移在 以太坊Ethereum 中不能被隐藏,因此任何人都可以看到转移的资金。
下面的合约通过接受任何大于最高出价的值来解决这个问题。 当然,因为这只能在披露阶段进行检查,有些出价可能是 **无效 **的, 并且,这是故意的(与高出价一起,它甚至提供了一个明确的标志来标识无效的出价): 投标人可以通过设置几个或高或低的无效出价来迷惑竞争对手。
pragma solidity ^0.4.21;
contract BlindAuction {
struct Bid {
bytes32 blindedBid;
uint deposit;
}
addresspublic beneficiary;
uint**** public biddingEnd;
** uint**** public** revealEnd;
bool**** public ended;
** mapping(address**=> Bid[]) **public **bids;
addresspublic highestBidder;
** uint** **public **highestBid;
// 可以取回的之前的出价
mapping(address=>**** uint) pendingReturns;
event AuctionEnded(address winner,uint highestBid);
  • /// 使用 modifier 可以更便捷的校验函数的入参。
    ///
    1. onlyBefore
    复制代码
    会被用于后面的
    1. bid
    复制代码
    函数:
    /// 新的函数体是由 modifier 本身的函数体,并用原函数体替换
    1. _;
    复制代码
    语句来组成的。*
    modifier onlyBefore(**uint **_time) { require(now< _time); _; }
    modifier
    onlyAfter(uint _time) { require(now> _time); _; }
** function** BlindAuction(
uint _biddingTime,
**  uint **_revealTime,
address _beneficiary
)public {
beneficiary= _beneficiary;
biddingEnd= now+ _biddingTime;
revealEnd= biddingEnd+ _revealTime;
}
  • /// 可以通过
    1. _blindedBid
    复制代码
    = keccak256(value, fake, secret)
    /// 设置一个秘密竞拍。
    /// 只有在出价披露阶段被正确披露,已发送的以太币才会被退还。
    /// 如果与出价一起发送的以太币至少为 “value” 且 “fake” 不为真,则出价有效。
    /// 将 “fake” 设置为 true ,然后发送满足订金金额但又不与出价相同的金额是隐藏实际出价的方法。
    /// 同一个地址可以放置多个出价。*
    function bid(bytes32 _blindedBid)
    ** public
    payable**
    onlyBefore(biddingEnd)
    {
    bids[msg.sender].push(Bid({
    blindedBid: _blindedBid,
    deposit: msg.value
    }));
    }
  • /// 披露你的秘密竞拍出价。
    /// 对于所有正确披露的无效出价以及除最高出价以外的所有出价,你都将获得退款。*
    ** function** reveal(
    uint[] _values,
    ** bool[] _fake,
    ** bytes32
    [] _secret
    )
    public
    onlyAfter(biddingEnd)
    onlyBefore(revealEnd)
    {
    **  uint** length = bids[msg.sender].length;
    require(_values.length== length);
    require(_fake.length== length);
    require(_secret.length== length);
    **  uint** refund;
    **  for(uinti = 0; i = value) {
    if (placeBid(msg.sender, value))
    refund-= value;
    }
    * // 使发送者不可能再次认领同一笔订金

    bid.blindedBid =****bytes32*(0);
    }
    msg.sender.transfer(refund);
    }
  • // 这是一个 "internal" 函数, 意味着它只能在本合约(或继承合约)内被调用*
    **  function** placeBid(address bidder,uint value)internal
    ** returns(bool** success)
    {
    ** if** (value 0) {
    * // 这里很重要,首先要设零值。
    // 因为,作为接收调用的一部分,
    // 接收者可以在
    1. transfer
    复制代码
    返回之前重新调用该函数。(可查看上面关于‘条件 -> 影响 -> 交互’的标注)*
    pendingReturns[msg.sender] = 0;
    1.    msg.sender.transfer(amount);
    复制代码
    }
    }
  • /// 结束拍卖,并把最高的出价发送给受益人*
    **   function** auctionEnd()
    public
    onlyAfter(revealEnd)
    {
    require(!ended);
    emit AuctionEnded(highestBidder, highestBid);
    ended= true;
    beneficiary.transfer(highestBid);
    }
安全的远程购买
pragma solidity ^0.4.21;
contract Purchase {
** uint ****public** value;
address**** public seller;
** address ****public** buyer;
enum State { Created, Locked, Inactive }
Statepublic state;
  • //确保
    1. msg.value
    复制代码
    是一个偶数。
    //如果它是一个奇数,则它将被截断。
    //通过乘法检查它不是奇数。*
    ** function** Purchase()public payable {
    seller= msg.sender;
    value= msg.value / 2;
    require((2** *** value)== msg.value);
    }
modifier condition(bool _condition) {
require(_condition);
_;
}
modifier onlyBuyer() {
require(msg.sender** ==** buyer);
_;
}
modifier onlySeller() {
require(msg.sender **== **seller);
_;
}
modifier inState(State _state) {
require(state== _state);
_;
}
event Aborted();
**   event **PurchaseConfirmed();
** event **ItemReceived();
  • ///中止购买并回收以太币。
    ///只能在合约被锁定之前由卖家调用。*
    function abort()
    **  public**
    onlySeller
    inState(State.Created)
    {
    emit Aborted();
    state= State.Inactive;
    seller.transfer(this.balance);
    }
  • /// 买家确认购买。
    /// 交易必须包含
    1. 2 * value
    复制代码
    个以太币。
    /// 以太币会被锁定,直到 confirmReceived 被调用。*
    **  function** confirmPurchase()
    public
    inState(State.Created)
    condition(msg.value == (2 * value))
    ** payable**
    {
    emit PurchaseConfirmed();
    buyer= msg.sender;
    state= State.Locked;
    }
/// 确认你(买家)已经收到商品。
/// 这会释放被锁定的以太币。

** function** confirmReceived()
**     public**
onlyBuyer
inState(State.Locked)
{
emit ItemReceived();
*  // 首先修改状态很重要,否则的话,由
  1. transfer
复制代码
所调用的合约可以回调进这里(再次接收以太币)。*
state = State.Inactive;
  1.   * // 注意: 这实际上允许买方和卖方阻止退款 - 应该使用取回模式。*   buyer.transfer(value);   seller.transfer(**this**.balance);
复制代码
}
}
微支付通道
To be written.
:本文为solidity翻译的第三部分《根据例子学习Solidity》,特发布出来邀请solidity爱好者、开发者做公开的审校,您可以添加微信baobaotalk_com,验证输入“solidity”,然后将您的意见和建议发送给我们,也可在文末“留言”区留言,或通过原文链接访问我们的Github。有效的建议我们会收纳并及时改进,同时将送一份小礼物给您以示感谢。
本文内容来源于HiBlock区块链社区翻译小组-以太坊中文社区,感谢全体译者的辛苦工作。
活动推荐技术沙龙|百万年薪招区块链开发者,区块链热度何时降温?(免费报名)

image点击“阅读原文”即可查看翻译原文。
         
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:40
帖子:314
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP