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

虚拟币硬件钱包调研

最近项目打算接硬件钱包,简单记录下调研信息
目前需求 需要支持 PC浏览器以及收集APP。
APP端的话相对较多,先查下PC浏览器相关的
主要信息来源MetaMask扩展和ScatteDesktop客户端。
目前流行的两个“龙头”PC浏览器钱包解决方案。

MetaMask

支持2种硬件钱包

  • Ledger
  • TREZOR

ScatteDesktop

也支持2种

  • Ledger Nano S
  • Scatter/LiguidEOS DIY Hardware Wallet

相关介绍

Ledger

https://zhuanlan.zhihu.com/p/32322818
https://weidian.com/p5/diary/pages/diary.php?id=14414801
https://0xzx.com/20190504193957697.html

Scatter/LiguidEOS DIY Hardware Wallet

https://medium.com/@liquideos/how-to-build-an-eos-hardware-wallet-a-step-by-step-guide-a62445786c0f

稍后再做补充

ScatterDesktop Backup

BackService 调用 saveFile

export default class BackupService {

    static async setBackupStrategy(strategy){
        const scatter = store.state.scatter.clone();
        scatter.settings.autoBackup = strategy;
        return store.dispatch(Actions.SET_SCATTER, scatter);
    }

    static async createBackup(){
        const location = getFolderLocation();
        if(! location) return false;

        await saveFile(location[0]);
    }

    static async setBackupLocation(){
        const location = getFolderLocation();
        if(!location) return false;
        const scatter = store.state.scatter.clone();
        scatter.settings.backupLocation = location[0];
        return store.dispatch(Actions.SET_SCATTER, scatter);
    }

    static async createAutoBackup(){
        if(!store.state.scatter || !store.state.scatter.settings) return;
        const strategy = store.state.scatter.settings.autoBackup;
        if(!strategy || !strategy.length || strategy === BACKUP_STRATEGIES.MANUAL) return;

        const backupLocation = store.state.scatter.settings.backupLocation;
        if(!backupLocation || !backupLocation.length) return false;


        await saveFile(backupLocation);
    }

}

写入备份文件

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/BackupService.js#L12:18

const saveFile = (filepath) => {
    return new Promise(resolve => {
        const scatter = getLatestScatter();
        const date = new Date();
        const month = date.getUTCMonth();
        const year = date.getUTCFullYear();
        const salt = StorageService.getSalt();
        const file = scatter + '|SLT|' + salt;
        const name = `${filepath}/scatter__${store.state.scatter.hash.substr(0,4)}-${store.state.scatter.hash.slice(-4)}__${store.state.scatter.meta.version}__${month}-${year}.json`;
        try {
            fs.writeFileSync(name, file, 'utf-8');
            resolve(true);
        }
        catch(e) {
            console.error('Error saving file', e);
            resolve(false);
        }
    })
};

备份文件的内容

const scatter = getLatestScatter();
const salt = StorageService.getSalt();
const file = scatter + '|SLT|' + salt;
const getLatestScatter = () => StorageService.getScatter();

StorageService

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/StorageService.js#L93

export default class StorageService {

    constructor(){}

    static async setScatter(scatter){
        return new Promise(async resolve => {
            clearSaveTimeouts();
            saveResolvers.push(resolve);
            safeSetScatter(scatter, resolve);
        })
    };

    static getScatter() {
        return scatterStorage().get('scatter');
    }

actions

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/store/actions.js#L91

[Actions.SET_SCATTER]:async ({commit, state}, scatter) => {
        return new Promise(async resolve => {
            const process = Process.savingData();

            const seed = await ipcAsync('seed');
            const savable = AES.encrypt(scatter.savable(seed), seed);
            StorageService.setLocalScatter(savable);
            process.updateProgress(50);
            StorageService.setScatter(savable).then(() => {
                BackupService.createAutoBackup()
            });

            commit(Actions.SET_SCATTER, scatter);
            resolve(scatter);
            process.updateProgress(100);
        })
    },

其中的

const seed = await ipcAsync('seed');

是从

