task:分布式自治协议(DGP)和动态的gas schedule
第一个由DGP控制的是,在不下载新的钱包也不创建网络分叉的情况下修改gas schedule参数。DGP最终会控制很多参数,但是最开始还是将它用于“动态的gas schedule”参数。
在每个DGP特性中主要涉及两个合约:
- 每个特性的DGP框架合约。(framework contract)
- 控制共识数据的实际的DGP特性合约。
合约代码:github.com/qtumproject/qtum-dgp/blob/master/dgp-template.sol.js
DGP分布式自治协议框架合约实现以下功能
1. 提案和投票 -- 每个参数改变包括内部治理席位管理需要先被提议,然后对它进行投票。如果投票符合所选择的条件,则该提议被接受,并执行该操作。投票使用“msg.sender”计算,这样公钥哈希地址或合约地址都可以作为参与者参与投票。
2. 治理席位管理 -- 可以添加和删除参与者,也可以修改治理席参数,比如一个提案被接受需要多少个治理席位同意,添加一个治理席位需要多少个治理席位同意等等。
3. 发送正确格式的数据给DGP特性合约
4. 允许自己被禁用,这样在不使用硬分叉的情况下就不能进行进一步的DGP修改(防止重大的漏洞或问题)
5. 一次只允许一个提案,提案只能由参与者提出。每个提案的有效期不超过5000个区块。每个提案在到期后,或者在投票结束后,完全可以拒绝或者批准它。
6.(可能)应该有一个管理员的列表,管理员可以删除提案,可选地,管理员也可以是唯一允许添加提案的人?
DGP分布式自治协议特性合约则更简单,它只需要完成以下两件事情:
- 只从合适的DGP框架合约接收信息/数据。(使用msg.sender)
- 使用“SSTORE”以一种标准化的形式存储共识数据,以便区块链在不运行EVM的情况下就能在RPL中检索和解析该数据。
每个DGP特性数据从该共识数据生效的区块高度开始被记录下来。注意,旧的共识数据记录不应该被替换或修改。虽然修改历史数据不会影响区块链的同步,但仍应保留以方便未来引用这些历史数据。
例如,有了动态的gas schedule数据,我们计划支持调用合约相关的新特性,使得合约调用可以选择采用合约创建时的gas schedule。为了使其在没有单独的数据库的情况下也能很容易实现,历史数据必须保留在RLP中。这也使得发生严重问题时,DGP可以对该特性进行回滚。
动态的Gas Schedule数据记录包含以下数据:
1. tierStepGas0
2. tierStepGas1
3. tierStepGas2
4. tierStepGas3
5. tierStepGas4
6. tierStepGas5
7. tierStepGas6
8. tierStepGas7
9. expGas
10. expByteGas
11. sha3Gas
12. sha3WordGas
13. sloadGas
14. sstoreSetGas
15. sstoreResetGas
16. sstoreRefundGas
17. jumpdestGas
18. logGas
19. logDataGas
20. logTopicGas
21. createGas
22. callGas
23. callStipend
24. callValueTransferGas
25. callNewAccountGas
26. suicideRefundGas
27. memoryGas
28. quadCoeffDiv
29. createDataGas
30. txGas
31. txCreateGas
32. txDataZeroGas
33. txDataNonZeroGas
34. copyGas
35. extcodesizeGas
36. extcodecopyGas
37. balanceGas
38. suicideGas
39. maxCodeSize (不是gas,但是是相关的参数,因此保留在这里)
对于每个DGP特性,都应该有一个在Qtum中硬编码的(即,写死的)等价值,这样即使在DGP没有部署或未工作的情况下,区块链也能正常运行。因此,对于动态的gas schedules,应该有一个默认的写死的gas schedule,该gas schedule在DGP合约产生一个新的gas schedule之前使用。
关于激活的考虑(Activation Consideration)
虽然不是由共识强制执行,但是DGP参数的修改应该在其被激活前的至少500个区块之前发布。不这样做会导致不必要的网络分叉以及孤块问题。DGP参与者有责任确保激活的速度快于500个区块的提案不被通过。
动态的Gas Schedule限制
我们应该为EVM的每个gas schedule项确定合理的最小值。一些操作码应该被允许保持免费,但是也有一些操作码例如签名和哈希永远都不会免费。目前,每个gas schedule项的最低限额应该与Qtum中写死的默认gas schedule相匹配。
DGP特性
- getGasSchedule
- 为getReward预留。
- 为getMinGasPrice预留。
DGP分布式自治协议未来的可扩展性
未来可能出现需要采用更复杂授权模型的场景,比如需要来自社区的投票或两种独立的multi-sig(多重签名)配置,或者其他与在目前DGP框架合约中实现的完全不同的模型。
可以通过以下方法来完全改变授权模型:添加一个新的“参与者key”,然后删除所有其他的key并且将需要的最大签名数减少到1。
本例中的“参与者key”将是实现所有授权逻辑的智能合约。注意,本例中的授权合约也需要处理提案/投票系统,然后在一次运行中简单地提议并通过对实际的DGP框架合约的匹配修改。
DGP分布式自治协议参数修改流程
- 在和社区讨论后提出一个提案。除非出现紧急事件,否则激活日期不应该早于这之后的20000个区块。如果是紧急事件,那么激活日期不应早于这之后的1000个区块。(500区块用于投票,500个区块用于激活)
- 将提案发送给DGP框架合约。
- 对提案进行投票。
- 假设投票通过,那么DGP框架将提案数据发送给DGP特性合约。
- 在提案激活的区块上新修改的DGP参数被激活。
DGP分布式自治协议实际必须的功能
我们将支持多个DGP合约。因此,我们应该实现一个用于支持它们的框架。
每个DGP合约将部署在区块链上,并且它们的地址将硬编码入区块链中。
每个DGP合约将有一个特定的地址,该地址包含了所有用于共识的DGP数据。该数据可以直接从RLP数据库中读取,且不需要运行EVM。每个DGP“记录”将包含2项:
- 其被激活的区块高度。
- 在特定的区块高度之后使用的新的参数值。
这些记录将以数组的形式顺序存储在内存中。还应该有一段数据,包含了数组的总长度。该数据应该在某个标准化了的地方(你可能需要查找Solidity是如何存储数组的来找到这个地方)。
由于DGP的框架实现可以发现存储在RLP中的参数,可以很容易地使用DGP提供的参数来确定当前区块的gas schedule。
DGP分布式自治协议注意事项
1. 可以有多个DGP参数记录
2. 参数可以缓存,但是当一个信息发送给DGP合约时该缓存将变得无效(因为参数是可以改变的)
3. 如果DGP记录有一个追溯的区块高度(例如,记录显示它在第500个区块被激活,并且接收到更新时的区块高度为1000),那么它应该立即生效,且不会影响前面的区块。
4. 一定要注意无效的数据。我们应该忽略无效的DGP记录。
5. 对于gas schedule DGP,如果DGP gas schedule记录显示使用的值小于模板参数的默认值 (github.com/qtumproject/qtum-dgp/blob/master/gasSchedule-dgp-template.sol.js),那么那个值应该被忽略,并设置为模板参数的值。
6. 旧的DGP数据不应该被覆盖,应该只能附加(append-only)。因此,当新的DGP记录被激活时,没有数据被修改或删除,只有数据被添加进来(除了显示数组长度的整形值)。