CIPs
核心 Conflux 网络改进提案
- CIP-94 On-chain DAO Vote for Chain Parameters
- CIP-99 增强 PoS 强制退休机制的容错性
- CIP-105 DAO 投票生效的最少投票数
- CIP-107 基于DAO 决定的可调整比例在返还存储抵押时进行销毁
CIP-94 On-chain DAO Vote for Chain Parameters
Conflux 计划在近期引入CIP-94(On-chain DAO Vote for Chain Parameters)提案。该提案将引入新的内置合约ParamsControl
, 允许DAO在链上投票来调整Conflux的链参数,如PoW的每个区块的出块奖励,或PoS链上的利率。
引入 CIP-94 前,链参数是硬编码在Conflux的代码中的,需要进行 hardfork 才能对链中的关键参数进行修改。引入该更新后,DAO在内置合约
ParamsControl
中投票后链参数就可被在线地更新(无需 hardfork)。
与之前的治理投票类似,用户需要质押并锁定CFX以获取投票权,之后利用投票权进行投票。完整的交互流程分为以下两大步。
- 在内置合约
Staking
中锁定CFX,以获取投票权(votePower
)- 首先质押 CFX(
deposit
) - 之后为投票锁定 CFX(
voteLock
)
- 首先质押 CFX(
-
与新引入的内置合约
ParamsControl
交互,为链参数进行投票(castVote
)。
本文会先介绍内置合约ParamsControl
所引入的投票机制——包括对投票选项、链参数的调整方式、投票的方式等内容,这些也是CIP-94的核心内容。之后会给出上述流程的完整交互代码供参考。
投票机制
持有投票权的用户将可以在ParamsControl
合约中投票调整链参数。下面我们对投票的相关机制进行介绍。
如何获取投票权可以参考锁定与投票权的说明。本文也在之后的代码部分提供了供参考的代码。
投票轮 投票对链参数的影响不是即时的。投票被分为若干轮(round/vote_round
),每轮持续 2 * 60 * 60 * 24 * 60
个 blockNumber(按照Conflux每秒出2个块计算即60天)。用户可以通过ParamsControl
合约的currentRound()
接口获知当前的投票轮。一轮内,每位用户都可以任意地重新分配自己的投票权。每轮的投票结果会在下一轮末生效,而非在当轮结束时立刻生效。
可投票的链参数与投票选项 CIP-94计划支持对链参数 “PoW 区块的挖矿奖励” 与 “PoS 的利率”投票。对于每个参数,有三个投票选项,投票者可以任意地将自己拥有的票数分配给这三个选项。三个投票选项分别意味着:
- 保持当前链参数“不变”
- “增加”链参数(所有投票均投该项将会使链参数变为当前的 2 倍)
- “减少”链参数(所有投票均投该项将会使链参数变为当前的 1/2)
链参数调整公式 在第x
轮结束时,链参数会根据x-1
轮(如前所述,参数调整存在一轮的延迟)的 所有投票 进行调整。我们以 old
表示调整前链参数,new
表示调整后的链参数,n_unchange, n_increase, n_decrease
表示“不变”“增加”“减少”选项的投票数,调整方式如下:
这一公式意味着,在每轮结束时:
- 当“增加”的投票数与“减少”的投票数相等时,链参数将不变。
- 每轮链参数的调整范围为
[1/2 * old, 2 * old]
,最小值与最大值分别对应着所有投票均投“减少”或“增加”。- 投“不变”选项时会导致最终的调整比例向
1
靠拢(即更加趋向于不变)。
投票方式 用户通过与ParamsControl
合约的castVote(uint64 vote_round, Vote[] vote_data)
接口交互来进行投票。vote_round
参数为指定的投票轮。vote_data
为 “投票”(Vote
结构体)数组,其中 Vote
的定义如下:
struct Vote {
// topic_index 代表投票的链参数。 0 代表 PoW 区块的挖矿奖励,1 代表 PoS 的利率
uint16 topic_index;
// votes[0], votes[1], votes[2] 代表分别为“不变”“增加”与“减少”选项分配的票数
// 每个Vote中votes各元素之和应小于等于用户持有的votePower
uint256[3] votes;
}
覆盖已有投票 在同一轮内,用户可以调用ParamsControl
合约的castVote(uint64 vote_round, Vote[] vote_data)
进行多次投票。对于同一参数而言,只有最新的投票会生效。换言之,用户可以通过这种方式覆盖已有的投票。
为了说明的方便,我们以形如
(0, [100, 0, 100])
的方式表示对PoW区块挖矿奖励(topic_index = 0
)的投票, 且分别为“不变”与“减少”分配了100票(votes[0] = 100, votes[2] = 100
)。如用户之前已有的两份投票为(0, [100, 0, 100]), (1, [0, 0, 200])
,用户的新投票为(0, [0, 0, 0])
, 那么用户现有的投票为(0, [0, 0, 0]), (1, [0, 0, 200])
,仅有topic_index
相同的投票被覆盖了。
CIP-105 的补充:当投票参与者较少时,操纵链参数投票的结果的代价会较小。因此CIP-105为链投票设置了额外的生效条件:投票数小于PoS质押数的5%时,投票结果将不会生效。
合约交互方式(附js代码)
如前所述,交互流程分为以下两步:
- 在内置合约
Staking
中锁定CFX,以获取投票权(votePower
)- 首先质押 CFX(
deposit
) - 之后为投票锁定 CFX(
voteLock
)
- 首先质押 CFX(
- 与新引入的内置合约
ParamsControl
交互,为链参数进行投票(castVote
)。
与 Staking
合约交互
与Staking
合约的交互方式没有发生变化。为了方便未曾了解过相关内容的读者,这里我们以代码为例对必要的交互步骤进行介绍,更多的交互细节可以参考之前文章中对锁定与投票权的说明。
// 这段代码用于对Staking合约功能进行说明
const { Conflux } = require('js-conflux-sdk');
async function main() {
// 初始化钱包
const PRIVATE_KEY = '0xxxxxxx'; // 填入私钥
const cfx = new Conflux({
url: 'https://portal-test.confluxrpc.com',
networkId: 1,
logger: console,
});
const account = cfx.wallet.addPrivateKey(PRIVATE_KEY);
const staking_contract = cfx.InternalContract('Staking');
// 质押 deposit(uint amount) 接收的单位为Drip, 这里我们质押 1CFX(即 1e18 Drip)
const stake_amount = BigInt(1e18);
await staking_contract.deposit(stake_amount).sendTransaction({
from: account
}).executed();
console.log("Stake finished")
// 锁定 voteLock(uint amount, uint unlock_block_number) 的单位与质押相同,也为Drip
// 在这里锁定 1CFX
const lock_amount = stake_amount;
// 投票权与锁定的CFX数量、时长有关,锁定时长在 1 年以上时 1 Drip 可获取 1 投票权。
// 低于 1 年时获取的投票权与锁定的季度数相关(注意并不连续)。
// Conflux 按照区块数量计算时间,Conflux网络每秒能生成两个区块。
// 这里我们选择锁定 1.01 年(略多于 1 年),解锁区块对应设置为 当前blockNumber + 1.01年产生的区块数。
const current_block_number = (await cfx.getStatus())['blockNumber']
const unlock_block_number = current_block_number + 2 * 60 * 60 * 24 * 365 * 1.01
await staking_contract.voteLock(lock_amount, unlock_block_number).sendTransaction({
from: account
}).executed();
console.log("Lock finished")
const votePower = await staking_contract.getVotePower(account.address, "")
console.log(`vote power: ${votePower}`) // vote power: 1000000000000000000
}
main()
与 ParamsControl
合约交互
需要说明的是,目前的测试网还未进行CIP-94的更新,以下给出的代码暂时无法正常运行
const { Conflux } = require('js-conflux-sdk');
async function main() {
// 初始化钱包
const PRIVATE_KEY = '0xxxxxxxxx';
const cfx = new Conflux({
url: 'https://portal-test.confluxrpc.com',
networkId: 1,
// logger: console,
});
const account = cfx.wallet.addPrivateKey(PRIVATE_KEY);
const control_contract = cfx.InternalContract('ParamsControl');
// 获取当前的投票轮
const current_round = await control_contract.currentRound()
const base_amount = BigInt(1e17);
// 初始化两份投票
let vote0 = [0, [base_amount, base_amount, base_amount]]
let vote1 = [1, [base_amount, base_amount, 0]]
await control_contract.castVote(current_round, [vote0, vote1]).sendTransaction({
from: account
}).executed();
console.log("Cast vote finished")
// 当前的个人投票
const vote_result = await control_contract.readVote(account.address)
console.log(vote_result)
// 当前的总体投票
const all_votes = await control_contract.totalVotes(current_round)
console.log(all_votes)
}
main()
CIP-99 增强 PoS 强制退休机制的容错性
本文是整理好的CIP-99中文介绍,供大家交流讨论。
CIP-99详情链接
内容
在强制节点退休之前允许其更多的不投票任期,并缩短退休节点的解锁周期,以允许节点更快地重新加入 PoS 投票。
摘要
当前的参数使得节点运营容易导致强制退休,从而造成利息损失。该 CIP 建议使参数更具容错性,即增加所需的不投票任期的数量并减少解锁期限。
动机
如果委员会中的一个节点在一个任期内(大约一个小时)没有投票,则当前的 PoS 机制会使其强制退休。但是,一个节点的正常重启过程一般是 30-50 分钟左右,所以如果节点运营者重启或升级某个在委员会中的节点时出现任何问题,该节点很可能会被强制退休。而如果主机遇到一些随机故障(比如断电),节点运营者几乎无法在这1小时的窗口期内及时响应。
现在,由于强制退休有时是不可避免的,7天的解锁期用于惩罚主机错误也似乎时间过长,因为在此期间节点没有收益。并且这使得调试相关问题更加困难,因为我们需要等待 7 天才能重试。
规格说明
在硬分叉之后,强制退休节点所需的不投票任期数变为 3 个连续任期。注意,如果一个节点在当选的最后两个任期没有投票,并且在下一轮选举中没有被选为委员会成员,该节点不应该被强制退休。 在硬分叉后,解锁期变为 1 天(适用于正常退休和强制退休),锁定期时间变为13天。
理论依据
正常退休的解锁周期不应长于强制退休,因此没有节点会主动触发强制退休。 由于每个节点为委员会服务 6 个任期,因此无论节点的投票权如何,检查 3 个连续任期都会有所帮助。 一个节点锁定和解锁的总时间仍然至少为 14 天,因此该提案不会引入更多的攻击机会。
后向兼容性
此改动将改变原有系统规范。
安全性考虑
允许节点有更多的不投票任期使得崩溃故障影响系统的时间更长。但是,如果这个不投票节点的投票权不妨碍系统的正常运行,即使让它在委员会中再多保留两个任期,整个系统中仍然有足够的诚实投票权。
另一个问题是,在硬分叉高度之前质押并在高度之后退出的账户将能够在不到 14 天后解锁退出。但是由于这只发生在硬分叉期间而不是之后,所以应该没有问题。
版权
此提案遵守CC0 协议,所有版权及相关权利不设限。
CIP-105 DAO 投票生效的最少投票数
概述
CIP-94 引入的合约并未强制所有质押者参与投票,因此当参与投票的诚实的投票者票数较少时,恶意的投票者只需要少量的质押份额就可以大幅操纵链参数。CIP-105 为 DAO 投票设置了投票结果生效的下限。当参与投票对应的质押份额低于PoS总质押份额的5%时,投票结果将不会生效。
CIP-107 基于DAO 决定的可调整比例在返还存储抵押时进行销毁
简要概述
CIP-107提出了一种代币销毁机制:在存储抵押被返还时(包括存储owner的改变),将退还存储抵押的一定比例销毁。该比例可以基于链上DAO投票进行决定。该CIP的动机在于缓解CFX代币的持续通胀。
规范(暂定)
假设m CFX是与某些状态相关联的存储抵押量,p是要销毁的存储抵押的比例。当状态在交易中释放时,m*(1-p) CFX将退还给状态的owner,剩余的将被销毁。p的取值可以投票确定,取值为0、0.25、0.5、0.75、1。
可能影响
- 缓解CFX的通胀,根据DAO决定的销毁比例与链上交易情况,甚至有可能使CFX发生通缩。
- 间接提高交易的费用。在Conflux原有的存储抵押机制中,存储抵押被释放时会被全额退回,在CIP-107实施后将不会全额退回,一定程度上提高了交易费用。
合约存储被代付时的结算方式
在合约存储被代付时,(如果)存储条目的owner为赞助者,此时交易在释放、写入状态时可能不会导致存储的释放或存储抵押的增加,此时将不会导致存储抵押被销毁。
例如ERC721的转账函数的典型实现
目前的推定结算方式,以正式结算为准。