您正在查看: EOS-新手教程 分类下的文章

DApp接入最新版本Scatter.js支持,以及ScatterDesktop的使用

我们知道目前EOS DApp运行,目前分为两种方式

  • App提供DApp运行环境。App内置浏览器控件,注入js,DApp运行时用注入的js与App内置的钱包交互,DApp需要私钥签名时,将需要签名的数据通过注入的js将数据传给外部的钱包,使用钱包当前选中的私钥将数据签名,然后将数据返回给DApp。
  • 浏览器扩展提供支持。目前支持EOS链的扩展主要是以Scatter,或者基于此二次开发为主。

本篇我们主要讲下DApp对Scatter的接入,大多的App提供的运行环境也是支持Scatter的,比如tp钱包等,并且Scatter在EOS链的绝对地位(不低于Metamask对于以太坊),所以我们开发DApp最少要支持Scatter的支持。

先来个主角Scatter介绍

Scatter 是一个去中心化的签名、身份、私人数据与身份验证解决方案。它在用户的计算机本地运行,采用非对称加密技术,令用户可以在不访问集中式服务器的情况下通过网站进行身份验证。Scatter 主要包含两个部分:钱包与 RIDL (Reputation & Identity Layer) 系统。

Scatter 钱包目前支持 EOS 和 ETH 钱包,未来会支持更多钱包。Scatter 已推出 Chrome 浏览器插件版本和桌面 Beta 版本,之后会推出移动端版本,其中浏览器插件版与以太坊轻钱包 MetaMask 类似。Scatter 钱包作为 EOS 应用程序与用户信息之间的桥梁,能让用户安全地向应用程序签名和提供私人数据,并保证在与EOS 区块链通信的 Web 应用程序进行交互时不会暴露密钥和其他不必要的信息。Scatter 不需要用户提交私钥,只需对交易签名,它是本地的应用,不会给用户发送需要解密或加密私钥的请求。而用户如果使用直接手动将私钥输入到应用程序的网页表单中,会存在资产被盗取的严重风险。

Scatter 的 RIDL (Reputation & Identity Layer) 系统包含了声望与身份系统。用户可以创建多个身份,每个身份都包含用户身份名称、EOS 账户/密钥对、姓名、电话和地址等个人信息。用户只需设置一次身份, Dapp 就可以经过用户授权后从 Scatter 接入用户身份信息。因此用户不必在多个 Dapp 重复填写个人信息,并避免个人信息泄漏。而在 Scatter 声望系统当中,用户和 Dapp 可以互相对彼此的声望进行评分。这一系统允许应用程序评估用户做出某种行为的可能性,比如偿还贷款。反之,它也允许用户衡量应用程序的质量,例如安全性与可用性。

Scatter 项目代码

现在Scatter 分为ScatterWebExtension(浏览器扩展)和ScatterDesktop(桌面客户端)两个版本。

编写一个支持Scatter的DApp例子

//TODO

ScatterDesktop使用步骤,并与上面例子交互

//TODO

中秋快乐,稍后继续完善本文。节后会紧跟几篇,详细针对Scatter接口方面的讲解。

以传统的WEB开发方式,来举例理解Dapp开发

前言

常规的讲解DApp开发的文章,大都直接从区块链方式讲起,对于没有接触过区块链的同学,可能不太好理解,今天我们尝试从传统的web开发,对比讲解DApp开发。

对于目前常见的DApp大都是以Web的形式,其实DApp并不局限于Web形式,也可以是PC客户端,也可以是App。为了更好理解和演示,我们将以常见的Web形式的DApp讲起。

演示实例

我们将要演示的DApp例子为,一个计算器,合约中计算两个输入的值,并将值存入链上,并提供查询的接口。

如果我们拿常规的Web去实现下这个App。基本分为3部分,前端(获取输入的值),服务器Api接收程序(接收前端输入的值,并计算结果,并将结果写入数据库,以及提供查询的接口),数据库(存储计算后的值)。

