Skip to main content

tempo_contracts/precompiles/
validator_config_v2.rs

1use alloc::string::String;
2
3pub use IValidatorConfigV2::{
4    IValidatorConfigV2Errors as ValidatorConfigV2Error,
5    IValidatorConfigV2Events as ValidatorConfigV2Event,
6};
7
8crate::sol! {
9    /// Validator Config V2 interface for managing consensus validators with append-only,
10    /// delete-once semantics.
11    ///
12    /// V2 uses an append-only design that eliminates the need for historical state access
13    /// during node recovery. Validators are immutable after creation and can only be deleted once.
14    ///
15    /// Key differences from V1:
16    /// - `active` bool replaced by `addedAtHeight` and `deactivatedAtHeight`
17    /// - No `updateValidator` - validators are immutable after creation
18    /// - Requires Ed25519 signature on `addValidator` to prove key ownership
19    /// - Both address and public key must be unique across all validators (including deleted)
20    #[derive(Debug, PartialEq, Eq)]
21    #[sol(abi)]
22    interface IValidatorConfigV2 {
23        /// Validator information
24        struct Validator {
25            bytes32 publicKey;
26            address validatorAddress;
27            string ingress;
28            string egress;
29            address feeRecipient;
30            uint64 index;
31            uint64 addedAtHeight;
32            uint64 deactivatedAtHeight;
33        }
34
35        // =====================================================================
36        // View functions
37        // =====================================================================
38
39        /// Get only active validators (deactivatedAtHeight == 0)
40        function getActiveValidators() external view returns (Validator[] memory validators);
41
42        /// Get the block height at which the contract was initialized
43        function getInitializedAtHeight() external view returns (uint64);
44
45        /// Get the contract owner
46        function owner() external view returns (address);
47
48        /// Get total count of validators ever added (including deactivated)
49        function validatorCount() external view returns (uint64);
50
51        /// Get validator by index
52        function validatorByIndex(uint64 index) external view returns (Validator memory);
53
54        /// Get validator by address
55        function validatorByAddress(address validatorAddress) external view returns (Validator memory);
56
57        /// Get validator by public key
58        function validatorByPublicKey(bytes32 publicKey) external view returns (Validator memory);
59
60        /// Get the epoch for next network identity rotation (full DKG ceremony)
61        function getNextNetworkIdentityRotationEpoch() external view returns (uint64);
62
63        /// Check if V2 has been initialized
64        function isInitialized() external view returns (bool);
65
66        // =====================================================================
67        // Mutate functions
68        // =====================================================================
69
70        /// Add a new validator (owner only)
71        function addValidator(
72            address validatorAddress,
73            bytes32 publicKey,
74            string calldata ingress,
75            string calldata egress,
76            address feeRecipient,
77            bytes calldata signature
78        ) external returns (uint64 index);
79
80        /// Deactivate a validator (owner or validator)
81        function deactivateValidator(uint64 idx) external;
82
83        /// Rotate a validator to new identity (owner or validator)
84        function rotateValidator(
85            uint64 idx,
86            bytes32 publicKey,
87            string calldata ingress,
88            string calldata egress,
89            bytes calldata signature
90        ) external;
91
92        /// Update fee recipient.
93        function setFeeRecipient(
94            uint64 idx,
95            address feeRecipient
96        ) external;
97
98        /// Update IP addresses (owner or validator)
99        function setIpAddresses(
100            uint64 idx,
101            string calldata ingress,
102            string calldata egress
103        ) external;
104
105        /// Transfer validator ownership to new address (owner or validator)
106        function transferValidatorOwnership(
107            uint64 idx,
108            address newAddress
109        ) external;
110
111        /// Transfer contract ownership (owner only)
112        function transferOwnership(address newOwner) external;
113
114        /// Set the epoch for next network identity rotation via full DKG ceremony (owner only)
115        function setNetworkIdentityRotationEpoch(uint64 epoch) external;
116
117        /// Migrate a single validator from V1 (owner only)
118        function migrateValidator(uint64 idx) external;
119
120        /// Initialize V2 after migration (owner only)
121        function initializeIfMigrated() external;
122
123        // =====================================================================
124        // Events
125        // =====================================================================
126
127        event ValidatorAdded(uint64 indexed index, address indexed validatorAddress, bytes32 publicKey, string ingress, string egress, address feeRecipient);
128        event ValidatorDeactivated(uint64 indexed index, address indexed validatorAddress);
129        event ValidatorRotated(
130            uint64 indexed index,
131            uint64 indexed deactivatedIndex,
132            address indexed validatorAddress,
133            bytes32 oldPublicKey,
134            bytes32 newPublicKey,
135            string ingress,
136            string egress,
137            address caller
138        );
139        event FeeRecipientUpdated(uint64 indexed index, address feeRecipient, address caller);
140        event IpAddressesUpdated(uint64 indexed index, string ingress, string egress, address caller);
141        event ValidatorOwnershipTransferred(uint64 indexed index, address indexed oldAddress, address indexed newAddress, address caller);
142        event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
143        event ValidatorMigrated(uint64 indexed index, address indexed validatorAddress, bytes32 publicKey);
144        event NetworkIdentityRotationEpochSet(uint64 indexed previousEpoch, uint64 indexed nextEpoch);
145        event Initialized(uint64 height);
146        event SkippedValidatorMigration(uint64 indexed index, address indexed validatorAddress, bytes32 publicKey);
147
148        // =====================================================================
149        // Errors
150        // =====================================================================
151
152        error AlreadyInitialized();
153        error IngressAlreadyExists(string ingress);
154        error EmptyV1ValidatorSet();
155        error InvalidMigrationIndex();
156        error InvalidOwner();
157        error InvalidPublicKey();
158        error InvalidSignature();
159        error InvalidSignatureFormat();
160        error InvalidValidatorAddress();
161        error MigrationNotComplete();
162        error NotInitialized();
163        error NotIp(string input, string backtrace);
164        error NotIpPort(string input, string backtrace);
165        error PublicKeyAlreadyExists();
166        error Unauthorized();
167        error AddressAlreadyHasValidator();
168        error ValidatorAlreadyDeactivated();
169        error ValidatorNotFound();
170    }
171}
172
173impl ValidatorConfigV2Error {
174    pub const fn unauthorized() -> Self {
175        Self::Unauthorized(IValidatorConfigV2::Unauthorized {})
176    }
177
178    pub const fn address_already_has_validator() -> Self {
179        Self::AddressAlreadyHasValidator(IValidatorConfigV2::AddressAlreadyHasValidator {})
180    }
181
182    pub const fn public_key_already_exists() -> Self {
183        Self::PublicKeyAlreadyExists(IValidatorConfigV2::PublicKeyAlreadyExists {})
184    }
185
186    pub const fn validator_not_found() -> Self {
187        Self::ValidatorNotFound(IValidatorConfigV2::ValidatorNotFound {})
188    }
189
190    pub const fn validator_already_deactivated() -> Self {
191        Self::ValidatorAlreadyDeactivated(IValidatorConfigV2::ValidatorAlreadyDeactivated {})
192    }
193
194    pub const fn invalid_public_key() -> Self {
195        Self::InvalidPublicKey(IValidatorConfigV2::InvalidPublicKey {})
196    }
197
198    pub const fn invalid_signature() -> Self {
199        Self::InvalidSignature(IValidatorConfigV2::InvalidSignature {})
200    }
201
202    pub const fn invalid_signature_format() -> Self {
203        Self::InvalidSignatureFormat(IValidatorConfigV2::InvalidSignatureFormat {})
204    }
205
206    pub const fn invalid_validator_address() -> Self {
207        Self::InvalidValidatorAddress(IValidatorConfigV2::InvalidValidatorAddress {})
208    }
209
210    pub const fn not_initialized() -> Self {
211        Self::NotInitialized(IValidatorConfigV2::NotInitialized {})
212    }
213
214    pub const fn already_initialized() -> Self {
215        Self::AlreadyInitialized(IValidatorConfigV2::AlreadyInitialized {})
216    }
217
218    pub const fn migration_not_complete() -> Self {
219        Self::MigrationNotComplete(IValidatorConfigV2::MigrationNotComplete {})
220    }
221
222    pub const fn empty_v1_validator_set() -> Self {
223        Self::EmptyV1ValidatorSet(IValidatorConfigV2::EmptyV1ValidatorSet {})
224    }
225
226    pub const fn invalid_migration_index() -> Self {
227        Self::InvalidMigrationIndex(IValidatorConfigV2::InvalidMigrationIndex {})
228    }
229
230    pub const fn invalid_owner() -> Self {
231        Self::InvalidOwner(IValidatorConfigV2::InvalidOwner {})
232    }
233
234    pub fn not_ip(input: String, backtrace: String) -> Self {
235        Self::NotIp(IValidatorConfigV2::NotIp { input, backtrace })
236    }
237
238    pub fn not_ip_port(input: String, backtrace: String) -> Self {
239        Self::NotIpPort(IValidatorConfigV2::NotIpPort { input, backtrace })
240    }
241
242    pub fn ingress_already_exists(ingress: String) -> Self {
243        Self::IngressAlreadyExists(IValidatorConfigV2::IngressAlreadyExists { ingress })
244    }
245}