• J
    jimi2018

    今天我们推出了一个全新的系列,Hacking the Blockchain!它适用于刚刚开始开发EOSIO的所有开发人员。它也适用于所有EOS Blockchain爱好者,他们不是完全技术性的,但想要搞清楚该技术的工作原理。

    在每篇文章中,我们将探讨区块链的特定部分。我们从EOS通信模型开始,希望能坚持下去!

    今天,我们将探索EOS通信模型。我们将深入探讨不同类型的沟通模式和行动。对于dessert,我们将看到如何在我们的代码中使用它,并在我们要开发一个自动化的演示中使用它。

    但首先,让我们从EOS智能合约的内容开始。这将奠定基础。

    EOS 智能合约

    eos_smart_contracts

    每个EOS智能合约都有一组操作和类型。action表示单个操作。你可以将其视为JavaScript中的函数或C#中的方法。type定义合约中使用的所需内容和结构。大多数时候我们将它们用于我们的表。

    EOSIO中的合约可以相互通信。它是通过基于消息的通信架构实现的。

    EOS通信模型就是他们沟通的方式。通信模型有两种类型:Inline Communication Model(内联通信模型)和Deferred Communication Model(延时通信模型)。

    内联操作(内联通信模型)

    内联操作是内联通信模型的一部分。如果你了解它们,就能理解内联通信。

    我们来看看下图:

    inline_action_diagram

    用户从智能合约A执行操作(Action #1)。当操作开始执行时,它会触发另外两个操作:来自智能合约B的操作Action #1.1来自智能合约C的操作Action #1.2。一切都在当前交易中完成。

    在当前交易中执行并与其完成相关的操作,称为inline action内联操作

    重要的是要记住内联操作是作为调用操作的一部分执行的。因此,它们与原始交易的范围和权限相同。这是他们将被执行的保证。如果其中一个操作失败,则整个交易将失败。

    所以,你应该已经知道内联通信是什么意思了吧。

    请求将执行操作作为调用操作的一部分是inline communication内联通信的示例。

    延时操作(延时通信模式)

    第二种类型是延时通信模型。表示模型的延时操作非常有趣,因为它们不在同一交易中执行。我们来看看下图:

    deferred_action_diagram

    我们有相同的交易工作流程。这里唯一的区别是从智能合约C执行的第二个操作不是内联而是延时。延时操作计划在将来运行。

    根据生产者的判断,延时的操作最好可以安排在稍后的时间运行。无法保证延期操作将执行。

    即使它们不属于同一交易,它们也具有发送它们的合约的权限。

    所以基本上,延时通信在概念上采用发送给对等交易的操作通知的形式。

    交易与操作

    在继续演示之前,让我们检查一些有趣的东西。

    在EOSIO中,交易和操作之间存在差异。操作表示单个操作,而交易是一个或多个操作的集合。

    deferred_action_diagram

    交易可以包含N个操作。但是,每个交易必须在30ms或更短的时间内执行。如果交易包含多个操作,并且这些操作的总和大于30毫秒,则整个交易将失败。

    机器人工厂

    我们要做个机器人。你可以在我们的GitHub中找到包含所有智能合约和代码的项目。

    作为一家创造未来的机器人公司,我们希望一切都是完美的。新建新的机器人时,应发送出售信息,并在终端上打印相关信息。为了实现这三个操作,我们将使用内联操作。

    看一下下面的代码片段。

    void RobotFactory::create(account_name account, robot newRobot) {
            robotIndex robots(_self, _self);
    
            auto iterator = robots.find(newRobot.series_number);
            eosio_assert(iterator == robots.end(), "Robot with this series number already exists");
    
            robots.emplace(account, [&](auto& robot) {
                robot.series_number = newRobot.series_number;
                robot.model = newRobot.model;
                robot.operating_system = newRobot.operating_system;
                robot.profession = newRobot.profession;
                robot.owner = name{account}.to_string();
                robot.manufactured = now();
            });
    
            // Execute INLINE ACTION from another contract
            // action({permission_level}, {contract_deployer}, {contract_action}, {data_to_pass}).send();
            action(permission_level(account, N(active)), N(market), N(forsale), make_tuple(account, 
                newRobot.series_number, 
                newRobot.model, 
                newRobot.manufactured
            )).send();
    
            // Execute INLINE ACTION from another contract
            // action({permission_level}, {contract_deployer}, {contract_action}, {data_to_pass}).send();
            action(permission_level(account, N(active)), N(messenger), N(printmessage), make_tuple(newRobot.model)).send();
        }
    

    首先,我们开始创建一个新的机器人。操作完成后,它将出现第一个内联操作。我们让发送机器人一个出售信息,所以我们要求RobotMarketplace智能合约的forsale

    请注意,当我们要求智能合约A从智能合约B执行操作时,应首先添加适当的权限。我们将在下一部分介绍,目前,请务必遵循README.md中的指南。

    第一个内联操作完成后,第二个内联操作就会完成。这次我们从Messenger智能合约中请求printmessage。 同样应该添加适当的权限。

    在这两种情况下,当我们通过终端执行创建操作时,我们已收到操作已完成(或失败)的通知。

    cleos push action weyland create '{"account":"weyland","newRobot":{"series_number":14441992,"model":"A330","operating_system":"DX42","profession":"engineer","owner":"","manufactured":0}}' -p weyland
    
    executed transaction: 9874a8a5f516ca540c44cafd8b9b371c856fe7958be1fc6268641cc7ab67fdaf  136 bytes  6000 us
    #      weyland <= weyland::create             {"account":"weyland","newRobot":{"series_number":14441992,"model":"A330","operating_system":"DX42",...
    #        market <= market::forsale              {"account":"weyland","robotForSale":{"series_number":14441992,"model":"A330","manufactured":0}}
    #     messenger <= messenger::printmessage      {"message":"A330"}
    >>  ==== For sale | Robot model: A330
    

    让我们将printmessage操作从内联更改为延时。为此,我们需要使用EOSIO的transaction.hpp标头。

    void RobotFactory::create(account_name account, robot newRobot) {
            robotIndex robots(_self, _self);
    
            auto iterator = robots.find(newRobot.series_number);
            eosio_assert(iterator == robots.end(), "Robot with this series number already exists");
    
            robots.emplace(account, [&](auto& robot) {
                robot.series_number = newRobot.series_number;
                robot.model = newRobot.model;
                robot.operating_system = newRobot.operating_system;
                robot.profession = newRobot.profession;
                robot.owner = name{account}.to_string();
                robot.manufactured = now();
            });
    
            // Execute inline action from another contract
            // action({permission_level}, {contract_deployer}, {contract_action}, {data_to_pass}).send();
            action(permission_level(account, N(active)), N(market), N(forsale), make_tuple(account, 
                newRobot.series_number, 
                newRobot.model, 
                newRobot.manufactured
            )).send();
    
            // Execute DEFERRED ACTION from another contract
            eosio::transaction tx;
            tx.actions.emplace_back(permission_level{account, N(active)}, N(messenger), N(printmessage), make_tuple(newRobot.model));
            tx.delay_sec = 12;
            tx.send(N(newRobot.model), account); 
        }
    

    要创建延时交易,我们首先从类型交易声明一个变量tx。然后我们在其操作集合中添加一个新操作。我们可以选择设置延时。如果它为0,则延时交易将在调用之后立即进行。

    设置完所有后,我们只需调用send方法即可。

    但是,不保证将执行延时交易。此外,我们不会像在内联操作中那样收到有关其成功或失败的任何通知。

    cleos push action weyland1 create '{"account":"weyland1","newRobot":{"series_number":14441993,"model":"A330","operating_system":"DX42","profession":"engineer","owner":"","manufactured":0}}' -p weyland1
    
    executed transaction: 5f45b48877aac9d03172616a2443b7a9079ee9f74a124a0976d2fcf0b756e985  176 bytes  2722 us
    #      weyland1 <= weyland1::create             {"account":"weyland1","newRobot":{"series_number":14441993,"model":"A330","operating_system":"DX42",...
    #        market <= market::forsale              {"account":"weyland1","robotForSale":{"series_number":14441993,"model":"A330","manufactured":0}}
    
    # No notification for printmessage action
    

    正如你在12秒后看到的那样,执行延时交易。

    deferred_action_diagram

    总结一下它们是EOS中的两种通信模型:内联和延时。内联通信期间使用的操作称为内联操作,在延时通信中使用时称为延时操作。

    分享一个EOS区块链相关的交互式在线编程实战教程:

    EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。

    汇智网原创翻译,转载请标明出处。这里是原文EOS区块链的通信模型

    发布在 编程 阅读更多
  • J
    jimi2018

    Tendermint是一个开源的完整的区块链实现,可以用于公链或联盟链,其官方定位是面向开发者的区块链共识引擎:与其他区块链平台例如以太坊或者EOS相比,tendermint最大的特点是其差异化的定位,尽管包含了区块链的完整实现,但它却是以SDK的形式将这些核心功能提供出来,供开发者方便地定制自己的专有区块链:

    tendermint

    汇智网 tendermint

    tendermint的SDK中包含了构造一个区块链节点旳绝大部分组件,例如加密算法、共识算法、区块链存储、RPC接口、P2P通信等等,开发人员只需要根据其应用开发接口(Application Blockchain Communication Interface)的要求实现自己的应用即可。

    ABCI是开发语言无关的,开发人员可以使用自己喜欢的任何语言来开发基于tendermint的专用区块链。不过由于tendermint本身是采用go语言开发的,因此用go开发ABCI应用的一个额外好处就是,你可以把tendermint完整的嵌入自己的应用,干净利落地交付一个单一的可执行文件。

    tendermint的共识算法

    在技术方面,tendermint引以为傲的是其共识算法——世界上第一个可以应用于公链的拜占庭容错算法。tendermint曾于2016年国际区块链周获得最具创新奖,并在Hyperledger的雨燕(Burrow)等诸多产品中被采纳为共识引擎。

    tendermint采用的共识机制属于一种权益证明( Proof Of Stake)算法,一组验证人(Validator)代替了矿工(Miner)的角色,依据抵押的权益比例轮流出块:

    vaildator

    由于避免了POW机制,tendermint可以实现很高的交易吞吐量。根据官方的说法,在合理(理想)的应用数据结构支持下,可以达到42000交易/秒,引文参考这里。不过在现实环境中,部署在全球的100个节点进行共识沟通,实际可以达到1000交易/秒。

    tendermint同时是拜占庭容错的(Byzantine Fault Tolerance),因此对于3f+1个验证节点组成的区块链,即使有f个节点出现拜占庭错误,也可以保证全局正确共识的达成。同时在极端环境下,tendermint在交易安全与停机风险之间选择了安全,因此当超过f个验证节点发生 故障时,系统将停止工作。

    什么是拜占庭错误?简单的说就是任何错误:既包括节点宕机、也包括恶意节点的欺骗和攻击。

    tendermint共识机制的另一个特点就是其共识的最终确定性:一旦共识达成就是真的达成,而不是像比特币或以太坊的共识是一种概率性质的确定性,还有可能在将来某个时刻失效。因此在tendermint中不会出现区块链分叉的情况。

    课程地址:
    http://xc.hubwiz.com/course/5bdec63ac02e6b6a59171df3

    tendermint vs. 以太坊

    tendermint的定位决定了在最终交付的节点软件分层中,应用程序占有相当部分的分量。让我们通过与以太坊的对比来更好地理解这一点:

    tendermint vs. ethereum

    在上图中,tendermint结构中的abci应用和以太坊结构中的智能合约,都是由用户代码实现的。显然,ABCI应用大致与EVM+合约的组合相匹配。

    在以太坊中,节点是一个整体,开发者提供的智能合约则运行在受限的虚拟机环境中;而在tendermint中,并不存在虚拟机这一层,应用程序是一个标准的操作系统进程,不受任何的限制与约束——听起来这很危险,但当你考虑下使用tendermint的目的是构建专有的区块链 时,这种灵活性反而更有优势了。

    事实上,tendermint留下的应用层空间如此之大,以至于你完全可以在ABCI应用中实现一个 EVM,然后提供solidity合约开发能力,这就是超级账本的 Burrow 做的事情。

    课程概述

    本课程适合希望开发自己的专有区块链的go语言工程师,课程内容如下:

    第一章 课程简介

    简单介绍tendermint的定位、特点以及对于开发者而言tendermint与以太坊的区别。

    第二章 初识tendermint

    tendermint本身是一个完整的区块链实现,本章介绍tendermint的主要组成部分,包括节点软件的使用、最小ABCI应用编写以及RPC API开发接口。

    第三章 应用开发模型

    tendermint是一个标准的状态机复制模型的实现,因此基于tendermint的应用就是一个标准的分布式状态机。本章通过一个分布式计数器的开发来学习基于ABCI接口的应用开发。

    第四章 去中心化身份识别机制

    本章介绍如何基于非对称加密技术实现去中心化的身份识别。课程的内容包括非对称密钥 的生成、身份验证原理与实现、哈希地址计算等。

    第五章 案例:代币发行

    代币是区块链的一种典型应用。在这一章里我们通过发行代币来进一步深入学习基于tendermint 的状态机应用的设计与实现。

    第六章 代币案例:使用默克尔树

    merkle树是区块链中经常使用的一种数据结构,在这一章我们将学习其原理、用途与使用方法,并使用它增强代币案例的功能。

    第七章 代币案例:使用多版本状态库

    在区块链的每个高度都对应着应用状态的特定历史快照。本章介绍如何使用tendermint的多版本状态库iavl来实现应用状态的管理。

    第八章 多节点组网

    本章介绍如何进行多个tendermint节点/应用旳组网。

    课程地址:tendermint区块链开发详解

    发布在 编程 阅读更多
  • J
    jimi2018

    收费实战教程:

    python以太坊,主要是针对python程序员围绕web3.py库进行区块链以太坊开发的讲解:
    http://xc.hubwiz.com/course/5b40462cc02e6b6a59171de4?affid=827v2mm

    web3j,主要是针对java和android程序员围绕web3j库进行区块链以太坊开发的讲解:
    http://xc.hubwiz.com/course/5b2b6e82c02e6b6a59171de2?affid=827v2mm

    php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和事件等内容:

    http://xc.hubwiz.com/course/5b36629bc02e6b6a59171de3?affid=827v2mm

    C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和事件等:
    http://xc.hubwiz.com/course/5b6048c3c02e6b6a59171dee?affid=827v2mm

    以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶:
    http://xc.hubwiz.com/course/5abbb7acc02e6b6a59171dd6?affid=827v2mm

    以太坊教程,主要介绍智能合约与dapp应用开发,适合入门:
    http://xc.hubwiz.com/course/5a952991adb3847553d205d1?affid=827v2mm

    EOS智能合约与DApp开发入门:
    http://xc.hubwiz.com/course/5b52c0a2c02e6b6a59171ded?affid=827v2mm

    收集整理了一些免费区块链、以太坊技术开发相关的文件,有需要的可以下载,文件链接:

    1. web3.js API官方文档中文版:https://pan.baidu.com/s/1hOV9hEzi7hFxJCL4LTvC6g
    2. 以太坊官方文档中文版 :https://pan.baidu.com/s/1ktODJKLMBmkOsi8MPrpIJA
    3. 以太坊白皮书中文版 :https://pan.baidu.com/s/1bzAFnzJ35hlQxJ2J4Oj-Ow
    4. Solidity的官方文档中文版 :https://pan.baidu.com/s/18yp9XjEqAHpiFm2ZSCygHw
    5. Truffle的官方文档中文版 :https://pan.baidu.com/s/1y6SVd7lSLUHK21YF5FzIUQ
    6. C#区块链编程指南 :https://pan.baidu.com/s/1sJPLqp1eQqkG7jmxqwn3EA
    7. 区块链技术指南: :https://pan.baidu.com/s/13cJxAa80I6iMCczA04CZhg
    8. 精通比特币中文版: :https://pan.baidu.com/s/1lz6te3wcQuNJm28rFvBfxg
    9. Node.js区块链开发 :https://pan.baidu.com/s/1Ldpn0DvJ5LgLqwix6eWgyg
    10. geth使用指南文档中文版 :https://pan.baidu.com/s/1M0WxhmumF_fRqzt_cegnag
    11. 以太坊DApp开发环境搭建-Ubuntu : https://pan.baidu.com/s/10qL4q-uKooMehv9X2R1qSA
    12. 以太坊DApp开发环境搭建-windows :https://pan.baidu.com/s/1cyYkhIJIFuI2oyxM9Ut0eA
    13. 以太坊DApp开发私链搭建-Ubuntu : https://pan.baidu.com/s/1aBOFZT2bCjD2o0EILBWs-g
    14. 以太坊DApp开发私链搭建-windows :https://pan.baidu.com/s/10Y6F1cqUltZNN99aJv9kAA
    15. 以太坊ganache CLI命令行参数详解:https://pan.baidu.com/s/1lnknFkwenacaeM4asOcBdg
    16. 使用truflle和infura部署以太坊合约:https://pan.baidu.com/s/1PTxSVff2vHSVUihYczRRqw
    17. IPFS安装部署与开发环境搭建-windows:https://pan.baidu.com/s/1bnhDvqCoOgAqEBZXMtVbRg

    发布在 编程 阅读更多
  • J
    jimi2018

    推荐一个C#开发以太坊区块链的教程:

    .net c#以太坊开发
    本课程详细讲解如何使用C#开发基于.Net的以太坊应用,课程内容即涉及以太坊中的核心概念,例如账户管理、状态与交易、智能合约开发与交互、过滤器和事件等,同时也详细说明如何使用C#与以太坊进行交互,是C#工程师学习以太坊应用开发的不二选择。

    发布在 编程 阅读更多
  • J
    jimi2018

    EOS智能合约与DApp开发入门:

    EOS教程

    本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。

    发布在 编程 阅读更多
  • J
    jimi2018

    web3.php是一个PHP接口,主要用于与以太坊区块链及其生态系统进行交互.

    安装

    通过Composer来管理依赖关系,首先将minimum-stability设置为dev

    "minimum-stability": "dev"
    

    然后执行:

    composer require sc0vu/web3.php dev-master
    

    或者你可以在composer.json中添加这行。

    <!--more-->

    "sc0vu/web3.php": "dev-master"
    

    用法

    实例

    use Web3\Web3;
    
    $web3 = new Web3('http://localhost:8545');
    

    接口调用

    use Web3\Web3;
    use Web3\Providers\HttpProvider;
    use Web3\RequestManagers\HttpRequestManager;
    
    $web3 = new Web3(new HttpProvider(new HttpRequestManager('http://localhost:8545')));
    
    // timeout
    $web3 = new Web3(new HttpProvider(new HttpRequestManager('http://localhost:8545', 0.1)));
    

    使用回调函数调用rpc

    $web3->clientVersion(function ($err, $version) {
        if ($err !== null) {
            // do something
            return;
        }
        if (isset($client)) {
            echo 'Client version: ' . $version;
        }
    });
    

    eth

    use Web3\Web3;
    
    $web3 = new Web3('http://localhost:8545');
    $eth = $web3->eth;
    

    这样也行:

    use Web3\Eth;
    
    $eth = new Eth('http://localhost:8545');
    

    net

    use Web3\Web3;
    
    $web3 = new Web3('http://localhost:8545');
    $net = $web3->net;
    

    或者

    use Web3\Net;
    
    $net = new Net('http://localhost:8545');
    

    batch

    web3

    $web3->batch(true);
    $web3->clientVersion();
    $web3->hash('0x1234');
    $web3->execute(function ($err, $data) {
        if ($err !== null) {
            // do something
            // it may throw exception or array of exception depends on error type
            // connection error: throw exception
            // json rpc error: array of exception
            return;
        }
        // do something
    });
    

    eth

    $eth->batch(true);
    $eth->protocolVersion();
    $eth->syncing();
    
    $eth->provider->execute(function ($err, $data) {
        if ($err !== null) {
            // do something
            return;
        }
        // do something
    });
    

    net

    $net->batch(true);
    $net->version();
    $net->listening();
    
    $net->provider->execute(function ($err, $data) {
        if ($err !== null) {
            // do something
            return;
        }
        // do something
    });
    

    personal

    $personal->batch(true);
    $personal->listAccounts();
    $personal->newAccount('123456');
    
    $personal->provider->execute(function ($err, $data) {
        if ($err !== null) {
            // do something
            return;
        }
        // do something
    });
    

    智能合约Contract

    use Web3\Contract;
    
    $contract = new Contract('http://localhost:8545', $abi);
    
    // deploy contract
    $contract->bytecode($bytecode)->new($params, $callback);
    
    // call contract function
    $contract->at($contractAddress)->call($functionName, $params, $callback);
    
    // change function state
    $contract->at($contractAddress)->send($functionName, $params, $callback);
    
    // estimate deploy contract gas
    $contract->bytecode($bytecode)->estimateGas($params, $callback);
    
    // estimate function gas
    $contract->at($contractAddress)->estimateGas($functionName, $params, $callback);
    
    // get constructor data
    $constructorData = $contract->bytecode($bytecode)->getData($params);
    
    // get function data
    $functionData = $contract->at($contractAddress)->getData($functionName, $params);
    

    将值分配给外部域(从回调域到域外)

    由于和JavaScript回调不同,如果需要将值赋值到域外,我们需要给回调赋值。
    
    $newAccount = '';
    
    $web3->personal->newAccount('123456', function ($err, $account) use (&$newAccount) {
        if ($err !== null) {
            echo 'Error: ' . $err->getMessage();
            return;
        }
        $newAccount = $account;
        echo 'New account: ' . $account . PHP_EOL;
    });
    
    

    为了解决php程序员学习以太坊的需求,我们提供很受欢迎的互动教程:
    php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和事件等内容。

    发布在 编程 阅读更多
  • J
    jimi2018

    web3j是一个轻量级、高度模块化、响应式、类型安全的Java和Android类库提供丰富API,用于处理以太坊智能合约及与以太坊网络上的客户端(节点)进行集成。

    可以通过它进行以太坊区块链的开发,而无需为你的应用平台编写集成代码。

    本文是对web3j官网的完整翻译,大家可以参考。

    阅读全文 »

    当然如果希望有一个快速入门的web3j内容,并且最好是边练习实例边学习的实操教程的话。

    我们有一个web3j课程可以满足需要,专门详细的讲解区块链、以太坊、web3j。

    发布在 编程 阅读更多
  • J
    jimi2018

    在前面的一些文章中,我们学习了以太坊智能合约编程的基础知识。现在我们来建立一个实战以太坊dapp案例:彩票。

    我们彩票案例的目的是多个玩家能够通过发送钱参与彩票。玩家发送的钱越多,他赢得所有资金的机会就越大。当彩票的运营发行者决定关闭彩票后,就会选择一个优胜者,并将全部资金转给这名优胜者。

    为了存储每个玩家的彩金,我们将看到一个新的数据类型,这就是mappingmappingkey绑定到一个值。声明必须同时指定key的类型和值。例如,这里我们将存储属于某个地址的钱:

    mapping(address => uint) usersBet;
     
    usersBet[msg.sender] = 10;
     
    // usersBet[msg.sender] == 10
    

    不爽的是如果索引不是线性的,即使我们知道记录的数量,也无法迭代mapping的值。因此,为了迭代我们的彩金,我们需要单独地存储玩家的数量和玩家在另一个映射中的地址列表。

    所以我们将存储3个变量包括彩票运营发行者的地址:

    mapping(address => uint) usersBet;
    mapping(uint => address) users;
    uint nbUsers = 0;
    uint totalBets = 0;
     
    address owner;
    

    我们然后构建一个Bet函数。正常账户一样,智能合约可以操控以太坊。我们Bet函数需要有一个支付彩金的功能。当函数被调用的时候他就将投入的彩金值发送给以太坊智能合约,并将发送以太币的数量存储在msg.value

    所以当函数被调用时,我们先检查发送的以太币值是否大于零即msg.value>0。然后我们将发送值存储在usersBet的映射中。如果这个玩家的彩金等于0,我们递增我们的nbUsers并存储玩家的地址,这样我们可以在关闭这一期彩票时遍历所有玩家。。

    function Bet() public payable  {
        if (msg.value > 0) {
           if (usersBet[msg.sender] == 0) { // Is it a new player
              users[nbUsers] = msg.sender;
              nbUsers += 1;
           }
         usersBet[msg.sender] += msg.value;
         totalBets += msg.value;
        }
    }
    

    我们的彩票dapp的最后一部分是挑选优胜者。我们的函数EndLottery()只能由彩票的所有者访问。为了简化程序,我们将选择一个随机数在0与玩家数量之间。然后,我们将进行迭代筛选,并检查谁赢了。当玩家被发现时,我们会简单地将智能合约作为确认优胜者的一个主要依据。他将得到合约中所有的钱。

    function EndLottery() public {
        if (msg.sender == owner) {
            uint sum = 0; 
            uint winningNumber = uint(block.blockhash(block.number-1)) % totalBets;
            for (uint i=0; i < nbUsers; i++) {
               sum += usersBet[users[i]]; 
               if (sum >= winningNumber) {
                   selfdestruct(users[i]);
                   return;
               }
            }
        }
    }
    

    一个特别的说明,我们在这个示例中使用了一个非常简单的方法来获取或取值,现实中特别是在处理钱的时候,你需要用一个更好的方法来获得真正的随机数。

    下面所有的智能合约代码放在一起:

    pragma solidity ^0.4.11;
     
    contract Lottery {
     
        mapping(address => uint) usersBet;
        mapping(uint => address) users;
        uint nbUsers = 0;
        uint totalBets = 0;
     
        address owner;
     
        function Lottery() {
            owner = msg.sender;
        }
        
        function Bet() public payable  {
            if (msg.value > 0) {
                if (usersBet[msg.sender] == 0) {
                    users[nbUsers] = msg.sender;
                    nbUsers += 1;
                }
                usersBet[msg.sender] += msg.value;
                totalBets += msg.value;
            }
        }
        
        function EndLottery() public {
            if (msg.sender == owner) {
                uint sum = 0;
                uint winningNumber = uint(block.blockhash(block.number-1)) % totalBets + 1;
                for (uint i=0; i < nbUsers; i++) {
                    sum += usersBet[users[i]];
                    if (sum >= winningNumber) {
                        selfdestruct(users[i]);
                        return;
                    }
                }
            }
        }
        
    }
    

    所以让我们部署我们的合约并且来玩一把。我们将用我们的两个账户来发送彩金用以太坊币。作为一个功能你会看到我们可以调用函数payable进行支付。

    发送了以太币后,你会发现智能合约现在成立了。

    如果你从彩票运营者账户调用EntLoTyTye()函数,彩票收益将转移给优胜者,并且智能合约也将结束。

    在本文中,我们使用payable修饰符,使它可以发送以太币到我们的智能合约。

    • 以太坊dapp,主要介绍智能合约与dapp应用开发,适合入门。
    • 以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。

    原文转自这个以太坊博客

    发布在 编程 阅读更多

与 V2MM 的连接断开,我们正在尝试重连,请耐心等待