实现和部署对比

实现 Web App Web DApp
前端 普通html 普通html
服务器Api接收程序 php开发的api程序 执行链上部署的合约
数据库 mysql 写入链上对应的RAM
服务器部署 云服务器 前端放在云服务器,合约部署在EOS网络

传统Web实现

1.前端

<form method="post" name="form" action="http://www.xxx.xx/postGet.php">
  <table >
      <tr>
       <td>第一个参数:</td>
       <td><input type="text" name="FirstParm"/></td>
      </tr>
      <tr>
       <td>第二个参数:</td>
       <td><input type="text" name="SecondParm"/></td>
      </tr>
      <tr>
       <td><input type="submit" name="Submit" value="计算两数和"/></td>
      </tr>
  </table>
</form>

2.创建数据库

CREATE DATABASE results;
CREATE TABLE result(name CHAR(13), iresult int);

3.Api接收程序

    <?php
    $firstparm = $_POST[FirstParm'];
    $secondparm = $_POST['SecondParm'];
    $result = $firstparm + $secondparm;
        $con = mysql_connect("localhost","cryptokylinq","5KKu8Nmm4XUavcZFzpvdGG5Mc9Rkg6LiwxuqXkSokEHKSXKXs9b");
        if (!$con) {
          die('Could not connect: ' . mysql_error());
          }
        mysql_select_db("results", $con);
        mysql_query("INSERT INTO result (iresult) VALUES ($result)");
        mysql_close($con);
    ?>

查询

    <?php
    $con = mysql_connect("localhost","cryptokylinq","5KKu8Nmm4XUavcZFzpvdGG5Mc9Rkg6LiwxuqXkSokEHKSXKXs9b");
    if (!$con) {
      die('Could not connect: ' . mysql_error());
      }
    mysql_select_db("results", $con);
    $result = mysql_query("SELECT * FROM result");
    while($row = mysql_fetch_array($result)) {
      echo $row['iresult'] ;
      echo "<br />";
      }
    mysql_close($con);
    ?>

上面三步简单的完成了,常规Web的计算,写入,查询操作。

Web DApp实现

1.编写合约

//Calculator.hpp
#include <eosiolib/asset.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>

class Calculator : public eosio::contract {
public:
    Calculator(account_name self)
            : eosio::contract(self)
            ,results(_self, _self){}

public:
    void doit(account_name from, const uint64_t firstParm, const uint64_t secoundParm);

private:
//@abi table results i64
    struct result{
        account_name name;
        uint8_t iresult;
        uint64_t primary_key()const { return name; }
        EOSLIB_SERIALIZE(result, (name)(iresult))
    };

    typedef eosio::multi_index<N(results),result> result_table;
    result_table results;
};
EOSIO_ABI( Calculator, (doit) )
#include "Calculator.hpp"


void Calculator::doit(account_name from, const uint64_t firstParm, const uint64_t secoundParm){
    require_auth(from);

    eosio_assert(firstParm >= 1, "firstParm mast >= 0"); //没有实际意义 只是做个数值的判断演示
    auto account_itr = results.find(from);
    if(account_itr == results.end()){
        account_itr = results.emplace(_self, [&](auto& result){
            result.name = from;
            result.iresult = firstParm + secoundParm;
        });
    }
    else{
        results.modify(account_itr, 0, [&](auto& result) {
            result.iresult = firstParm + secoundParm;
        });
    }
}

合约中包含了数据库的创建格式,合约部署后,相当于,数据库也创建好了,以及数据写入需要执行的api接口

2.合约编译,需要将合约初步编译,才能部署到链上

  • 生成API文件
    suroudeMacBook-Pro:Calculator surou$ eosiocpp -g Calculator.abi Calculator.cpp
  • 生成WAST文件
    suroudeMacBook-Pro:Calculator surou$ eosiocpp -o Calculator.wast Calculator.cpp

    执行完成后目录文件如下

    suroudeMacBook-Pro:Calculator surou$ ls
    Calculator.abi  Calculator.cpp  Calculator.hpp  Calculator.wasm Calculator.wast

3.创建麒麟测试网的测试账号,用于合约的部署,以及使用资源的购买

  • 创建账号:http://faucet.cryptokylin.io/create_account?new_account_name
    比如我们要创建的账号为cryptokylinq,访问链接:http://faucet.cryptokylin.io/create_account?cryptokylinq
    {
      msg: "succeeded",
      keys: - {
      active_key: - {
          public: "EOS6L7pr3AaKekTs1dbratDq1PutoSdmBWJFwbLcStsnKBbJtNUws",
          private: "5KKu8Nmm4XUavcZFzpvdGG5Mc9Rkg6LiwxuqXkSokEHKSXKXs9b"
      },
      owner_key: - {
          public: "EOS89vNXgGrkM4GYFAav78FgnX94QzVXYtcEKiKicSq4YcykPmnC7",
          private: "5KZbLRwZAZQJQKS6sM1RL1d2Af9s49zA9qka9f63ce7J2jUDWwQ"
      }
      },
      account: "cryptokylinq"
    }

    一个账号一般有两对秘钥,对应两个权限owner(类似网站后台的超级管理员)和active(部分权限的管理员),当然还可以创建多个自由配置权限的秘钥对。在EOS网络里,谁拥有这个私钥,谁就拥有对应账号的对应权限。相同的秘钥对可以创建多个账号。

  • 申请测试的EOS代币,访问 http://faucet.cryptokylin.io/get_token?cryptokylinq
    {
      msg: "succeeded"
    }
  • 查询账户余额 https://tools.cryptokylin.io/#/tx/

申请来的测试EOS代币,将用于购买EOS网络上的CPU,NET,RAM资源(RAM为购买,CPU和NET是按抵押EOS多少,计算分配你多少资源使用)。相当于云服务器中的增加对应的硬件资源。CPU和NET与云服务中的一样,计算和网络资源。RAM相当于云服务器中的RAM+磁盘存储,比如发起交易时会临时消耗,隔一段时间(暂时未确定恢复时间的规则,应该小于三天,稍后查证后,在做补充),如果是合约存储数据,那就相当于写入了磁盘,如果数据不删除的话,会持续占用。

下面开始购买所需的资源,之前统计一般部署合约需要消耗300k左右的 RAM(包含临时消耗)。 CPU和NET基本分别抵押 0.1EOS就可以了。

由于我们要操作账号,所以我们要先创建个钱包,可以使用eosio 自带的keosd,也可以使用其他三方的app 钱包中购买资源。
我们在开发环境,所以直接使用keosd操作了,

  • 创建钱包
    suroudeMacBook-Pro:eosio-wallet surou$ cleos  wallet create --to-console
    Creating wallet: default
    Save password to use in the future to unlock this wallet.
    Without password imported keys will not be retrievable.
    "PW5HxNY7tKndZp8c96afmhaHezq2CA9x1dbziYXzJcvK7sVdf7kQq"

    记得备份这个钱包的解锁密码"PW5HxNY7tKndZp8c96afmhaHezq2CA9x1dbziYXzJcvK7sVdf7kQq"

  • 将上面创建的账号cryptokylinq的私钥导入新创建的钱包 (一般常规操作只需要导入active权限的私钥)
    suroudeMacBook-Pro:eosio-wallet surou$ cleos wallet import
    private key: imported private key for: EOS6L7pr3AaKekTs1dbratDq1PutoSdmBWJFwbLcStsnKBbJtNUws

    导入完成后,购买所需的RAM,CPU,NET资源
    购买10EOS的RAM

    suroudeMacBook-Pro:contracts surou$ cleos -u http://kylin.fn.eosbixin.com system buyram cryptokylinq cryptokylinq "10 EOS"
    executed transaction: d59370bcb3dbf1d3aaa1b5c92de23283603c6d9bfc2e38e8def5e0de8eabe6e1  128 bytes  1511 us
    #         eosio <= eosio::buyram                {"payer":"cryptokylinq","receiver":"cryptokylinq","quant":"10.0000 EOS"}
    #   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"9.9500 EOS","memo":"buy ram"}
    #  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"9.9500 EOS","memo":"buy ram"}
    #     eosio.ram <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"9.9500 EOS","memo":"buy ram"}
    #   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.0500 EOS","memo":"ram fee"}
    #  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.0500 EOS","memo":"ram fee"}
    #  eosio.ramfee <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.0500 EOS","memo":"ram fee"}

CPU NET分别抵押10 EOS (实际使用量,一般在分别1 EOS就够了,测试网不花钱,可劲豪)

suroudeMacBook-Pro:contracts surou$ cleos -u http://kylin.fn.eosbixin.com system delegatebw cryptokylinq cryptokylinq "10 EOS" "10 EOS"
executed transaction: 4df295028046be07f669fd3dca1b496434f5ee36efb0cd6f31a738ff6e7b5602  144 bytes  2021 us
#         eosio <= eosio::delegatebw            {"from":"cryptokylinq","receiver":"cryptokylinq","stake_net_quantity":"10.0000 EOS","stake_cpu_quant...
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"20.0000 EOS","memo":"stake bandwidth"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"20.0000 EOS","memo":"stake bandwidth"}
#   eosio.stake <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"20.0000 EOS","memo":"stake bandwidth"}

