Qtum DGP 分布自治协议技术详解
Qtum 量子链的分布式自治协议(Decentralized Governance Protocol,DGP)是基于 Qtum 实现的链上协议,协议允许通过链上提案和投票系统对共识参数进行更改。提案一旦投票通过,就可以在不分叉主链的情况下对参数进行无缝调整。目前在Qtum链上部署了4个DGP合约,分别用于对4个共识参数进行动态控制:
区块大小: 区块的最大容量
默认是2 Mb, DGP 合约: 0000000000000000000000000000000000000081
最小Gas价格: 区块创建者可接受的最小Gas价格
默认是 40 satoshis, DGP 合约: 0000000000000000000000000000000000000082
区块Gas限制:一个区块所能消耗的最大Gas数
默认是4千万, DGP 合约: 0000000000000000000000000000000000000084
EVM Gas调度: 每个EVM操作花费的Gas
DGP 合约: 0000000000000000000000000000000000000080
将控制这4个常见的区块链参数的智能合约嵌入到 Qtum 主网的创世块的原因是:这4个参数是Qtum链中最为关键的几个参数,使用智能合约对它们进行动态更改,可以最大程度地减少对区块链网络的影响。
可以使用DGP合约来添加更多的可控参数,但这个过程需要执行一次硬分叉。因为需要对共识编码进行修改,才能让链上已经存储的参数值变得可控。
DGP 工作原理
每一个可被 DGP 合约控制的参数都需要独立部署一个相应的 DGP 合约。Qtum 客户端会从控制参数的各个 DGP 合约中获取每个区块共识下的 DGP 合约所控参数的值。
客户端如果没有读取到DGP合约中存储的参数值,就会直接返回在客户端代码中所定义的该参数的初始值。
DGP 合约管理席(管理人员)的任务是在需要时为每个 DGP 合约参数发起提案,并提交提案启动投票。一旦某个提案获得足够的支持票数,该提案会自动生效,同时新的参数规则将作为新的共识规则作用于相应的参数。
如果提案在21600个区块内没有获得所需的票数,那么它将被驳回,同时合约将接受新的提案。
DGP合约
DGP 合约是 solidity 合约,允许管理以下内容:
管理操作: 增加/删除合约管理席位和治理席位
设置管理操作所需的管理席位的票数
设置接受 DGP 合约参数值席位提案所需的管理席位票数
设置接受 DGP 合约参数值席位提案所需的治理席位票数
针对提案启动投票
获取投票中的提案:当前的票数,以及 DGP 合约参数和所需投票的当前值
首次部署DGP合约时,该合约是没有管理席位的。因此必须调用相应的setter方法(只能调用一次):setInitialAdmin(),来设置初始的管理席位。该方法将首次调用的发送者设置为第一个管理席位。设置完成后,该管理席位的代理人就可以发起提案并启动投票。提案有以下三种类型:
席位增加提案(3 种子类型):
增加新的管理席位提案
增加新的治理席位提案
增加新的 DGP 合约参数值席位提案
席位删除提案 (2种子类型):
删除当前管理席位提案
删除当前治理席位提案
所需票数更改提案 (3 种子类型):
更改接受 DGP 合约参数值席位增加提案所需的管理席票数
更改接受 DGP 合约参数值席位增加提案所需的治理席票数
针对管理席或治理席提案:席位增加/删除提案,或所需票数更改提案,更改接受这两类提案所需的管理席票数
提案一旦启动投票,获得的支持票数不能小于票数阈值,否则不能生效。
除了增加第一个管理席位之外,其他的任何操作(不包括标识提案过期操作)都需要创建提案并启动投票。
当管理席位代理人创建提案时,提案在创建完成那一刻就自动获得了该管理席位的投票。
任意给定时间,每种提案类型最多只能有一个提案启动投票。
治理席位代理人只能给增加新的DGP合约参数值席位提案进行投票。提案一旦通过,需要设置DGP合约所需的合约地址,用于获取共识下的该参数的值。
管理席位代理人除了可以投票给增加新的DGP合约参数值席位提案之外,还可以投票给管理提案,其中包括所有其他类型的提案。
示 例
下面通过一个例子来解释说明。在下面的例子中,我们将运行一个* qtumd regtest*节点并使用DGP合约来修改最小Gas价格这一参数的值 (DGP合约:
0000000000000000000000000000000000000082)。
通过增加3个管理席位和2个治理席位,并将DGP合约参数席位增加提案生效所需的最少票数设置为2张管理席位投票和1张治理席位投票,从而将最小Gas价格参数修改为80 satoshi。我们还需要2张管理席位的投票,以便在添加第二个管理席之后能够继续添加更多管理席位或治理席位。
为实现上述目标,我们需要执行以下步骤:
设置初始的管理席位
由初始的管理席代理人创建提案,用于增加第2个管理席位
由任一管理席代理人创建提案,用于获取2张管理席投票从而使管理提案生效
由任一管理席代理人创建提案,用于增加第3个管理席位
由另一个管理席代理人对步骤4中创建的提案进行投票,因为需获取2张管理席投票从而使管理提案生效(现在我们已经有了3个管理席位)
由任一管理席代理人创建提案,用于增加第1个治理席位
由另一个管理席代理人对步骤6中创建的提案进行投票
由任一管理席代理人创建提案,用于增加第2个治理席位
由另一个管理席代理人对步骤8中创建的提案进行投票
由任一管理席代理人创建提案,用于获取2张管理席投票,以便接受DGP参数值席位增加提案
由另一个管理席代理人对步骤10中创建的提案进行投票
由任一管理席代理人创建提案,用于获取1张治理席投票,以便接受DGP参数值席位增加提案
由另一个管理席代理人对步骤12中创建的提案进行投票
基于minGasPrice-dgp-template模板创建参数值合约,并将最小Gas价格参数设置为80 satoshis,编译合约并在链上部署
由任一管理席代理人创建提案,使用步骤14中的合约地址增加一个新的DGP参数值席位
由另一个管理席代理人对步骤15中创建的提案进行投票
由任一治理席代理人对步骤15中创建的提案进行投票(使更改后的最小Gas价格参数的值生效,对于所有合约来说,新共识下的最小Gas价格现在是80 satoshis)
下面是要运行的命令列表:
#将地址 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6 设置为初始管理席位
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 6fb81cbb 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#创建一个新的提案,用于将地址qKAM7BEZ1MiKAcqaRU5WGV1x2mm4j6naVZ 设置成第2个管理席位。该提案会立即生效,因为该管理提案生效所需的最少投票数是0,并且一旦提案创建完成会自动获得管理席投票
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e830000000000000000000000001194f94e7da8a424e629c267b41424a5ef1fe5150000000000000000000000000000000000000000000000000000000000000000 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#创建一个新的提案,用于获取管理提案生效所需的2张管理席投票。该提案会立即生效,因为该管理提案生效所需的最少投票数是0,并且一旦提案创建完成会自动获得管理席投票
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 19971cbd00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#创建一个新的提案,用于将地址qabQY66jipfynn2H56JrdYRCBQTnrELwvC 设置为管理席位
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e83000000000000000000000000badc1f59d59d5a3274b5e052dac3519b4b43bcf80000000000000000000000000000000000000000000000000000000000000000 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#由第2个管理席代理人给提案进行投票
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e83000000000000000000000000badc1f59d59d5a3274b5e052dac3519b4b43bcf80000000000000000000000000000000000000000000000000000000000000000 0 250000 0.0000004 qKAM7BEZ1MiKAcqaRU5WGV1x2mm4j6naVZ
#生成一个区块
./qtum-cli generate 1
#创建一个新的提案,用于将地址qcAQCipSCpDfoBntvmUXevXiVSDZYqMpB3设置为治理席位
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e83000000000000000000000000cc11b23d87876b0172b2421389c489b996bc44fe0000000000000000000000000000000000000000000000000000000000000001 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#由第3个管理席代理人对提案进行投票
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e83000000000000000000000000cc11b23d87876b0172b2421389c489b996bc44fe0000000000000000000000000000000000000000000000000000000000000001 0 250000 0.0000004 qabQY66jipfynn2H56JrdYRCBQTnrELwvC
#生成一个区块
./qtum-cli generate 1
#创建一个新的提案,用于将地址qU2DbCMwqBGQ1eSUEjmx44zNkPsXr1kUtw 设置为第2个治理席位
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e8300000000000000000000000072c480dfe3e5440f4ce280625182a16728cf1d050000000000000000000000000000000000000000000000000000000000000001 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#由第2个管理席代理人对提案进行投票
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e8300000000000000000000000072c480dfe3e5440f4ce280625182a16728cf1d050000000000000000000000000000000000000000000000000000000000000001 0 250000 0.0000004 qKAM7BEZ1MiKAcqaRU5WGV1x2mm4j6naVZ
#生成一个区块
./qtum-cli generate 1
#由任一管理席代理人创建提案,用于获取2张管理席投票,以便接受DGP参数值席位增加提案
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 19971cbd00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#由第2个管理席代理人对提案进行投票
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 19971cbd00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 0 250000 0.0000004 qKAM7BEZ1MiKAcqaRU5WGV1x2mm4j6naVZ
#生成一个区块
./qtum-cli generate 1
#由任一管理席代理人创建提案,用于获取1张治理席投票,以便接受DGP参数值席位增加提案
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 19971cbd00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#由第2个管理席代理人对提案进行投票.
/qtum-cli sendtocontract 0000000000000000000000000000000000000082 19971cbd00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 0 250000 0.0000004 qKAM7BEZ1MiKAcqaRU5WGV1x2mm4j6naVZ
#生成一个区块
./qtum-cli generate 1
#由任一管理席代理人创建提案,使用合约地址3a30025a06580f5ae7db89e4198b9667c408a8bf增加一个新的DGP参数值席位
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e830000000000000000000000003a30025a06580f5ae7db89e4198b9667c408a8bf0000000000000000000000000000000000000000000000000000000000000002 0 250000 0.0000004 qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f6
#生成一个区块
./qtum-cli generate 1
#由第2个管理席代理人对提案进行投票
./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e830000000000000000000000003a30025a06580f5ae7db89e4198b9667c408a8bf0000000000000000000000000000000000000000000000000000000000000002 0 250000 0.0000004 qKAM7BEZ1MiKAcqaRU5WGV1x2mm4j6naVZ
#生成一个区块
./qtum-cli generate 1
#由任一治理席代理人对提案进行投票./qtum-cli sendtocontract 0000000000000000000000000000000000000082 bf5f1e830000000000000000000000003a30025a06580f5ae7db89e4198b9667c408a8bf0000000000000000000000000000000000000000000000000000000000000002 0 250000 0.0000004 qU2DbCMwqBGQ1eSUEjmx44zNkPsXr1kUtw#生成一个区块./qtum-cli generate 1
修改后的minGasPrice-dgp-template如下所示:
pragma solidity ^0.4.8;
contract minGasPrice{
uint32[1] _minGasPrice=[
80 //最小Gas价格(单位:satoshis)
];
function getMinGasPrice() constant returns(uint32[1] _gasPrice){
return _minGasPrice;
}
}
运行 solc --evm-version=homestead --bin new-minGasPrice.sol 命令编译合约,结果如下字节码所示:
6080604052602060405190810160405280605060ff16815250600090600161002892919061003b565b5034801561003557600080fd5b5061010e565b8260016007016008900481019282156100ca5791602002820160005b8382111561009857835183826101000a81548163ffffffff021916908360ff1602179055509260200192600401602081600301049283019260010302610057565b80156100c85782816101000a81549063ffffffff0219169055600401602081600301049283019260010302610098565b505b5090506100d791906100db565b5090565b61010b91905b8082111561010757600081816101000a81549063ffffffff0219169055506001016100e1565b5090565b90565b61015f8061011d6000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633fb5881914610046575b600080fd5b34801561005257600080fd5b5061005b610099565b6040518082600160200280838360005b8381101561008657808201518184015260208101905061006b565b5050505090500191505060405180910390f35b6100a1610110565b6000600180602002604051908101604052809291908260018015610106576020028201916000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116100c95790505b5050505050905090565b6020604051908101604052806001906020820280388339808201915050905050905600a165627a7a72305820521e4650ac723cc5046bec623cccc3af87ea598afb5b367d50fbf75c55afa1230029
我们已经将新参数值对应的DGP合约部署到示例中的地址: “3a30025a06580f5ae7db89e4198b9667c408a8bf”。
为了便于阅读示例,下面是DGP合约模板中函数的哈希值:
bf5f1e83: addAddressProposal(address,uint256)
e9944a81: alreadyVoted(address,address[])
19971cbd: changeValueProposal(uint256,uint256)
850d9758: getAddressesList(uint256)
3a32306c: getArrayNonNullLength(address[])
0c83ebac:getCurrentOnVoteAddressProposal(uint256,uint256)
5f302e8b: getCurrentOnVoteStatus(uint256,uint256)
4364725c: getCurrentOnVoteValueProposal(uint256)
f9f51401: getCurrentOnVoteVotes(uint256,uint256)
15341747: getParamAddressAtIndex(uint256)
27e35746: getParamCount()
8a5a9d07: getParamHeightAtIndex(uint256)
f769ac48: getParamsForBlock(uint256)
1ec28e0f: getRequiredVotes(uint256)
6b102c49: isAdminKey(address)
7b993bf3: isGovKey(address)
4cc0e2bc: removeAddressProposal(address,uint256)
6fb81cbb: setInitialAdmin()
bec171e5: tallyAdminVotes(address[])
4afb4f11: tallyGovVotes(address[])
所使用地址的hash160值:
管理席位1
qU6SWGUnAcxAbvESD98rkFCWaAeWmo54f67390f2bbb83e2d4ce5694dd8ab8dbfae827bb864
管理席位2
qKAM7BEZ1MiKAcqaRU5WGV1x2mm4j6naVZ1194f94e7da8a424e629c267b41424a5ef1fe515
管理席位3
qabQY66jipfynn2H56JrdYRCBQTnrELwvCbadc1f59d59d5a3274b5e052dac3519b4b43bcf8
治理席位1
qcAQCipSCpDfoBntvmUXevXiVSDZYqMpB3cc11b23d87876b0172b2421389c489b996bc44fe
治理席位2
qU2DbCMwqBGQ1eSUEjmx44zNkPsXr1kUtw72c480dfe3e5440f4ce280625182a16728cf1d05
需要注意的是,所需的票数值只需设置一次(必要时可进行修改),因此如果需要创建增加DGP参数值席位的提案,只需从示例步骤14开始向下执行。
通过智能合约进行治理
使用 DGP 合约给参数进行投票最基本的方法是,假定每个治理席位从属于一个实体/个人,我们可以增加多个治理席位,其中每一个都可以给提案投票。但是治理席地址也可能是其他的合约地址,这种情况下,治理席位可以创建子合约用于收集提案所需的投票。
一旦子合约的投票收集完成,就会向相应的主干 DGP 合约发送1张投票,代表了该治理席位的投票。比如,假定我们创建了一个子合约,用于收集委托方的加权票数。该子合约将作为一个治理席位添加进主干 DGP 合约,并且它的地址将作为治理席的合约地址。子合约会根据自己的规则收集委托方的投票,一旦票数满足共识阈值,它就会向主干 DGP 合约发送1张投票。
再比如,创建一个子合约,该合约根据自己的规则收集社区的投票,或者 AI 投票。一旦子合约收集的票数满足共识阈值,就会向主干 DGP 合约发送投票。
这为 DGP 参数更改提案投票的自治管理提供了无限的可能性。
推荐阅读