Skip to content
2 changes: 1 addition & 1 deletion src/RFC-0110_BaseNodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ Pseudocode:
output_weight += serialize(output.script) / BYTES_PER_GRAM
output_weight += serialize(output.features) / BYTES_PER_GRAM

input_weight = num_inputs * PER_INPUT_GRAMS(9)
input_weight = num_inputs * PER_INPUT_GRAMS(8)
kernel_weight = num_kernels * PER_KERNEL_GRAMS(10)

weight = output_weight + input_weight + kernel_weight
Expand Down
11 changes: 6 additions & 5 deletions src/RFC-0111_BaseNodeArchitecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,17 @@ This module is used by the Base Node Service, Base Node State Machine, Mempool S
this is delivered using the Lightning Memory-mapped Database (LMDB). LMDB is highly performant, intelligent and
straightforward to use. An LMDB is essentially treated as a hash map data structure that transparently handles
memory caching, disk Input/Output (I/O) and multi-threaded access. This module is shared by many services and so must
be thread-safe.
be thread-safe. The current UTXO set is maintained as a Jellyfish Merkle Tree (JMT) — a sparse Merkle tree — backed by
the LMDB store, whose root is committed to in the block header as `output_mr`.

## Communication Interfaces

### P2P communications
The Tari Peer to Peer messaging protocol is defined in [RFC-0172]. It is a fire-and-forget style protocol. Messages can
be sent directly to a known peer, sent indirectly to an offline or unknown peer and broadcast to a set of peers. When
a message is sent to a specific peer it is propagated to the peer's local neighbourhood and stored by those peers until it
comes online to receive the message. Messages that are broadcast will be propagated around the network until the whole
network has received them, they are not stored.
be sent directly to a known peer or broadcast to a set of peers. Messages that are broadcast will be propagated around
the network until the whole network has received them; they are not stored. (Store-and-forward messaging, which
previously allowed messages to be stored for offline peers, has been removed; all current nodes discard store-and-forward
messages.)

### RPC Services
Fire-and-forget messaging is not efficient for point to point communications between online peers. For these applications
Expand Down
42 changes: 21 additions & 21 deletions src/RFC-0120_Consensus.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ A coinbase transaction contained in a block MUST:
* MUST NOT have a script offset other than 0

A coinbase transaction contained in a block MAY:
* include any arbitrary 64 bytes of extra data; see [coinbase-extra]
* include any arbitrary extra data up to 256 bytes (as limited by `coinbase_output_features_extra_max_length`); see [coinbase-extra]

### Block Headers
[block headers]: #block-headers "Block headers"
Expand All @@ -146,13 +146,12 @@ Every [block header] MUST contain the following fields:
* output_mr;
* block_output_mr;
* output_smt_size;
* witness_mr;
* kernel_mr;
* kernel_mmr_size;
* total_kernel_offset;
* script_kernel_offset;
* total_script_offset;
* validator_node_mr;
* validator_size;
* validator_node_size;
* pow;
* nonce.

Expand Down Expand Up @@ -215,17 +214,17 @@ The output_mr MUST conform to the following:
* Represented as an array of unsigned 8-bit integers (bytes) in little-endian format.
* The hashing function used MUST be blake2b with a 256-bit digest.

#### Output_mmr_size
#### Output_smt_size

This is the total size of the leaves in the output Merkle mountain range.
This is the total number of leaves in the output sparse Merkle tree (Jellyfish Merkle Tree), which tracks the current UTXO set.

The Output_mmr_size MUST conform to the following:
The Output_smt_size MUST conform to the following:

* Represented as a single unsigned 64-bit integer.

#### Block_output_mr

The `block_output_mr` MUST be calculated as the Merkle mountain range tree root of all non-coinbase outputs, appended with the Merkle mountain range tree root of all coinbase outputs.
The `block_output_mr` MUST be calculated as the Merkle mountain range root of a structure that contains, as leaves, the hash of each coinbase output in canonical order, followed by the Merkle mountain range root of all non-coinbase outputs.

The block_output_mr MUST conform to the following:

Expand Down Expand Up @@ -283,18 +282,20 @@ This is the Nonce used in solving the Proof of Work.
The Nonce MUST conform to the following:

* MUST be transmitted as an unsigned 64-bit integer.
* For RandomX blocks, this MUST be 0.
* For RandomX-M (Monero merge-mined) blocks, this MUST be 0. RandomX-T blocks may use the nonce as part of the PoW solution.

#### PoW

This is the Proof of Work algorithm used to mine the block. It is used in conjunction with the Nonce.

The [PoW] MUST contain the following:

