Creare un servizio di notarizzazione: Scrypta Blockchain

Utilizza Scrypta Blockchain per creare in modo semplice un servizio di notarizzazione

notarizzazione
Tempo di lettura: 7 minuti

banner1

Sempre più spesso sentiamo l’esigenza di “notarizzare” o inserire dati in blockchain, questo può sembrare un task parecchio complicato, soprattutto se non siamo ferrati sui vari tipi di blockchain e le varie caratteristiche. In questo articolo affronteremo un caso di notarizzazione all’interno di una blockchain italiana: Scrypta Blockchain.
Se non conosci la blockchain di Scrypta ti invito a farti due passi qui: https://scryptachain.org e qui https://scrypta.wiki così da avere un’idea generica, ma non preoccuparti non serve andare così a fondo con la comprensione di quanto è stato effetivamente fatto dalla fondazione. Possiamo paragonare Scrypta ad una versione un po’ più evoluta di Bitcoin essendo un fork di PIVX. Dal punto di vista della programmazione e dello sviluppatore è importante sapere che è decentralizzata, permissionless e puoi inserire fino a 50KB di dati arbitrari per ogni transazione pagando una flat-fee di 0.001 LYRA.
All’interno di questo tutorial non affronteremo la parte di installazione nodi, sincronizzazione etc, ma utilizzeremo alcuni dei tool che Scrypta Foundation ha realizzato per creare, in pochi passi, un servizio managed di notarizzazione.
Per chi avesse fretta e volesse semplicemente andare al codice, può tranquillamente andare qui: https://github.com/turinglabsorg/simple-notarization-service

Notarizza, chi?

La cosa importante da capire, quando si parla di notarizzazione, è chi scrive dati in blockchain, ovvero l’indirizzo che effettivamente andrà a scrivere il dato. Questo dato è molto importante in quanto in alcuni casi i dati inseriti in blockchain possono essere usati come prova quindi la questione dell’identità diventa assolutamente importante.
Nel caso di un servizio managed, ovvero gestito da voi che lo create, l’utente può avere a disposizione la chiave privata dell’indirizzo, ma questa deve inevitabilmente essere condivisa con il servizio stesso, in quanto permetterà all’utente di notarizzare i dati in modo “semplice”.
Questo tutorial parte appunto da questo assunto ovvero che abbiamo bisogno di una chiave (BIP39/39) da cui derivare il resto delle chiavi degli utenti e che queste verranno usate per scrivere effettivamente dei dati.

Scaffolding del progetto

Cloniamo il progetto pubblico ed installiamo tutte le dipendenze, è fondamentale che abbiate NodeJS installato.
git clone https://github.com/turinglabsorg/simple-notarization-service
cd simple-notarization-service
npm install
Il progetto che abbiamo appena clonato è realizzato con NestJS ed espone degli endpoint che ci permetteranno già di realizzare delle notarizzazioni.
La prima cosa che dobbiamo controllare è se il file .env, contenente la nostra chiave principale, esiste ed abbia il parametro.
Per farlo aggiungiamo questo codice all’interno dell’ app.module.ts :
const scrypta = new ScryptaCore
scrypta.staticnodes = true
scrypta.generateMnemonic().then(mnemonic => {
fs.writeFileSync('.env', "MAIN_WALLET=" + mnemonic)
   console.log('Mnemonic generated successfully, please restart the process now.')
   process.exit(1);
})
Questo permetterà di creare una nuova seed phrase ed agganciarla al file .env, fatto questo saremo già pronti a partire e derivare chiavi private.

Definizione metodi principali

I metodi principali saranno 3: – Derivazione di identità: servirà per ottenere le chiavi private relative ad un determinato hash. – Notarizzazione: servirà per inserire dati in blockchain. – Lettura dati: servirà per leggere i dati precedentemente scritti in blockchain dallo stesso indirizzo.

Implementazione del codice

Inseriamo ora i metodi relativi al controller all’interno di app.controller.ts:
 @Get('identity/:hash')
  async getIdentity(@Request() request): Promise<Object> {
    if(request.params.hash !== undefined && request.params.hash.length === 64){
      return await this.appService.getIdentity(request.params.hash)
    }else{
      return JSON.stringify({
        error: true,
        message: "*hash* is required."
      })
    }
  }

  @Get('data/:hash')
  async returnData(@Request() request): Promise<Object> {
    if(request.params.hash !== undefined && request.params.hash.length === 64){
      return await this.appService.returnData(request.params.hash)
    }else{
      return JSON.stringify({
        error: true,
        message: "*hash* is required."
      })
    }
  }

  @Post('notarize')
  async notarizeData(@Body() request): Promise<Object> {
    if(request.hash !== undefined && request.data !== undefined){
      return await this.appService.notarizeData(request.hash, request.data)
    }else{
      return JSON.stringify({
        error: true,
        message: "*hash* and *data* are required."
      })
    }
  }
