Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ commit_out.txt
# Rust build artifacts
target/
*.rs.bk
/contracts/oracles/test_snapshots/
/contracts/oracles/test_snapshots/
/full_structure3.txt
56 changes: 54 additions & 2 deletions contracts/validators/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
//! | `get_validator` | Anyone (read-only) |
//! | `is_validator` | Anyone (read-only) |
//! | `validator_count` | Anyone (read-only) |
//! | `list_validators` | Anyone (read-only) |
//! | `is_validators_paused` | Anyone (read-only) |
//! | `admin` | Anyone (read-only) |
//! | `version` | Anyone (read-only) |
Expand All @@ -44,7 +45,7 @@ mod types;
pub use errors::ValidatorError;
pub use types::{DataKey, ValidatorInfo};

use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Env};
use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Env, Vec};

/// The Validators contract.
///
Expand Down Expand Up @@ -107,6 +108,9 @@ impl ValidatorsContract {
env.storage()
.persistent()
.set(&DataKey::ValidatorCount, &0u32);
env.storage()
.persistent()
.set(&DataKey::ValidatorList, &Vec::<Address>::new(&env));
env.storage().instance().set(&DataKey::MinStake, &min_stake);
env.storage().instance().set(&DataKey::MaxStake, &max_stake);

Expand Down Expand Up @@ -202,6 +206,15 @@ impl ValidatorsContract {
env.storage()
.persistent()
.set(&DataKey::Validator(validator), &info);
let mut validators: Vec<Address> = env
.storage()
.persistent()
.get(&DataKey::ValidatorList)
.unwrap_or_else(|| Vec::new(&env));
validators.push_back(info.address.clone());
env.storage()
.persistent()
.set(&DataKey::ValidatorList, &validators);
env.storage()
.persistent()
.set(&DataKey::ValidatorCount, &new_count);
Expand Down Expand Up @@ -244,7 +257,7 @@ impl ValidatorsContract {
Self::assert_initialized(&env)?;
Self::assert_not_paused(&env)?;

let key = DataKey::Validator(validator);
let key = DataKey::Validator(validator.clone());
if !env.storage().persistent().has(&key) {
return Err(ValidatorError::ValidatorNotFound);
}
Expand All @@ -254,6 +267,21 @@ impl ValidatorsContract {

env.storage().persistent().remove(&key);

let registered: Vec<Address> = env
.storage()
.persistent()
.get(&DataKey::ValidatorList)
.unwrap_or_else(|| Vec::new(&env));
let mut remaining = Vec::new(&env);
for address in registered.iter() {
if address != validator {
remaining.push_back(address);
}
}
env.storage()
.persistent()
.set(&DataKey::ValidatorList, &remaining);

let count: u32 = env
.storage()
.persistent()
Expand Down Expand Up @@ -743,6 +771,30 @@ impl ValidatorsContract {
.unwrap_or(0)
}

/// Return a page of registered validator addresses in registration order.
///
/// `start` is a zero-based offset and `limit` is the maximum number of
/// addresses to return. Deregistered validators are omitted; a validator
/// that registers again is appended to the end of the list.
pub fn list_validators(env: Env, start: u32, limit: u32) -> Vec<Address> {
let validators: Vec<Address> = env
.storage()
.persistent()
.get(&DataKey::ValidatorList)
.unwrap_or_else(|| Vec::new(&env));
let mut page = Vec::new(&env);
let mut index = start;

while index < validators.len() && page.len() < limit {
if let Some(address) = validators.get(index) {
page.push_back(address);
}
index += 1;
}

page
}

/// Return whether the validators subsystem is currently paused.
///
/// # What it does
Expand Down
2 changes: 2 additions & 0 deletions contracts/validators/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub enum DataKey {
MaxStake,
/// Whether the validator is participating in an active resolution round.
ActiveRound(soroban_sdk::Address),
/// Ordered list of currently registered validator addresses.
ValidatorList,
}

/// On-chain representation of a registered validator.
Expand Down
29 changes: 29 additions & 0 deletions contracts/validators/tests/auth_boundary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,35 @@ fn test_double_register_fails() {
assert!(result.is_err(), "duplicate registration must fail");
}

#[test]
fn test_list_validators_preserves_order_and_paginates() {
let env = Env::default();
let ts = setup_with_validator(&env);
let second = Address::generate(&env);
let third = Address::generate(&env);

ts.client.register_validator(&second, &INIT_STAKE);
ts.client.register_validator(&third, &INIT_STAKE);

let first_page = ts.client.list_validators(&0, &2);
assert_eq!(first_page.len(), 2);
assert_eq!(first_page.get(0).unwrap(), ts.validator);
assert_eq!(first_page.get(1).unwrap(), second);

let second_page = ts.client.list_validators(&1, &2);
assert_eq!(second_page.len(), 2);
assert_eq!(second_page.get(0).unwrap(), second);
assert_eq!(second_page.get(1).unwrap(), third);
assert_eq!(ts.client.list_validators(&3, &2).len(), 0);
assert_eq!(ts.client.list_validators(&0, &0).len(), 0);

ts.client.deregister_validator(&second);
let remaining = ts.client.list_validators(&0, &3);
assert_eq!(remaining.len(), 2);
assert_eq!(remaining.get(0).unwrap(), ts.validator);
assert_eq!(remaining.get(1).unwrap(), third);
}

/// Deregistering an unknown address should return ValidatorNotFound.
#[test]
fn test_deregister_unknown_fails() {
Expand Down
14 changes: 7 additions & 7 deletions crates/hermes-errors/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Three layers ensure single-source-of-truth:

### For End Users (Contract Developers)

See `CONTRIBUTING_ERRORS.md` for the workflow of adding/modifying errors.
See [CONTRIBUTING_ERRORS.md](../../docs/impl/CONTRIBUTING_ERRORS.md) for the workflow of adding/modifying errors.

TL;DR to add a new error:

Expand All @@ -72,7 +72,7 @@ cargo build # Regenerate contract files

1. Registry is already defined in `src/lib.rs`
2. Code generation is in `crates/hermes-codegen/`
3. Migrate contracts one at a time using `MIGRATION_ERROR_SYNC.md`
3. Migrate contracts one at a time using [MIGRATION_ERROR_SYNC.md](../../docs/impl/MIGRATION_ERROR_SYNC.md)

## Code Ranges

Expand Down Expand Up @@ -219,7 +219,7 @@ For existing contracts not yet using the registry:
5. Regenerate error files
6. Test and commit

See `MIGRATION_ERROR_SYNC.md` for detailed steps.
See [MIGRATION_ERROR_SYNC.md](../../docs/impl/MIGRATION_ERROR_SYNC.md) for detailed steps.

## Future Enhancements

Expand All @@ -232,7 +232,7 @@ See `MIGRATION_ERROR_SYNC.md` for detailed steps.

## Contributing

1. Read `CONTRIBUTING_ERRORS.md`
1. Read [CONTRIBUTING_ERRORS.md](../../docs/impl/CONTRIBUTING_ERRORS.md)
2. Edit `src/lib.rs` with new error definitions
3. Run `cargo test`
4. Rebuild affected contracts
Expand All @@ -245,6 +245,6 @@ Same as Hermes project.
## Questions?

See:
- `ERROR_DOCS_SYNC.md` — Overall architecture and benefits
- `MIGRATION_ERROR_SYNC.md` — Step-by-step migration guide
- `CONTRIBUTING_ERRORS.md` — Adding/modifying errors
- [ERROR_DOCS_SYNC.md](../../docs/impl/ERROR_DOCS_SYNC.md) — Overall architecture and benefits
- [MIGRATION_ERROR_SYNC.md](../../docs/impl/MIGRATION_ERROR_SYNC.md) — Step-by-step migration guide
- [CONTRIBUTING_ERRORS.md](../../docs/impl/CONTRIBUTING_ERRORS.md) — Adding/modifying errors
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ A complete, production-ready specification and implementation roadmap for a **Pl
- Cost-benefit analysis (1+ prevented attack = ROI)
- Success criteria & metrics

### 3. **PLATFORM_EMERGENCY_HALT_DESIGN.md** (Technical Specification)
### 3. **[PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md)** (Technical Specification)
- **12 pages**
- Complete architecture with diagrams
- Data structures & storage schema
Expand Down Expand Up @@ -234,13 +234,13 @@ Final Verification & Resume

### For Full Technical Understanding (2-3 hours)
1. Read: EMERGENCY_HALT_SUMMARY.md
2. Read: PLATFORM_EMERGENCY_HALT_DESIGN.md
2. Read: [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md)
3. Read: EMERGENCY_HALT_INTEGRATION_GUIDE.md

### For Implementation Work (ongoing)
1. Bookmark: EMERGENCY_HALT_IMPLEMENTATION_PLAN.md (current phase)
2. Reference: EMERGENCY_HALT_INTEGRATION_GUIDE.md
3. Use: Code examples and patterns from PLATFORM_EMERGENCY_HALT_DESIGN.md
3. Use: Code examples and patterns from [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md)

### For Operational Readiness
1. Study: EMERGENCY_HALT_QUICK_REFERENCE.md
Expand Down
18 changes: 9 additions & 9 deletions EMERGENCY_HALT_INDEX.md → docs/impl/EMERGENCY_HALT_INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This directory contains comprehensive documentation for implementing a **Platfor

---

### 2. **PLATFORM_EMERGENCY_HALT_DESIGN.md**
### 2. **[PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md)**
**Complete technical specification**

- Architecture and design patterns
Expand Down Expand Up @@ -109,21 +109,21 @@ This directory contains comprehensive documentation for implementing a **Platfor

**Engineering Lead**
1. Start: EMERGENCY_HALT_SUMMARY.md (entire document)
2. Then: PLATFORM_EMERGENCY_HALT_DESIGN.md (Architecture section)
2. Then: [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md) (Architecture section)
3. Then: EMERGENCY_HALT_IMPLEMENTATION_PLAN.md (full roadmap)

**Implementing Engineer**
1. Start: EMERGENCY_HALT_IMPLEMENTATION_PLAN.md (Phase for your task)
2. Reference: EMERGENCY_HALT_INTEGRATION_GUIDE.md (ongoing)
3. Check: PLATFORM_EMERGENCY_HALT_DESIGN.md (specific details)
3. Check: [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md) (specific details)

**Platform Operator**
1. Learn: EMERGENCY_HALT_QUICK_REFERENCE.md (API & Workflow sections)
2. Practice: Common Incident Scenarios section
3. Reference: Troubleshooting Guide (when issues occur)

**Security Reviewer**
1. Start: PLATFORM_EMERGENCY_HALT_DESIGN.md (Security Considerations)
1. Start: [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md) (Security Considerations)
2. Then: EMERGENCY_HALT_INTEGRATION_GUIDE.md (Cross-Contract Interface)
3. Review: Implementation code for auth patterns

Expand All @@ -144,13 +144,13 @@ This directory contains comprehensive documentation for implementing a **Platfor
→ EMERGENCY_HALT_INTEGRATION_GUIDE.md - Integration Checklist for Each Subsystem

**"What's the exact API?"**
→ PLATFORM_EMERGENCY_HALT_DESIGN.md - Entrypoints section
→ [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md) - Entrypoints section

**"How long will halt take?"**
→ EMERGENCY_HALT_SUMMARY.md - Implementation Timeline (~4 weeks)

**"What are the error cases?"**
→ PLATFORM_EMERGENCY_HALT_DESIGN.md - Error Handling section
→ [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md) - Error Handling section

**"What tests should I write?"**
→ EMERGENCY_HALT_INTEGRATION_GUIDE.md - Testing Pyramid
Expand All @@ -166,12 +166,12 @@ This directory contains comprehensive documentation for implementing a **Platfor
- [ ] Read EMERGENCY_HALT_SUMMARY.md
- [ ] Discuss design with team
- [ ] Get stakeholder approval
- [ ] Review PLATFORM_EMERGENCY_HALT_DESIGN.md in detail
- [ ] Review [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md) in detail
- [ ] Assign phase leads

### Phase 1: EHC Contract (Week 1-2)
- [ ] Follow Phase 1 in EMERGENCY_HALT_IMPLEMENTATION_PLAN.md
- [ ] Reference PLATFORM_EMERGENCY_HALT_DESIGN.md for details
- [ ] Reference [PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md) for details
- [ ] Use EMERGENCY_HALT_INTEGRATION_GUIDE.md for storage schema
- [ ] Write tests per Testing Pyramid in guide

Expand Down Expand Up @@ -247,7 +247,7 @@ A: Yes - see Phased Rollout in EMERGENCY_HALT_IMPLEMENTATION_PLAN.md
/workspaces/hermes/
├── EMERGENCY_HALT_INDEX.md (this file)
├── EMERGENCY_HALT_SUMMARY.md (executive overview)
├── PLATFORM_EMERGENCY_HALT_DESIGN.md (technical spec)
├── ../design/PLATFORM_EMERGENCY_HALT_DESIGN.md (technical spec)
├── EMERGENCY_HALT_IMPLEMENTATION_PLAN.md (phased roadmap)
├── EMERGENCY_HALT_INTEGRATION_GUIDE.md (integration reference)
├── EMERGENCY_HALT_QUICK_REFERENCE.md (ops guide)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ A: Not recommended. Use testnet for all drills. Emergency halt should only be us

## Additional Resources

- **Full Design Doc**: `/PLATFORM_EMERGENCY_HALT_DESIGN.md`
- **Full Design Doc**: `../design/PLATFORM_EMERGENCY_HALT_DESIGN.md`
- **Implementation Plan**: `/EMERGENCY_HALT_IMPLEMENTATION_PLAN.md`
- **Integration Guide**: `/EMERGENCY_HALT_INTEGRATION_GUIDE.md`
- **Contract Code**: `/contracts/emergency-halt/src/`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ Each contract adds three components:
- [ ] Event emission system

### Documentation
- [ ] **PLATFORM_EMERGENCY_HALT_DESIGN.md** - Full architecture spec
- [ ] **[PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md)** - Full architecture spec
- [ ] **EMERGENCY_HALT_IMPLEMENTATION_PLAN.md** - Phased rollout plan
- [ ] **EMERGENCY_HALT_INTEGRATION_GUIDE.md** - Technical integration guide
- [ ] **EMERGENCY_HALT_QUICK_REFERENCE.md** - Operations & incident response guide
Expand Down Expand Up @@ -385,7 +385,7 @@ A: Use `health_check()` query (no auth required). Returns pause status of all su

All details available in accompanying documents:

1. **PLATFORM_EMERGENCY_HALT_DESIGN.md**
1. **[PLATFORM_EMERGENCY_HALT_DESIGN.md](../design/PLATFORM_EMERGENCY_HALT_DESIGN.md)**
- Complete architecture specification
- Data structures and storage schema
- Entrypoints and error handling
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
**New to this solution?** Start here:
1. Read [`SOLUTION_SUMMARY.md`](./SOLUTION_SUMMARY.md) (5 min) — Problem & solution overview
2. Read [`ERROR_DOCS_SYNC.md`](./ERROR_DOCS_SYNC.md) (10 min) — Architecture details
3. See [`crates/hermes-errors/README.md`](./crates/hermes-errors/README.md) — Registry guide
3. See [`crates/hermes-errors/README.md`](../../crates/hermes-errors/README.md) — Registry guide

**Adding a new error?** Go to:
→ [`CONTRIBUTING_ERRORS.md`](./CONTRIBUTING_ERRORS.md) — Complete workflow
Expand Down Expand Up @@ -208,9 +208,9 @@ git commit -m "feat(analytics): add InvalidTimeRange error"

#### 📚 Registry API Reference

**Read:** [`crates/hermes-errors/README.md`](./crates/hermes-errors/README.md)
**Read:** [`crates/hermes-errors/README.md`](../../crates/hermes-errors/README.md)

**Plus:** [`crates/hermes-errors/src/lib.rs`](./crates/hermes-errors/src/lib.rs) (docstrings in code)
**Plus:** [`crates/hermes-errors/src/lib.rs`](../../crates/hermes-errors/src/lib.rs) (docstrings in code)

**Topics:**
- `ErrorDefinition` struct API
Expand Down Expand Up @@ -292,7 +292,7 @@ git commit -m "feat(analytics): add InvalidTimeRange error"
2. [`CONTRIBUTING_ERRORS.md`](./CONTRIBUTING_ERRORS.md) (20 min)
- Learn how to add/modify errors

3. [`crates/hermes-errors/README.md`](./crates/hermes-errors/README.md) (10 min)
3. [`crates/hermes-errors/README.md`](../../crates/hermes-errors/README.md) (10 min)
- Understand registry API

4. **Hands-on:** Add a test error to the registry
Expand Down Expand Up @@ -329,7 +329,7 @@ git commit -m "feat(analytics): add InvalidTimeRange error"
2. [`ERROR_DOCS_SYNC.md`](./ERROR_DOCS_SYNC.md) (30 min)
- Deep architecture review

3. [`crates/hermes-errors/README.md`](./crates/hermes-errors/README.md) (20 min)
3. [`crates/hermes-errors/README.md`](../../crates/hermes-errors/README.md) (20 min)
- Registry design review

4. Code review:
Expand Down Expand Up @@ -442,9 +442,9 @@ A: Foundation complete (Week 0), migrate 1 contract/week (4 weeks total).
| Architecture & design | [`ERROR_DOCS_SYNC.md`](./ERROR_DOCS_SYNC.md) |
| Adding errors | [`CONTRIBUTING_ERRORS.md`](./CONTRIBUTING_ERRORS.md) |
| Migrating contracts | [`MIGRATION_ERROR_SYNC.md`](./MIGRATION_ERROR_SYNC.md) |
| Registry API | [`crates/hermes-errors/README.md`](./crates/hermes-errors/README.md) |
| Code reference | [`crates/hermes-errors/src/lib.rs`](./crates/hermes-errors/src/lib.rs) |
| Code generation | [`crates/hermes-codegen/src/lib.rs`](./crates/hermes-codegen/src/lib.rs) |
| Registry API | [`crates/hermes-errors/README.md`](../../crates/hermes-errors/README.md) |
| Code reference | [`crates/hermes-errors/src/lib.rs`](../../crates/hermes-errors/src/lib.rs) |
| Code generation | [`crates/hermes-codegen/src/lib.rs`](../../crates/hermes-codegen/src/lib.rs) |

---

Expand Down Expand Up @@ -474,7 +474,7 @@ A: Foundation complete (Week 0), migrate 1 contract/week (4 weeks total).
| [`ERROR_DOCS_SYNC.md`](./ERROR_DOCS_SYNC.md) | ~600 | Architecture & design |
| [`MIGRATION_ERROR_SYNC.md`](./MIGRATION_ERROR_SYNC.md) | ~800 | Step-by-step guide |
| [`CONTRIBUTING_ERRORS.md`](./CONTRIBUTING_ERRORS.md) | ~700 | Error workflow |
| [`crates/hermes-errors/README.md`](./crates/hermes-errors/README.md) | ~300 | Registry guide |
| [`crates/hermes-errors/README.md`](../../crates/hermes-errors/README.md) | ~300 | Registry guide |
| [`ERROR_DOCUMENTATION_INDEX.md`](./ERROR_DOCUMENTATION_INDEX.md) | ~500 | This file (navigation) |
| **Total Documentation** | **~3,250 lines** | Complete reference |

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading
Loading