Expand description
Graphene wire-format primitives.
Everything Hive signs is a byte string produced by these encoders, so a divergence
here does not fail loudly — it produces a valid-looking signature over the wrong
bytes, which the chain then rejects. That makes this the highest-risk module in the
crate and the one the differential digest oracle in tests/ targets hardest.
§Fixes relative to beem
§String matches what hived’s JSON parser produces — beem was right
This section previously claimed the opposite, and the crate’s published findings said so too. It was wrong, and the correction is worth keeping visible.
beem’s String.__bytes__ runs the payload through unicodify():
if (o <= 7) or (o == 11) or (o > 13 and o < 32):
r.append("u%04x" % o) # note: no backslash
elif o == 8: r.append("b") # note: no backslash
elif o == 12: r.append("f") # note: no backslashThe missing backslashes read as an obvious defect. They are not. Hive is reached
over JSON-RPC, and hived parses that JSON with fc, which does not implement the
\uXXXX, \b or \f escapes – it strips the backslash and keeps the rest
literally. Asked to serialize a comment whose body is the three characters
x, U+0001, y, a live node returns the bytes for the seven characters
xu0001y.
So unicodify is a model of the transport, and it is an exact one: measured
against a node, hived mangles precisely the set beem lists – everything under
0x20 except \t, \n and \r, with 0x08 and 0x0c collapsing to b
and f.
Writing raw UTF-8, which this crate did until the node was asked, yields a digest
hived does not compute and a signature it rejects. write_string now applies
the same transform.
§Length prefixes count bytes, and are bounded
beem computed varint(len(d)) where d was already the encoded bytes, which is
correct, but nothing anywhere bounded the length. A String longer than
u32::MAX would silently truncate through the varint. We return an error.
§Timestamps are parsed strictly, in UTC
beem’s PointInTime appended the literal text "UTC" to the input and parsed with
%Y-%m-%dT%H:%M:%S%Z, and in the datetime branch called timegm(d.timetuple()),
which reads a timezone-aware, non-UTC datetime as though its wall-clock fields
were UTC. That silently shifts a transaction’s expiration by the UTC offset. Here
there is one representation — seconds since the Unix epoch, UTC — and parsing is
strict.
§Validation is not assert
beem validated hash lengths with bare assert statements (Sha256, Ripemd160,
Sha1 in types.py). Python strips those under -O, so the length checks vanish
in an optimised deployment. These are ordinary checked errors.
Structs§
- Point
InTime - A point in time on the Graphene wire:
uint32seconds since the Unix epoch, UTC.
Traits§
- Graphene
Serialize - Anything that can be written in Graphene wire format.
Functions§
- read_
varint32 - Read a LEB128 varint, returning the value and the number of bytes consumed.
- write_
array - Write an array: varint element count, then each element.
- write_
bool - Write a bool as one byte:
0or1. hived rejects any other value. - write_
bytes - Write a length-prefixed byte buffer.
- write_
i16 - Write a signed 16-bit integer, little-endian (vote weights).
- write_
i64 - Write a signed 64-bit integer, little-endian (asset amounts).
- write_
optional - Write an
optional<T>: a presence byte, then the value if present. - write_
raw - Write a fixed-width byte array with no length prefix (hashes, chain ids).
- write_
static_ variant - Write a static_variant: varint type tag, then the value.
- write_
string - Write a Graphene string: varint byte length, then the UTF-8 bytes.
- write_
u8 - Write one byte.
- write_
u16 - Write an unsigned 16-bit integer, little-endian.
- write_
u32 - Write an unsigned 32-bit integer, little-endian.
- write_
u64 - Write an unsigned 64-bit integer, little-endian.
- write_
varint32 - Write a LEB128 varint.