BCSkill (Block chain skill )
区块链中文技术社区

只讨论区块链底层技术
遵守一切相关法律政策!

EOS智能合约开发点滴记录-第二篇智能合约编写

前文 《EOS智能合约开发点滴记录-第一篇开发环境搭建》

开发合约前,我们先选择下将要用的编辑工具
我常用的有 clion 和vscode,电脑os为mac,不过其他系统差别不大,如果你习惯用于Windows,那建议选择 Windows Subsystem for Linux,不建议用其他三方封装的工具,以免更新不及时,或者不兼容,导致生产上出问题.

下面我们讲用以vscode 做演示.

配置智能合约项目

先用vscode打开eosio.cdt项目代码目录,按提示安装相应的扩展插件.一般只需要安装个 c/c++
等vscode加载索引完,会根据eosio.cdt项目下的cmakelists.txt 配置好开发环境及其include路径.
所以我一般习惯是直接将自己的智能合约项目直接clone 在 eosio.cdt/examples目录下,省的自己做相关依赖配置.

我们先假定一个智能合约项目,项目名为bcskill.game (项目名与合约名一致,省的后面弄混)
新建bcskill.game目录(目录名也要与合约名一致,方便后面部署),路径为eosio.cdt/examples/bcskill.game
目录结构如下

eosio.cdt/examples/bcskill.game
eosio.cdt/examples/bcskill.game/common //存放一些公用的源码文件
eosio.cdt/examples/bcskill.game/bcskill.game.hpp //智能合约头文件
eosio.cdt/examples/bcskill.game/bcskill.game.cpp // 智能合约源文件
eosio.cdt/examples/bcskill.game/README.md // 帮助文档

习惯的代码结构

bcskill.game.hpp

#pragma once
//一些常用的头文件依赖 根据实际所需添加
#include <eosiolib/eosio.hpp>
#include <eosiolib/time.hpp>
#include <eosiolib/transaction.hpp>
#include <eosiolib/asset.hpp>
#include <eosiolib/crypto.h>

namespace bcskillgame // 为自己的项目创建单独的命名空间
{
// 一些用到的命名空间 根据实际需要添加
    using eosio::time_point;
    using eosio::microseconds;
    using eosio::name;
    using namespace std;
    // 定义下一些用到的宏,比如系统EOS代币符号
    #define EOS_SYMBOL symbol(symbol_code("EOS"),4)
    一些内部会用到的结构体
    struct play_hero_info{
        uint8_t hero_id;
        uint8_t hero_grade;
        uint8_t count;
    };
    ...
    // 定义所需的table表 
    struct [[eosio::table("system"), eosio::contract("bcskill.game")]] system{
        uint64_t id;
        bool upgrading; //升级或维护中,暂时停止合约内所有的业务
        time_point zero_time;
        auto primary_key() const { return id; }
    };
    // `eosio::table("system")`中的system为合约内table的名字,后面可以用 get table 这个名字查看链上此table数据
    //  eosio::contract("bcskill.game")]] 中的 "bcskill.game" 为合约的名字,也就是我们之前定好的,也就是说这个表属于"bcskill.game" 合约
    ...
    // 为上面定义好的table 创建实例化对象
    typedef eosio::multi_index<"system"_n, system> system_tables;
    // multi_index<"system" 中的 system 为table的表名, 第二个system 为表的定义名.system_tables为实例化后的对象名.
    //下面开始创建合约类
    class [[eosio::contract("bcskill.game")]] bcskill_contract : public eosio::contract // 从系统合约对象继承下
    {
        public:
            using eosio::contract::contract; // 引入父命名空间
            // 创建合约action接口 后面可以用push action调用
            ACTION upgrading(bool upgrading);
            ...