* pow_algo as an enum (0 for RandomX-M, 1 for Sha3x, 2 for RandomX-T, and 3 for C29).
* pow_data for RandomX blocks as an array of unsigned 8-bit integers (bytes) in little-endian format, containing the RandomX merge-mining Proof-of-Work data.
* The RandomX seed, stored as `randomx_key` within the RandomX block, MUST NOT have been first seen in a block with more than `max_randomx_seed_height` confirmations.
* pow_algo as an enum (0 for RandomX-M, 1 for Sha3x, 2 for RandomX-T, and 3 for Cuckaroo, also known as C29).
* pow_data for RandomX-M (Monero merge-mined) blocks as an array of unsigned 8-bit integers (bytes) in little-endian format, containing the Monero merge-mining Proof-of-Work data.
* The RandomX seed, stored as `randomx_key` within the RandomX-M block, MUST NOT have been first seen in a block with more than `max_randomx_seed_height` confirmations (3000 blocks on mainnet).
* pow_data for RandomX-T (Tari solo RandomX) blocks MUST be at most 32 bytes.
* pow_data for Sha3x blocks MUST be empty.
* pow_data for Cuckaroo blocks MUST be exactly `ceil(cuckaroo_cycle_length * cuckaroo_edge_bits / 8)` bytes (153 bytes on mainnet where cycle length=42 and edge bits=29), containing the packed cuckaroo cycle edges. The last byte MUST be zero-padded if the total bit count is not a multiple of 8.

#### Difficulty Calculation
[target difficulty]: #target-difficulty "Target Difficulty"
Expand All @@ -310,8 +311,8 @@ $$
| Symbol | Value | Description |
|-------------------------|-------------------------|---------------------------------------------------------------------------------------------------------------------|
| N | 90 | Target difficulty block window |
| T | 480 | Target block time in seconds. The value used depends on the PoW algorithm being used. |
| \\( \solvetimemax \\) | 2880 | Maximum solve time. This is six times the target time of the current PoW algorithm. |
| T | 480 (current) | Target block time in seconds per PoW algorithm. The value used depends on the PoW algorithm and the block height. On mainnet: 240s for heights 0–14,999; 360s for heights 15,000–94,999; 480s from height 95,000 onward. |
| \\( \solvetimemax \\) | 6 × T | Maximum solve time. This is six times the target time of the current PoW algorithm (e.g. 2880s when T=480, 2160s when T=360, 1440s when T=240). |
| \\( \solvetime \\) | variable | The timestamp difference in seconds between block _i_ and _i - 1_ where \\( 1 \le \solvetime \le \solvetimemax \\) |
| \\( \mathrm{D_{avg}} \\)| variable | The average difficulty of the last _N_ blocks |

Expand All @@ -324,31 +325,30 @@ $$
\tag{2}
$$

It is important to note that the two proof-of-work algorithms are calculated _independently_; i.e., if the current block uses _SHA3x_ proof of work, the block window and solve times only include _SHA3x_ blocks, and vice versa.
It is important to note that the proof-of-work algorithms are calculated _independently_; i.e., if the current block uses _SHA3x_ proof of work, the block window and solve times only include _SHA3x_ blocks. The same applies to each of the other algorithms (RandomX-M, RandomX-T, and Cuckaroo).

### FTL
[FTL]: #ftl "Future Time Limit"

The Future Time Limit (FTL) defines how far into the future a timestamp is accepted as valid. Any block with a timestamp beyond the FTL is rejected until the current time catches up.

The FTL is calculated as (T*N)/20, with T and N defined as:
- T: Target time — the ideal time that should pass between mined blocks.
- N: Block window — the number of blocks used when calculating difficulty adjustments.
The FTL is hardcoded per consensus version. On mainnet it is 540 seconds. The design formula is (T_chain*N)/20, where T_chain is the overall chain target block time (the ideal time between any two consecutive blocks, which equals the per-algorithm target time divided by the number of active PoW algorithms), and N is the difficulty block window (90). For mainnet, T_chain = 120s (e.g. 240s/2 algos or 480s/4 algos), so FTL = 120*90/20 = 540. Note that T_chain is distinct from the per-algorithm target time T used in the difficulty calculation table.

### MTP
[MTP]: #mtp "Median Time Passed"

The Median Time Passed (MTP) is the lower bound calculated by taking the median timestamp of the last _N_ blocks. Any block with a timestamp less than the MTP will be rejected.
The Median Time Passed (MTP) is the lower bound calculated by taking the median timestamp of the last `median_timestamp_count` blocks (11 blocks on mainnet). This is a separate consensus constant from the difficulty block window _N_. Any block with a timestamp less than or equal to the MTP will be rejected.

### Total accumulated proof of work

