# Amendment Architecture

[← Back to Building Amendments: Lifecycle and Core Protocol Impact](/core-dev-bootcamp/module10.md)

***

### Introduction

The amendment system is one of the most sophisticated architectural components of rippled. It allows the XRPL network to evolve in a decentralized manner by introducing new features and bug fixes while maintaining network consistency. Unlike traditional blockchain systems that require coordinated hard forks, XRPL uses a distributed consensus mechanism to activate protocol changes.

In this section, we will explore the internal architecture of the amendment system: the fundamental components, data structures, and integration with the consensus engine. We will see how rippled manages the list of amendments, tracks their state, and coordinates their activation across the network.

***

## Amendment System Overview

The amendment system in XRPL is based on several key principles:

**Distributed consensus**: Amendments can only be activated if more than 80% of the UNL validators vote in their favor for a minimum period of two weeks. This ensures that no single entity can impose changes on the network.

**Stability period**: The two-week period after the 80% threshold is exceeded allows node operators to prepare for upcoming changes. This critical window provides the necessary time to update software, test integrations, and coordinate.

**Automatic activation**: Once consensus is reached and the stability period has elapsed, the amendment is automatically activated via an `EnableAmendment` pseudo-transaction injected into the ledger by the network itself.

**Network protection**: If a node does not support an activated amendment, it automatically enters "amendment blocked" mode and stops participating in consensus until it is updated. This protects network integrity by preventing an outdated node from applying incorrect rules.

***

## AmendmentTable: The Central Manager

### AmendmentTable Interface

The `AmendmentTable` class is the public interface of the amendment system. It is defined in `src/xrpld/app/misc/AmendmentTable.h` and provides essential methods for:

**Amendment management**:

* `find(uint256 const& amendment)`: Search for an amendment by its hash
* `enable(uint256 const& amendment)`: Activate an amendment locally
* `isEnabled(uint256 const& amendment)`: Check if an amendment is enabled
* `isSupported(uint256 const& amendment)`: Check if the node supports an amendment

**Voting and validation**:

* `doVoting(NetClock::time_point closeTime, ...)`: Execute voting logic for a consensus round
* `doValidation(std::set<uint256> const& enabledAmendments)`: Determine which amendments to announce in validations
* `getDesired()`: Return all amendments that the node wishes to see enabled

**Ledger synchronization**:

* `doValidatedLedger(std::shared_ptr<ReadView const> const& ledger)`: Synchronize amendment state after ledger validation
* `hasUnsupportedEnabled()`: Check if unsupported amendments are enabled
* `firstUnsupportedExpected()`: Return when the first unsupported amendment is expected to activate

**Monitoring and inspection**:

* `getJson()`: Generate a JSON representation of all amendment states
* `trustChanged(hash_set<PublicKey> const& added, ...)`: Notify changes in the trusted validator list

### AmendmentTableImpl: The Implementation

The concrete implementation `AmendmentTableImpl` (in `src/xrpld/app/misc/detail/AmendmentTable.cpp`) manages the complete internal state of the amendment system.

**Key data structures**:

```cpp
// Map of all known amendments with their state
hash_map<uint256, AmendmentState> amendmentMap_;

// Votes from trusted validators
TrustedVotes previousTrustedVotes_;

// Last vote issued by this node
std::unique_ptr<AmendmentSet> lastVote_;

// Indicator if an unsupported amendment is enabled
bool unsupportedEnabled_;

// Time when the first unsupported amendment should activate
std::optional<NetClock::time_point> firstUnsupportedExpected_;

// Database connection for persistence
DatabaseCon& db_;

// Mutex for thread safety
std::mutex mutable mutex_;
```

**Thread safety**: All operations on amendment state are protected by a mutex. The amendment system can be queried from multiple threads simultaneously (network thread, consensus thread, RPC thread), so synchronization is critical.

***

## AmendmentState: The State of an Amendment

Each amendment in the system is represented by an `AmendmentState` structure that captures its complete state:

```cpp
struct AmendmentState {
    // Local node's vote (up, down, obsolete)
    AmendmentVote vote;

    // Is the amendment enabled in the ledger?
    bool enabled;

    // Does the node support this amendment?
    bool supported;

    // Human-readable name of the amendment
    std::string name;
};
```

### AmendmentVote: Vote Types

The `AmendmentVote` type represents the local node's position:

* **`up`**: The node votes to activate the amendment
* **`down`**: The node votes against the amendment (or has no opinion)
* **`obsolete`**: The amendment is marked as obsolete and should no longer be voted on

### Enabled vs Supported

It is crucial to understand the distinction between these two states:

**`enabled`**: The amendment is activated on the network (present in the ledger in the `sfAmendments` field). All nodes must apply the rules of this amendment, whether they support it or not.

**`supported`**: The local node has the necessary code to apply the rules of this amendment. If a node does not support an enabled amendment, it will block (amendment blocked).

***

## Amendment Registry: features.macro

All known amendments are defined in the macro file `include/xrpl/protocol/detail/features.macro`. This file uses preprocessor macros to automatically generate the necessary code.

### Declaration Format

```cpp
// Supported amendment, does not vote by default
XRPL_FEATURE(Subscriptions, Supported::yes, VoteBehavior::DefaultNo)

// Bug fix, voted by default
XRPL_FIX(fixAmendmentMajorityCalc, Supported::yes, VoteBehavior::DefaultYes)

// Retired amendment (active for more than 2 years)
XRPL_RETIRE(MultiSign)

// Obsolete amendment (should no longer be voted on)
XRPL_FEATURE(Tickets, Supported::yes, VoteBehavior::Obsolete)
```