此时RAM,CPU,NET资源都准备好了,相当于云服务器硬件配置都买好了
下面开始部署合约,相当于传统的Web开发,将API程序部署到云服务器

suroudeMacBook-Pro:contracts surou$ cleos -u http://kylin.fn.eosbixin.com  set contract cryptokylinq Calculator/ -p  
Reading WASM from Calculator/Calculator.wasm...
Publishing contract...
executed transaction: f0086795a65644a96e282b165e1fc146869a37cfd6a2e51528367f7594d4d21f  3056 bytes  1329 us
#         eosio <= eosio::setcode               {"account":"cryptokylinq","vmtype":0,"vmversion":0,"code":"0061736d01000000015d1060047f7e7e7e0060000...
#         eosio <= eosio::setabi                {"account":"cryptokylinq","abi":"0e656f73696f3a3a6162692f312e30000206726573756c740002046e616d65046e6...

下一步我们直接测下合约action接口,相当于直接测试云服务器的API接口

suroudeMacBook-Pro:contracts surou$ cleos -u http://kylin.fn.eosbixin.com  push action cryptokylinq doit '["cryptokylinq","1","2"]' -p cryptokylinq
executed transaction: 7c0de68f77a656f98cd54e03f37dbb00a1a325cee844614968d7d05a2668f36c  120 bytes  1834 us
#  cryptokylinq <= cryptokylinq::doit           {"from":"cryptokylinq","firstParm":1,"secoundParm":2}