 [Actions.SET_SEED]:({commit}, password) => {
        return new Promise(async (resolve, reject) => {
            const [mnemonic, seed] = await PasswordService.seedPassword(password, true);
            resolve(mnemonic);
        })
    },

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/PasswordService.js#L48

static async seedPassword(password, setToState = true){
        return new Promise(async (resolve, reject) => {
            try {
                let seed, mnemonic;
                if(password.split(' ').length >= 12) {
                    seed = await Mnemonic.mnemonicToSeed(password);
                    mnemonic = password;
                } else {
                    const [m, s] = await Mnemonic.generateMnemonic(password);
                    seed = s;
                    mnemonic = m;
                }

                if(setToState) ipcFaF('seeding', seed);
                resolve([mnemonic, seed]);
            } catch(e){
                resolve([null, null]);
            }
        })
    }

Scatter

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop/-/blob/src/models/Scatter.js#L76:1

savable(seed){
        this.keychain.keypairs.map(keypair => keypair.encrypt(seed));

        const clone = this.clone();
        clone.keychain.identities.map(id => id.encrypt(seed));

        // Keychain is always stored encrypted.
        clone.encrypt(seed);

        return clone;
    }

Keychain

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/models/Keychain.js#L20:1

static fromJson(json){
        let p = Object.assign(this.placeholder(), json);
        if(json.hasOwnProperty('keypairs')) p.keypairs = json.keypairs.map(x => Keypair.fromJson(x));
        if(json.hasOwnProperty('accounts')) p.accounts = json.accounts.map(x => Account.fromJson(x));
        if(json.hasOwnProperty('identities')) p.identities = json.identities.map(x => Identity.fromJson(x));
        if(json.hasOwnProperty('permissions')) p.permissions = json.permissions.map(x => Permission.fromJson(x));
        if(json.hasOwnProperty('apps')) p.apps = json.apps.map(x => AuthorizedApp.fromJson(x));
        return p;
    }

nodeos 输出log方式

https://github.com/EOSIO/fc/blob/a6f94bae0b2b4a0b68dc1db2677331cafa4716a5/src/log/logger_config.cpp#L24

