Come funziona la filiera Carrefour con Blockchain?


INTRODUZIONE

Carrefour è passata alla storia per essere stata la prima azienda della grande distribuzione ad utilizzare una soluzione blockchain per certificare la filiera alimentare dei prodotti che vende all'interno dei punti vendita.

Tutto è iniziato nel 2017 quando un team "segreto" iniziò ad avviare un nodo Ethereum per cercare una soluzione utilizzando una DApp (e quindi uno Smart Contract).

Il punto di arrivo era ben chiaro, il punto di partenza invece fu andare ad incontrare tutti gli attori coinvolti:

  • sindacato degli allevatori
  • stabilimento alimentari
  • veterinari
  • mattatoi
  • trasformatori del prodotto
Tutti in quel periodo sono stati coinvolti in questo progetto che aveva come fine comune il certificare il passaggio del pollo da quando era pulcino al frigo del punto vendita.

La prima sfida risolta da Carrefour è stata inserire all'interno dei propri sistemi di memorizzazione delle chiamate verso la rete Ethereum memorizzando tutti i passaggi rendendoli di fatto immodificabili.

AL SUPERMARKET

Se ci rechiamo al punto vendita, nell'imballaggio del pollo ci sarà un'etichetta con la spiegazione e un QR CODE che, grazie all'app ufficiale o una semplice app generica, farà in modo di far visitare una pagina dedicata al prodotto.




All'interno della pagina potremmo visionare:
  • Dove è nato il pollo 
  • L'allevamento che l'ha cresciuto
  • Il luogo di confezionamento
Ma veramente tutte queste informazioni sono scritte sulla blockchain di Ethereum? 

COME FUNZIONA?

Andando a controllare il funzionamento del sito internet di Carrefour ho notato che uno dei servizi che recupera i dati ha un transaction id (cerchiato in rosso qui sotto) che è evidente si tratti di un id della blockchain Ethereum

Grazie a questo link infatti è possibile andare a controllare cosa c'e' direttamente all'interno dell'explorer della blockchain.

Inizialmente però le infomazioni inserite nella pagina di Carrefour non erano visibili, cliccando sul "Click to see more" finalmente ho potuto verificare che veramente Carrefour memorizza questi dati



Purtroppo le informazioni sono codificate dal linguaggio di programmazione solidity usato dentro Ethereum


LO SMART CONTRACT

Come detto precedentemente, tutta la filiera blockchain è sviluppata tramite uno smart contract il cui indirizzo è questo qui

Tramite la pagina è possibile interagire direttamente con lo smart contract (se è permesso dal codice sorgente), visionare gli eventi che ha generato e la storia delle transazioni.

Proprio grazie a questa storia è possibile risalire al primo pollo italiano in blockchain, la data della transazione è (Sep-18-2018 04:42:35 PM +UTC)

Grazie sempre a Etherscan è possibile visionare il codice sorgente che potete trovare a questo url oppure in fondo a questo post

NON TUTTO E' SULLA BLOCKCHAIN

Purtroppo però c'e' qualcosa che non va... dove sono memorizzate tutte le informazioni visibili sulla pagina?

Mancano all'appello 3 cose essenziali:

  • immagine
  • la razza del pollo
  • l'indirizzo dello stabilimento

Purtroppo di queste cose non c'e' traccia all'interno della blockchain. Il motivo sicuramente è sicuramente tecnico infatti le informazioni memorizzate incidono sul costo di transazione (che equivale al tempo di elaborazione computazionale e memorizzazione)

Sotto questo punto di vista forse la scelta di usare Ethereum non è stata la più geniale. Rimane il fatto che questo progetto con delle informazioni in blockchain e altre su un altro database non può essere definito il massimo della trasparenza!

A presto

