v3 : le vote par la chaîne Ğ1, côté moteur et serveur

Le bulletin scellé (ld1: + blake2b-256 du bulletin canonique, sel de 128 bits),
l'ordre de la chaîne (bloc, puis rang de l'événement : le dernier fait foi), les
adresses SS58 comparées par clé (ld-engine, pur). trustin-access : Monnaie libre
vote par la chaîne, les groupes gérés sur le serveur ; le droit de vote se lit à
la confirmation. Serveur : bulletins en attente, confirmation sur l'indexeur
(virement, auteur, identité, membre), identité idty:<index> créée au besoin,
tâche de fond toutes les 10 s, expiration à 24 h, vote groupé en une écriture
dans les groupes gérés. Migration additive 0006. Sans LD_VOTE_ACCOUNT, le vote
par la chaîne est éteint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-10-30 20:52:47 +01:00
co-authored by Claude Opus 5.5
parent a576b68570
commit 3541e1b1a6
19 changed files with 2595 additions and 105 deletions
+5 -3
View File
@@ -109,7 +109,7 @@ pub async fn decisions(
) -> AppResult<Json<Value>> {
let group = docs::load_group(&state, &slug).await?;
docs::require_open(&state, &user, &group).await?;
let can_vote = docs::may_vote(&state, &user, &group).await?;
let can_vote = crate::ballots::access(&state, &user, &group).await?["open"].as_bool().unwrap_or(false);
#[derive(sqlx::FromRow)]
struct DocRow {
id: String,
@@ -149,9 +149,11 @@ async fn modules(state: &AppState, doc_id: &str, me: &str) -> AppResult<Vec<Modu
IFNULL(p.id = u.in_force_id, 0) AS in_force,
(p.entered_at IS NOT NULL OR p.confirmed_at IS NOT NULL OR p.origin <> 'seed') AS adopted,
EXISTS (SELECT 1 FROM votes v
WHERE v.proposal_id = p.id AND v.identity_id = ? AND v.revision = p.revision) AS voted
WHERE v.proposal_id = p.id AND v.revision = p.revision
AND (v.identity_id = ?1 OR v.ballot_id IN
(SELECT b.id FROM ballots b WHERE b.requested_by = ?1 AND b.status = 'confirmed'))) AS voted
FROM units u JOIN proposals p ON p.unit_id = u.id
WHERE u.doc_id = ? AND p.kind <> 'inertia' AND (p.id = u.in_force_id OR p.status = 'open')
WHERE u.doc_id = ?2 AND p.kind <> 'inertia' AND (p.id = u.in_force_id OR p.status = 'open')
ORDER BY u.position, u.id",
)
.bind(me)