### Amendment Categories

**Supported Amendments**: Amendments for which the node has implementation code. They are listed in `features.macro` with `Supported::yes`.

**Obsolete Amendments**: Historical amendments that are no longer relevant but must remain in the code in case they are activated. Marked with `VoteBehavior::Obsolete`.

**Retired Amendments**: Amendments that have been active for at least two years, whose pre-amendment code has been removed, and whose identifiers are deprecated. Marked with `XRPL_RETIRE`.

### Registration Process

To register a new amendment in the system:

1. Add the entry in `features.macro` with the appropriate macro (`XRPL_FEATURE` or `XRPL_FIX`)
2. Increment `numFeatures` in `include/xrpl/protocol/Feature.h`
3. The amendment will be automatically included in the feature registry and available for voting

***

## FeatureInfo: Amendment Metadata

The `FeatureInfo` structure encapsulates amendment metadata:

```cpp
struct FeatureInfo {
    // Human-readable name of the amendment
    std::string const name;

    // SHA-512Half hash of the name (unique identifier)
    uint256 const feature;

    // Default voting behavior
    VoteBehavior const vote;
};
```

### Amendment Hash Calculation

The hash of an amendment is calculated by taking the SHA-512Half of the amendment name. For example:

```
Name: "Subscriptions"
Hash: 7B73B9E8D8E6E8E8A8B8C8D8E8F8A8B8C8D8E8F8A8B8C8D8E8F8A8B8C8D8E8F8
```

This hash is used as a unique identifier throughout the system: in validations, in EnableAmendment transactions, and in the ledger's `sfAmendments` field.

***

## Integration with Consensus

The amendment system is tightly integrated with XRPL's consensus engine. This integration occurs at several levels:

### Validation Phase

When a validator creates a validation for a ledger, it includes the list of amendments it supports and wishes to see activated. This list is generated by `doValidation()` and included in the validation message broadcast to the network.

### Vote Collection

During each consensus round, the validations received from other validators are analyzed to extract their amendment votes. These votes are aggregated into the `TrustedVotes` structure which maintains:

* The total number of trusted validations received
* The number of votes for each specific amendment
* A timeout mechanism to expire old votes

### Threshold Calculation

The system calculates whether an amendment has exceeded the required threshold (more than 80% of UNL validators) using the `AmendmentSet` class which:

1. Aggregates all collected votes
2. Calculates the threshold based on the number of trusted validators
3. Determines which amendments pass the threshold
4. Generates the necessary actions (tfGotMajority, tfLostMajority, or activation)

### Application to Ledger

Amendment decisions (got majority, lost majority, or enable) are applied to the ledger via pseudo-transactions that modify the `sfMajorities` and `sfAmendments` fields of the global ledger object.

***

## Database Persistence

The amendment system persists critical data in the node's database.

### FeatureVotes Table

The `FeatureVotes` table stores the local node's votes:

```sql
CREATE TABLE FeatureVotes (
    Hash        CHAR(64) PRIMARY KEY,
    Name        TEXT,
    Vote        INTEGER,
    VoteTime    INTEGER
);
```

**Fields**:

* `Hash`: The amendment hash (in hexadecimal)
* `Name`: The human-readable name of the amendment
* `Vote`: The vote value (0=down, 1=up, 2=obsolete)
* `VoteTime`: Timestamp of the vote (for history)

### Persistence Operations

**`persistVote()`**: Records the current vote of an amendment in the database. This function is called when an administrator changes the vote via RPC or when the node initializes its votes at startup.

**`readAmendments()`**: Reads previously recorded votes from the database at node startup. Uses a SQL window function to retrieve only the most recent vote for each amendment.

***

## Special Cases and Edge Cases

### Low Number of Validators

If the network has very few UNL validators, the threshold calculation ensures that at least 1 vote is required. The threshold is calculated as:

```cpp
threshold = max(1, (trustedValidations * 80) / 100)
```

This avoids situations where a single validator could activate an amendment in a test network with a single validator.

### Network Partition

In case of network partition, amendments may not reach the required threshold if validators are divided. The normal consensus process handles these cases by not activating the amendment until consensus is restored.

### Standalone Mode

In standalone mode (a single node without network), the node can still execute voting logic, but since there are no other validators, no amendment will ever be activated by consensus. Amendments can be manually enabled via admin commands for testing.

***

## Source Code References

The amendment system components are distributed across multiple files:

**Interface and implementation**:

* `src/xrpld/app/misc/AmendmentTable.h` - Public interface
* `src/xrpld/app/misc/detail/AmendmentTable.cpp` - Complete implementation

**Feature registry**:

* `include/xrpl/protocol/detail/features.macro` - Definitions of all amendments
* `include/xrpl/protocol/Feature.h` - Declarations and constants
* `src/libxrpl/protocol/Feature.cpp` - Code generated from macros

**Persistence**:

* `src/xrpld/app/rdb/detail/Wallet.cpp` - Functions `voteAmendment()` and `readAmendments()`
* `src/xrpld/app/rdb/Wallet.h` - Declarations of persistence functions

**Consensus integration**:

* `src/xrpld/app/consensus/RCLConsensus.cpp` - Integration with consensus
* `src/xrpld/consensus/Consensus.h` - Generic consensus engine


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.xrpl-commons.org/core-dev-bootcamp/module10/amendment-architecture.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
