原文链接:https://github.com/ethereum/casper/blob/master/VALIDATOR_GUIDE.md
翻译:OKCOIN区块链工程院许乾
本文档概述了实施FFG验证器的组件。这些包括:
- 验证工作流程概述
- 验证器状态
- 验证码
- 选票格式和生成
- 注销格式
simple_casper
合约概述- Casper交易gas返还
- 简单的验证器投票逻辑
验证工作流程概述
- 创建 valcode:
- 部署用于验证验证者签名的新合同.
- 提交保证金:
- 调用
casper.deposit(validation_addr, withdrawal_addr)
传入步骤(1)中的智能合约地址和你的提现地址。
- 调用
- [每个Epoch] 提交新选票内容:
- 等待投票,直到检查点在主链中至少有
EPOCH_LENGTH/4
区块深度为止。
这确保所有验证器在同一个块上投票。 - 根据你的链的当前头部生成未签名的投票消息。
- 将未签名的投票交易广播给网络。
- 等待投票,直到检查点在主链中至少有
- 注销:
- 提交注销消息。
- 调用
casper.logout(logout_msg)
传入新生成的logout_msg.
- 提现:
- 调用
casper.withdraw(validator_index)
你的资金将被发送到在步骤(2)中指定的验证人提现地址。
- 调用
验证器状态
验证器的状态很复杂。他们必须处理valcode创建,提交保证金,投票和注销。每个阶段还需要等待交易确认。由于这种复杂性,使用了状态到处理程序的映射。
在pyethapp中实现 的验证器状态映射如下所示::
uninitiated: self.check_status,
waiting_for_valcode: self.check_valcode,
waiting_for_login: self.check_status,
voting: self.vote,
waiting_for_log_out: self.vote_then_logout,
waiting_for_withdrawable: self.check_withdrawable,
waiting_for_withdrawn: self.check_withdrawn,
logged_out: self.check_status
验证器状态转换图
箭头是在给定状态下接收新块时遵循的逻辑。例如,如果验证程序处于状态voting
并接收到一个高度为in_first_quarter_of_epoch
的新块,则验证程序将按照箭头保持该状态voting
。
验证码
验证人必须部署他们自己的签名验证合约。这将用于检查附在他们投票上的签名。此验证代码必须是纯函数。这意味着不允许存储读取/写入,环境变量读取或外部调用(除了已经通过纯度验证或预编译的其他合同)。
对于基本签名验证,ecdsa签名目前正在使用。这些ecdsa签名的验证码可以在这里找到。请注意,此LLL代码使用椭圆曲线公钥恢复预编译。
验证代码合约当前正在作为此处找到的induct_validator()
函数的一部分进行部署:
def induct_validator(chain, casper, key, value):
sender = utils.privtoaddr(key)
valcode_addr = chain.tx(key, "", 0, mk_validation_code(sender)) # Create a new validation code contract based on the validator's Ethereum address
assert utils.big_endian_to_int(chain.tx(key, purity_checker_address, 0, purity_translator.encode('submit', [valcode_addr]))) == 1
casper.deposit(valcode_addr, sender, value=value) # Submit deposit specifying the validation code contract address
Casper选票格式
Casper选票是一个RLP编码列表,包含以下元素::
[
validator_index: number, # Index of the validator sending this vote
target_hash: bytes32, # Hash of the target checkpoint block for this vote
target_epoch: number, # Epoch number of the target checkpoint
source_epoch: number, # Epoch number of the source checkpoint
signature # A signed hash of the first four elements in this list, RLP encoded. (ie. RLP([validator_index, target_hash, target_epoch, source_epoch])
]
Casper选票信息仅包含在发送给Casper合约casper.vote(vote_msg)
函数的普通交易中。
生成Casper选票
为了获得投票消息内容,使用Casper合约调用:
casper.validator_indexes(WITHDRAWAL_ADDRESS)
for thevalidator_index
casper.recommended_target_hash()
for thetarget_hash
casper.current_epoch()
for thetarget_epoch
casper.recommended_source_epoch()
for thesource_epoch
接下来,RLP编码所有这些元素。要计算您的签名,对投票的RLP编码列表的进行sha3
计算,并签名hash。您的签名必须与您的验证器的“validation_code”合同进行核对时有效。最后,将签名附加到投票信息内容的末尾。
Pyethereum中的实现 如下:
def mk_vote(validator_index, target_hash, target_epoch, source_epoch, key):
msg_hash = utils.sha3(rlp.encode([validator_index, target_hash, target_epoch, source_epoch]))
v, r, s = utils.ecdsa_raw_sign(msg_hash, key)
sig = utils.encode_int32(v) + utils.encode_int32(r) + utils.encode_int32(s)
return rlp.encode([validator_index, target_hash, target_epoch, source_epoch, sig])
生成Logout Message
像Casper选票消息一样,Logout Message是RLP编码列表,其中最后一个元素是验证者的签名。包括未签名的validator_index
和epoch
其中epoch
是当前epoch。签名的生成方式与上述投票方式相同。
这在Pyethereum中实现如下:
def mk_logout(validator_index, epoch, key):
msg_hash = utils.sha3(rlp.encode([validator_index, epoch]))
v, r, s = utils.ecdsa_raw_sign(msg_hash, key)
sig = utils.encode_int32(v) + utils.encode_int32(r) + utils.encode_int32(s)
return rlp.encode([validator_index, epoch, sig])
simple_casper
合约概述
Simple Casper Contract
包含casper的核心逻辑,它是用 Vyper 编写的,可以像任何其他合约一样部署到区块链中CASPER_ADDR
。
然后通过vote(vote_msg)
将Casper消息发送到合约,其中vote_msg
的结构参见Casper选票格式。
[Contract Source]
####构造函数
def init(epoch_length: int128, warm_up_period: int128,
withdrawal_delay: int128, dynasty_logout_delay: int128,
msg_hasher: address, purity_checker: address,
base_interest_factor: decimal, base_penalty_factor: decimal,
min_deposit_size: wei_value)
下面的参数部署后不能更改
epoch_length
withdrawal_delay
dynasty_logout_delay
min_deposit_size
base_interest_factor
base_penalty_factor
####初始化epoch
def initialize_epoch(epoch: int128)
根据finality的时间计算此epoch的利率和惩罚因子。
一旦新epoch开始,这个函数立即被称为应用于该状态的第一个交易。
####保证金
def deposit(validation_addr: address, withdrawal_addr: address)
接受预期验证人的存款并将其添加到下一个验证人set中。
####注销
def logout(logout_msg: bytes <= 1024)
启动验证程序注销。在进入withdrawal_delay
等待期之前,验证人必须继续验证dynasty_logout_delay
朝代。
####提现
def withdraw(validator_index: int128)
如果验证人等待的时间超过他们的withdrawal_delay
epoch的end_dynasty
epoch,则将他们的ETH发送给他们的存款。
####投票
def vote(vote_msg)
每个验证者每个epoch调用一次。投票信息包含Casper投票格式中显示的字段。
####惩罚
def slash(vote_msg_1, vote_msg_2)
任何检测到违规情况的人都可以调用。作为发现者的费用,向调用者发送削减验证者资金的4%,并烧掉剩下的96%。
Casper交易gas返还
如果成功Casper选票不花费gas,并且将被视为无效交易,如果失败则不被包括在该区块中。这避免了验证器上的大量gas负担。
简单的验证器投票逻辑
验证人登录后,他们可以使用以下逻辑来确定何时发送投票:
- 当接收到一个新块并替换我们链的当前head时,请调用
validate(block)
- 内部
validate(block)
检查:- 该区块至少有
EPOCH_LENGTH/4
blocks deep以确保检查点hash可以安全地投票。 - [NO_DBL_VOTE] 该区块的epoch没有被投票.
- [NO_SURROUND] 该区块的
target_epoch
>=self.latest_target_epoch
并且source_epoch
>=self.latest_source_epoch
.
NOTE: 这项检查非常简单,但它排除了可以安全投票的情况。
- 该区块至少有
- 如果所有检查都通过,则生成并发送新的选票!
NOTE: 要检查验证程序是否已注册,可以使用:
return casper.validators__start_dynasty(validator_index) >= casper.dynasty()
Congratulations @lanzhizhuxia! You received a personal award!
Click here to view your Board
Congratulations @lanzhizhuxia! You received a personal award!
You can view your badges on your Steem Board and compare to others on the Steem Ranking
Vote for @Steemitboard as a witness to get one more award and increased upvotes!