查询下结果

suroudeMacBook-Pro:contracts surou$ cleos -u http://kylin.fn.eosbixin.com  get table cryptokylinq cryptokylinq results
{
  "rows": [{
      "name": "cryptokylinq",
      "iresult": 3
    }
  ],
  "more": false
}

可以看到,已经将结果写到了链上 "iresult": 3,相当于常规Web程序数据库中已存入数据
目前此DApp对比常规Web程序已经完成了,API和数据库部分,下面开始完成前端的调用

DApp前端

前端与链交互,是通过rpc进行操作的,并且eosio 官方也提供了 eosjs.js 开发库,方便操作。
html中调用的关键js代码为

import EOS from 'eosjs'
const EOS_CONFIG = {
  contractName: "cryptokylinq", // Contract name 更好理解的应该是合约的部署所在的账号名
  contractReceiver: "cryptokylinq", // User executing the contract (should be paired with private key)
  clientConfig: {
    keyProvider: '5KKu8Nmm4XUavcZFzpvdGG5Mc9Rkg6LiwxuqXkSokEHKSXKXs9b', // Your private key
    httpEndpoint: 'http://api-kylin.starteos.io', // EOS http endpoint
    chainId: '5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191'
  }
}
//执行合约
DoContract(){
let eosClient = EOS(EOS_CONFIG.clientConfig)
    eosClient.contract(EOS_CONFIG.contractName)
      .then((contract) => {
      //执行链上合约
        contract.doit(EOS_CONFIG.contractReceiver,"1","2", { authorization: [EOS_CONFIG.contractReceiver] })
          .then((res) => { console.log("Success") })
          .catch((err) => {console.log("Fail"); console.log(err) })
      })
}

