amino 编码协议

amino是对象编码规范。它是Proto3的子集,具有接口支持扩展

amino与Proto3很大程度上兼容(但与Proto2不兼容)

amino 协议目标

  • 通过支持接口将奇偶校验分为逻辑对象和持久对象。
  • 具有唯一/确定性的值编码。
  • 二进制字节必须可以使用模式进行解码。
  • 模式必须是可升级的。
  • 没有模式,足够的结构必须可以解析。
  • 编码器和解码器逻辑必须相当简单。
  • 序列化必须合理紧凑。
  • 必须保持足够兼容的JSON格式(但不能与JSON进行一般转换)

Amino vs JSON

JavaScript Object Notation(JSON)易于阅读,结构合理,非常适合与Javascript进行互操作,但是效率低下。之所以存在Protobuf3,BER,RLP,是因为我们需要更紧凑,更有效的二进制编码标准。Amino为复杂的对象(例如嵌入式对象)提供了有效的二进制编码,这些对象自然地与您喜欢的现代编程语言集成在一起。此外,Amino具有完全兼容的JSON编码

Amino vs Protobuf3

Amino希望成为Protobuf4

  • Protobuf3不支持接口。它支持oneof,它作为一种联合类型,但在现代语言(例如C ++类,Java接口/类,Go接口/实现和Rust特性)中不能很好地转换为“接口”和“实现”

如果Protobuf支持接口,则外部定义的模式文件的用户将能够支持调用者定义的接口的具体类型。相反,oneofProtobuf3的功能要求在oneof字段的定义中预先声明具体的类型

Amino 细则

接口

Amino是可以处理接口的编码库。这是通过在每个“具体类型”之前添加字节前缀来实现的。

具体类型是实现已注册接口的非接口类型。并非所有类型都需要注册为具体类型-仅当它们将存储在接口类型字段(或包含接口元素的列表)中时,才需要注册它们。接口的注册和实现的具体类型应在程序初始化时进行,以检测任何问题

注册类型

要对接口进行编码和解码,必须向其注册,codec.RegisterInterface

amino.RegisterInterface((*MyInterface1)(nil), nil)
amino.RegisterInterface((*MyInterface2)(nil), nil)
amino.RegisterConcrete(MyStruct1{
    
    }, "com.tendermint/MyStruct1", nil)
amino.RegisterConcrete(MyStruct2{
    
    }, "com.tendermint/MyStruct2", nil)
amino.RegisterConcrete(&MyStruct3{
    
    }, "anythingcangoinhereifitsunique", nil)

前缀字节来标识具体类型

所有已注册的具体类型均以前4个字节(称为“前缀字节”)进行编码,即使它不在接口字段/元素中也是如此。这样,Amino可以确保(几乎)具体类型始终具有相同的规范表示形式。前缀字节的第一个字节不能为零字节

当注册了1024个实现同一接口的具体类型时,发生冲突的可能性约为0.01%

前缀字节从不以零字节开头,因此歧义字节以0x00进行转义。

4个前缀字节始终紧接在具体类型的二进制编码之前

计算前缀和歧义字节

要计算消歧字节,我们取hash := sha256(concreteTypeName)和删除前导0x00字节。

> hash := sha256("com.tendermint.consensus/MyConcreteName")
> hex.EncodeBytes(hash) // 0x{00 00 A8 FC 54 00 00 00 BB 9C 83 DD ...} (example)

在上面的示例中,hash有两个前导0x00字节,因此我们将其删除。

> rest = dropLeadingZeroBytes(hash) // 0x{A8 FC 54 00 00 00 BB 9C 83 DD ...}
> disamb = rest[0:3]
> rest = dropLeadingZeroBytes(rest[3:])
> prefix = rest[0:4]

不支持的类型

浮点数

不建议使用浮点数类型,因为它们通常是不确定的。如果需要使用它们,请使用field标签amino:"unsafe"

猜你喜欢

转载自blog.csdn.net/lk2684753/article/details/113849251