        private:
            // 添加一些私有的数据类型
            // 一些整数类型可以用 enum 枚举
            enum GAME_STATUS_TYPE{
                GAME_STATUS_PADDING = 1,
                GAME_STATUS_RUNNING,
                GAME_STATUS_FINISHED
            };
            // 如果是小数,可以用class
            class RACE_PWOER_TYPE{
                public:
                static constexpr auto RACE_PWOER_ORC_HUM_TA = 0.3;
                static constexpr auto RACE_PWOER_UD_VS_HUM_ORC_TA = 0.3;
                static constexpr auto RACE_PWOER_HUM_ORC_TA_VS_NE = 0.3;
                static constexpr auto RACE_PWOER_NE_VS_UD = 1.3;
            };
            // 合约内不建议使用小数操作,一些场景可以先统一增大倍数,转为整数
            class UPDATE_RATE_TYPE{
                public:
                static constexpr auto PROBABILITY_ACCURACY = 100;
                static constexpr auto UPDATE_RATE_1_SUCCESS = 0.7 * PROBABILITY_ACCURACY;
                ...
            };
            // 定义写私有的方法,合约内部使用,这里的方法不会被 push action调用到
            bool is_upgrading();
    };
}

bcskill.game.cpp

#include "bcskill.game.hpp" //引入头文件
// 引入一些其他的头文件,比如
#include "common/utils.hpp"
// 引入所需的命名空间
using namespace bcskillgame;
using namespace eosio;
// 为头文件中各个action添加实现方法
void bcskill_contract::upgrading(bool upgrading){
    require_auth( _self.value );
    system_tables system_table(_self, _self.value);
    auto itr = system_table.begin();
    if(itr == system_table.end()){
        system_table.emplace( _self, [&]( auto& s ) {
            s.id = system_table.available_primary_key();
            s.upgrading = upgrading;
        });
    }else{
        system_table.modify( itr, _self, [&]( auto& s ) {
            s.upgrading = upgrading;
        });
    }
}
...
// 一些私有方法实现
bool bcskill_contract::is_upgrading(){
    bool result = false;
    system_tables system_table(_self, _self.value);
    auto itr = system_table.begin();
    if(itr != system_table.end()){
        result = itr->upgrading;
    }
    return result;
}
....

