V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
duimi
V2EX  ›  程序员

基于区块链的 DAPP 开发笔记 (5)-EOS 从 helloworld 到 hello 红包之二

  •  
  •   duimi · 2018-09-18 16:30:49 +08:00 · 1485 次点击
    这是一个创建于 2295 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我们不定期更新我们的开发心得,汇总在 github 上,欢迎 star: https://github.com/rrtoken/DAPP_Blog

    另,我们建了一个 DAPP 开发者群,平常大家一起交流开发心得,感兴趣的开发者请加微信:mindflow2017,我拉你入群。


    从 helloworld 到 hello 红包之二

    上次我们学会了用 EOS 智能合约发红包,发红包时需要合约方知道对方的 EOS 账号,并通过合约账号授权发定向红包(转账送钱)。今天我们要实现的是多人“领红包”的功能,固定金额,见者有份,分完为止,不需要通过合约的 EOS 账号授权。(有人问,为什么不做拼手气红包呢?因为智能合约的随机数比较特殊,有机会再单独讲。)

    数据存储

    只要我记得你,你就永远不会消失的啊 ----《寻梦幻游记》 CoCo

    首先,我们需要让合约记住已经领过红包的账号,机会均等,每人只能领一次。在 EOS 上,最简单的办法就是用 table 保存合约的状态和数据。

    创建表格

    首先,我们在 helloworld.cpp 里加上两个表格。其中 primary_key 是主键,bonustable 是表名,bonus_t 是表结构。

    红包表:

    struct bonus_t {
        uint64_t id;
        asset balance;
        uint64_t primary_key() const { return id;}
        EOSLIB_SERIALIZE( bonus_t, (id)(balance) )
    };
    multi_index<N(bonustable), bonus_t > _bonus;
    

    领红包的用户表:

    struct user_t {
        uint64_t id;
        account_name user;
        uint64_t primary_key() const { return user;}
        EOSLIB_SERIALIZE( user_t, (id)(user) )
    };
    multi_index<N(usertable), user_t> _users;
    

    初始化表格

    加上 default constructor,把红包金额初始化为 10 EOS。

    	hello( account_name self )
    	:contract(self),_bonus( _self, _self),_users( _self, _self) {
    		asset quantity;
    		quantity.set_amount(100000); // 10 EOS
    		if ( _bonus.begin() == _bonus.end() )
    		_bonus.emplace( self, [&](auto& a) {
    			a.id = 1;
    			a.balance = quantity;
    		});
    	}
    }
    

    检查用户状态

    我们增加一个检查用户的函数 checkuser,检查用户是否领过红包。如果用户没领过红包,就把用户的账号加到表格里。

    bool checkuser( account_name user ) {
    	bool found = true;
    	auto itr = _users.find(user);
    	if( itr == _users.end() ) {
    		found = false;
    	    itr = _users.emplace(_self, [&](auto& acnt){
    	        acnt.id = _users.available_primary_key();
    	        acnt.user = user;
    	    });
    	}
    	return found;
    }
    
    

    更新红包金额

    再把取红包金额的功能放到一个函数里:

    asset getbonus() {
    	asset quantity;
    	auto itr = _bonus.begin();
    	auto balance = itr->balance;
    	eosio_assert( balance.amount > 0, "must be positive quantity" );
    	if (balance.amount > 10000){
    		quantity.set_amount(10000); // 1 EOS
    		_bonus.modify(itr, _self, [&](auto& p) {
    		    eosio_assert( p.balance.amount > quantity.amount, "we're out of bonus!" );
    		    p.balance.amount -= quantity.amount;
    		});
    	} else {
    		quantity = balance;
            itr = _bonus.erase(itr);
    	}
    	return quantity;
    }
    

    新的红包接口

    最后,我们把用户检查和取红包金额的功能加到领红包的接口上,改造后的 hi()接口不再传入金额。

    /// @abi action hi
    void hi( account_name to ) {
    	if ( checkuser(to) )
    		return;
    
    	asset bonus = getbonus();
    	eosio_assert( bonus.amount > 0, "must be positive quantity" );
    	require_recipient( _self );
    	require_recipient( to );
    
    	action(
    		permission_level{ _self, N(active) },
    		N(eosio.token), N(transfer),
    		std::make_tuple(_self, to, bonus, std::string("hello money"))
    	).send();
          print( "Hello, here is some money for ", name{to} );
    }
    

    具体的测试方法,请参考《从 helloworld 到 hello 红包 part1 》

    知识点总结

    创建表格

    struct user_t {
        uint64_t id;
        account_name user;
        asset balance;
        uint64_t primary_key() const { return user;}
        EOSLIB_SERIALIZE( user_t, (id)(user)(balance) )
    };
    multi_index<N(usertable), user_t> _users;
    

    查询表格:

    	auto itr = _users.find(user);
    

    给表格添加元素:

    	auto itr = _users.find(user);
    	if( itr == _users.end() ) {
    	    itr = _users.emplace(_self, [&](auto& acnt){
    	        acnt.id = _users.available_primary_key();
    	        acnt.user = user;
    	    });
    	}
    

    更新表格:

    	auto itr = _users.find(user);
    	if( itr != _users.end() ) {
    	    _users.modify( itr, _self, [&]( auto& acnt ){
    	        acnt.user = user;
    	        acnt.balance.amount = new_amount;
    	    });
    	}
    

    清空表格:

        for (auto itr = _users.begin(); itr != _users.end();)
            itr = _users.erase(itr);
    
    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   982 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 20:45 · PVG 04:45 · LAX 12:45 · JFK 15:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.