查询结果

eos.getTableRows(true,"cryptokylinq","cryptokylinq","results")

返回

{
    "rows":[
        {
        "name":"cryptokylinq",
        "iresult":3
        }
    ],
        "more":false
}

至此完成了DApp从合约编写,合约部署,账号创建,合约调用,eosjs使用,一整套简单的流程。

ubuntu 安装最新版本 yarn

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn

NPM发布和更新包

注册登录账号

  • 网站创建账号 https://www.npmjs.com/signup
  • 或者在终端命令创建,终端内输入npm adduser输入新注册的账号和密码以及邮箱

已经创建账号后npm login登录账号
输入npm whoami可以查看已登录的账号

本篇文章只演示提交过程,假设npm包文件已准备好。
package.json内name必须唯一,version要比已上传的新

发布

执行npm publish提交文件
提交成功后会收到邮件

测试

https://npmjs.com/package/<package>即可看到新提交的npm包
e.g.e.g.https://www.npmjs.com/package/bcskill-eosio-mongodb-queries

参考:docs.npmjs.com

EOS mongodb + GraphQL 查询

为了更灵活的查询EOS blocks入库到MongoDB的数据,我们将支持 GraphQL

GraphQL

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

项目支持

基于开源项目 eosio-graphql 提供GraphQL支持
此项目内部依赖 eosio-mongodb-queries提供MongoDB查询支持

开始部署

clone代码

git clone https://github.com/EOS-BP-Developers/eosio-graphql.git

进入源码目录,安装依赖

cd eosio-graphql
npm i
npm 安装参考 ubuntu npm 升级到新版

修改项目配置

修改 config.ts文件中的 MongoDB uri为本地配置的MongoDB配置

export const MONGODB_URI = process.env.MONGODB_URI || "mongodb://localhost:20000";

编辑index.ts 修改远程访问地址和端口

export function eosGraphQLGateway(config: any = {}) {
  const {
    host = "0.0.0.0",
    port = 443,
    mongoClient,
    buildSchema = defaultBuildSchema,
    buildResolvers = defaultBuildResolvers,
    abiDir = "",
  } = config;

运行项目

npm start
  • 如果出现Error: Cannot find module 'typescript/tsc.js'
    sudo npm install -g typescript

此时程序已经运行

> eosio-graphql@0.2.0 start /mnt/data/eosio-graphql
> tsc && node service.js

?. Server ready at http://0.0.0.0:443/graphql

访问服务器

访问服务器ip:端口/graphql
测试查询

query {
  blocks(sort: { block_num: -1 }, match: { irreversible: true }) {
    block_num
    irreversible
    block {
      producer
    }
  }
}

注意

由于eosio-mongodb-queries项目中写死了查询的EOS在MongoDB数据库名称为EOS(区分大小写),所以要将nodeos同步到MongoDB数据库时,确认数据库名字为EOS

plugin = eosio::mongo_db_plugin
mongodb-uri = mongodb://localhost:20000/EOS
mongodb-filter-on = *