// 为action 申明调用
extern "C" {
    [[noreturn]] void apply(uint64_t receiver, uint64_t code, uint64_t action) {
        if(code=="eosio.token"_n.value && action=="transfer"_n.value) {
            execute_action( name(receiver), name(code), &bcskill_contract::transfer);
        }
        else if(code==receiver){
            switch(action)
            {
                EOSIO_DISPATCH_HELPER( bcskill_contract, (upgrading) //只有添加后,action才能被外部 push action
                default:
                    eosio_assert(false, "it is not my action"); // 为安全,防止被恶意调用,影响合约响应
                    break;
            }
        }
        eosio_exit(0);
    }
};

此时合约的基本代码结构已完成

编译合约

进入代码目录执行

eosio-cpp -o bcskill.game.wasm bcskill.game.cpp --abigen

执行完毕后,会生成
bcskill.game.abi 和 bcskill.game.wasm
我们可以简单的理解为 abi 为(.h)头文件,wasm 为dll或so 库.
我们想执行某个账号下的合约时,先会获取这个合约的abi信息,也就是先获取合约内所有的action接口,然后根据所指定的接口在发起交易,执行合约内对应的逻辑.

合约部署

cleos -u https://api.eoslaomao.com  set contract bcskillsurou ../bcskill.game/ -p bcskillsurou

合约执行

cleos -u https://api.eoslaomao.com push action bcskillsurou upgrading '{"upgrading": 1}' -p bcskillsurou

查看链上table

cleos -u https://api.eoslaomao.com get table bcskillsurou bcskillsurou system

类似返回数据如下

{
  "rows": [{
      "id": 0,
      "upgrading": 1,
      "zero_time": "2019-03-30T16:00:00.000"
    }
  ],
  "more": false
}

建议

对于数据类型的选取,编写前,最好专门花时间确定下,避免不必要的RAM浪费或者后面数据溢出.
比如uint8_t 到 uint64_t的选取,如果小于255 就用 uint8_t节约内存
对于一些数据table的划分,最好能实现评估下,如果前端没有全局(_self)查找或排序要求,创建对应合适的scope下,降低find时的消耗.
尽量避免后面做数据迁移.迁移会存在一些人为的操作失误风险,以及期间可能需要暂停dapp,影响用户体验.

本文结束,全文演示了我目前习惯的合约目录及代码结构,以及基本的合约使用,后面有时间再补充,如果大家有什么更好的方法或者建议可以留言,一起学习~

EOS智能合约开发点滴记录-第一篇开发环境搭建

最近一直在做Dapp开发,一直忙的没时间更新博客,最近换工作空闲时间,更几片连续文章,总结下EOS合约开发的步骤,一些遇到的问题,以及一些实际场景,哪些数据适合上链的选取,以及怎样方便调用.方便一起的学习的同学参考,以及自己备忘.

我们先尽量简单直白的说下什么是EOS链,资源,智能合约,以及之间的关系.

  1. EOS链
    我们可以把EOS链想成一个由多台服务器组成的一个计算机云集群{无意突出此链的中心化}.每台服务器(节点)上都部署着一个EOS节点程序,各个节点彼此链接.这个计算机集群,根据投票排名前21名的节点,可以参与计算任务(出块),并且计算后会有相应的奖励(挖矿).

  2. 资源:RAM,CPU,NET
    我们把EOS链想成云服务器集群,我们购买的EOS账号就相当于在云服务的服务商那购买了个账号,然后给账号购买使用的资源:存储(RAM),算力(CPU)用于计算任务,网络(NET)用于任务与集群传输.我们使用EOS链,就相当于使用云服务器提供商提供的计算和存储服务.

  3. 智能合约
    我们可以把智能合约想成是一个执行脚本,每个合约可以部署到自己的EOS账号下(可以理解成每个账号会有个专门的存储索引,指引存放的合约,每个普通账号只能同时部署一个合约,后面的会把前面的覆盖掉),合约内可以写一些逻辑,以及数据的增删改查,也可以调用其余的合约.我们外部可以用过rpc方法访问EOS链(发起交易),指定运行哪个账号下的合约的某个接口(执行action).

也许举例还不够简单,或者不妥,等之后在完善.
下面我们开始主题

智能合约开发环境搭建

先介绍下智能合约的开发编译工具,在v1.3.0之前使用的是eosiocpp(直接包含在eos项目代码内,整体项目编译完或者安装完二进制包,直接可以使用).之后版本已经弃用(EOSIO 1.3.0 Release Notes),统一使用新版本编译工具 eosio.cdt,并放在单独的仓库管理(需要单独编译,或者下载二进制包安装).如果只开发合约的话,可以只安装eosio.cdt,无需再编译安装eos链项目.
新旧版本合约规则变化较大,目前网络上的文章一部分还停留在旧版本,不建议再参考语法.

安装eosio.cdt

编写此文时 eosio.cdt最新版本 1.6.1, EOSIO v1.7.0
eosio.cdt 可以使用源码编译安装,也可以直接使用官方编译好的二进制安装包

1. 源码编译安装

clone 源代码

git clone https://github.com/EOSIO/eosio.cdt

切换此时最新release分支

cd eosio.cdt
git checkout -b v1.6.1

编译源代码

git submodule update --init --recursive
./build.sh

编译完成之后会显示

然后执行安装

sudo ./install.sh

2.二进制包安装

EOSIO.CDT目前支持Mac OS X brew,Linux x86_64 Debian软件包和Linux x86_64 RPM软件包
如果之前已经用源码等方式安装过,需要先卸载,

Mac OS X Brew

安装

$ brew tap eosio/eosio.cdt
$ brew install eosio.cdt

卸载

$ brew remove eosio.cdt
Ubuntu Debian Package

安装

$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt_1.6.1-1_amd64.deb
$ sudo apt install ./eosio.cdt_1.6.1-1_amd64.deb

卸载

    $ sudo apt remove eosio.cdt
Fedora RPM Package

安装

    $ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.fedora-x86_64.rpm
    $ sudo yum install ./eosio.cdt-1.6.1-1.fedora-x86_64.rpm

卸载

    $ sudo yum remove eosio.cdt
Centos RPM Package

安装

    $ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.centos-x86_64.rpm
    $ sudo yum install ./eosio.cdt-1.6.1-1.centos-x86_64.rpm

卸载

    $ sudo yum remove eosio.cdt

建议

个人还是推荐使用Ubuntu 18.04/16.04系统,目前了解到的bp以及社区其他节点,大都在此系统上运行,相对测试较多,并且查找问题资料相对较多.

常见问题

  1. ubuntu安装完,执行eosio-cpp compile可能会报错误
    libstdc++.so.6 version glibcxx_3.4.21' not found

    解决方式如下

    sudo apt-get install software-properties-common
    sudo add-apt-repository ppa:ubuntu-toolchain-r/test
    sudo apt-get update
    sudo apt-get install libstdc++6

参考

  1. https://github.com/EOSIO/eosio.cdt
  2. https://blog.csdn.net/ITleaks/article/details/85841850

后文 《EOS智能合约开发点滴记录-第二篇智能合约编写》

合约数据表字段升级

有些时候,由于前期考虑不周,或者后期设计升级,导致合约table 字段需要增加,或者类型需要更改,所以需要数据迁移,
下面举例我常用的升级方法
假设目前合约内有个table xxxinfo

struct [[eosio::table("xxxinfo"), eosio::contract("eosxxx.game")]] xxxinfo{
        uint64_t id;
        uint64_t test; // 为测试添加的字段
        uint8_t test1; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo"_n, xxxinfo> xxxinfo_tables;

现在升级需要解决的问题是test 当初设计字段类型过大,导致ram 浪费,test1 选型过小,增加 test2字段{uint32_t}.

在合约中增加新的表结构xxxinfo1 及其对象,并修正上面问题

struct [[eosio::table("xxxinfo1"), eosio::contract("eosxxx.game")]] xxxinfo1{
        uint64_t id;
        uint32_t test; // 为测试添加的字段
        uint16_t test1; // 为测试添加的字段
        uint32_t test2; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo1"_n, xxxinfo1> xxxinfo1_tables;

此时合约内同时存在 xxxinfo1 和 xxxinfo1两张表.

增加 迁移执行的action 接口

//.h
ACTION migratexxx();
//.cpp
void migratexxx(){
    xxxinfo1_tables xxxinfo1_table(_self, _self.value);

    xxxinfo_tables xxxinfo_table(_self, _self.value);
    auto itr = xxxinfo_table.begin();
    while(itr != xxxinfo_table.end()){
        xxxinfo1_table.emplace( _self, [&]( auto& h ) {
            h.id = xxxinfo1_table.available_primary_key();
            h.test = itr->test;
            h.test1= itr->test1;
        });
        itr ++;
    }
}

停止Dapp,避免迁移期间数据改变,然后执行action
cleos -u https://api.eoslaomao.com push action 合约账户 migratexxx '{}' -p 合约账户

如果数据较多,且数据是累计增长(不修改历史数据),可以分区间执行迁移,迁移过程中,可以不停止dapp,等迁移差不多追上旧表了,再暂停dapp,然后等数据全部迁移完.

修正合约中的新表为

struct [[eosio::table("xxxinfo1"), eosio::contract("eosxxx.game")]] xxxinfo{
        uint64_t id;
        uint32_t test; // 为测试添加的字段
        uint16_t test1; // 为测试添加的字段
        uint32_t test2; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo1"_n, xxxinfo> xxxinfo_tables;

将旧表修改为

struct [[eosio::table("xxxinfo"), eosio::contract("eosxxx.game")]] xxxinfo_bak{
        uint64_t id;
        uint64_t test; // 为测试添加的字段
        uint8_t test1; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo"_n, xxxinfo_bak> xxxinfo_bak_tables;

修正前后端调用的table名,重新上线,并运行dapp, 建议等 运行一段时间,在删除旧表
增加清理旧表的action

//.h
ACTION clearxxxbak();
//.cpp
void clearxxxbak(){
    xxxinfo_bak_tables xxxinfo_bak_table(_self, _self.value);
    auto itr = xxxinfo_bak_table.begin();
    while(itr != xxxinfo_bak_table.end()){
        itr = xxxinfo_bak_table.erase(itr);
    }
}

然后执行action
cleos -u https://api.eoslaomao.com push action 合约账户 clearxxxbak '{}' -p 合约账户
最后再删除 合约内旧表及对象 就完成了此次合约表升级过程.

EOS 新型攻击手法之 hard_fail 状态攻击

前言

昨日(2019 年 3 月 10 日)凌晨,EOS 游戏 Vegas Town (合约帐号 eosvegasgame)遭受攻击,损失数千 EOS。慢雾安全团队及时捕获这笔攻击,并同步给相关的交易所及项目方。本次攻击手法之前没有相同的案例,但可以归为假充值类别中的一种。对此慢雾安全团队进行了深入的分析。

攻击回顾

根据慢雾安全团队的持续分析,本次的攻击帐号为 fortherest12,通过 eosq 查询该帐号,发现首页存在大量的错误执行交易:

查看其中任意一笔交易,可以发现其中的失败类型均为 hard_fail:

这立即就让我想起了不久前的写过的一篇关于 EOS 黑名单攻击手法的分析,不同的是实现攻击的手法,但是原理是类似的,就是没有对下注交易的状态进行分析。

攻击分析

本次攻击的一个最主要的点有两个,一个是 hard_fail,第二个是上图中的延迟。可以看到的是上图中的延迟竟达到了 2 个小时之久。接下来我们将对每一个要点进行分析。

(1)hard_faild:

参考官方开发文档(https://developers.eos.io/eosio-nodeos/docs/how-to-monitor-state-with-state-history-plugin

可以得知 fail 有两种类型,分别是 soft_fail 和 hard_fail,soft_fail 我们遇见的比较多,我们一般自己遇到合约内执行 eosio_assert 的时候就会触发 soft_fail,回看官方对 soft_fail 的描述:客观的错误并且错误处理器正确执行,怎么说呢?拿合约内 eosio_assert 的例子来说

{
    //do something
    eosio_assert(0,"This is assert by myself");
    //do others
}

这种用户自己的错误属于客观错误,并且当发生错误之后,错误处理器正确执行,后面提示的内容 This is assert by myself 就是错误处理器打印出来的消息。

那么 hard_fail 是什么呢?回看官方对 hard_fail 的描述:客观的错误并且错误处理器没有正确执行。那又是什么意思呢?简单来说就是出现错误但是没有使用错误处理器(error handler)处理错误,比方说使用 onerror 捕获处理,如果说没有 onerror 捕获,就会 hard_fail。

OK,到这里,我们已经明白了 hard_fail 和 soft_fail 的区别,接下来是怎么执行的问题,传统的错误抛出都是使用 eosio_assert 进行抛出的,自然遇到 hard_fail 机会不多,那怎么抛出一个 hard_fail 错误呢?我们继续关注下一个点—延迟时间。

(2)延迟时间:

很多人可能会疑惑,为什么会有延迟时间,我们通过观察可以知道 fortherest12 是一个普通帐号,我们惯常知道的延时交易都是通过合约发出的,其实通过 cleos 中的一个参数设置就可以对交易进行延迟,即使是非合约帐号也可以执行延迟交易,但是这种交易不同于我们合约发出的 eosio_assert,没有错误处理,根据官方文档的描述,自然会变成 hard_fail。而且最关键的一个点是,hard_fail 会在链上出现记录。

攻击细节分析

根据 jerry@EOSLive 钱包的讲解,本次的攻击发生和 EOS 的机制相关,当交易的延迟时间不为 0 的时候,不会立马校验是否执行成功,对延迟交易的处理是 push_schedule_transaction,而交易的延迟时间等于 0 的时候,会直接 push_transaction。这两个的处理机制是存在区别的。

攻击成因

本次攻击是因为项目方没有对 trx 的 status 状态进行校验,只是对 trx 是否存在作出了判断。从而导致了本次攻击的发生。

防御手法

项目方在进行线下开奖的时候,要注意下注订单的执行状态,不要只是判断交易是否存在,还要判断下注订单是否成功执行。如下图

相关参考

引起 object fail 的错误类型参考:

https://eos.live/detail/16715
官方对交易执行状态的描述:

https://developers.eos.io/eosio-nodeos/docs/how-to-monitor-state-with-state-history-plugin

by yudan@慢雾安全团队

数字身份,Scatter 与 RIDL简介

Scatter 目前是 EOS 生态之中不可缺少的一部分,尽管,你可能并不知道它是什么。

你每日使用MeetOne、TP等 EOS 手机钱包玩游戏、访问dApps的时候,就是得益于 Scatter 这一项目所提供的协议。另外,Scatter 也创建了桌面版应用和Chrome插件形式的钱包(已经下架),也是 EOS 社区之中所推崇的最安全的 EOS 钱包之一。

不过,Scatter 的野心不止于成为EOS生态中使用最广的钱包而已,在数字身份领域的探索,也值得关注。自从EOS主网启动之前,Scatter 团队就发布了他们的设想,而如今看来,在数字身份和信任网络领域的探索,他们正在一步一步走来。

当然,值得一提的是,项目与代币的价格,并不会一一对应,本文不构成任何投资建议,仅供希望了解RIDL的朋友参考。另外,在数字身份领域,除了Scatter之外,也有包括IBM、MyKey Lab团队在内的国内外多个公司团队在进行探索和实验,也期待未来更多的成果出现,找到数字身份ID和可信网络这一圣杯。

数字身份有什么用?

对这一赛道,我现在所做的有限的了解,并不足以支撑我作出更为全面的判断,因此,此部分所谈仅供参考,如有错误,欢迎随时指正批评。
在互联网初兴起之时,有个段子:你不知道屏幕另外一侧的聊天者,是人还是狗。

在去中心化的网络之中,增加了数字化资产这一层,在交易之时,如何确认对方的身份?如果你使用一个dapp,除了在网络上搜索相应信息之外,是否有方法可以快速了解到这个dapp靠不靠得住?
如果你使用某个交易所,在使用之前对此一无所知,是否会恶意拔网线?是否会暴露你的隐私?…
另外,如何证明你是你?

如上的种种问题,都是涉及到两个事情:

  • 交易参与的实体(网站,账号,地址,公钥,dapps,合约等等)是否是你所预想的交易对象?
  • 交易实体,是否可信?

安全和可信,降低交易风险,不需要借助于信念或者运气来参与交易,是可信网络和数字身份这一领域所重点关注的问题之一。

圣杯

咕噜曾于2018年9月发文,提到区块链领域的圣杯之一:
基于密码学的身份体系,例如自主身份(Self-soveignein Identity),以及衍生出来的信任网络(Web-of-Trust)
而对于加密身份体系,咕噜认为,“是今后web3.0的入口,是每个人的必需品”。他主要看好两个部分:

加密身份体系的成熟,有助于加密资产在互联网用户中的渗透,以及区块链应用的普及
基于加密身份体系所形成的信任网络(network of trust), 通过信息交叉验证的方式,对于当前误解的新闻和信息造假的问题,提供了最可靠的方式。
在加密身份体系(数字身份)和可信网络的领域,已经有许多的玩家。除了所提到的IBM、scatter团队和MyKey团队以外, BitPortal的创始人在一次访谈之中也提到了他个人所关注的几个团队:

  • ETH上的ERC-725
  • 国内的Ont
  • 国内的BTM
  • 国外的Sorvin

其中Ont和Sorvin都会提供去中心化的KYC系统,对合规和一些落地的应用比较有益,BTM的身份方案基于ODIN,主要用于标识资产

Scatter 团队发文提到说即将发布RIDL,不过按照实际情况看来,上线仍然要等1~2个月。
在RIDL实际上线之前就写文章谈论,难免因为资料有限理解有误,不过,好奇心趋势下,我仍然试着聊聊 RIDL。也随时欢迎朋友们一起交流和指正。
昨天谈到了数字身份和信任网络这一领域的概况,今天就整体聊聊 RIDL 这一EOS社区中的数字ID产品,谈谈它的设计思路。
我所写的任何文章,都不构成投资建议,本文也不例外,仅为提供信息参考之用。

RIDL 方案:为区块链添加声誉和数字身份层

RIDL是什么?


RIDL 的全称有些拗口:声誉与身份层(Reputation and Identity Layer)。
用来解决:

  • 在区块链上的数字身份问题(主要是基于EOSIO的区块链,也会支持其他链)
  • 某个身份实体的信誉问题,公开可见,为安全交易提供参考

RIDL 有两重含义:

  • RIDL是产品,通过RIDL 可以对网站/用户/合约等实体进行评级,使用者也可以根据对应的评级来得到
  • RIDL 也是代币名称,在RIDL中使用该代币进行评级

RIDL的运行机制

这个RIDL上线后,围绕声誉和数字身份,是怎么运行的?这部分简单一聊。主要分为三个过程:

  • 注册一个数字身份,由RIDL所承载,全网唯一
  • 通过“大众点评”方式,形成对于数字身份实体的综合评价。评分会消耗RIDL
  • 得到的评级,链上可查,供交易时参考。

展开聊聊。

1. 注册数字身份(Identity)

简单来说:在RIDL中,引入了身份(Identity)这一概念. 对身份的一个通俗解释:

什么是身份?身份是一个“壳”,壳里装的是“我”。
—- MyKey 白皮书

在 RIDL 中,一个网站、app、合约、用户等实体,都可以注册来绑定一个身份,并接受评价。
你可能留意到: Scatter 桌面版中有一个设置为:Identity,即身份。这是为RIDL所设计的。

目前,其实没多少用处。我们用Scatter 去与dApp交互的时候,不会见到身份的存在,而是要选择对应的EOS 账号。

而在RIDL发布之后,这一身份就派上用场了。 可以将这个身份理解为对账号的一层封装,该身份可以关联多个 EOS 账号。
有几个特点:

  • 付费获得, 年费 $25
    按照Scatter团队说法, 是为了避免羊毛党或者刷评价者恶意占用。如果次年不续费,则身份所积累的信誉会清零,任何人都可以付费去注册该身份.
    此前在EOS上线前 Scatter 曾经做过预注册的方式,可以通过MetaMask 来预留身份 100年。在 RIDL 上线后,可以支付100 RIDL代币,领取所预留的身份。
  • 名称全网唯一
  • 网站、app、合约、用户等实体,都可以绑定身份
  • 可以对身份进行评价,并且该评价是在区块链上公开可查询的,下文会详述
  • 注册了身份之后,可以使用 RIDL Defender,在存在欺诈和恶意行为可能时会提供预警,保护交易的安全

2. 对身份的评级

这部分我认为是RIDL的重点:如何对实体进行评价?评分系统是否可信?
并且,需要在两者之间进行权衡综合:

  • 激励用户参与对某个主体的评价
  • 避免用户恶意刷评价,且消除恶意负面评价的影响

这里,RIDL 采用了评级挖矿的方式来设计。下面会展开聊一聊。先看看身份评级这部分功能的一些特征。

设想如下场景:
你在玩某个dApp游戏,感觉体验很不好,想对此进行评价。

  • 首先,只有注册了身份之后,才能够对其他对身份进行评级。注册身份需要消耗代币,门槛不低,Scatter 团队是希望以此打压羊毛党恶意注册。是否会有效?还需观察。
  • 其次,评价会分为多个维度,最多五个维度。如下图所示,可以从多个角度去打分:


评价需要消耗RIDL代币

看白皮书中的例子:

这是给某个身份(比如,一个交易所)的评分,总计的评级是 10 个RIDL代币,意味着,这一次评级,消耗了你10个代币。
许多人肯定会疑问:对我有什么好处?为何要花费代币去评价?
看看Scatter团队的回复:

Rami 给出的理由是:

  • 用户参与了一个系统,允许我们定义在线安全性。这本身是个卖点。
  • 如果你是第一个评价者,或者在前一个评价者的矿工资格过期(3个月)后,你可以成为“评级矿工”,获得RIDL的代币收益。
  • 你评价之后,会成为“最后评价者”。如果有个人在你之后评价成为了评价矿工,你能够分到一部分的评级RIDL代币。
  • 参与评级,也能够增加你的身份中的RIDL额度。(注:你能够得到的评级是有限的,如果额度扩大,意味着你可以得到更多的RIDL)使用越多,投票得到更多的尊重。

简单说来:
参与评价,可以以挖矿的方式,分得 RIDL 代币奖励;并且,每个月 RIDL 会进行空投,给符合一定标准的评价者(至少评价了10个不同的身份实体)从RIDL的保留代币池中空投一部分RIDL代币给参与评价者。
被评价的身份主体会累积 REP
你花费了 10 个RIDL 代币,评级了某个交易所;那么,在RIDL系统中,这个交易所绑定的身份,会立即得到10个REP。
REP 不可以转账,不能够交易,只是一个标记工具,用来表示评价该身份实体所消耗的RIDL总量。

3. 获取评级信息,供安全交易参考

RIDL上线后,会提供两个工具:

  • RIDL网页
  • RIDL的浏览器插件


通过这些入口,可以查看某个身份主体的评分详情。并且,在 Scatter 内部,还会通过 RIDL Defender 的方式,来对于交易进行预警。比如,如果你准备发起交易的对象,是被RIDL系统中标记为诈骗,则会提示你。

Scatter 发了一个视频,演示插件的效果,可以看看:

https://twitter.com/i/status/1096053747766226944

RIDL 代币机制

最后,顺带聊下RIDL的代币发行情况。

值得一提的是,Scatter 团队没有选择直接给自己留代币份额,而是选择了类似 EOS 发行的众筹方式(他们称之为捐赠),拿出来了16.6% 的代币,即2.5亿 RIDL,用于 Scatter 开发基金。

如果参加”捐赠”,则可以按照参与当期EOS的比例,分得一定的 RIDL 代币作为酬谢。

为期两年共730天,每期12个小时,每期的上限为2千个EOS,释放17万 RIDL。
下图可以看到,当前的 RIDL “捐赠”是第428期。预计还有10分钟结束。


通过这种方式,使得RIDL的价格维持相对平衡的水平。交易所中价格高,可以通过“捐赠”方式得到更多的RIDL代币,拿去交易所卖掉;交易所价格低,则会刺激RIDL的购买者放弃“捐赠”方式得到代币,而直接去交易所购买。

链接为: https://ridl.get-scatter.com/#/

参考信息来源

上周 Scatter 发文: Scatter即将发布RIDL,剑指三大圣杯之一——数字身份ID

RIDL 白皮书: 阅读白皮书

转载自:https://mp.weixin.qq.com/s/egoWhoYN0yRWUv2l9arH0A (EOS42)