客户端状态

solo machine 轻客户端的 ClientState 用于存储最新序列、冻结序列、最新共识状态,以及一个客户端标志,用于指示该客户端是否应当允许在治理提案之后被更新。 如果客户端未被冻结,则冻结序列为 0。

共识状态

共识状态存储 solo machine 轻客户端的公钥、diversifier 和时间戳。 diversifier 用于防止在不同链上使用相同客户端标识符且复用同一公钥时发生意外作恶行为。它应当对该轻客户端所使用的链保持唯一。

公钥

公钥可以是单个公钥,也可以是多重签名公钥。所使用的公钥类型必须满足 tendermint 公钥接口的要求(在不久的将来,这将变为 SDK 公钥接口)。公钥必须注册到应用程序 codec 中,否则会出现编码/解码错误。存储在共识状态中的公钥以 protobuf Any 表示。 这使得未来支持其他公钥类型时具备更好的灵活性。

对手方验证

solo machine 轻客户端可以验证对手方的客户端状态、共识状态、连接状态、通道状态、数据包承诺、数据包确认、数据包回执缺失,以及下一个接收序列号。每次成功调用验证方法后,轻客户端的序列号都会递增。 要使验证成功,当前公钥必须对证明进行签名。

证明

solo machine 证明应当验证 solomachine 公钥是否对某些指定数据进行了签名。用于为 SDK 的 solo machine 实现生成已编组证明的格式如下:
  1. 使用对应的 protobuf 定义构造数据,并对其进行编组。
例如:
data := &ClientStateData{
    Path:        []byte(path.String()),
    ClientState: protoAny,
}

dataBz, err := cdc.Marshal(data)
proof.go 中的辅助函数 ...DataBytes() 负责处理这部分功能。
  1. 构造 SignBytes,并对其进行编组。
例如:
signBytes := &SignBytes{
    Sequence:    sequence,
    Timestamp:   timestamp,
    Diversifier: diversifier,
    DataType:    CLIENT,
    Data:        dataBz,
}

signBz, err := cdc.Marshal(signBytes)
proof.go 中的辅助函数 ...SignBytes() 负责处理这部分功能。DataType 字段用于区分被签名的数据类型,以防止潜在的 proto 编码重叠。
  1. 对 sign bytes 进行签名。将签名嵌入 SingleSignatureData 或 MultiSignatureData。将 SignatureData 转换为 proto 并进行编组。
例如:
sig, err := key.Sign(signBz)
    sigData := &signing.SingleSignatureData{
    Signature: sig,
}
    protoSigData := signing.SignatureDataToProto(sigData)

bz, err := cdc.Marshal(protoSigData)
  1. 构造一个 TimestampedSignatureData 并进行编组。编组后的结果可以作为证明参数传入验证函数。
例如:
timestampedSignatureData := &solomachine.TimestampedSignatureData{
    SignatureData: sigData,
    Timestamp: solomachine.Time,
}

proof, err := cdc.Marshal(timestampedSignatureData)
注意:在此流程结束时,需要更新与该密钥关联的序列。每次生成证明时,序列都必须递增。

通过 Header 更新

只有在以下条件满足时,通过 header 进行更新才会成功:
  • 提供的 header 可以被解析为 solo machine header
  • header 的序列与当前序列匹配
  • header 的时间戳大于或等于共识状态时间戳
  • 当前已注册的公钥生成了该证明
如果更新成功:
  • 公钥会被更新
  • diversifier 会被更新
  • 时间戳会被更新
  • 序列加 1
  • 新的共识状态会被设置到客户端状态中

通过提案更新

只有在以下条件满足时,通过治理提案进行更新才会成功:
  • 提供的 substitute 可以被解析为 solo machine 客户端状态
  • 新共识状态的公钥不等于当前共识状态的公钥
如果更新成功:
  • subject 客户端状态会被更新为 substitute 客户端状态
  • subject 共识状态会被更新为 substitute 共识状态
  • 客户端会被解冻(如果此前已被冻结)
注意:此前,AllowUpdateAfterProposal 用于表示 solo machine 客户端的更新/恢复选项。然而,该字段现已被弃用,因为代码迁移可以覆盖客户端状态和共识状态,而无需考虑该参数的值。如果治理愿意投票覆盖某个客户端状态或共识状态,那么治理很可能也愿意通过执行一次代码迁移来完成同样的操作。

作恶行为

只有在以下条件满足时,作恶行为处理才会成功:
  • 提供的 misbehaviour 可以被解析为 solo machine misbehaviour
  • 客户端尚未被冻结
  • 当前公钥在相同的 sequence 和 diversifier 下对两条不同的数据消息进行了签名。
如果作恶行为被成功处理:
  • 客户端会通过将冻结序列设置为该 misbehaviour 的序列而被冻结
