您正在查看: Surou 发布的文章

多签更新系统合约的方法 {Upgrade System Contract 1.1.0-patched}

Upgrade System Contract 1.1.0-patched

背景

主网上的 eosio 等系统账户的 RAM 资源没有限制(unlimited)。在 EOS 网络中进行 transfer 等操作的时候,如果对方是一个合约账户,存在 RAM 被对方账户恶意占用的风险。另外,还有一项涉及 namebid 功能的风险,具体细节请参见:https://www.eoscanada.com/en/update-on-the-august-21st-2018-security-update-to-the-eosio-system-contract-dubbed-v1.1.0-sec.patch-3

在彻底修复上述问题之前,Block.One 出了一个针对 1.1.0 系统合约的补丁,该补丁包括如下内容:

  1. 在 eosio.system 合约内新增 setalimits 接口,该接口可以将系统账户的 RAM/NET/CPU 资源从无限(unlimited)限制为特定值。
  2. 优化 bidrefund 逻辑。

1.1.0 的 patch 版本代码参见:https://github.com/EOSLaoMao/eosio.contracts/tree/laomao/v1.1.0-new-patch

1.1.0 patch 版本的 build 位于本项目的 eosio.system-1.1.0-patched 目录。

本次升级合约的目标:

  1. 部署 patch 版 1.1.0 系统合约。
  2. 将除了 eosio 之外的系统账户的 RAM 设定为该账户当前已用的 RAM 值。

升级系统合约

1. 生成升级合约的 transaction 数据

cleos set contract -s -j -d eosio eosio.system > upgrade_system_contract_trx.json

数据结构如下:


$ cat upgrade_system_contract_trx.json