Questi tre metodi richiameranno quelli di app.service.ts:
  async getIdentity(hash): Promise<any> {
    const scrypta = new ScryptaCore
    scrypta.staticnodes = true

    if (process.env.MAIN_WALLET !== undefined) {

      try {
        /**
         * Deriving path from requested hash using Core method:
         * https://scrypta.wiki/en/#/core/advanced-management#hashtopathhash-hardened--false
         */
        let hashtopath = await scrypta.hashtopath(hash)

        /**
         * Deriving key from mnemonic using Core method:
         * https://scrypta.wiki/en/#/core/advanced-management#derivekeyfrommnemonic-menmonic-index
         */

        let identity = await scrypta.deriveKeyFromMnemonic(process.env.MAIN_WALLET, hashtopath)
        identity.path = hashtopath

        return identity;
      } catch (e) {
        return { message: "Service errored, retry.", error: true }
      }

    } else {
      return { message: "Identity passphrase not found", error: true }
    }
  }

  async returnData(hash): Promise<any> {
    const scrypta = new ScryptaCore
    scrypta.debug = true
    scrypta.staticnodes = true

    try {

      /**
       * Returning identity using previous method
       */
      const identity = await this.getIdentity(hash)

      /**
       * Reading data from IdaNode using post endpoint:
       * https://scrypta.wiki/en/#/idanode/pdm#post-read
       */

      const data = await scrypta.post('/read', { address: identity.pub })

      if (data.data !== undefined) {
        return data.data;
      } else {
        return { message: "IdANode errored, retry.", error: true }
      }

    } catch (e) {
      return { message: "Service errored, retry.", error: true }
    }
  }
  
  async notarizeData(hash, data): Promise<any> {
    const scrypta = new ScryptaCore
    scrypta.debug = true

    try {

      let canWrite = true

      /**
       * Returning identity using previous method.
       */
      const identity = await this.getIdentity(hash)

      /**
       * Returning address balance using get endpoint:
       * https://scrypta.wiki/en/#/idanode/block-explorer#get-balanceaddress
       */
      const balance = await scrypta.get('/balance/' + identity.pub)

      /**
       * Checking if balance is enough, if not funding balance with master key.
       */
      if (balance.balance < 0.001) {

        /**
         * Deriving key with Core method:
         * https://scrypta.wiki/en/#/core/advanced-management#derivekeyfrommnemonic-menmonic-index
         */
        var master = await scrypta.deriveKeyFromMnemonic(process.env.MAIN_WALLET, 'm/0')

        /**
         * Funding address using Core method:
         * https://scrypta.wiki/en/#/core/addresses-management#fundaddressprivatekey-to-amount
         */
        canWrite = await scrypta.fundAddress(master.prv, identity.pub, 0.001)
        await scrypta.sleep(1500)

      }

      if (canWrite) {
        /**
         * Importing private key because we always need encrypted wallets by default:
         * https://scrypta.wiki/en/#/core/addresses-management#importprivatekeykey-password
         */
        let temporaryKey = await scrypta.importPrivateKey(identity.prv, '-', false)

        /**
         * Checking if data can be stringified because we must pass a string into write method.
         */
        try {
          data = JSON.stringify(data)
        } catch (e) {
          console.log('Data is a string.')
        }

        /**
         * Finally write the data using Core method:
         * https://scrypta.wiki/en/#/core/pdm#writepassword-metadata-collection---refid---protocol---key---uuid--
         */
        return await scrypta.write(temporaryKey.walletstore, '-', data)
      } else {
        return { message: "This address can't write right now, seems master address can't fund it.", master: master.pub, error: true }
      }

    } catch (e) {
      console.log(e)
      return { message: "Service errored, retry.", error: true }
    }
  }

Scrypta Core

Il tool che abbiamo utilizzato è principalmente @scrypta/core (https://www.npmjs.com/package/@scrypta/core) e che permette l’interfacciamento alla rete pubblica di IdANode e, in definitiva, alla blockchain.
Le tre funzionalità principali riguardano:
– derivazione delle chiavi private grazie al metodo deriveKeyFromMnemonic.
– invio di fondi o scrittura grazie ai metodi fundAddress e write.
– interrogazione della rete degli idanode grazie ai metodi post e get.

Mettiamo in moto il tutto

Dopo aver sistemato tutto il codice siamo pronti per far partire il progetto con npm start o npm run start:dev se vogliamo andare in modalità sviluppo.
Al primo avvio l’applicativo vi creerà una nuova seed phrase e vi chiederà di riavviarlo. Diamo nuovamente `npm start` e saremo definitivamente pronti a partire.
Per l’interrogazione del servizio consigliamo l’utilizzo di Postman, di cui abbiamo già creato una collezione importabile qui: https://github.com/turinglabsorg/simple-notarization-service/blob/master/postman.json
Mi raccomando ad inviare il quantitativo di LYRA necessario per far partire le transazioni all’indirizzo master. Per ottenere il vostro indirizzo master basterà provare a fa partire una transazione richiamando l’endpoint notarize.
La prima risposta sarà quindi del tipo: { "message": "This address can't write right now, seems master address can't fund it.", "master": "LKjvThy4EsJYhqui1QHQzKoT7TjEYnqd3U", "error": true}
Il valore corrispondende a master sarà il vostro indirizzo.

Conclusioni

Non vi resta quindi che provare voi stessi a notarizzare delle stringhe o degli oggetti, mi raccomando.. questi rimarranno per sempre all’interno di una blockchain pubblica e permissionless!
Tutti i riferimenti agli endpoint sono presenti all’interno del README.md del repository https://github.com/turinglabsorg/simple-notarization-service.
Questo in effetti non è che un solo passo verso gli applicativi decentralizzati. Dopo aver effettivamente messo le mani nel mondo dell’archiviazione decentralizzata non potrete altro che domandarvi cosa notarizzare in blockchain!
Se aveste bisogno di una mano no esitate ad aggiungere issue su GitHub o contattarmi direttamente via e-mail a info@scrypta.foundation
Scritto da
Contributore
Scrypta è un'infrastruttura digitale decentralizzata che semplifica e rende più efficienti i processi di gestione, archiviazione e certificazione dei dati che caratterizzano i settori economico, produttivo e sociale. Il sistema flessibile di Scrypta consente di creare architetture complete per progetti illimitati e nuovi casi d'uso
Subscribe
Notificami
0 Commenti
Inline Feedbacks
View all comments

Condividi l'articolo

Articoli correlati
0
Would love your thoughts, please comment.x
()
x