 bool configure_logging( const logging_config& cfg )
   {
      try {
      static bool reg_console_appender = appender::register_appender<console_appender>( "console" );
      static bool reg_gelf_appender = appender::register_appender<gelf_appender>( "gelf" );
      get_logger_map().clear();
      get_appender_map().clear();

支持输出到 console 和 gelf 两种方式

gelf
https://sourcegraph.com/github.com/EOSIO/fc@a6f94bae0b2b4a0b68dc1db2677331cafa4716a5/-/blob/include/fc/log/gelf_appender.hpp

namespace fc 
{
  // Log appender that sends log messages in JSON format over UDP
  // https://www.graylog2.org/resources/gelf/specification
  class gelf_appender final : public appender 
  {
  public:
    struct config 
    {
      string endpoint = "127.0.0.1:12201";
      string host = "fc"; // the name of the host, source or application that sent this message (just passed through to GELF server)
    };

类似 https://github.com/mattwcole/gelf-extensions-logging

BOS节点部署,版本升级与测试

昨晚BOSCore已经完成了3秒LIB测试网启动,测试结果是1-3秒内达到不可逆,今天要再进行下中国社区部分的测试。

社区通知消息原文如下

国内社区 3s LIB版本升级演练

BOS 3s LIB测试网已经启动,为了让更多社区成员了解升级流程和特性,中国社区定于北京时间5月15日16:00开始演练,请大家提前做好准备。

此次版本升级的流程:
1.首先启动链时用boscore/bos:v2.0.3版本启动,各位注册bp,出块,模拟现在BOS的网络环境。
2.升级
   1)各个bp升级自己的节点版本至新版本,大多数bp升级好后进行下一步
   2)bp多签升级系统合约
   3)bp多签设置网络升级的块高度:target_number
  当lib到达设置的块高度时,共识变为pbft共识,3s可进lib,网络完成升级。

此外,邀请社区开发者对昨晚的lib-testnet做公开测试,发现问题者可以在github上提出issue,最终会根据大家提出的issue奖励BOS,最高奖励 1000 BOS 欢迎大家踊跃参与进来!!!可以加入:https://t.me/BOSTestnet

会议链接:
主题:BOS中国社区3s LIB版本升级演练
时间:五月 15, 2019 4:00 下午 北京,上海
加入 Zoom 会议
https://zoom.us/j/353729204

大家可以提前将自己的bp名字和公钥发给我,网络启动时帮大家创建好。

前段时间一直在忙,没有参与,只是默默围观,今天单独抽出时间参与下。
从技术方面来说,如果此方案稳定可行的话,对当前公司项目用户体验,可以有极大的提升。

环境准备

节点搭建对比EOS的来说,基本没差别,我们简单的记录下

准备个简单配置的测试机器

  • CPU: 4核
  • RAM: 8G
  • 地点: 香港阿里云

下载和编译代码

下载代码

git clone https://github.com/boscore/bos.git
git checkout -b v2.0.3

编译

cd bos/
git submodule update --init --recursive
./eosio_build.sh -s BOS

安装

sudo ./eosio_install.sh

配置节点

先运行下nodeos 初始化创建config.ini

配置config.ini

增加 p2p-peer-address

p2p-peer-address = 47.75.48.230:5016  #abp
p2p-peer-address = 47.75.107.217:2022
p2p-peer-address = 47.75.48.230:2018  #abp
p2p-peer-address = 3.1.39.190:10772 #blockedencom
p2p-peer-address = 47.52.101.176:9476 #itokenpocket
p2p-peer-address = 47.75.48.230:2018  #abp
p2p-peer-address = 47.75.48.230:5016  #abp
p2p-peer-address = 47.75.107.217:2022 # saylovetomom
p2p-peer-address = 15.164.99.58:9876 #starteosiobp

其余配置参考《从零开始,纯净机器上部署EOS测试网 (版本v1.4.1)》")

创建genesis.json

{
  "initial_timestamp": "2019-05-15T00:30:00.000",
  "initial_key": "EOS6YFfrYZ3z7bNnzoZF4V2zJStudMJ4NJBBE1JXGzebVzMG9aLc7",
  "initial_configuration": {
    "max_block_net_usage": 1048576,
    "target_block_net_usage_pct": 1000,
    "max_transaction_net_usage": 524288,
    "base_per_transaction_net_usage": 12,
    "net_usage_leeway": 500,
    "context_free_discount_net_usage_num": 20,
    "context_free_discount_net_usage_den": 100,
    "max_block_cpu_usage": 200000,
    "target_block_cpu_usage_pct": 1000,
    "max_transaction_cpu_usage": 150000,
    "min_transaction_cpu_usage": 100,
    "max_transaction_lifetime": 3600,
    "deferred_trx_expiration_window": 600,
    "max_transaction_delay": 3888000,
    "max_inline_action_size": 4096,
    "max_inline_action_depth": 4,
    "max_authority_depth": 6
  }
}

模拟现在BOS的网络环境

此时运行nodeos --genesis-json 加上面genesis.json的路径,启动节点,此时能正常接收其他节点的出块。
注册BP节点,并被投票,成为出块节点

升级节点,更新共识协议

升级节点到最新版本

当前最新版本v3.0.0-rc3

git checkout -b v3.0.0-rc3

同上,编译,并安装,重新启动。

升级系统合约

新版本的系统合约:https://github.com/boscore/bos.contracts

cleos -u http://47.75.48.230:5015 set contract eosio ./eosio.system/ -p eosio -s -j -d > updatasystem.json
cleos -u http://47.75.48.230:5015 multisig propose_trx updatesystem bppermission1.json updatesystem.json bosstorebest
cleos -u http://47.75.48.230:5015 multisig approve bosstorebest updatesystem  '{"actor":"bosstorebest","permission":"active"}' -p bosstorebest
cleos -u http://47.75.48.230:5015 multisig exec bosstorebest updatesystem -p bosstorebest@active
cleos -u http://47.75.48.230:5015 multisig review bosstorebest updatesystem
cleos -u http://47.75.48.230:5015 get table eosio.msig bosstorebest approvals2

设置升级块高度提案

cleos -u http://47.75.48.230:5015   push action eosio setupgrade '{"up":{"target_block_num":21000}}' -p eosio  -s -j -d > setnum.json
cleos -u http://47.75.48.230:5015  multisig propose_trx setnum  bppermission1.json   setnum.json bosstorebest
cleos  -u http://47.75.48.230:5015  multisig approve  bosstorebest setnum  '{"actor":"bosstorebest","permission":"active"}'  -p  bosstorebest
cleos  -u http://47.75.48.230:5015  multisig exec bosstorebest setnum -p bosstorebest@active
查询设置的升级块高度
cleos -u http://47.75.48.230:5015 get table eosio eosio upgrade
{
  "rows": [{
      "target_block_num": 21000
    }
  ],
  "more": false
}

设置块高度时

达到设定的高度时输出以下log

表示升级成功了。

查询区块块信息

surou@DESKTOP-444S803:/mnt/c/Users/Surou$ cleos -u http://47.75.48.230:5015 get info
{
  "server_version": "82de16b9",
  "chain_id": "5c70c434cfd0ae8a2fde509fd452f8f64236ac120ba81631b239fb4bd1b1e2c3",
  "head_block_num": 29732,
  "last_irreversible_block_num": 29731,
  "last_irreversible_block_id": "000074234261f645187eae528b720577235d5bd306efb6a11906976c725e5583",
  "head_block_id": "00007424d2c9aecdf90f1e123c4ffbe4c30e14ce9428cffa18c70bda981de290",
  "head_block_time": "2019-05-15T10:02:49.000",
  "head_block_producer": "bospacificbp",
  "current_view": 0,
  "target_view": 1,
  "last_stable_checkpoint_block_num": 29701,
  "virtual_block_cpu_limit": 200000000,
  "virtual_block_net_limit": 1048576000,
  "block_cpu_limit": 199900,
  "block_net_limit": 1048576,
  "server_version_string": "v3.0.0-rc2-21-g82de16b98"
}

最新区块与不可逆块数,相差1块,此时不可逆确认时间间隔为0.5s

参考

常见问题

  • "RdKafka::rdkafka" but the target was not found

https://www.bcskill.com/index.php/archives/604.html

特别感谢 shiqi@eostore小妹妹补充的信息。