Skip to main content

Week4 - 7.25

Day1 - PoW 链中区块的确认

攻击者利用算力攻击网络时,可能使 Conflux 的 PoW 链中的 pivot 区块发生变更,进而导致已上链区块中交易的顺序与执行结果发生改变。我们可以通过RPC cfx_getConfirmationRiskByHash 获知持有全网 15% 算力的攻击者对指定区块发起攻击的成功概率。当该值小于 1e-8,即 0.000001% 时,该区块可被视作已确认。区块从上链到确认一般需要40-50秒。

广为人知的比特币的确认时间为6个区块(1个小时)。这意味着持有全网10%算力的攻击者对6个区块之前的区块发起攻击的成功概率为0.1%。

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"cfx_getConfirmationRiskByHash","params":["0x3912275cf09f8982a69735a876c14584dae95078762090c5d32fdf0dbec0647c"],"id":1}' -H "Content-Type: application/json" localhost:12539

// fix64 格式的返回值,使用该值除以2**256-1可以得到概率为1e-8
{
  "jsonrpc": "2.0",
  "result": "0x2af31dc4611873bf3f70834acdae9f0f4f534f5d60585a5f1c1a3ced1b", 
  "id": 1
}

Day2 - 进行重要交易时的区块确认方法

一般情况下,RPC cfx_getConfirmationRiskByHash 的返回值足以满足日常交易的安全性需求。但在特定情况下,例如在发送某些重要交易时,我们可能有更高级别的安全需求,这时可以借助 PoS 链为 PoW 链提供的 Finality(最终性)来确认交易。简单来说,PoS 链会指定 PoW 链中的 pivot 区块,在这之后,即使 51% 攻击者尝试逆转这个区块,也不会被 PoW 节点认可。

通过RPC cfx_getStatus 可以得到当前的节点状态,其中的 latestFinalized 字段就包括当前已被 PoS 链确认的最新 Epoch。通过比较该值与区块的 Epoch,就能知道区块是否已被最终确认。

这种确认方式要更加安全,但同时也会更加耗时。从区块上链到确认需要花费400秒左右。可以在Conflux Scan中查看最新状态到 PoS 最终确认状态的间隔

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"cfx_getStatus","id":1}' -H "Content-Type: application/json" localhost:12539

// Result
{
  "jsonrpc": "2.0",
  "result": {
    "bestHash": "0x7bbb518ec0b8671a60e9c98619137b0d52522a9ef9490c9b4c23c30f178312f8",
    "chainId": "0x405",
    "ethereumSpaceChainId": "0x406",
    "networkId": "0x405",
    "epochNumber": "0x2fa1a24",
    "blockNumber": "0x70a7fda",
    "pendingTxNumber": "0x83b",
    "latestCheckpoint": "0x2f91bc0",
    "latestConfirmed": "0x2fa19e1",
    "latestState": "0x2fa1a20",
    "latestFinalized": "0x2fa1854" // 已被 PoS 链确认的最新 Epoch
  },
  "id": 1
}

Day3 - 使用内置合约在链上读取 EpochNumber 等信息

在链下我们可以借助SDK提供的接口或直接通过RPC cfx_getStatus 获取 EpochNumber 等信息。在链上的合约中,则可以借助内置合约ConfluxContext来获取相关信息。合约可以借助ConfluxContext提供的epochNumber(), posHeight(), finalizedEpochNumber() 函数获取当前的区块链状态。

ConfluxContext的地址为CFX:TYPE.BUILTIN:AAEJUAAAAAAAAAAAAAAAAAAAAAAAAAAAAU5XA6TK73 / CFXTEST:TYPE.BUILTIN:AAEJUAAAAAAAAAAAAAAAAAAAAAAAAAAAAUV2XPKD3X。包含 abi 的 metadata 文件可以在这里获取。

pragma solidity >=0.4.15;

contract ConfluxContext {
    /*** Query Functions ***/
    /**
     * @dev get the current epoch number
     * @return the current epoch number
     */
    function epochNumber() public view returns (uint256) {}
    /**
     * @dev get the height of the referred PoS block in the last epoch
`    * @return the current PoS block height
     */
    function posHeight() public view returns (uint256) {}
    /**
     * @dev get the epoch number of the finalized pivot block.
     * @return the finalized epoch number
     */
    function finalizedEpochNumber() public view returns (uint256) {}
}

Day4 - 估算gas消耗时的 gasUsedgasLimit

通过SDK或RPC cfx_estimateGasAndCollateral 估算交易gas消耗时,得到的返回值 estimate 中包括 estimate.gasUsedestimate.gasLimit 字段。其中 estimate.gasUsed 字段代表交易将实际消耗的燃气数,但由于在EVM中每次子函数调用只会传入63/64的gasLimit,直接将交易txtx.gasLimit字段直接设置为estimate.gasUsed常常会引发 gas 不足的问题。通常推荐使用 estimate.gasLimit 作为交易的燃气上限 tx.gasLimit ,该值为 estimate.gasUsed4/3 倍。这样一般可以保证 gas 上限设置得足够, gasUsed 以外的燃气消耗也能够全额返还。

在以太坊中,超出gasUsed的燃气消耗将会全额返还,但Conflux中返还的燃气消耗至多为 tx.gasLimit * 1/4。换言之,设置的tx.gasLimit大于 gasUsed * 4/3 将会导致 gasUsed 以外的燃气消耗无法被全额返还。更详细的 gas 知识可以参考 Gas 科普

// Request
curl -X POST --data '{"method":"cfx_estimateGasAndCollateral","id":1,"jsonrpc":"2.0","params":[{"from":"cfx:type.user:aarc9abycue0hhzgyrr53m6cxedgccrmmyybjgh4xg","to":"cfx:type.contract:acc7uawf5ubtnmezvhu9dhc6sghea0403y2dgpyfjp","data":"0x","gasPrice":"0x2540be400","nonce":"0x0"}]}' -H "Content-Type: application/json" localhost:12539

// Result
{
  "jsonrpc": "2.0",
  "result": {
    "gasLimit": "0x6d60", // 21000 * 4/3
    "gasUsed": "0x5208", // 21000
    "storageCollateralized": "0x80"
  },
  "id": 1
}

Day5 - 交易中的 EpochHeight 参数

Conflux中的交易中需要指定EpochHeight参数。当 -100000 < currentEpochNumber - tx.epochHeight < 100000 时交易才会被执行。一般将交易的EpochHeight设置为当前的EpochNumber即可。如果交易对执行的时间点比较敏感,也可以通过设置更小的EpochNumber来避免交易被过晚执行。

产生 100000 个 Epoch 需要 100000 秒左右,约 28 个小时