This is defined as the total accumulated proof of work done on the blockchain. Tari uses four _independent_ proof-of-work algorithms rated at different difficulties. To compare them, they are simply multiplied together into one number:
This is defined as the total accumulated proof of work done on the blockchain. Tari uses up to four _independent_ proof-of-work algorithms rated at different difficulties. To compare them, their accumulated difficulties are multiplied together into one number. The total accumulated difficulty is computed as the product of the accumulated RandomX-M, RandomX-T, and SHA3x difficulties. The accumulated Cuckaroo (C29) difficulty is additionally included in the product only when the consensus flag `include_c29_accumulated_difficulty_into_total` is set (on mainnet, this is true from block height 126,000 onward):
$$
\begin{align}
\textit{accumulated_randomxM_difficulty} * \textit{accumulated_sha3x_difficulty} * \textit{accumulated_randomxT_difficulty} * \textit{accumulated_C29_difficulty}
\textit{total} = \textit{accumulated\_randomxM} \times \textit{accumulated\_randomxT} \times \textit{accumulated\_sha3x} \quad [\times \textit{accumulated\_cuckaroo} \text{ if enabled}]
\end{align}
\tag{3}
$$
Algorithms that have not yet been activated have an accumulated difficulty of 1 (the minimum), so they do not affect the product.
This value is used to compare chain tips to determine the strongest chain.

### Transaction Ordering
Expand Down
18 changes: 10 additions & 8 deletions src/RFC-0131_Mining.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ and it proved to be a good choice in the multi-PoW scene as well.
Tari's proof-of-work mining algorithm is summarized below:

- Four mining algorithms, with an average combined target block time of 120 s, to match Monero's block interval.
- A log-weighted moving average difficulty adjustment algorithm using a window of 90 blocks.
- A linear weighted moving average (LWMA) difficulty adjustment algorithm using a window of 90 blocks.

### Tari mining hash

Expand All @@ -136,14 +136,16 @@ First, the block header is hashed with the 256-bit Blake2b hashing algorithm usi
- input Merkle root
- output Merkle root
- output Merkle mountain range size
- witness Merkle root
- block output Merkle root
- kernel Merkle root
- kernel Merkle mountain range size
- total kernel offset
- total script offset
- validator node Merkle root
- validator node Merkle mountain range size

This hash is used in both the SHA-3 and RandomX proof-of-work algorithms. The header version for the Tari Genesis
block is 1.
block is 0.

#### RandomX
##### RxM
Expand All @@ -153,7 +155,7 @@ Monero blocks that are merge-mining Tari MUST include the Tari mining hash in th
Tari also imposes the following consensus rules:
- The `seed_hash` MUST only be used for 3000 blocks, after which a block MUST be discarded if it's used again.
- The little-endian difficulty MUST be equal to or greater than the target for that block as determined by the LWMA for Tari.
- The LWMA MUST use a target time of 800 seconds.
- The LWMA MUST use a target time of 480 seconds.
- MUST set the header field PoW:pow_algo as 0 for a RxM block
- MUST encode the following data into the Pow:Pow_data field:
- Monero BlockHeader,
Expand All @@ -168,7 +170,7 @@ Using RandomX solely with Tari, the following consensus is enforced:

- The `seed_hash` MUST only be used for 3000 blocks, after which a block MUST be discarded if it's used again.
- The little-endian difficulty MUST be equal to or greater than the target for that block as determined by the LWMA for Tari.
- The LWMA MUST use a target time of 800 seconds.
- The LWMA MUST use a target time of 480 seconds.
- MUST set the header field PoW:pow_algo as 2 for an RxT block
- MUST encode the following data into the Pow:Pow_data field:
- 32 bytes extra data
Expand All @@ -195,7 +197,7 @@ Tari imposes the following consensus rules:
LWMA for Tari. The difficulty and target are related by the equation `difficulty = (2^256 - 1) / target`.
- MUST set the header field PoW:pow_algo as 1 for a Sha block.
- The PoW:pow_data field is empty
- The LWMA MUST use a target time of 800 seconds.
- The LWMA MUST use a target time of 480 seconds.

A triple hash is selected to keep the requirements on hardware miners (FPGAs, ASICs) fairly low. But we also want to
avoid making the proof-of-work immediately "NiceHashable". There are several coins that already use a single or
Expand All @@ -212,8 +214,8 @@ expectation in block explorers and elsewhere that block hashes should always sta
#### C29
Using C29 with Tari, the following consensus is enforced:

- The little-endian difficulty MUST be equal to or greater than the target for that block as determined by the LWMA for Tari.
- The LWMA MUST use a target time of 800 seconds.
- The big-endian difficulty MUST be equal to or greater than the target for that block as determined by the LWMA for Tari.
- The LWMA MUST use a target time of 480 seconds.
- MUST set the header field PoW:pow_algo as 3 for a C29 block
- MUST encode the following data into the Pow:Pow_data field:
- Cuckaroo 29 Pow data bits
Expand Down
Loading
Loading