Skip to content

Commit 6564780

Browse files
mvadariTapanito
andauthored
Add XLS-15d: 0015 XLS-15d: Concise Transaction Identifier (#317)
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
1 parent 5c6f37a commit 6564780

File tree

1 file changed

+231
-0
lines changed

1 file changed

+231
-0
lines changed

XLS-0015-concise-tx-id/README.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
<pre>
2+
xls: 15
3+
title: Concise Transaction Identifier
4+
description: Introduces concise transaction identifier
5+
author: RichardAH (@RichardAH)
6+
created: 2021-03-09
7+
discussion-from: https://github.com/XRPLF/XRPL-Standards/discussions/34
8+
status: Withdrawn
9+
category: Protocol
10+
</pre>
11+
12+
## Change Log
13+
14+
This standard was amended on 25th March 2021:
15+
16+
### XLS15.1
17+
18+
- Add an optional 7 bit `control byte` to the most significant byte position.
19+
- `Control byte` may be absent in which case assumed to be 0x00 for backwards compatibility.
20+
- Credit for these changes to @nbougalis
21+
22+
### Current Identifiers
23+
24+
Transactions in the XRPL ecosystem are identified using the namespace-biased SHA512-half of their canonical byte-wise serialisation [[1]](https://xrpl.org/basic-data-types.html#hashes) whether or not the transaction has been submitted to consensus.
25+
26+
Ledgers are also identified by hashes. [[2]](https://xrpl.org/basic-data-types.html#ledger-index) However provided there is a human consensus about validation (sufficient UNL overlap) ledgers may instead be identified by their 4 byte sequence number. [[3]](https://xrpl.org/basic-data-types.html#ledger-index)
27+
28+
Transactions are recorded in the protocol-defined canonical order within each ledger. [[4]](https://xrpl.org/basic-data-types.html#ledger-index) This ordering means each transaction has a sequence number within the ledger. This offset is present in the transaction metadata as `TransactionIndex`.[[5]](https://xrpl.org/transaction-metadata.html)
29+
30+
It may be useful in a range of applications to be able to uniquely identify a transaction by the point at which it was validated rather than by its explicit contents. Thus for an unvalidated (unsubmitted or locally rejected) transaction this type of identifier would not apply.
31+
32+
### New Identifier: Concise Transaction Identifier
33+
34+
At time of the publication we assume for the foreseeable future that there will not be more than 65535 transactions in a given ledger. Therefore we can uniquely identify a txn within a ledger with a 2 byte integer, and we can uniquely identify the ledger by its 4 byte sequence number. Thus a 6 byte number uniquely identifies a validated transaction.
35+
36+
To prevent transcription errors (and to provide some validation for the contents) the first hex nibble of the ledger's canonical hash and the first hex nibble of the transaction's canonical hash are included in byte position 0, bringing the total number of bytes to 7. This is referred to a the checksum byte.
37+
38+
To future-proof this format an additional, optional, 7 bit control byte **may** be prepended to these 7 bytes. If this control byte is absent then it is assumed to be 0x00 which is referred to as the _simple case_. This is a change introduced in XLS15.1, and is strictly backwards compatible with existing CTIs.
39+
40+
The control byte (if set) allows the CTI to identify a transaction in:
41+
42+
- A different network (other than XRPL mainnet)
43+
- With a double-wide `TransactionIndex`
44+
- With a double-wide `LedgerSequence`
45+
- Or any combination of these
46+
47+
In the simple case the CTI fits neatly and unambiguously in a positive signed 64 bit integer. In the advanced case, depending on which options are selected a big number may be required to store and process the CTI.
48+
49+
### CTI Format — Simple Case
50+
51+
_Must be handled by all implementations._
52+
| Byte/s | Field |
53+
|--------|--------------------------------------------------------------------------|
54+
| 0 | `<first four bits of ledger hash> <first four bits of transaction hash>` |
55+
| 1-3 | `<16 bit TransactionIndex>` |
56+
| 3-7 | `<32 bit LedgerSequence>` |
57+
58+
### CTI Format — Advanced Case
59+
60+
_Required for implementations that need to handle non-mainnet transactions or for "fully future-proofed implementations", otherwise optional._
61+
| Byte/s | Field |
62+
|--------|-----------------------------------------------------------------------------------------------------------|
63+
| 0 | `<reserved 00> <T double-wide txn bit> <L double-wide lgr bit> <four bits of network id>` |
64+
| 1 | `<first four bits of ledger hash> <first four bits of transaction hash>` |
65+
66+
- Byte 0 is the control byte and may be absent which gracefully degrades into the `simple case` above.
67+
- Most significant bit of the control byte is always 0 such that most CTIs can be encoded as a positively signed int64.
68+
- The next most significant bit is reserved for future use and must also be zero.
69+
- The `T double-wide txn bit`, when `1`, doubles the size of the `TransactionIndex` field.
70+
- The `L double-wide lgr bit`, when `1`, doubles the size of the `LedgerSequence` field.
71+
- Network ID is an unsigned 4 bit integer corresponding to a network identified in the range 0-15. A table of assigned values appears below.
72+
73+
Taken together the two double-wide bits inform the parsing application how to proceed:
74+
75+
Case 1: Normal Field Sizes `TL = 00`
76+
| Byte/s | Field |
77+
|--------|-----------------------------------------------------------------------------------------------------------|
78+
| 2-4 | `<16 bit TransactionIndex>` |
79+
| 4-8 | `<32 bit LedgerSequence>` |
80+
81+
Case 2: Double wide LedgerSequence `TL = 01`
82+
| Byte/s | Field |
83+
|--------|-----------------------------------------------------------------------------------------------------------|
84+
| 2-4 | `<16 bit TransactionIndex>` |
85+
| 4-12 | `<64 bit LedgerSequence>` |
86+
87+
Case 3: Double-wide TransactionIndex `TL = 10`
88+
| Byte/s | Field |
89+
|--------|-----------------------------------------------------------------------------------------------------------|
90+
| 2-6 | `<32 bit TransactionIndex>` |
91+
| 6-10 | `<32 bit LedgerSequence>` |
92+
93+
Case 4: Double-wide TransactionIndex and LedgerSequence `TL = 11`
94+
| Byte/s | Field |
95+
|--------|-----------------------------------------------------------------------------------------------------------|
96+
| 2-6 | `<32 bit TransactionIndex>` |
97+
| 6-14 | `<64 bit LedgerSequence>` |
98+
99+
### Network IDs
100+
101+
| Number | Network |
102+
| ------ | ------------------------------ |
103+
| 0 | XRPL mainnet |
104+
| 1 | XRPL testnet |
105+
| 2 | XRPL devnet |
106+
| 3 | XRPL-Labs Public Hooks Testnet |
107+
| 4..15 | Reserved for future use |
108+
109+
### Canonical Presentation
110+
111+
To prevent copy-paste errors and non-canonical CTIs, presentation of CTIs to end users must be in decimal _without leading zeros_. The only allowable characters in a presented CTI are `[0-9]`.
112+
113+
In the case of an advanced CTI the smallest possible way to describe the transaction is always the Canonical CTI. Thus if `double-wide` bits are set but the high bytes of those fields are `0x00` then this is a non-canonical and therefore an invalid CTI. Any implementation that handles `advanced case` CTIs must identify this.
114+
115+
### Examples—Simple Case
116+
117+
This randomly selected transaction: [1C0FA22BBF5D0A8A7A105EB7D0AD7A2532863AA48584493D4BC45741AEDC4826](https://livenet.xrpl.org/transactions/1C0FA22BBF5D0A8A7A105EB7D0AD7A2532863AA48584493D4BC45741AEDC4826/raw)
118+
119+
- Has a transaction index of 25
120+
- Resides in ledger 62084722
121+
- The transaction hash's first nibble is `1`
122+
- The ledger hash's first nibble is `F`
123+
Thus this transaction in CTI format encodes to
124+
- CTI: `67835576823535218`
125+
- Hex: `F1001903B35672`
126+
- URI: `xrpl://cti/67835576823535218`
127+
128+
Another randomly selected transaction [AE1C4AD620251CA97C320052A5B9755CD002B5FBDBECC9A49F088FD58B71A44E](https://livenet.xrpl.org/transactions/AE1C4AD620251CA97C320052A5B9755CD002B5FBDBECC9A49F088FD58B71A44E)
129+
130+
- Has a transaction index of 9
131+
- Resides in ledger 62090589
132+
- CTI: `43347185130237277`
133+
You can resolve these CTIs right now: [cti-resolver](https://richardah.github.io/cti-resolver/index.html)
134+
135+
### CTI Reference Implementations—Simple Case
136+
137+
In C:
138+
139+
```C
140+
int64_t
141+
cti_encode(
142+
uint8_t* txn_hash,
143+
uint16_t txn_index,
144+
uint8_t* ledger_hash,
145+
uint32_t ledger_index)
146+
{
147+
uint64_t cti = (((ledger_hash[0]>>4U) & 0xFU)<<4U) + ((txn_hash[0]>>4U) & 0xFU); // these are the 8 check bits
148+
cti <<= 16; // shift left 2 bytes to make space for the transaction index
149+
cti += txn_index;
150+
cti <<= 32; // shift left 4 bytes to make space for the ledger sequence number
151+
cti += ledger_index;
152+
return (int64_t)cti;
153+
}
154+
155+
uint8_t
156+
cti_is_simple(
157+
int64_t cti)
158+
{
159+
return (cti >>56U) == 0;
160+
}
161+
162+
uint16_t
163+
cti_transaction_index(
164+
int64_t cti)
165+
{
166+
return (cti >> 32U) & 0xFFFFU;
167+
}
168+
169+
uint32_t
170+
cti_ledger_index(
171+
int64_t cti)
172+
{
173+
return (cti & 0xFFFFFFFFUL);
174+
}
175+
176+
uint8_t
177+
cti_ledger_check(
178+
int64_t cti)
179+
{
180+
return (cti >> 52) & 0xFU;
181+
}
182+
183+
uint8_t
184+
cti_transaction_check(
185+
int64_t cti)
186+
{
187+
return (cti >> 48) & 0xFU;
188+
}
189+
```
190+
191+
In JS:
192+
193+
```js
194+
function cti_encode(
195+
txn_hash /* hex string */,
196+
txn_index,
197+
ledger_hash /* hex string */,
198+
ledger_index,
199+
) {
200+
let ledger_check = BigInt(parseInt(ledger_hash.slice(0, 1), 16));
201+
let txn_check = BigInt(parseInt(txn_hash.slice(0, 1), 16));
202+
let cti = (ledger_check << 4n) + txn_check;
203+
cti <<= 16n;
204+
cti += BigInt(txn_index);
205+
cti <<= 32n;
206+
cti += BigInt(ledger_index);
207+
return cti;
208+
}
209+
210+
function cti_is_simple(cti) {
211+
return cti >> 56n == 0;
212+
}
213+
214+
function cti_transaction_index(cti) {
215+
return (cti >> 32n) & 0xffffn;
216+
}
217+
218+
function cti_ledger_index(cti) {
219+
return cti & 0xffffffffn;
220+
}
221+
222+
function cti_ledger_check(cti) {
223+
return (cti >> 52n) & 0xfn;
224+
}
225+
226+
function cti_transaction_check(cti) {
227+
return (cti >> 48n) & 0xfn;
228+
}
229+
```
230+
231+
RH Note: Advanced case (XLS15.1) examples and reference implementations to be added shortly

0 commit comments

Comments
 (0)