Tracciabilità dell'olio, passo passo

6. Chi può fare cosa

Obiettivo: Limitare ogni fase al ruolo giusto e imporre l'ordine delle fasi direttamente nel contratto.

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

  1. Le due costanti sono i nomi dei ruoli; keccak256 li trasforma in un numero fisso.
  2. Passo è una riga del registro: fase, chi l'ha scritta, quando, impronta del documento.
  3. _passi è l'elenco dei passi, solo in aggiunta; error definisce il messaggio di errore usato se l'ordine è sbagliato.
  4. Il costruttore assegna l'amministratore (chi dà e toglie i ruoli) e registra la Raccolta come primo passo.
  5. molisci e analizza possono essere chiamate solo da chi ha il ruolo giusto (onlyRole).
  6. _avanza legge l'ultima fase scritta: la nuova deve essere esattamente la successiva, altrimenti revert annulla tutto.
  7. _registra aggiunge 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:

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

Per approfondire