pragma solidity ^0.4.24;
contract Articolo
{
    bytes   public codice_articolo;
    bytes10 public data_produzione;
    bytes10 public data_scadenza;
    bytes   public id_stabilimento;
    constructor(bytes   _codice_articolo,
                bytes10 _data_produzione,
                bytes10 _data_scadenza,
                bytes   _id_stabilimento) public
    {
        require(_codice_articolo.length > 0, "Codice Art. vuoto");
        require(_data_produzione.length > 0, "Data produzione vuota");
        require(_data_scadenza.length   > 0, "Data scadenza vuota");
        require(_id_stabilimento.length > 0, "ID stabilimento vuoto");
        codice_articolo = _codice_articolo;
        data_produzione = _data_produzione;
        data_scadenza   = _data_scadenza;
        id_stabilimento = _id_stabilimento;
    }
}
contract Lotto
{
    bytes   public id_owner_informazione;
    bytes   public codice_tracciabilita;
    bytes   public id_allevatore;
    bytes10 public data_nascita_pulcino;
    bytes10 public data_trasferimento_allevamento;
    mapping(bytes => mapping(bytes10 => address)) private articoli;
    address private owner;
    modifier onlymanager()
    {
        require(msg.sender == owner);
        _;
    }
    constructor(bytes _codice_tracciabilita,
                bytes _id_allevatore,
                bytes10 _data_nascita_pulcino,
                bytes10 _data_trasferimento_allevamento,
                bytes _id_owner_informazione) public
    {
        require(_codice_tracciabilita.length > 0, "cod. tra. non valido");
        require(_id_allevatore.length > 0, "id all. non valido");
        require(_data_nascita_pulcino.length > 0, "data nas. pul. non valida");
        require(_data_trasferimento_allevamento.length > 0, "data trasf. non valida");
        require(_id_owner_informazione.length > 0, "ID owner informazione non valido");
        // This will only be managed by the "father" contract ("CarrefourFactory"):
        owner = msg.sender;
        codice_tracciabilita = _codice_tracciabilita;
        id_allevatore = _id_allevatore;
        data_nascita_pulcino = _data_nascita_pulcino;
        data_trasferimento_allevamento = _data_trasferimento_allevamento;
        id_owner_informazione = _id_owner_informazione;
    }
    function addArticolo(bytes   _codice_articolo,
                         bytes10 _data_produzione,
                         bytes10 _data_scadenza,
                         bytes   _id_stabilimento) public onlymanager
    {
        require(_codice_articolo.length > 0, "Codice Art. vuoto");
        require(_data_produzione.length > 0, "Data produzione vuota");
        require(_data_scadenza.length   > 0, "Data scadenza vuota");
        require(_id_stabilimento.length > 0, "ID stabilimento vuoto");
        address articolo = new Articolo(_codice_articolo, _data_produzione, _data_scadenza, _id_stabilimento);
        articoli[_codice_articolo][_data_scadenza] = articolo;
    }
    function get_articolo(bytes codice_articolo, bytes10 data_scadenza) public view returns(bytes10, bytes)
    {
        address articolo_addr = articoli[codice_articolo][data_scadenza];
        Articolo articolo = Articolo(articolo_addr);
        return (
            articolo.data_produzione(),
            articolo.id_stabilimento()
        );
    }
}
contract CarrefourFactory
{
    address private owner;
    mapping(bytes => address) private lotti;
    event lottoAdded(bytes codice_tracciabilita);
    event articoloAdded(bytes lotto, bytes codice_articolo, bytes10 data_scadenza);
    constructor() public
    {
        owner = msg.sender;
    }
    modifier onlymanager()
    {
        require(msg.sender == owner);
        _;
    }
    function createLotto(bytes codice_tracciabilita,
                         bytes id_allevatore,
                         bytes10 data_nascita_pulcino,
                         bytes10 data_trasferimento_allevamento,
                         bytes id_owner_informazione) public onlymanager
    {
        require(codice_tracciabilita.length > 0, "Codice tracciabilità non valido");
        require(id_allevatore.length > 0, "Codice allevatore non valido");
        require(data_nascita_pulcino.length > 0, "Data di nascita non valida");
        require(data_trasferimento_allevamento.length > 0, "Data trasferimento allevamento non valida");
        address lotto = new Lotto(codice_tracciabilita, id_allevatore, data_nascita_pulcino, data_trasferimento_allevamento, id_owner_informazione);
        lotti[codice_tracciabilita] = lotto;
        emit lottoAdded(codice_tracciabilita);
    }
    function get_dati_lotto(bytes codice_tracciabilita) public view
             returns(bytes, bytes10, bytes10, bytes)
    {
        address lotto_addr = lotti[codice_tracciabilita];
        require(lotto_addr != 0x0, "Lotto non trovato");
        Lotto lotto = Lotto(lotto_addr);
        return (
            lotto.id_allevatore(),
            lotto.data_nascita_pulcino(),
            lotto.data_trasferimento_allevamento(),
            lotto.id_owner_informazione()
        );
    }
    function createArticolo(bytes   _lotto, // Here a synonym of "codice_tracciabilita"
                            bytes   _codice_articolo,
                            bytes10 _data_produzione,
                            bytes10 _data_scadenza,
                            bytes   _id_stabilimento) public onlymanager
    {
        require(_lotto.length > 0, "Codice tracciabilità vuoto");
        require(_codice_articolo.length > 0, "Codice Art. vuoto");
        require(_data_produzione.length > 0, "Data produzione vuota");
        require(_data_scadenza.length > 0, "Data scadenza vuota");
        require(_id_stabilimento.length > 0, "ID stabilimento vuoto");
        address lotto_addr = lotti[_lotto];
        require(lotto_addr != 0x0, "Lotto non trovato");
        Lotto lotto = Lotto(lotto_addr);
        lotto.addArticolo(_codice_articolo, _data_produzione, _data_scadenza, _id_stabilimento);
        emit articoloAdded(_lotto, _codice_articolo, _data_scadenza);
    }
    function get_dati_articolo(bytes codice_tracciabilita, bytes codice_articolo, bytes10 data_scadenza) public view
             returns(bytes10, bytes, bytes, bytes10, bytes10)
    {
        address lotto_addr = lotti[codice_tracciabilita];
        require(lotto_addr != 0x0, "Lotto non trovato");
        Lotto lotto = Lotto(lotto_addr);
        (bytes10 produzione, bytes memory stabilimento) = lotto.get_articolo(codice_articolo, data_scadenza);
        bytes memory allevatore = lotto.id_allevatore();
        bytes10 nascita = lotto.data_nascita_pulcino();
        bytes10 trasferimento = lotto.data_trasferimento_allevamento();
        return (
            produzione,
            stabilimento,
            allevatore,
            nascita,
            trasferimento
        );
    }


Commenti

Post popolari in questo blog

Hadoop, how to create a single node cluster using docker

How to install IOTA node with docker

Apache Spark - Try it using docker!