本文介绍了ACP-77提案,旨在重新设计Avalanche子网的创建和管理机制,以提高子网创建者的灵活性,特别是在验证者管理和费用机制方面。提案中强调了如何通过引入新的交易类型和费用模型,解决当前模型中存在的一些高成本和使用限制,使得Permissionless子网的创建更加容易和经济。
ACP | 77 |
---|---|
标题 | 重塑子网 |
作者 | Dhruba Basu (@dhrubabasu) |
状态 | 已激活 (讨论) |
类别 | 标准 |
取代 | ACP-13 |
通过以下方式彻底改革子网的创建和管理,以解锁子网创建者更大的灵活性:
该ACP取代了ACP-13并借用了其中的一些表述。
每个节点操作员必须至少质押2000 $AVAX(当前价值为7万美元)才能先成为主网络验证者,然后才有资格成为子网验证者。大多数子网计划启动时至少有8个子网验证者,这需要质押16000 $AVAX(当前价值为56万美元)。所有子网验证者为了满足其作为主网络验证者的角色,还必须分配8个AWS vCPU、16 GB RAM和1 TB存储空间来同步整个主网络(X链、P链和C链),并参与其共识,此外还需要为其验证的每个子网提供额外资源。
被禁止验证无权限、支持智能合约的区块链(如C链)的受监管实体无法启动子网,因为他们不能选择退出主网络验证。这种部署障碍阻止了一大批现实世界资产(RWA)发行人将独特的、有价值的代币引入Avalanche生态系统(这些代币可以通过Avalanche Warp Messaging/Teleporter在C链<>子网之间移动)。
未正确计量且被广泛验证的子网如果使用量意外激增,可能会破坏主网络的稳定性。运行这些子网的主网络验证者如果不足,可能会因内存溢出而退出,磁盘性能下降,或难以分配CPU时间给P/X/C链验证。反之,一些不确定行为也可能导致子网离线。
尽管运营子网支付给主网络的费用不随子网上的活动量增加而增长,但主网络上设置子网验证者的固定前期成本阻碍了那些更希望较小甚至可变成本的新项目,直至观察到需求为止。不同于L2s在活动规模增加时需向外部链支付一些递增费用(通常以每笔交易字节为单位计费),子网提供自己的安全性和数据可用性,运营商处理更多活动所需的唯一成本是支持额外负载的硬件成本。
在Banff中引入的弹性子网允许子网创建者使用他们自己的代币激活权益证明验证和基于正常运行时间的奖励。然而,这种代币必须是ANT(在X链上创建)并在P链上锁定。所有质押奖励都在P链上分配,奖励曲线定义在TransformSubnetTx
中,并且一旦设定后就无法修改。
没有弹性子网在主网上运行,显而易见的是,当前无需许可的子网可以更具吸引力。有许多成功的需许可子网在生产环境中运行,但许多子网创建者提出了上述担忧。总之,Avalanche社区可以从一种更灵活和更经济的机制中受益,该机制可以用来启动无需许可的子网。
Avalanche子网是由主网络验证者集合的一个子集验证的子网络。此ACP中概述的新网络创建流程不需要新网络的验证者集合与主网络的验证者集合有任何交集。此外,新的网络比子网具有更多的功能和主权。为了区分这两种网络类型,社区把这些新网络称为Avalanche Layer 1s,简称L1s。
通过旧网络创建流程创建的所有网络将继续被称为Avalanche子网。
在一个高层次上,L1s可以将其验证者集合管理定位在P链之外,通过设置其_validator manager_的区块链ID和地址。P链会消费用于修改L1验证者集合的Warp消息。为了确认L1验证者集合的修改,P链还会生成Warp消息。L1验证者不要求验证主网络,并且不像子网验证者那样有2000 $AVAX的质押要求。为了维持一个活跃的L1验证者,每隔一段时间会收取以$AVAX计价的连续费用。L1验证者只需要同步P链(而不是X/C链)即可追踪验证者集合的变化并支持跨L1通信。
为了能够在P链外部管理L1的验证者集合,Warp消息验证将在PlatformVM
中添加。对于P链来说,若要认为Warp消息有效,至少67%的 sourceChainID
权重必须参与聚合BLS签名。这一阈值相当于为C链设定的阈值。未来可能会提出一份ACP,在每个L1的基础上支持修改该阈值。
对于P链为某个L1产生的消息,只有该L1的验证者愿意提供签名即可,而非整个主网络验证者集合。这个优化是可能实现的,因为所有验证者仍将同步P链。
在P链上引入了以下Warp消息有效载荷:
SubnetToL1ConversionMessage
RegisterL1ValidatorMessage
L1ValidatorRegistrationMessage
L1ValidatorWeightMessage
签署这些消息的签名请求方法未指定。一种可行的选择在ACP-118中的SignatureRequest
消息中有详细描述。
所有包含在消息规范中的节点ID都表示为可变长度数组,以便在未来P链增加对新节点ID类型的支持时能够适用。
这些消息的序列化如下所示。
SubnetToL1ConversionMessage
P链可以为消费者(即验证管理者)生成SubnetToL1ConversionMessage
,让他们知道初始验证器集合。
以下是ValidatorData
的序列化定义:
字段 | 类型 | 大小 |
---|---|---|
nodeID |
[]byte |
4 + len(nodeID ) bytes |
blsPublicKey |
[48]byte |
48 bytes |
weight |
uint64 |
8 bytes |
60 + len(nodeID ) bytes |
以下是ConversionData
的序列化定义:
字段 | 类型 | 大小 |
---|---|---|
codecID |
uint16 |
2 bytes |
subnetID |
[32]byte |
32 bytes |
managerChainID |
[32]byte |
32 bytes |
managerAddress |
[]byte |
4 + len(managerAddress ) bytes |
validators |
[]ValidatorData |
4 + sum(validatorLengths ) bytes |
74 + len(managerAddress ) + sum(validatorLengths ) bytes |
codecID
是用于序列化有效载荷的编解码版本号,并硬编码为 0x0000
sum(validatorLengths)
是包含在 validators
中的 ValidatorData
序列化的长度总和。subnetID
标识正在转换为 L1 的子网(下面进一步描述)。managerChainID
和 managerAddress
标识新创建的 L1 的验证器管理器。这是允许发送 WARP 消息以修改 L1 验证器集的 (blockchain ID, address) 对。validators
是给定 L1 的初始连续付费验证器集合。SubnetToL1ConversionMessage
被指定为一个 AddressedCall
,其中 sourceChainID
设置为 P 链 ID,sourceAddress
设置为空字节数组,并具有以下有效载荷:
字段 | 类型 | 大小 |
---|---|---|
codecID |
uint16 |
2 bytes |
typeID |
uint32 |
4 bytes |
conversionID |
[32]byte |
32 bytes |
38 bytes |
codecID
是用于序列化有效载荷的编解码版本号,并硬编码为 0x0000
typeID
是有效载荷类型的标识符,对于此消息为 0x00000000
conversionID
是来自 ConvertSubnetToL1Tx
的 ConversionData
的 SHA256 哈希值RegisterL1ValidatorMessage
P链可以通过RegisterL1ValidatorTx
从验证管理者那里消费一条RegisterL1ValidatorMessage
消息,以注册L1的验证器集增添成员。
以下是PChainOwner
的序列化:
字段 | 类型 | 大小 |
---|---|---|
threshold |
uint32 |
4 bytes |
addresses |
[][20]byte |
4 + len(addresses ) * 20 bytes |
8 + len(addresses ) * 20 bytes |
threshold
是必须提供签名的addresses
数量,以授权PChainOwner
进行某种操作。threshold
是0
,则addresses
必须为空threshold
<= len(addresses
)addresses
中的条目必须是唯一的,并按升序排序RegisterL1ValidatorMessage
被指定为具有以下有效载荷的 AddressedCall
:
字段 | 类型 | 大小 |
---|---|---|
codecID |
uint16 |
2 bytes |
typeID |
uint32 |
4 bytes |
subnetID |
[32]byte |
32 bytes |
nodeID |
[]byte |
4 + len(nodeID ) bytes |
blsPublicKey |
[48]byte |
48 bytes |
expiry |
uint64 |
8 bytes |
remainingBalanceOwner |
PChainOwner |
8 + len(addresses ) * 20 bytes |
disableOwner |
PChainOwner |
8 + len(addresses ) * 20 bytes |
weight |
uint64 |
8 bytes |
122 + len(nodeID ) + (len(addresses1 ) + len(addresses2 )) * 20 bytes |
codecID
是用于序列化有效载荷的编解码版本号,并硬编码为 0x0000
typeID
是有效载荷类型的标识符,对于此有效载荷为 0x00000001
subnetID
, nodeID
, weight
和 blsPublicKey
是被添加的验证器信息expiry
是消息失效的时间。当P链时间戳 >= expiry
时,此 Avalanche Warp 消息不能再用于将nodeID
添加到subnetID
的验证器集中。remainingBalanceOwner
是P链上所有者,在验证器被移除时,剩余的余额将会发给该对象。disableOwner
是唯一允许通过DisableL1ValidatorTx
禁用验证器的P链所有者,如下所述。L1ValidatorRegistrationMessage
P链可以生成一个L1ValidatorRegistrationMessage
,供消费者验证验证期限已经开始或者已经被无效化。
L1ValidatorRegistrationMessage
被指定为一个 AddressedCall
,其sourceChainID
设置为P链ID,sourceAddress
设为一个空字节数组,其有效载荷为:
字段 | 类型 | 大小 |
---|---|---|
codecID |
uint16 |
2 bytes |
typeID |
uint32 |
4 bytes |
validationID |
[32]byte |
32 bytes |
registered |
bool |
1 byte |
39 bytes |
codecID
是用于序列化有效载荷的编解码版本号,并硬编码为 0x0000
typeID
是有效载荷类型的标识符,对于此消息为 0x00000002
validationID
标识消息对应的验证器registered
是代表 validationID
状态的布尔值。如果为 true,则 validationID
对应于当前验证器集中的验证器。如果为 false,则 validationID
不对应于当前验证器集中的验证器,并且将来也不会。L1ValidatorWeightMessage
P链可以通过SetL1ValidatorWeightTx
来消费一条L1ValidatorWeightMessage
,以更新现有验证器的权重。P链还可以生成一条L1ValidatorWeightMessage
,供消费者验证验证器权重更新是否已生效。
L1ValidatorWeightMessage
被指定为具有以下有效载荷的 AddressedCall
。当从P链发送时,sourceChainID
设置为P链ID,sourceAddress
设置为空字节数组。
字段 | 类型 | 大小 |
---|---|---|
codecID |
uint16 |
2 bytes |
typeID |
uint32 |
4 bytes |
validationID |
[32]byte |
32 bytes |
nonce |
uint64 |
8 bytes |
weight |
uint64 |
8 bytes |
54 bytes |
codecID
是用于序列化有效载荷的编解码版本号,并硬编码为 0x0000
typeID
是有效载荷类型的标识符,对于此消息为 0x00000003
validationID
标识消息对应的验证器nonce
是一个严格递增的数字,表示最新的验证器权重更新,并为该交易提供了重放保护weight
是验证器的新权重在此ACP前后,都需要在P链上发出CreateSubnetTx
来创建一个子网。此交易包括一个Owner
字段,它定义了一个密钥,目前可以用来授权任何验证器集合的添加(AddSubnetValidatorTx
)或删除(RemoveSubnetValidatorTx
)。
被视为无需许可的网络或者说Avalanche Layer 1:
Owner
密钥不能再拥有修改验证器集合的能力。P链引入以下新交易类型以支持此功能:
ConvertSubnetToL1Tx
RegisterL1ValidatorTx
SetL1ValidatorWeightTx
DisableL1ValidatorTx
IncreaseL1ValidatorBalanceTx
ConvertSubnetToL1Tx
为了将子网转换为L1,必须发出ConvertSubnetToL1Tx
,以设置将管理L1验证器集合的(chainID,address)对。CreateSubnetTx
中定义的Owner
密钥必须提供签名以授权此转换。
ConvertSubnetToL1Tx
规范如下:
type PChainOwner struct {
// The threshold number of `Addresses` that must provide a signature in order for
// the `PChainOwner` to be considered valid.
Threshold uint32 `json:"threshold"`
// The 20-byte addresses that are allowed to sign to authenticate a `PChainOwner`.
// Note: It is required for:
// - len(Addresses) == 0 if `Threshold` is 0.
// - len(Addresses) >= `Threshold`
// - The values in Addresses to be sorted in ascending order.
Addresses []ids.ShortID `json:"addresses"`
}
type L1Validator struct {
// NodeID of this validator
NodeID []byte `json:"nodeID"`
// Weight of this validator used when sampling
Weight uint64 `json:"weight"`
// Initial balance for this validator
Balance uint64 `json:"balance"`
// [Signer] is the BLS public key and proof-of-possession for this validator.
// Note: We do not enforce that the BLS key is unique across all validators.
// This means that validators can share a key if they so choose.
// However, a NodeID + L1 does uniquely map to a BLS key
Signer signer.ProofOfPossession `json:"signer"`
// Leftover $AVAX from the [Balance] will be issued to this
// owner once it is removed from the validator set.
RemainingBalanceOwner PChainOwner `json:"remainingBalanceOwner"`
// The only owner allowed to disable this validator on the P-Chain.
DisableOwner PChainOwner `json:"disableOwner"`
}
type ConvertSubnetToL1Tx struct {
// Metadata, inputs and outputs
BaseTx
// ID of the Subnet to transform
// Restrictions:
// - Must not be the Primary Network ID
Subnet ids.ID `json:"subnetID"`
// BlockchainID where the validator manager lives
ChainID ids.ID `json:"chainID"`
// Address of the validator manager
Address []byte `json:"address"`
// Initial continuous-fee-paying validators for the L1
Validators []L1Validator `json:"validators"`
// Authorizes this conversion
SubnetAuth verify.Verifiable `json:"subnetAuthorization"`
}
在接受此交易后,子网上的CreateChainTx
和AddSubnetValidatorTx
都将被禁用。Owner
密钥唯一能够执行的操作是使用RemoveSubnetValidatorTx
移除曾通过AddSubnetValidatorTx
添加的子网验证器。除非被Owner
密钥移除,否则此前使用AddSubnetValidatorTx
添加的任何子网验证器都会继续验证子网,直到其【结束时间】到达为止。一旦所有使用AddSubnetValidatorTx
添加的子网验证器都已不再存在于验证器集合中,Owner
密钥将失去权力。必须使用RegisterL1ValidatorTx
和SetL1ValidatorWeightTx
来管理L1的验证器集合。
通过ConvertSubnetToL1Tx
添加的验证器的validationID
定义为连接32字节的subnetID
和4字节的validatorIndex
(交易中的Validators
数组索引)结果的SHA256哈希。
接受此交易后,P链必须愿意签署具有与此交易值填充的ConversionData
对应的conversionID
的SubnetToL1ConversionMessage
。
RegisterL1ValidatorTx
在接受ConvertSubnetToL1Tx
之后,只能使用RegisterL1ValidatorTx
来添加新的验证器。这个交易的规范如下:
type RegisterL1ValidatorTx struct {
// 元数据、输入和输出
BaseTx
// Balance <= sum($AVAX 输入) - sum($AVAX 输出) - TxFee。
Balance uint64 `json:"balance"`
// [Signer] 是一个BLS签名,证明拥有下方 `Message` 中为该验证器指定的BLS公钥。
// 注意:我们不会强制要求BLS密钥在整个验证器集合中是唯一的。
// 这意味着如果验证器们选择这么做的话,可以共享一个密钥。
// 然而,NodeID + L1 仍然唯一映射到一个BLS密钥。
Signer [96]byte `json:"signer"`
// 一个RegisterL1ValidatorMessage有效载荷
Message warp.Message `json:"message"`
}
通过RegisterL1ValidatorTx
添加的验证器的validationID
定义为 Message
中的 AddressedCall
的 Payload
的 SHA256 哈希。
当 RegisterL1ValidatorTx
在 P 链上被接受时,验证器会被添加到 L1 的验证器集合中。与 validationID
相关的 minNonce
字段会在加入验证器集合时被存储(初始设置为 0
)。当验证下方定义的 SetL1ValidatorWeightTx
时,将使用此字段。
此 validationID
将用于防止重放攻击。使用过的 validationID
将存储在 P 链上。如果 RegisterL1ValidatorTx
的 validationID
已经被使用过,该交易将被认为无效。为了防止存储无限数量的 validationID
,RegisterL1ValidatorMessage
的 expiry
必须在交易在 P 链上发布后的未来24小时内。任何与过期时间戳相对应的 validationID
可以从 P 链的状态中清除。
L1 负责定义如何从潜在的验证器那里检索上述信息的过程。
兼容EVM的L1可以选择如下这样实施此步骤:
要使 RegisterL1ValidatorTx
有效,Signer
必须是一个有效的 RegisterL1ValidatorMessage
中定义的 blsPublicKey
的占有证明。
在接受 RegisterL1ValidatorTx
后,P链必须愿意为给定的 validationID
签署一个 L1ValidatorRegistrationMessage
,其中 registered
设置为 true
。这种情况将持续到使用 SetL1ValidatorWeightTx
将验证器从验证器集合中移除的时间为止,如下所述。
当确定某个特定的 validationID
不是并且永远不会是 注册过的,P链必须愿意为 validationID
签署一个 L1ValidatorRegistrationMessage
,其中 registered
设置为 false
。如果 RegisterL1ValidatorTx
中的消息失效时间在消息被交付之前已经过去,或者验证器成功注册后又被删除,就会出现这种情况。这使得P链能够向验证管理者证明某个验证器已被移除或从未被添加。P链必须拒绝签署任何 validationID
不对应活跃验证器且 expiry
在未来的 L1ValidatorRegistrationMessage
。
SetL1ValidatorWeightTx
SetL1ValidatorWeightTx
用于修改验证器的投票权重。此交易的规范如下:
type SetL1ValidatorWeightTx struct {
// 元数据、输入和输出
BaseTx
// 一个L1ValidatorWeightMessage有效载荷
Message warp.Message `json:"message"`
}
该交易的应用场景可能包括:
对于 L1ValidatorWeightMessage
的验证标准是:
nonce >= minNonce
。注意,每次相继的验证器权重更新时,nonce
并不要求必须递增 1
。minNonce == MaxUint64
时,nonce
必须为 MaxUint64
且 weight
必须为 0
。这防止了L1在未来交易中无法移除 nodeID
。weight == 0
,被移除的验证器不能是集合中的最后一个验证器。如果所有验证器都被移除,则无法产生任何有效的Warp消息通过 RegisterL1ValidatorMessage
来注册新的验证器。没有验证器,区块生产将会停止,且L1不可恢复。该验证标准在此处作为一种防护措施。随着用户对新的L1机制和工具的熟悉,未来可能的ACP可以移除此防护措施。当 weight != 0
时,验证器的权重被更新为 weight
,且 minNonce
被更新为 nonce + 1
。
当 weight == 0
时,验证器被从验证器集合中移除。与验证器相关的所有状态,包括 minNonce
和 validationID
都将从P链状态中移除。由于 RegisterL1ValidatorTx
中 expiry
提供的防重放保护,因此 validationID
不可能被重新初始化。验证器余额中所有未花费的 $AVAX 都将以单个UTXO形式发行给此验证器的 RemainingBalanceOwner
。回想一下,当验证器首次添加到L1的验证器集合中时(在 ConvertSubnetToL1Tx
或 RegisterL1ValidatorTx
中),会指定 RemainingBalanceOwner
。
注意:通过 ConvertSubnetToL1Tx
或 RegisterL1ValidatorTx
添加的 L1 验证器没有明确的结束时间。只有在 weight == 0
时,L1 验证器才会从L1的验证器集合中移除。
DisableL1ValidatorTx
L1验证器可以使用DisableL1ValidatorTx
标记他们的验证器为不活跃状态。此交易的规范如下:
type DisableL1ValidatorTx struct {
// Metadata, inputs and outputs
BaseTx
// ID corresponding to the validator
ValidationID ids.ID `json:"validationID"`
// Authorizes this validator to be disabled
DisableAuth verify.Verifiable `json:"disableAuthorization"`
}
为此验证器指定的DisableOwner
必须签署该交易。验证器未花费余额中的所有$AVAX将全部以单个UTXO的形式分发给该验证器的RemainingBalanceOwner
。回想一下,DisableOwner
和RemainingBalanceOwner
是在将验证器首次添加到L1的验证器集合中时(无论是在ConvertSubnetToL1Tx
还是RegisterL1ValidatorTx
)指定的。
为了完全从L1的验证器集合中移除,需要发出带有权重0
的SetL1ValidatorWeightTx
。为此,需要来自L1验证管理员的Warp消息。然而,支持在未经授权的情况下索取验证器的未花费余额对于失败的L1至关重要。
请注意,这并不会改变L1的总权益重量。此交易仅将验证器标记为不活跃,但并未将其从L1的验证器集合中移除。不活跃验证器可以随时通过IncreaseL1ValidatorBalanceTx
增加余额重新激活。
L1创建者应了解P链并不强制执行任何最小质定期限MinStakeDuration
的概念。预计选择执行MinStakeDuration
的L1将锁定验证器的权益以符合L1所需的时间。
IncreaseL1ValidatorBalanceTx
L1 验证器需要保持非零余额,以支付在 P 链上的连续费用,从而被视为活跃。任何人都可以使用 IncreaseL1ValidatorBalanceTx
来向验证器的余额添加额外的 $AVAX。此交易的规范如下:
type IncreaseL1ValidatorBalanceTx struct {
// Metadata, inputs and outputs
BaseTx
// ID corresponding to the validator
ValidationID ids.ID `json:"validationID"`
// Balance <= sum($AVAX inputs) - sum($AVAX outputs) - TxFee
Balance uint64 `json:"balance"`
}
如果与 ValidationID
对应的验证器当前不活跃(余额耗尽或已发出 DisableL1ValidatorTx
),此交易将把它们移回活跃验证器集合。
注意:添加到 Balance
的 $AVAX 可以随时通过 DisableL1ValidatorTx
由验证器领取。
引导节点/验证器的过程是在本地安全地重建区块链的最新状态。在这一过程结束时,节点/验证器的本地状态必须与其他诚实节点/验证器的本地状态同步。然后,节点/验证器可以验证新的传入交易,并与其它节点/验证器达成共识。
要引导一个节点/验证器,必须回答以下几个关键问题:如何发现网络中的对等节点?如何确定发现的对等节点诚实地参与网络?
对于像Avalanche主网络这样的独立网络,通常是通过连接到一组硬编码的可信引导程序来发现新的对等节点。以太坊将其称之为bootnodes。
由于L1验证器不需要是主网络验证器,因此无法通过简单连接到主网络验证器来提供L1的IP列表(L1的功能引导程序)。然而,主网络可以帮助节点跟踪L1,通过跟踪和传播L1验证器IP。L1不需要操作和维护一组引导程序,而是可以依靠主网络进行对等发现。
激活此ACP后,P链将不再支持除$AVAX外的任何资产抵押用于主网络。P链将不支持分发L1的抵押奖励。所有与L1验证相关的操作必须由L1的验证器管理器管理。P链只需要每个验证器缴纳连续费用。如果一个L1想要管理其验证器在P链上的余额,它可以将$AVAX余额发布在P链上来覆盖所有的L1验证器。L1可以实现任何机制来支付P链参与者所收取的连续费用。
L1对其验证器集合拥有完全的所有权,而不是P链。对于要加入的验证器,L1没有任何限制。加入L1验证器集合所需的任何权益均不在P链上锁定。如果验证器通过SetL1ValidatorWeightTx
(权重为0
)从L1的验证器集合中移除,权益将继续在外锁定。每个L1如何处理与验证器相关联的权益完全由L1自行决定,并且与发生在P链上的情况不同步。
P链与L1之间的关系提供了一种动态机制,L1可以使用P链作为公正的法官来修改参数(除了现有的帮助验证传入Avalanche Warp消息的角色)。如果验证器行为不端,L1验证器可以共同生成BLS多重签名来减少违规验证器的投票权重。此操作由Avalanche主网络完全担保(目前为2.25亿$AVAX,价值约83.25亿美元)。
后续的ACP可能会扩展P链<> L1的关系,包括参数化67%的阈值,以使L1可以根据其安全模型选择不同的阈值(例如简单的多数票51%)。
P链上的每一个额外的验证器都会为Avalanche网络持续加载负担。当在P链上发布一个验证器交易时,它只支付该交易本身的计算成本,而无需支付在网络中验证期间所消耗的成本(可能无限期)。这是一个区块链领域常见的问题,引发了大量关于状态租金的提案。以下费用机制利用了这样一个事实:每个L1验证器使用的计算量相同,并为每个离散的时间单元向每个L1验证器收取动态基本费用。
为了向每个L1验证器收费,引入了“余额”的概念。验证器的“余额”将在其活跃时间内持续扣费,以覆盖存储关联验证器属性(BLS密钥、权重、随机数)在内存中的成本,以及跟踪IP的成本(此外还包括主网络提供的其他服务)。此“余额”通过添加他们的活跃验证器集合初始化为RegisterL1ValidatorTx
。余额
可以在任何时候使用IncreaseL1ValidatorBalanceTx
增加。当此余额
达到0
时,验证器将被视作“不活跃”,并且不再参与验证L1。使用相同的IncreaseL1ValidatorBalanceTx
可以随时将不活跃的验证器移回活跃验证器集合。一旦验证器被视为不活跃,P链将从内存中移除这些属性,仅保留在磁盘上。来自该验证器的所有消息将被视为无效,直到使用IncreaseL1ValidatorBalanceTx
使其复活为止。L1可以通过减少不活跃的权重来删除不活跃的验证器,通过SetL1ValidatorWeightTx
将权重设置为0
。
由于每个L1验证器在每次计费时都收取相同的费用,因此跟踪整个验证器集合的费用非常直接。整个网络的累计动态基础费用记录在一个单独的uint中。该累计值应等于从计数器实例化以来验证器一直处于活跃所需收取的费用。验证器集合维护在一个优先队列中。以下是连续费用机制的伪代码实现。
## 伪代码
class ValidatorQueue:
def __init__(self, fee_getter):
self.acc = 0
self.queue = PriorityQueue()
self.fee_getter = fee_getter
# 每经过一个时间段,增加累加器并
# 弹出队列顶部耗尽资金的验证器。
# 注意:单个区块内所做的工作量
# 应该有界,以防止大量的
# 验证器操作同时发生。
def time_elapse(self, t):
self.acc = self.acc + self.fee_getter(t)
while True:
vdr = self.queue.peek()
if vdr.balance < self.acc:
self.queue.pop()
continue
return
# 验证器被加入
def validator_enter(self, vdr):
vdr.balance = vdr.balance + self.acc
self.queue.add(vdr)
```# 验证器已移除
def validator_remove(self, vdrNodeID):
vdr = find_and_remove(self.queue, vdrNodeID)
vdr.balance = vdr.balance - self.acc
vdr.refund() # 将 [vdr.balance] 退还给 [RemainingBalanceOwner]
self.queue.remove()
# 验证器的余额已充值
def validator_increase(self, vdrNodeID, balance):
vdr = find_and_remove(self.queue, vdrNodeID)
vdr.balance = vdr.balance + balance
self.queue.add(vdr)
ACP-103 提出了一种用于 P 链上交易的动态费用机制。该机制经过轻微修改后重新用于活动的 L1 验证器的连续费用。
在激活时,超出活动 L1 验证器的数量 $x$ 被设为 0
。
每个活动 L1 验证器每秒的费率是:
$$M \cdot \exp\left(\frac{x}{K}\right)$$
其中:
$M$ 是活动 L1 验证器的最低价格
$\exp\left(x\right)$ 是按照 EIP-4844 规范 $e^x$ 的近似值
# 使用泰勒展开式来近似 factor * e ** (numerator / denominator)
def fake_exponential(factor: int, numerator: int, denominator: int) -> int:
i = 1
output = 0
numerator_accum = factor * denominator
while numerator_accum > 0:
output += numerator_accum
numerator_accum = (numerator_accum * numerator) // (denominator * i)
i += 1
return output // denominator
$K$ 是一个控制 L1 验证器价格变化率的常数
每过一秒,$x$ 就会更新:
$$x = \max(x + (V - T), 0)$$
其中:
每当 $x$ 增加 $K$,每个活动 L1 验证器的价格就会增加大约 2.7
倍。如果每个活动 L1 验证器的价格变得过于昂贵,一些活动 L1 验证器将退出活动验证集,从而降低 $x$ 和价格。每个活动 L1 验证器的价格不断调整,以确保 P 链上的活动 L1 验证器数量平均不超过 $T$。
在处理区块中的交易之前,所有不再具有足够(非零)余额的验证器都会被停用。
在处理区块中的交易之后,所有没有足够余额支付下一秒的验证器都会被停用。
为了确保验证器收费准确,只有在推进链时间不会导致验证器出现负余额的情况下,这些区块才被视为有效。
这维护了在区块之间 L1 验证器数量保持恒定的预期。
通过首先检查挂钟时间是否会因资金不足而移除任何验证器,对区块构建协议进行了修改以适应这一变化。如果挂钟时间未移除任何 L1 验证器,则使用挂钟时间来构建区块。如果挂钟时间确实移除了某些验证器,则使用第一个验证器被移除的时间。
在 $\Delta t$ 时间内评估的总验证器费用是:
## 计算Δt内的费用
def cost_over_time(V:int, T:int, x:int, Δt: int) -> int:
cost = 0
for _ in range(Δt):
x = max(x + V - T, 0)
cost += fake_exponential(M, x, K)
return cost
激活时的参数如下:
参数 | 定义 | 值 |
---|---|---|
$T$ | 目标验证器数量 | 10_000 |
$C$ | 容量验证器数量 | 20_000 |
$M$ | 最低费率 | 512 nAVAX/s |
$K$ | 控制费率变化的常数 | 1_246_488_515 |
$M$ 为 512 nAVAX/s 等于每月大约 1.33 AVAX 来运行 L1 验证器,只要连续支付费用的 L1 验证器总数保持在 $T$ 或以下。
选择 $K$ 是为了让最大费用翻倍速度约为 24 小时。在极端情况下,网络长时间拥有 $C$ 个验证器;如果网络有 $T+1$ 个验证器,例如,费用率每约 27 年翻一番。
未来的 ACP 可以调整参数以增加 $T$、降低 $M$ 和/或修改 $K$。
L1 验证器持续收取少量费用。这对 L1 验证器提出了挑战:如何随时间维护余额?
节点客户端应提供 API 来跟踪验证器账户中剩余余额。这将为 L1 验证器提供一种方法来跟踪余额下降的速度,并在需要时进行充值。上述设计的一个良好副产品是验证器账户中的余额是可以申领的。这意味着用户可以充值任意数量的 $AVAX,并放心知道如有过多余额时他们总是可以将其取回。
预计大多数用户不会与节点客户端交互或跟踪何时以及需要充值多少到他们的验证器账户。钱包提供商将抽象化这个过程的大部分内容。对于希望更加便利的用户,L1 即服务 (L1-as-a-Service) 提供商将完全抽象化这个过程。
这种针对子网的新设计提出全面重做所有 L1 相关机制。推出应逐步进行,以免对现有子网造成服务中断。所有当前的子网验证器将继续能够同时验证主网络和它们正在验证的任何子网。
任何状态执行更改必须通过强制升级进行协调。实施者必须注意在升级激活前继续验证现有的规则集。激活后,节点应验证新的规则集。实施者必须注意仅在激活前验证是否存在 2000 $AVAX。
P 链
TransformSubnetTx
激活此 ACP 后,弹性子网将被禁用。TransformSubnetTx
在激活后将不予接受。由于主网上没有弹性子网,因此应无生产影响。
ConvertSubnetToL1Tx
RegisterL1ValidatorTx
SetL1ValidatorWeightTx
DisableL1ValidatorTx
IncreaseL1ValidatorBalanceTx
ACP-77 已实施并将合并到 AvalancheGo 中,位于 Etna
升级标志后。完整的工作可以通过标签 acp77
在这里找到。
由于 Etna 尚未激活,ACP-77 引入的所有新交易都将被 AvalancheGo 拒绝。如果在 ACP 过程中对 ACP-77 进行任何修改,则必须在激活前更新实现。
此 ACP 引入 Avalanche Layer 1s,这是一种比 Avalanche 子网成本显著更低的新网络类型。这可能导致网络数量大幅增加,从而验证器数量也相应增加。每个额外的验证器都会给 P 链增加一致的 RAM 使用量。然而,这应该通过上述连续费用机制适当地进行管理。
由于 L1 具有从 P 链独立的主权,L1 的抵押代币不会锁定在 P 链上。这对于 L1 验证器来说是一个安全考虑:恶意链可以选择随意移除验证器并获取验证器在 L1 上锁定的资金。P 链只保证 L1 验证器可以通过 DisableL1ValidatorTx
取回其剩余的 $AVAX 余额。L1 上的任何资产完全在 L1 的范围内。责任在于 L1 验证器来审核转移到 L1 的任何资产的安全性。
由于 RegisterL1ValidatorTx
中 Warp 消息的有效期较长(24 小时),验证器注册的垃圾信息可能导致 P 链内存压力大。未来的 ACP 可以如果发现 24 小时成为问题,减少有效期窗口。
NodeIDs 可以无意间添加到 L1 的验证集中。但是,需要注意的是任何质押/奖励都不受风险。对于被迫添加到验证集中的节点运营商,只需要通过密钥轮换来生成新的 NodeID,因为创建 NodeID 没有任何质押锁定期。比起更轻松地加入 NodeID,这是明确做出的折衷。这映射了主网验证器关于不存在质押/奖励风险的保证。
上述连续费用机制不适用于非活动的 L1 验证器,因为它们不存储在内存中。然而,非活动的 L1 验证器会被持久化存储在磁盘上,这可能致使 P 链状态持续增长。未来的 ACP 可以引入机制减缓 P 链状态增长速度或提供状态过期路径以减少 P 链状态总量。
特别感谢 @StephenButtolph、@aaronbuchwald 和 @patrick-ogrady 对这些想法的反馈。感谢 Ava Labs 平台工程组更广泛的反馈意见,帮助本 ACP 发布前改进。
版权及相关权利通过 CC0 豁免。
- 原文链接: github.com/avalanche-fou...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!