Generic Transaction Protocol (GTX)
Generic Transaction Protocol (GTX) is a protocol that's built on top of Generic Transfer Value (GTV), specifically focusing on how to encode transactions in a way that Postchain can comprehend.
Postchain uses GTX for sending and receiving transactions. It's not recommended to use GTV directly, even though it's possible to construct various Rell types directly into GTV.
GTX transaction format has the following features:
- The format is based on ASN.1 DER serialization (standardized by ITU-T, ISO, IEC)
- Has native support for multi-signature
- Has native support for atomic transactions
GTX transaction consists of one or more operations; its name and list of arguments define each operation. For example, one transaction might encode two operations:
issue(<Alice account ID>, 1000, USD)
transfer(<Alice account ID>, <Bob account ID>, 100, USD)
This looks similar to making function calls, so GTX operations can be understood as a kind of RPC, where the client submits calls (operations) to be performed on the server (network of Postchain nodes). GTX transaction is a batch of such operations signed by clients who wish to perform them. Usually, operations update the database, but they might only perform checks. GTX transaction is atomic; all operations succeed or fail as a whole.
GtxMessages DEFINITIONS ::= BEGIN
IMPORTS RawGtv FROM GtvMessages;
-- All types are using the same tags as RawGtv to make gtv<->gtx encoding equivalent
-- Gtx operation
-- [ string, [ gtv ] ]
RawGtxOp ::= [5] EXPLICIT SEQUENCE {
name [2] EXPLICIT UTF8String, -- RawGtv { string } --
args [5] EXPLICIT SEQUENCE OF RawGtv -- RawGtv { array } --
}
-- Gtx Body
-- [ bytearray, [ gtxOp ], [ bytearray ] ]
RawGtxBody ::= [5] EXPLICIT SEQUENCE {
blockchainRid [1] EXPLICIT OCTET STRING, -- RawGtv { bytearray } --
operations [5] EXPLICIT SEQUENCE OF RawGtxOp,
signers [5] EXPLICIT SEQUENCE OF [1] EXPLICIT OCTET STRING -- RawGtv { bytearray} --
}
-- Gtx
-- [ gtxBody, [ bytearray] ]
RawGtx ::= [5] EXPLICIT SEQUENCE {
body RawGtxBody,
signatures [5] EXPLICIT SEQUENCE OF [1] EXPLICIT OCTET STRING -- RawGtv { bytearray } --
}
END
Generic Transfer Value (GTV)
Generic Transfer Value (GTV) is a general-purpose protocol for sending and decoding any data structure in a way that postchain can understand it.
GTV is used to express data in:
- Primitive types (integers, strings, byte arrays, etc.)
- Complex types (only array and dictionary)
GTV gets converted to ASN.1 DER when it's sent.
GtvMessages DEFINITIONS ::= BEGIN
DictPair ::= SEQUENCE {
name UTF8String,
value RawGtv
}
RawGtv ::= CHOICE {
null [0] NULL,
byteArray [1] OCTET STRING,
string [2] UTF8String,
integer [3] INTEGER,
dict [4] SEQUENCE OF DictPair,
array [5] SEQUENCE OF RawGtv,
bigInteger [6] INTEGER
}
END
Type conversions
Here's a table to visualize the type conversions in the Rell backend to its corresponding GTV types when inserting into and querying them.
Rell type | Operation input | Query input | Query output |
---|---|---|---|
entity | GtvInteger | GtvInteger | GtvInteger |
enum | GtvInteger | GtvInteger (can be GtvString) | GtvString |
struct | GtvArray | GtvArray (can be GtvDict) | GtvDict |
integer | GtvInteger | GtvInteger | GtvInteger |
big_integer | GtvBigInteger | GtvBigInteger | GtvBigInteger |
decimal | GtvString | GtvString | GtvString |
boolean | GtvInteger | GtvInteger | GtvInteger |
rowid | GtvInteger | GtvInteger | GtvInteger |
json | GtvString | GtvString | GtvString |
text | GtvString | GtvString | GtvString |
byte_array | GtvByteArray | GtvByteArray | GtvByteArray |
nullable | GtvNull or type | GtvNull or type | GtvNull or type |
collection | GtvArray | GtvArray | GtvArray |
text map | GtvDict | GtvDict | GtvDict |
non-text map (e.g., [[k1, v1], [k2, v2], ...] ) | GtvArray | GtvArray | GtvArray |
named tuple (e.g., (x = 1, y = 2, z = 3) ) | GtvDict | GtvDict | GtvDict |
unnamed tuple (e.g., (1, 2, 3) ) | GtvArray | GtvArray | GtvArray |
Strict type conversion
Since Rell Version 0.13.9 the default behavior of GTV type conversion have changed, from non-strict to strict. The following table highlights how this affects how operation arguments gets parsed.
Operation input Rell type | Types accepted in strict | Types accepted in non-strict |
---|---|---|
byte_array | GtvByteArray | GtvByteArray |
GtvString | ||
integer | GtvInteger | GtvInteger |
GtvBigInteger | ||
big_integer | GtvBigInteger | GtvBigInteger |
GtvInteger | ||
decimal | GtvString | GtvString |
GtvInteger | ||
GtvBigInteger | ||
rowid | GtvInteger | GtvInteger |
GtvBigInteger |
Next up
Next, we'll look at how all the technology described so far comes together to form a platform for dapp developers. We'll explore the different parts of a dapp on Chromia and how you, as a developer, can get started quickly and easily.