注意:作恶行为处理依赖于数据处理顺序。发生作恶行为的 solo machine 可能会先更新到新的公钥,从而在提交作恶行为之前避免被冻结。

升级

solo machine 轻客户端不支持升级,因为通过普通客户端更新就可以设置完全不同类型的公钥。

Client State

The ClientState for a solo machine light client stores the latest sequence, the frozen sequence, the latest consensus state, and client flag indicating if the client should be allowed to be updated after a governance proposal. If the client is not frozen then the frozen sequence is 0.

Consensus State

The consensus states stores the public key, diversifier, and timestamp of the solo machine light client. The diversifier is used to prevent accidental misbehaviour if the same public key is used across different chains with the same client identifier. It should be unique to the chain the light client is used on.

Public Key

The public key can be a single public key or a multi-signature public key. The public key type used must fulfill the tendermint public key interface (this will become the SDK public key interface in the near future). The public key must be registered on the application codec otherwise encoding/decoding errors will arise. The public key stored in the consensus state is represented as a protobuf Any. This allows for flexibility in what other public key types can be supported in the future.

Counterparty Verification

The solo machine light client can verify counterparty client state, consensus state, connection state, channel state, packet commitments, packet acknowledgements, packet receipt absence, and the next sequence receive. At the end of each successful verification call the light client sequence number will be incremented. Successful verification requires the current public key to sign over the proof.

Proofs

A solo machine proof should verify that the solomachine public key signed over some specified data. The format for generating marshaled proofs for the SDK’s implementation of solo machine is as follows:
  1. Construct the data using the associated protobuf definition and marshal it.
For example:
data := &ClientStateData{
    Path:        []byte(path.String()),
    ClientState: protoAny,
}

dataBz, err := cdc.Marshal(data)
The helper functions ...DataBytes() in proof.go handle this functionality.
  1. Construct the SignBytes and marshal it.
For example:
signBytes := &SignBytes{
    Sequence:    sequence,
    Timestamp:   timestamp,
    Diversifier: diversifier,
    DataType:    CLIENT,
    Data:        dataBz,
}

signBz, err := cdc.Marshal(signBytes)
The helper functions ...SignBytes() in proof.go handle this functionality. The DataType field is used to disambiguate what type of data was signed to prevent potential proto encoding overlap.
  1. Sign the sign bytes. Embed the signatures into either SingleSignatureData or MultiSignatureData. Convert the SignatureData to proto and marshal it.
For example:
sig, err := key.Sign(signBz)
    sigData := &signing.SingleSignatureData{
    Signature: sig,
}
    protoSigData := signing.SignatureDataToProto(sigData)

bz, err := cdc.Marshal(protoSigData)
  1. Construct a TimestampedSignatureData and marshal it. The marshaled result can be passed in as the proof parameter to the verification functions.
For example:
timestampedSignatureData := &solomachine.TimestampedSignatureData{
    SignatureData: sigData,
    Timestamp: solomachine.Time,
}

proof, err := cdc.Marshal(timestampedSignatureData)
NOTE: At the end of this process, the sequence associated with the key needs to be updated. The sequence must be incremented each time proof is generated.

Updates By Header

An update by a header will only succeed if:
  • the header provided is parseable to solo machine header
  • the header sequence matches the current sequence
  • the header timestamp is greater than or equal to the consensus state timestamp
  • the currently registered public key generated the proof
If the update is successful:
  • the public key is updated
  • the diversifier is updated
  • the timestamp is updated
  • the sequence is incremented by 1
  • the new consensus state is set in the client state

Updates By Proposal

An update by a governance proposal will only succeed if:
  • the substitute provided is parseable to solo machine client state
  • the new consensus state public key does not equal the current consensus state public key
If the update is successful:
  • the subject client state is updated to the substitute client state
  • the subject consensus state is updated to the substitute consensus state
  • the client is unfrozen (if it was previously frozen)
NOTE: Previously, AllowUpdateAfterProposal was used to signal the update/recovery options for the solo machine client. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of this parameter. If governance would vote to overwrite a client or consensus state, it is likely that governance would also be willing to perform a code migration to do the same.

Misbehaviour

Misbehaviour handling will only succeed if:
  • the misbehaviour provided is parseable to solo machine misbehaviour
  • the client is not already frozen
  • the current public key signed over two unique data messages at the same sequence and diversifier.
If the misbehaviour is successfully processed:
  • the client is frozen by setting the frozen sequence to the misbehaviour sequence
NOTE: Misbehaviour processing is data processing order dependent. A misbehaving solo machine could update to a new public key to prevent being frozen before misbehaviour is submitted.

Upgrades

Upgrades to solo machine light clients are not supported since an entirely different type of public key can be set using normal client updates.