tendermint/docs/specs/wire-protocol.md

120 lines
4.7 KiB
Markdown
Raw Normal View History

2017-06-20 12:58:26 -07:00
# Wire Protocol
The [Tendermint wire protocol](https://github.com/tendermint/go-wire) encodes data in [c-style binary](#binary) and [JSON](#json) form.
## Supported types
- Primitive types
- `uint8` (aka `byte`), `uint16`, `uint32`, `uint64`
- `int8`, `int16`, `int32`, `int64`
- `uint`, `int`: variable length (un)signed integers
- `string`, `[]byte`
- `time`
- Derived types
- structs
- var-length arrays of a particular type
- fixed-length arrays of a particular type
- interfaces: registered union types preceded by a `type byte`
- pointers
## Binary
**Fixed-length primitive types** are encoded with 1,2,3, or 4 big-endian bytes.
- `uint8` (aka `byte`), `uint16`, `uint32`, `uint64`: takes 1,2,3, and 4 bytes respectively
- `int8`, `int16`, `int32`, `int64`: takes 1,2,3, and 4 bytes respectively
- `time`: `int64` representation of nanoseconds since epoch
**Variable-length integers** are encoded with a single leading byte representing the length of the following big-endian bytes. For signed negative integers, the most significant bit of the leading byte is a 1.
- `uint`: 1-byte length prefixed variable-size (0 ~ 255 bytes) unsigned integers
- `int`: 1-byte length prefixed variable-size (0 ~ 127 bytes) signed integers
NOTE: While the number 0 (zero) is encoded with a single byte `x00`, the number 1 (one) takes two bytes to represent: `x0101`. This isn't the most efficient representation, but the rules are easier to remember.
| number | binary `uint` | binary `int` |
| ------------ | ------------- | ------------- |
| 0 | `x00` | `x00` |
| 1 | `x0101` | `x0101` |
| 2 | `x0102` | `x0102` |
| 256 | `x020100` | `x020100` |
| 2^(127*8)-1 | `x7FFFFF...` | `x7FFFFF...` |
| 2^(127*8) | `x800100...` | overflow |
| 2^(255*8)-1 | `xFFFFFF...` | overflow |
| -1 | n/a | `x8101` |
| -2 | n/a | `x8102` |
| -256 | n/a | `x820100` |
**Structures** are encoded by encoding the field values in order of declaration.
```go
type Foo struct {
MyString string
MyUint32 uint32
}
var foo = Foo{"626172", math.MaxUint32}
/* The binary representation of foo:
0103626172FFFFFFFF
0103: `int` encoded length of string, here 3
626172: 3 bytes of string "bar"
FFFFFFFF: 4 bytes of uint32 MaxUint32
*/
```
**Variable-length arrays** are encoded with a leading `int` denoting the length of the array followed by the binary representation of the items. **Fixed-length arrays** are similar but aren't preceded by the leading `int`.
```go
foos := []Foo{foo, foo}
/* The binary representation of foos:
01020103626172FFFFFFFF0103626172FFFFFFFF
0102: `int` encoded length of array, here 2
0103626172FFFFFFFF: the first `foo`
0103626172FFFFFFFF: the second `foo`
*/
foos := [2]Foo{foo, foo} // fixed-length array
/* The binary representation of foos:
0103626172FFFFFFFF0103626172FFFFFFFF
0103626172FFFFFFFF: the first `foo`
0103626172FFFFFFFF: the second `foo`
*/
```
**Interfaces** can represent one of any number of concrete types. The concrete types of an interface must first be declared with their corresponding `type byte`. An interface is then encoded with the leading `type byte`, then the binary encoding of the underlying concrete type.
NOTE: The byte `x00` is reserved for the `nil` interface value and `nil` pointer values.
```go
type Animal interface{}
type Dog uint32
type Cat string
RegisterInterface(
struct{ Animal }{}, // Convenience for referencing the 'Animal' interface
ConcreteType{Dog(0), 0x01}, // Register the byte 0x01 to denote a Dog
ConcreteType{Cat(""), 0x02}, // Register the byte 0x02 to denote a Cat
)
var animal Animal = Dog(02)
/* The binary representation of animal:
010102
01: the type byte for a `Dog`
0102: the bytes of Dog(02)
*/
```
**Pointers** are encoded with a single leading byte `x00` for `nil` pointers, otherwise encoded with a leading byte `x01` followed by the binary encoding of the value pointed to.
NOTE: It's easy to convert pointer types into interface types, since the `type byte` `x00` is always `nil`.
## JSON
The JSON codec is compatible with the [`binary`](#binary) codec, and is fairly intuitive if you're already familiar with golang's JSON encoding. Some quirks are noted below:
- variable-length and fixed-length bytes are encoded as uppercase hexadecimal strings
- interface values are encoded as an array of two items: `[type_byte, concrete_value]`
- times are encoded as rfc2822 strings