amino是对象编码规范。它是Proto3的子集,具有接口支持扩展
amino与Proto3很大程度上兼容(但与Proto2不兼容)
JavaScript Object Notation(JSON)易于阅读,结构合理,非常适合与Javascript进行互操作,但是效率低下。之所以存在Protobuf3,BER,RLP,是因为我们需要更紧凑,更有效的二进制编码标准。Amino为复杂的对象(例如嵌入式对象)提供了有效的二进制编码,这些对象自然地与您喜欢的现代编程语言集成在一起。此外,Amino具有完全兼容的JSON编码
Amino希望成为Protobuf4
oneof
,它作为一种联合类型,但在现代语言(例如C ++类,Java接口/类,Go接口/实现和Rust特性)中不能很好地转换为“接口”和“实现”如果Protobuf支持接口,则外部定义的模式文件的用户将能够支持调用者定义的接口的具体类型。相反,oneof
Protobuf3的功能要求在oneof
字段的定义中预先声明具体的类型
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"
。