6. Chi può fare cosa
Come le chiavi di un palazzo: il portiere ha quella dell'ingresso, l'idraulico quella dei locali tecnici. Nessuno può aprire una porta che non è la sua.
AccessControl di OpenZeppelin gestisce i ruoli: un ruolo è un nome (calcolato con keccak256) e un elenco di indirizzi che lo possiedono. Il modificatore onlyRole blocca chi non ce l'ha. Nel registro di Pietre di Vita i ruoli sono PRODUTTORE_ROLE, FRANTOIO_ROLE, LABORATORIO_ROLE e IMBOTTIGLIATORE_ROLE; qui ne usiamo due.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
contract PassiMinimi is AccessControl {
bytes32 public constant FRANTOIO_ROLE = keccak256("FRANTOIO_ROLE");
bytes32 public constant LABORATORIO_ROLE = keccak256("LABORATORIO_ROLE");
enum Fase { Raccolta, Molitura, Analisi }
struct Passo { Fase fase; address attore; uint64 timestamp; bytes32 docHash; }
Passo[] private _passi;
error FaseFuoriOrdine(Fase fase);
constructor() {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_registra(Fase.Raccolta, bytes32(0));
}
function molisci(bytes32 docHash) external onlyRole(FRANTOIO_ROLE) { _avanza(Fase.Molitura, docHash); }
function analizza(bytes32 docHash) external onlyRole(LABORATORIO_ROLE) { _avanza(Fase.Analisi, docHash); }
function _avanza(Fase fase, bytes32 docHash) private {
Fase ultima = _passi[_passi.length - 1].fase;
if (uint8(fase) != uint8(ultima) + 1) revert FaseFuoriOrdine(fase);
_registra(fase, docHash);
}
function _registra(Fase fase, bytes32 docHash) private {
_passi.push(Passo(fase, msg.sender, uint64(block.timestamp), docHash));
}
}Riga per riga
- Le due costanti sono i nomi dei ruoli;
keccak256li trasforma in un numero fisso. Passoè una riga del registro: fase, chi l'ha scritta, quando, impronta del documento._passiè l'elenco dei passi, solo in aggiunta;errordefinisce il messaggio di errore usato se l'ordine è sbagliato.- Il costruttore assegna l'amministratore (chi dà e toglie i ruoli) e registra la Raccolta come primo passo.
moliscieanalizzapossono essere chiamate solo da chi ha il ruolo giusto (onlyRole)._avanzalegge l'ultima fase scritta: la nuova deve essere esattamente la successiva, altrimentirevertannulla tutto._registraaggiunge il passo con chi lo firma (msg.sender) e l'ora (block.timestamp).
Il contratto completo fa lo stesso con più fasi: controlla il ruolo (RuoloNonAutorizzato) e l'ordine (FaseFuoriOrdine), e per l'imbottigliamento usa una funzione a parte, imbottiglia, che fissa anche il numero di bottiglie una sola volta.
Per dare un ruolo, l'amministratore chiama grantRole(FRANTOIO_ROLE, indirizzo): è quello che fa lo script di installazione della demo.
Provalo tu: la modalità prova dell'Area filiera
Nella pagina Area filiera chiunque può percorrere la filiera senza password. Si scelgono i quattro ruoli, uno alla volta (Agricoltore, Frantoio, Laboratorio, Imbottigliatore), e si registra il passo di ciascuno su un lotto di prova tutto proprio, con un codice del tipo PROVA-K7Q2. Un contatore dice sempre a che punto si è ("Sei al passo 3 di 5") e un pulsante grande porta al ruolo successivo. Alla fine si apre la propria bottiglia: stessa pagina pubblica e stesso QR delle bottiglie vere, con la storia verificata sulla catena.
Le scritture sulla catena le paga il portafoglio del server, quindi la prova ha dei limiti pensati per durare nel tempo:
- fino a 3 percorsi di prova al giorno per ogni connessione, e un numero limitato di richieste al minuto;
- un tetto giornaliero di 150 transazioni di prova per tutti i visitatori insieme (ogni percorso ne prenota 4: lotto, molitura, analisi, imbottigliamento);
- se un portafoglio scende sotto una soglia (0,5 POL), la prova si mette in pausa e riparte quando il portafoglio è stato ricaricato. Oltre i limiti, la pagina invita a riprovare il giorno dopo.
Il lotto di prova è separato dai lotti d'esempio: il visitatore scrive solo sul proprio lotto, con una sessione distinta da quella dei ruoli veri, e il lotto non compare in nessun elenco pubblico (si ritrova con il proprio link). Il referto di laboratorio è un PDF di esempio generato dal server, con dati di fantasia. Tutto avviene su rete di prova.
Prova tu
Aggiungi un terzo ruolo, IMBOTTIGLIATORE_ROLE, e una fase Imbottigliamento dopo Analisi con la sua funzione. Ricompila: se hai ricopiato lo schema di molisci, ci metti pochi minuti.
Cosa hai imparato
- Un ruolo è un nome a cui assegniamo degli indirizzi; onlyRole blocca gli altri.
- L'ordine delle fasi è controllato dal contratto, non dalla buona volontà.
- Un passo scritto non si cancella: il registro cresce soltanto.