{"id":13414418,"url":"https://github.com/tendermint/go-amino","last_synced_at":"2025-05-16T11:06:30.777Z","repository":{"id":52416691,"uuid":"44698621","full_name":"tendermint/go-amino","owner":"tendermint","description":"Protobuf3 with Interface support - Designed for blockchains (deterministic, upgradeable, fast, and compact)","archived":false,"fork":false,"pushed_at":"2021-10-19T22:27:30.000Z","size":8187,"stargazers_count":260,"open_issues_count":58,"forks_count":78,"subscribers_count":33,"default_branch":"master","last_synced_at":"2024-07-31T21:52:57.159Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tendermint.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-21T19:16:59.000Z","updated_at":"2024-06-08T01:55:24.000Z","dependencies_parsed_at":"2022-09-11T10:20:39.667Z","dependency_job_id":null,"html_url":"https://github.com/tendermint/go-amino","commit_stats":null,"previous_names":["tendermint/go-wire"],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tendermint%2Fgo-amino","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tendermint%2Fgo-amino/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tendermint%2Fgo-amino/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tendermint%2Fgo-amino/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tendermint","download_url":"https://codeload.github.com/tendermint/go-amino/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254518383,"owners_count":22084374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T21:00:20.885Z","updated_at":"2025-05-16T11:06:25.757Z","avatar_url":"https://github.com/tendermint.png","language":"Go","funding_links":[],"categories":["Go","Language bundles"],"sub_categories":["Golang bundle"],"readme":"# Amino Spec (and impl for Go)\n\nThis software implements Go bindings for the Amino encoding protocol.\n\nAmino is an object encoding specification. It is a subset of Proto3 with\nan extension for interface support.  See the [Proto3 spec](https://developers.google.com/protocol-buffers/docs/proto3)\nfor more information on Proto3, which Amino is largely compatible with (but not with Proto2).\n\nThe goal of the Amino encoding protocol is to bring parity into logic objects\nand persistence objects.\n\n**DISCLAIMER:** We're still building out the ecosystem, which is currently most\ndeveloped in Go.  But Amino is not just for Go — if you'd like to contribute by\ncreating supporting libraries in various languages from scratch, or by adapting\nexisting Protobuf3 libraries, please [open an issue on\nGitHub](https://github.com/tendermint/go-amino/issues)!\n\n\n# Why Amino?\n\n## Amino Goals\n\n* Bring parity into logic objects and persistent objects\n  by supporting interfaces.\n* Have a unique/deterministic encoding of value.\n* Binary bytes must be decodeable with a schema.\n* Schema must be upgradeable.\n* Sufficient structure must be parseable without a schema.\n* The encoder and decoder logic must be reasonably simple.\n* The serialization must be reasonably compact.\n* A sufficiently compatible JSON format must be maintained (but not general\n  conversion to/from JSON)\n\n## Amino vs JSON\n\nJavaScript Object Notation (JSON) is human readable, well structured and great\nfor interoperability with Javascript, but it is inefficient.  Protobuf3, BER,\nRLP all exist because we need a more compact and efficient binary encoding\nstandard.  Amino provides efficient binary encoding for complex objects (e.g.\nembedded objects) that integrate naturally with your favorite modern\nprogramming language. Additionally, Amino has a fully compatible JSON encoding.\n\n## Amino vs Protobuf3\n\nAmino wants to be Protobuf4. The bulk of this spec will explain how Amino\ndiffers from Protobuf3. Here, we will illustrate two key selling points for\nAmino.\n\n* Protobuf3 doesn't support interfaces.  It supports `oneof`, which works as a\n  kind of union type, but it doesn't translate well to \"interfaces\" and\n\"implementations\" in modern langauges such as C++ classes, Java\ninterfaces/classes, Go interfaces/implementations, and Rust traits.  \n\nIf Protobuf supported interfaces, users of externally defined schema files\nwould be able to support caller-defined concrete types of an interface.\nInstead, the `oneof` feature of Protobuf3 requires the concrete types to be\npre-declared in the definition of the `oneof` field.\n\nProtobuf would be better if it supported interfaces/implementations as in most\nmodern object-oriented languages. Since it is not, the generated code is often\nnot the logical objects that you really want to use in your application, so you\nend up duplicating the structure in the Protobuf schema file and writing\ntranslators to and from your logic objects.  Amino can eliminate this extra\nduplication and help streamline development from inception to maturity.\n\n## Amino in the Wild\n\n* Amino:binary spec in [Tendermint](\nhttps://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md)\n\n\n# Amino Spec\n\n### Interface\n\nAmino is an encoding library that can handle Interfaces. This is achieved by\nprefixing bytes before each \"concrete type\".\n\nA concrete type is a non-Interface type which implements a registered\nInterface. Not all types need to be registered as concrete types — only when\nthey will be stored in Interface type fields (or in a List with Interface\nelements) do they need to be registered.  Registration of Interfaces and the\nimplementing concrete types should happen upon initialization of the program to\ndetect any problems (such as conflicting prefix bytes -- more on that later).\n\n#### Registering types\n\nTo encode and decode an Interface, it has to be registered with `codec.RegisterInterface`\nand its respective concrete type implementers should be registered with `codec.RegisterConcrete`\n\n```go\namino.RegisterInterface((*MyInterface1)(nil), nil)\namino.RegisterInterface((*MyInterface2)(nil), nil)\namino.RegisterConcrete(MyStruct1{}, \"com.tendermint/MyStruct1\", nil)\namino.RegisterConcrete(MyStruct2{}, \"com.tendermint/MyStruct2\", nil)\namino.RegisterConcrete(\u0026MyStruct3{}, \"anythingcangoinhereifitsunique\", nil)\n```\n\nNotice that an Interface is represented by a nil pointer of that Interface.\n\nNOTE: Go-Amino tries to transparently deal with pointers (and pointer-pointers)\nwhen it can.  When it comes to decoding a concrete type into an Interface\nvalue, Go gives the user the option to register the concrete type as a pointer\nor non-pointer.  If and only if the value is registered as a pointer is the\ndecoded value will be a pointer as well.\n\n#### Prefix bytes to identify the concrete type\n\nAll registered concrete types are encoded with leading 4 bytes (called \"prefix\nbytes\"), even when it's not held in an Interface field/element.  In this way,\nAmino ensures that concrete types (almost) always have the same canonical\nrepresentation.  The first byte of the prefix bytes must not be a zero byte,\nso there are `2^(8x4)-2^(8x3) = 4,278,190,080` possible values.\n\nWhen there are 1024 concrete types registered that implement the same Interface,\nthe probability of there being a conflict is ~ 0.01%.\n\nThis is assuming that all registered concrete types have unique natural names\n(e.g.  prefixed by a unique entity name such as \"com.tendermint/\", and not\n\"mined/grinded\" to produce a particular sequence of \"prefix bytes\"). Do not\nmine/grind to produce a particular sequence of prefix bytes, and avoid using\ndependencies that do so.\n\n```\nThe Birthday Paradox: 1024 random registered types, Wire prefix bytes\nhttps://instacalc.com/51554\n\npossible = 4278190080                               = 4,278,190,080 \nregistered = 1024                                   = 1,024 \npairs = ((registered)*(registered-1)) / 2           = 523,776 \nno_collisions = ((possible-1) / possible)^pairs     = 0.99987757816 \nany_collisions = 1 - no_collisions                  = 0.00012242184 \npercent_any_collisions = any_collisions * 100       = 0.01224218414 \n```\n\nSince 4 bytes are not sufficient to ensure no conflicts, sometimes it is\nnecessary to prepend more than the 4 prefix bytes for disambiguation.  Like the\nprefix bytes, the disambiguation bytes are also computed from the registered\nname of the concrete type.  There are 3 disambiguation bytes, and in binary\nform they always precede the prefix bytes.  The first byte of the\ndisambiguation bytes must not be a zero byte, so there are 2^(8x3)-2^(8x2)\npossible values.\n\n```\n// Sample Amino encoded binary bytes with 4 prefix bytes.\n\u003e [0xBB 0x9C 0x83 0xDD] [...]\n\n// Sample Amino encoded binary bytes with 3 disambiguation bytes and 4\n// prefix bytes.\n\u003e 0x00 \u003c0xA8 0xFC 0x54\u003e [0xBB 0x9C 0x83 0xDD] [...]\n```\n\nThe prefix bytes never start with a zero byte, so the disambiguation bytes are\nescaped with 0x00.\n\nThe 4 prefix bytes always immediately precede the binary encoding of the\nconcrete type.\n\n#### Computing the prefix and disambiguation bytes\n\nTo compute the disambiguation bytes, we take `hash := sha256(concreteTypeName)`,\nand drop the leading 0x00 bytes.\n\n```\n\u003e hash := sha256(\"com.tendermint.consensus/MyConcreteName\")\n\u003e hex.EncodeBytes(hash) // 0x{00 00 A8 FC 54 00 00 00 BB 9C 83 DD ...} (example)\n```\n\nIn the example above, hash has two leading 0x00 bytes, so we drop them.\n\n```\n\u003e rest = dropLeadingZeroBytes(hash) // 0x{A8 FC 54 00 00 00 BB 9C 83 DD ...}\n\u003e disamb = rest[0:3]\n\u003e rest = dropLeadingZeroBytes(rest[3:])\n\u003e prefix = rest[0:4]\n```\n\nThe first 3 bytes are called the \"disambiguation bytes\" (in angle brackets).\nThe next 4 bytes are called the \"prefix bytes\" (in square brackets).\n\n```\n\u003e \u003c0xA8 0xFC 0x54\u003e [0xBB 0x9C 9x83 9xDD] // \u003cDisamb Bytes\u003e and [Prefix Bytes]\n```\n\n## Unsupported types\n\n### Floating points\nFloating point number types are discouraged as [they are generally\nnon-deterministic](http://gafferongames.com/networking-for-game-programmers/floating-point-determinism/).\nIf you need to use them, use the field tag `amino:\"unsafe\"`.\n\n### Enums\nEnum types are not supported in all languages, and they're simple enough to\nmodel as integers anyways.\n\n### Maps\nMaps are not currently supported.  There is an unstable experimental support\nfor maps for the Amino:JSON codec, but it shouldn't be relied on.  Ideally,\neach Amino library should decode maps as a List of key-value structs (in the\ncase of langauges without generics, the library should maybe provide a custom\nMap implementation).  TODO specify the standard for key-value items.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftendermint%2Fgo-amino","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftendermint%2Fgo-amino","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftendermint%2Fgo-amino/lists"}