{
  "expiration": "2018-08-26T12:44:31",
  "ref_block_num": 0,
  "ref_block_prefix": 0,
  "max_net_usage_words": 0,
  "max_cpu_usage_ms": 0,
  "delay_sec": 0,
  "context_free_actions": [],
  "actions": [
    {
      "account": "eosio",
      "name": "setcode",
      "authorization": [
        {
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": {
        "account": "eosio",
        "vmtype": 0,
        "vmversion": 0,
        "code": "CODECODECODECODE"
      }
    },
    {
      "account": "eosio",
      "name": "setabi",
      "authorization": [
        {
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": {
        "account": "eosio",
        "abi": "ABIABIABIABIABIABI"
      }
    }
  ],
  "transaction_extensions": [],
  "signatures": [],
  "context_free_data": []
}

2. 生成设置系统账户 RAM 的 transaction 数据

在升级合约时,主网上各个系统账户的 RAM 使用情况如下(单位 byte):

eosio.bpay = 5184
eosio.vpay = 8720
eosio.msig = 221325
eosio.token = 217920
eosio.names = 46106292
eosio.ram = 305824
eosio.ramfee = 2688
eosio.saving = 2688
eosio.stake = 403952

拿账户 eosio.bpay 举例,通过调用 setalimits 接口,可以得到将 eosio.bpay 的 RAM 限制为 5184 byte 的 transaction 数据:

cleos push action -s -j -d eosio setalimits '{"account": "eosio.vpay", "ram_bytes": 8720, "net_weight": -1, "cpu_weight": -1}' > eosio.vpay.json

其文件内容如下:

cat eosio.vpay.json

{
  "expiration": "2018-08-26T07:26:02",
  "ref_block_num": 1245,
  "ref_block_prefix": 462537812,
  "max_net_usage_words": 0,
  "max_cpu_usage_ms": 0,
  "delay_sec": 0,
  "context_free_actions": [],
  "actions": [{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [],
      "data": "0080377503ea30554014000000000000ffffffffffffffffffffffffffffffff"
    }
  ],
  "transaction_extensions": [],
  "signatures": [],
  "context_free_data": []
}

简单起见,本 repo 提供了生成限制所有系统账户 RAM 的脚本 gen_ram_limit.sh,使用方式如下:

./gen_ram_limit.sh > ramlimit.json

生成的 ramlimit.json 文件结构如下:

cat ramlimit.json

{
  "expiration": "2018-08-26T07:31:17",
  "ref_block_num": 1809,
  "ref_block_prefix": 2805690369,
  "max_net_usage_words": 0,
  "max_cpu_usage_ms": 0,
  "delay_sec": 0,
  "context_free_actions": [],
  "actions": [{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "008037f500ea30554014000000000000ffffffffffffffffffffffffffffffff"
    }
  ],
  "transaction_extensions": [],
  "signatures": [],
  "context_free_data": []
}
{
  "expiration": "2018-08-26T07:31:17",
  "ref_block_num": 1809,
  "ref_block_prefix": 2805690369,
  "max_net_usage_words": 0,
  "max_cpu_usage_ms": 0,
  "delay_sec": 0,
  "context_free_actions": [],
  "actions": [{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "0080377503ea30551022000000000000ffffffffffffffffffffffffffffffff"
    }
  ],
  "transaction_extensions": [],
  "signatures": [],
  "context_free_data": []
}

......

{
  "expiration": "2018-08-26T07:31:17",
  "ref_block_num": 1809,
  "ref_block_prefix": 2805690369,
  "max_net_usage_words": 0,
  "max_cpu_usage_ms": 0,
  "delay_sec": 0,
  "context_free_actions": [],
  "actions": [{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "0014341903ea3055f029060000000000ffffffffffffffffffffffffffffffff"
    }
  ],
  "transaction_extensions": [],
  "signatures": [],
  "context_free_data": []
}

ramlimit.json 文件中的 actions 数据就是我们需要的限制各系统账户的 transaction 数据。

3. 构造用于 proposal 的 transaction 数据。

1.将 upgrade_system_contract_trx.json 文件中的 ref_block_numref_block_prefix 改为 0,将 expiration 的日期向后推迟一定的时间(比如 1 天后),这个时间表示 transaction 的过期时间。由于这个 transaction 最终需要等待 BP 多签生效,因此过期时间不能太短。

2.将 ramlimit.json 中的 actions 数据,追加到 upgrade_system_contract_trx.json 原有的两个 action 之后(setcode setabi),最终得到的 upgrade_system_contract_trx.json 格式如下:

{
  "expiration": "2018-08-27T06:48:52",
  "ref_block_num": 0,
  "ref_block_prefix": 0,
  "max_net_usage_words": 0,
  "max_cpu_usage_ms": 0,
  "delay_sec": 0,
  "context_free_actions": [],
  "actions": [{
      "account": "eosio",
      "name": "setcode",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "CODECODECODE"
    },{
      "account": "eosio",
      "name": "setabi",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "ABIABIABI"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "008037f500ea30554014000000000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "0000735802ea30558d60030000000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "00b0926602ea3055b486bf0200000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "000090e602ea3055a0aa040000000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "a0d492e602ea3055800a000000000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "c0a6db0603ea3055800a000000000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "0014341903ea3055f029060000000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "00a6823403ea30554053030000000000ffffffffffffffffffffffffffffffff"
    },{
      "account": "eosio",
      "name": "setalimits",
      "authorization": [{
          "actor": "eosio",
          "permission": "active"
        }
      ],
      "data": "0080377503ea30551022000000000000ffffffffffffffffffffffffffffffff"
    }
  ],
  "transaction_extensions": [],
  "signatures": [],
  "context_free_data": []
}

该文件包含 11 个 action,其中 1 个 setcode,1 个 setabi,9 个 setalimits。

4. 生成 producer_permissions.json 文件

假设网络中有 21 个 BP,名字分别为 blkproducera,blkproducerb,......,blkproduceru。则 producer_permissions.json 的文件内容如下所示:

$ cat producer_permissions.json
[
   {"actor": "blkproducera", "permission": "active"},
   {"actor": "blkproducerb", "permission": "active"},
   {"actor": "blkproducerc", "permission": "active"},
   {"actor": "blkproducerd", "permission": "active"},
   {"actor": "blkproducere", "permission": "active"},
   {"actor": "blkproducerf", "permission": "active"},
   {"actor": "blkproducerg", "permission": "active"},
   {"actor": "blkproducerh", "permission": "active"},
   {"actor": "blkproduceri", "permission": "active"},
   {"actor": "blkproducerj", "permission": "active"},
   {"actor": "blkproducerk", "permission": "active"},
   {"actor": "blkproducerl", "permission": "active"},
   {"actor": "blkproducerm", "permission": "active"},
   {"actor": "blkproducern", "permission": "active"},
   {"actor": "blkproducero", "permission": "active"},
   {"actor": "blkproducerp", "permission": "active"},
   {"actor": "blkproducerq", "permission": "active"},
   {"actor": "blkproducerr", "permission": "active"},
   {"actor": "blkproducers", "permission": "active"},
   {"actor": "blkproducert", "permission": "active"},
   {"actor": "blkproduceru", "permission": "active"}
]

5. 发起多签 proposal,approve 并执行

发起 proposal:

$ cleos multisig propose_trx upgradesys producer_permissions.json upgrade_system_contract_trx.json PROPOSER_ACCOUNT

通知各 BP 分别 approve:

cleos multisig approve PROPOSER_ACCOUNT upgradesys '{"actor": "BP_ACCOUNT", "permission": "active"}' -p BP_ACCOUNT

approval 达到 15/21 之后,执行该 proposal:

cleos multisig exec PROPOSER_ACCOUNT upgradesys ANY_ACCOUNT

6. 升级之后的检查

1.检查 code hash 是否为 ec02a22b7f15064f3ff86564ef9e34e2c68ac9061023b11b47e1adfceedf1368

cleos get code eosio

code hash: ec02a22b7f15064f3ff86564ef9e34e2c68ac9061023b11b47e1adfceedf1368

2.检查各个系统账户的 RAM 是否已经从 unlimited 变为固定值,比如 eosio.bpay:

cleos get account eosio.bpay

permissions:
     owner     1:    1 eosio@active,
        active     1:    1 eosio@active,
memory:
     quota:     5.062 KiB    used:     2.625 KiB

net bandwidth:
     used:               unlimited
     available:          unlimited
     limit:              unlimited

cpu bandwidth:
     used:               unlimited
     available:          unlimited
     limit:              unlimited

至此,基于 1.1.0 的 patch 版本升级成功。

*注意,任何账户都可以执行 approval 达到 15/21 的 proposal,即使该账户不是 BP。

转载自:https://github.com/cryptokylin/contract-upgrade-manual

Error 3010014: Invalid symbol

问题复现

新建账号 bcskillsurou,并部署eosio.token合约,此账号创建代币EOS,并发行后

cleos set contract bcskillsurou /mnt/c/github/eos/build/contracts/eosio.token/ -p bcskillsurou
cleos push action bcskillsurou create '["eosio","1500000000.00000000 BSC",0,0,0]' -p bcskillsurou
cleos push action bcskillsurou issue '["eosio","150000000.00000000 BSC","issue"]' -p bcskillsurou

当使用cleos执行transfer时

cleos -u  https://www.bcskill.com transfer bcskillsurou xxxxxxxxxxxx "10 BSC"

提示

Error 3010014: Invalid symbol
Error Details:
Symbol BSC is not supported by token contract bcskillsurou

但使用push action

cleos -u https://dev-api-chain.valicn.com push action bcskillsurou transfer '["bcskillsurou", "xxxxxxxxxxxx","100000000.0000 BSC","vote"]' -p bcskillsurou

是发送正常的.说明问题判断条件不在合约.

查看cleos代码
问题代码所在(cleos/main.cpp)
因为cleos 执行transfer时会先执行rpc get_currency_stats_func,拿到代币的精度,然后补齐.但默认是从系统主代币token合约(eosio.token)获取,如果是自定义合约的话,需要单独参数(["--contract,-c"](https://github.com/EOSIO/eos/blob/448287d520f5f8c282139ecc60f227c218d42e82/programs/cleos/main.cpp#L3033 ""--contract,-c""))指定.
所以正确的transfer 命令为

cleos -u  https://www.bcskill.com transfer bcskillsurou xxxxxxxxxxxx "10 BSC" -c bcskillsurou

Scatter javascript warpper for webview

github:https://github.com/xuewuli/Tiny.Scatter

Tiny.Scatter

Scatter javascript warpper for webview

inject to iOS WKWebView

extension WKWebViewConfiguration {
    static func makeScatterEOSSupport(account: String, publicKey: String, in messageHandler: WKScriptMessageHandler, with config: WKWebViewConfiguration) -> Void {
        var js = ""

        if let filepath = Bundle.main.path(forResource: "tiny_scatter", ofType: "js") {
            do {
                js += try String(contentsOfFile: filepath)
            } catch { }
        }

        js +=
        """
        // value as string "SIG_K1_..."
        function onSignEOSMessageSuccessful(id, value) {
            BrigeAPI.sendResponse(id, value)
        }

        // value as string with this format '{"signatures":["SIG_K1_..."]}'
        function onSignEOSSuccessful(id, value) {
            BrigeAPI.sendResponse(id, JSON.parse(value))
        }

        // error as string
        function onSignEOSError(id, error) {
            BrigeAPI.sendError(id, {"type": "signature_rejected", "message": error, "code": 402, "isError": true})
        }

        TinyIdentitys.initEOS("\(account)", "\(publicKey)");

        const scatter = new TinyScatter();
        scatter.loadPlugin(new TinyEOS());

        window.scatter = scatter;

        document.dispatchEvent(new CustomEvent('scatterLoaded'));

        """
        let onLoadScript = WKUserScript(source: "document.dispatchEvent(new CustomEvent('scatterLoaded'))", injectionTime: .atDocumentEnd, forMainFrameOnly: false)
        config.userContentController.addUserScript(onLoadScript)
        let userScript = WKUserScript(source: js, injectionTime: .atDocumentStart, forMainFrameOnly: false)
        config.userContentController.add(messageHandler, name: XMethod.signEOS.rawValue)
        config.userContentController.addUserScript(userScript)
    }
}

Additional Android injection init.js, your need thirdpart lib suchlike https://github.com/TrustWallet/Web3View (or roll you own) to accomplish the injection.


/**
/* use webView.evaluateJavascript to call when your finish the sign
/* @param id as number , you got it when XWebView.signEOS called
/* @param value as string, with this format '{"signatures":["SIG_K1_..."]}'
**/
function onSignEOSSuccessful(id, value) {
    BrigeAPI.sendResponse(id, JSON.parse(value))
}

// value as string "SIG_K1_..."
function onSignEOSMessageSuccessful(id, value) {
    BrigeAPI.sendResponse(id, value)
}

function onSignEOSError(id, error) {
    BrigeAPI.sendError(id, {"type": "signature_rejected", "message": error, "code": 402, "isError": true})
}

const messageHandlers = {
    signEOS: {
        postMessage: function (param) {
            //XWebView is your @JavascriptInterface
            XWebView.signEOS(param.id, param.object.data);
        }
    },
    signEOSMsg: {
        postMessage: function (param) {
            XWebView.signEOSMsg(param.id, param.object.data);
        }
    }
}

window.webkit = { messageHandlers };

TinyIdentitys.initEOS("%1$s", "%2$s");

const scatter = new TinyScatter();
scatter.loadPlugin(new TinyEOS());

window.scatter = scatter;

setTimeout(function() {document.dispatchEvent(new CustomEvent('scatterLoaded'));}, 1000);

理解与计算比特币难度值Difficulty


挖矿实际就是在暴力猜谜,而要猜多少次,全凭全网共识的一个难度值。只有猜出一个数字能使得区块的哈希符合难度,才算答对谜题。
那么这个猜谜游戏由于越来越多人的加入,势必会更快猜出。所以为了维持一个恒定的游戏时间(两周),每次游戏难度均会根据上次游戏的用时而重新计算。

游戏越来越难,如何抢在别人前面猜出呢?所以开启了抱团团战模式(矿池)加入游戏,使得解谜速度更快也更难。速度与难度总是此消彼长。 这也是为何在2014,2015年后难度值呈几何级数式增长。当然也因解谜的设备(矿机)更新换代越来越快。

比特币难度值Difficulty

难度值在区块中并不记录,仅仅是为了人类直观感受解题难度而演变出的一个浮点数。公式如下:

此处的 difficulty_1_target 为一个常数,非常大的一个数字。表示矿池挖矿最大难度。目标值越小,区块生成难度越大。

难度值如何存储在区块中的

在区块中存储的是Target,但是将Target经类似于浮点数的一种压缩表示法,字段为bits。例如,如果区块bits记录为0x1b0404cb,那么他表示的十六进制的Target值为:

0x0404cb * 2**(8*(0x1b - 3)) = 0x00000000000404CB000000000000000000000000000000000000000000000000

在计算时,后面3个字节0x0404cb作为底,前面1字节0x1b表示次方数。具体压缩过程如下:

  • 将数字转换为256进制数
  • 如果第一位数字大于127(0x7f),则前面添加0
  • 压缩结果中的第一位存放该256进制数的位数
  • 后面三个数存放该256进制数的前三位,如果不足三位,则后面补零

例如,将数字1000压缩,先转换为256进制数

1000 = 0x03 * 256 + 0xe8 * 1

那么是由两个数字构成:

03   e8

第一个数未超过0x7f,则不需填0,但长度两位低于三位,在后面补零,最终表示为:

0x0203e800

有比如数字 2^(256-32)-1,转换为256进制为:

ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

第一位已经超过0x7f,前面添加零:

00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

现在长度为28+1=29 (0x1d),则最终压缩结果为:0x1d00ffffff。此时就用精度缺失,后面的26个ff 被丢弃了,因为总共才4字节,前两字节已经被长度和添加的0所占用,只剩下2个字节来存储数字。如果我们将压缩结果0x1d00ffffff解压,会是原值吗? 实际结果为:

0x00ffff *256** (0x1d - 3)  = ff ff 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

而此数为比特币的最大Target值,此时难度最小为1。将其结果前面添加4位0,其结果为:

0x00000000FFFFFF0000000000000000000000000000000000000000000000000000

此最小难度值1,在矿机上一般使用保留尾部的FF,则为:

0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

称上面数字为pool difficulty1 矿池难度1,矿池难度简称pdiff。而比特币客户端表示如此精度,也许是困难的,所以不保留尾部的FF,则结果为:

0x00000000FFFFFF0000000000000000000000000000000000000000000000000000

此值,在客户端上称之为bdiff。

如何查看当前难度值

当前难度值,可以在许多提供服务的网站上查看图表数据:

最大难度值是多少

按公式来看,当current_target=0时diffculty无穷大,标志着难以计算。而实际上current_target不会为0,最小current_traget=1时,难度值最大,接近2^(256-32)。

最小难度值是多少

当current_target=difficulty_1_target 为最大值时,难度值为最小值1

根据难度值如何计算网络算力network hash rate

网络算力,表示根据难度值,要计算多少次才能找到一个随机数使得区块哈希值低于目标值。
由当前目标值Target决定当前难度值 。如果当前难度为D,则根据公式:

因此,为找到一个难度为D区块,我们需计算哈希值的次数为:

目前难度计算速度要求是在10分钟内找到,即在600秒内完全计算,意味着网络算力最低必须是:

依上计算,当难度值D=1时,需要每秒计算7158278次哈希,即: 7.15 Mhahs/s。挖矿的每秒算力计算单位:

  • 1 KHash/s = 1000 Hash/s
  • 1 MHash/s = 1000 KHash/s
  • 1 GHash/s = 1000 MHash/s
  • 1 THash/s = 1000 GHash/s
  • 1 PHash/s = 1000 THash/s

比特币区块目标值

目标值是一个全网统一的一个256字节的数字,非常大。 最大目标值为0x1d00ffff。
比特币区块被设计为平均每10分钟生成一个新区块。那如何才能维持区块生成速度呢? 需要动态调整区块难度,而定期自动更新目标值,则可调整难度。所以比特币设计为每隔2016个区块时全网均会自动统计过去2016个区块生成耗时,重新计算出下一个2016个区块的目标值。

按10分钟一个区块生成速度,2016个区块生成时间为2016*10分钟=14天。

目标值计算细节

目标值计算公式如下,但在实际计算时有些特别处理,将目标值控制在一定范围内。

新目标值= 当前目标值 * 实际2016个区块出块时间 / 理论2016个区块出块时间(2周)。 
  • 判断是否需要更新目标值( 2016的整数倍),如果不是则继续使用最后一个区块的目标值
  • 计算前2016个区块出块用时
  • 如果用时低于半周,则按半周计算。防止难度增加4倍以上。
  • 如果用时高于8周,则按8周计算。防止难度降低到4倍以下。
  • 用时乘以当前难度
  • 再除以2周
  • 如果超过最大难度限制,则按最大难度处理

计算过程,Go代码如下。点击查看bticoin C++源码

var (
    bigOne = big.NewInt(1)
    // 最大难度:00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff,2^224,0x1d00ffff
    mainPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne)
    powTargetTimespan = time.Hour * 24 * 14 // 两周
)
func CalculateNextWorkTarget(prev2016block, lastBlock Block) *big.Int {
    // 如果新区块(+1)不是2016的整数倍,则不需要更新,仍然是最后一个区块的 bits
    if (lastBlock.Head.Height+1)%2016 != 0 {
        return CompactToBig(lastBlock.Head.Bits)
    }
    // 计算 2016个区块出块时间
    actualTimespan := lastBlock.Head.Timestamp.Sub(prev2016block.Head.Timestamp)
    if actualTimespan < powTargetTimespan/4 {
        actualTimespan = powTargetTimespan / 4
    } else if actualTimespan > powTargetTimespan*4 {
        // 如果超过8周,则按8周计算
        actualTimespan = powTargetTimespan * 4
    }
    lastTarget := CompactToBig(lastBlock.Head.Bits)
    // 计算公式: target = lastTarget * actualTime / expectTime
    newTarget := new(big.Int).Mul(lastTarget, big.NewInt(int64(actualTimespan.Seconds())))
    newTarget.Div(newTarget, big.NewInt(int64(powTargetTimespan.Seconds())))
    //超过最多难度,则重置
    if newTarget.Cmp(mainPowLimit) > 0 {
        newTarget.Set(mainPowLimit)
    }
    return newTarget
}

测试代码如下,计算的是对高度为497951+1出块时计算的新目标值。

func TestGetTarget(t *testing.T) {
    firstTime, _ := time.Parse("2006-01-02 15:04:05", "2017-11-25 03:53:16")
    lastTime, _ := time.Parse("2006-01-02 15:04:05", "2017-12-07 00:22:42")
    prevB := Block{Head: BlockHeader{Height: 497951, Bits: 0x1800d0f6, Timestamp: lastTime}}
    prev2016B := Block{Head: BlockHeader{Height: 495936, Bits: 0x1800d0f6, Timestamp: firstTime}}
    result := CalculateNextWorkTarget(prev2016B, prevB)
    bits := BigToCompact(result)
    if bits != 0x1800b0ed {
        t.Fatalf("expect 0x1800b0ed,unexpected %x", bits)
    }
}

转载自:https://yushuangqi.com/blog/2017/understand-bitcoin-difficulty.html

从源代码上理解REX

期待了这么长时间,REX 终于上线了!现在已经出现了很多怎么使用 REX 的教程,但是我们还没有看到有人解释在与 REX 交互的各种操作。所以 EOS Canada 希望深入地解析 REX 代码,给 EOS 社区做一下科普。
首先我们要定义八个术语,保证我们理解它们,它们对 REX 讨论都非常重要。

成熟期

当你购买 REX 代币时,在四天内将无法把它们换回 EOS。在此期间,这些代币被称为在成熟期。在同一天的不同时间购买的 REX 都从第二天0点开始计时,所以你最多可以有四个不同的到期日。

4天

如上所述,到期日的计算均从 UTC 时间的第二天00:00开始。因此,如果用户在今天16:00 UTC 购买 REX 代币,那么他们将只能在4天8小时后卖回 EOS(成熟后)。所以每当人们说“四天”时,它实际上是从购买后的 00:00 UTC 计算的四天。

30天

每次借用的 CPU 或网络带宽的有效期为30天。只有借来这些资源的用户才需要注意这个30天的期限。如果你是借出你的代币资源的用户,你只需要注意四天的成熟期。

储蓄桶

你可以选择把 REX 代币放到储蓄桶里,放到储蓄桶里的代不会自动进入成熟期的,直到你提出要取出里面的代币,它才会开始四天的成熟期,成熟后才能移动它们。这是为了让你能保证你的代币安全的一个选项。举一个具体的用例,如果你的活跃权限的密钥被盗,有你的密钥的人就能动用你已经成熟了的 REX 代币,换回 EOS 然后盗走。但是如果你的 REX 在储蓄桶里,你就有时间用拥有者权限更改你的活跃权限,然后取消储蓄桶里代币的成熟期。

REX 基金

要与 REX 交互,你先要在把 EOS 代币存入你的 REX 基金中 ,REX 基金中存的是 EOS 而不是 REX 代币。

投票前提

想用 REX 出租自己资源,有一个前提,他们必须至少投票给21个BP节点或者代理投票。

流动性紧缩

这种情况出现的几率很小,但是我们还是应该有所了解。如果在池中没有足够的EOS 代币来满足提款的数量,这种现象就叫“流动性紧缩”。这意味着所有提款订单会被排队,等有新的 EOS 代币进入 REX 池之后,或者有借用的资源到期。用户赎回 EOS 是没有风险的,他们可能最多需要等待30天,但再强调,这个现象是非常罕见的。

市场价

REX 由 Bancor 支持的,就是说价格不是由用户自己竞价决定的,而是由系统根据池中 EOS 和 REX 代币的比率去计算的。这就是为什么收益率或续约价格是不确定的,因为一切都是在购买时确定的,取决于买卖时间和当时的状况。

我们还想强调一下两件值得注意的事情。EOS:REX 比值的确定方式决定了你卖出REX收回EOS数量不是高于就是等于你投入的EOS数量。这意味着你永远不会因为持有 REX 而失去任何 EOS,你只会获益。

另一点是,在获取帐户快照时,空投可以选择是否考虑你的 REX 余额。就是说你在 REX 中的代币会不会被包含在内取决于该空投的开发者。
我们现在来看一下在与 REX 交互时可调用的所有操作,并作出相关解释。

转载自:https://mp.weixin.qq.com/s/zOmJA4R8JOHEedmHqhaoBw (by EOS Canada)