Conoscere Solidity ti permetterà di creare ICO, token, dapps e giochi su diverse Blockchain. La rivoluzione finanziaria è basata su Ethereum e, leggendo questa guida, sarai uno dei pochi sviluppatori in grado di creare applicazioni decentralizzate con questo nuovo linguaggio. Questa è una guida completa alla creazione ed alla distribuzione di Smart Contract performanti, sicuri ed efficenti, verranno affrontati diversi temi: come creare Smart Contract con web3.js, come controllare gli Smart Contract e come testarli correttamente.
Se non hai mai programmato prima, ti consiglio di seguire un corso base di Javascript o java e di tornare a questa guida quando avrai appreso al meglio almeno uno dei linguaggi appena citati. Avrai bisogno della conoscenza di Javascript per l’utilizzo di Web3.js, sebbene tu possa imparare gran parte dei contenuti di questa guida senza conoscere Javascript. Solidity è il linguaggio principale utilizzato per la programmazione di Smart Contract su Ethereum. È il più usato al momento anche se ce ne sono altri come Viper e LLL. È un linguaggio abbastanza semplice che consente di creare contratti facili da sviluppare e sicuri.
A differenza dei linguaggi più popolari come java, Solidity ha delle limitazioni date dalla blockchain. Non è possibile memorizzare grandi quantità di dati nelle variabili. Anche il calcolo è limitato. I cicli for e while sono limitati dal gas. Ciò significa che non sarai in grado di creare un ciclo for per un array di migliaia di elementi. Analizzeremo alcune tecniche per evitare tali limiti. Il mio obiettivo è insegnarti tutte le nozioni base necessarie per realizzare un buon Smart Contract in modo che tu possa iniziare fin da subito a sviluppare.
Questa guida contiene informazioni preziose, viene tutto dalla mia esperienza quindi probabilmente troverai alcune chicche che non vedrai da nessun’altra parte.
Se vuoi approfondire ulteriormente l’argomento, ti consiglio di leggere anche:
Solidity: come sviluppare Smart Contract per la Blockchain di Ethereum
Partiamo dalle basi | Solidity: la guida definitiva
Prima di tutto, cos’è uno Smart Contract? È solo uno script che risiede in modo permanente sulla blockchain. Si crea uno Smart Contract inviando una transazione con il codice del contratto compilato in bytecode per ridurne le dimensioni. I contratti non possono essere cancellati ma possono essere bloccati per evitare che le persone eseguano funzioni non autorizzate. La cosa buona degli Smart Contract è che loro codice, una volta salvato sulla Blockchain, non può essere modificato. Ad esempio, non è possibile caricare uno Smart Contract “Prova.sol” versione 1 e sovrascriverlo con “Prova.sol” versione 2. La versione 1 rimarrà lì poiché la blockchain è immutabile. Immutabile significa che è immutabile nel tempo o non può essere modificata.
A cosa serve uno Smart Contract?
Ti consente di creare codice che si comporta come un contratto reale in cui le condizioni non possono essere modificate. Chiunque utilizzi quel contratto accetta i termini e può fidarsi perché nessuno può modificare il codice dopo averlo distribuito. È come firmare un contratto per un lavoro e archiviarlo in un caveau super segreto a cui nessuno può accedere. Significa che non devi necessariamente fidarti di aziende per fare determinate operazioni. Basta dare un’occhiata al codice e sarai certo che farà esattamente quello che dice. Sono particolarmente utili quando si tratta di applicazioni finanziarie poiché possono gestire e archiviare del denaro in Ether.
Iniziamo subito a capire, come creare uno Smart Contract con Solidity
Durante tutta la guida userò atom.io poiché è il mio editor preferito, ma puoi usare qualsiasi editor tu voglia. Sublime Text e Visual Studio Code possono essere altrettanto buoni. Uno Smart Contract inizia sempre con la versione di Solidity utilizzata. Quindi apri un editor di testo come Atom, crea un nuovo documento e scrivi la versione di Solidity che verrà utilizzata il contratto all’inizio del file in questo modo:
pragma solidity 0.5.12;
In questo caso sto usando la versione 0.5.12, ma sentiti libero di usare l’ultima versione disponibile. Puoi trovare la versione corrente nelle guide ufficiali:
solidity.readthedocs.io
Nota che tutte le linee di codice devono terminare con un punto e virgola per essere valide in Solidity. È inoltre possibile specificare l’ultima versione con il simbolo ^ per indicare al compilatore che si desidera utilizzare la versione più recente di Solidity o quella indicata. Ad esempio:
pragma solidity ^0.5.12;
Se c’è una versione 0.5.12 o superiore, il compilatore userà quella versione invece di quella specificata. Dipende anche dal compilatore che stai usando. La maggior parte dei compilatori ti consente di cambiare la versione utilizzata in qualsiasi momento. Tuttavia non lo consiglio perché non si sa mai quale versione viene utilizzata durante la compilazione dei contratti e le versioni più recenti potrebbero non essere compatibili con il codice presente nel tuo contratto. Non è raro deprecare elementi che rendono il contratto non valido per la versione più recente. Per questo motivo, ricorda di non usare il simbolo ^ quando specifichi la versione di Solidity. Quindi, si avvia il contratto definendone il nome:
pragma solidity 0.5.12;
contract Prova {
}
Puoi usare qualsiasi nome, ricordati di scrivere la prima lettera in maiuscolo per indicare che si tratta di un contratto. Proprio come in java. Ora puoi iniziare a scrivere la logica del contratto. Ma prima di farlo, salva il file con estensione .sol, esempio Prova.sol. Questa è la estensione ufficiale di un file Solidity. Ricorda di nominare il file in base al nome del contratto scritto all’interno. Ad esempio, se stai creando un contratto chiamato Automobili, non ti consiglio di chiamare il file Case.sol. Sii intelligente e mantieni le cose semplici usando lo stesso nome nel file. A questo punto sai come creare la struttura di base di uno Smart Contract. Successivamente, andremo a vedere quali sono tipi di variabili che è possibile utilizzare in un contratto per archiviare le informazioni sulla Blockchain.
Tipi di variabili | Solidity: la guida definitiva
Solidity è un linguaggio tipizzato. Ciò significa che devi specificare il tipo di variabile che stai creando prima del suo nome, proprio come in java. Ecco le variabili che è possibile utilizzare in uno Smart Contract:
Numbers
uint, uint8, uint16, uint24, uint32, uint64, uint128 e uint256
Non lasciarti spaventare dal numero di variabili simili. Uint significa “numero intero senza la virgola” che è fondamentalmente un numero positivo. Non può essere negativo.
Se si tenta di memorizzare un numero negativo, andrà in “overflow”. Il numero dopo uint indica la dimensione della variabile. Ad esempio, uint8 è in grado di memorizzare qualsiasi numero positivo con il numero massimo di 2^ 8 che è 256.
Qualsiasi numero superiore a 256 come 257 manderà la variabile in “overflow” significa che supererà la capacità massima consentita. Quando si tenta di memorizzare 256 in una variabile uint8, il valore effettivo diventerà 0 perché è il limite della variabile che si “reimposta” da sola a partire da zero. Se provi a memorizzare 257 il valore diventerà 1. Quindi se leggi il valore della variabile vedrai 1 invece di 257. Spero sia chiaro.
Stessa cosa con uint16 e così via. Il valore massimo di uint24 è 2^ 24 = 16777216.
Esercizio: qual è il valore massimo che è possibile memorizzare in un uint256?
cosa succede se provi a memorizzare quel valore massimo + 2?
Soluzione: 2 ^ 256 = 1.15792089237316194242707098500869e + 77;
diventa 2 invece di quel valore massimo + 2 perché va in “overflow”.
Se scrivi uint senza numeri, questo diventa immediatamente uint256. È solo una scorciatoia. La mia raccomandazione è di scrivere sempre uint256 indipendentemente dalla dimensione della variabile perché richiede la stessa quantità di gas per essere elaborata ed è più semplice per te poiché aggiunge chiarezza al codice. In sintesi: mantieni le cose semplici. Usa sempre uint256 per definire i numeri.
Quindi come definiamo un numero?
Torniamo al file Prova.sol appena creato e definiamo un numero:
pragma solidity 0.5.12;
contract Prova {
uint256 provaNumero;
}
Semplice non è vero? Hai appena definito il tipo di variabile e il suo nome. Nota che è possibile convertire facilmente il tipo.
Ad esempio, supponiamo di avere una variabile:
uint256 provaNumero = 10;
E diciamo che tu vuoi convertirla in uint8. Puoi farlo in questo modo:
uint8 altroNumero = uint8(provaNumero); // Ora provaNumero è stato convertito in uint8 da uint256
Proprio così, hai una variabile uint8. Tienilo presente quando avrai bisogno di un tipo specifico di variabile. Funziona anche con int, che è solo un numero che può essere positivo e negativo. Per impostazione predefinita, il valore memorizzato su una variabile inizializzata senza valori è 0. Cambiamo quel valore con una funzione, questo ti aiuterà davvero a capire la logica negli Smart Contract:
pragma solidity 0.5.12;
contract Prova {
uint256 provaNumero;
function modificaNumero (uint256 _valore) public { provaNumero = _valore; }
}
Guarda cosa hai appena fatto! Hai appena creato una funzione che modifica il valore della tua variabile in 3 righe di codice. Quando si esegue la funzione, si riceve un numero chiamato _valore e si modifica il valore di provaNumero su quel numero. La parola chiave public viene utilizzata per indicare che questa funzione può essere eseguita da qualsiasi contratto e utente. Gli Smart Contract possono eseguire altri Smart Contract e la parola chiave public della funzione indica che quella funzione può essere eseguita da chiunque. Ti consiglio di definire sempre la visibilità delle funzioni e delle variabili ma per ora non ti preoccupare. C’è una sezione dedicata alla visibilità delle funzioni in seguito. Presto vedrai come eseguire effettivamente questo codice su una vera Blockchain. Continuiamo ad imparare tutti i tipi di variabili che puoi usare in Solidity.
Address
L’indirizzo pubblico di ogni utente. Quando crei un account, ottieni un indirizzo che le persone possono utilizzare per inviarti Ether. La cosa buona è che è possibile memorizzare tali indirizzi sul contratto per cose come limitare l’accesso al contratto a determinati indirizzi o semplicemente registrare chi sta usando il tuo codice. Ecco come si dichiara una variabile per l’indirizzo:
pragma solidity 0.5.12;
contract Prova {
uint256 provaValore;
address indirizzo_proprietario;
function modificaNumero (uint256 _value) { provaNumero = _value; }
}
Gli indirizzi si dichiarano come stringhe ma senza virgolette.
Ad esempio: address indirizzo_proprietario = 0x055E36b2BB4eF1121F99e3e134c66A8DCb6ef58e;
Assicurati di aggiungere il 0x all’inizio dell’indirizzo. Per impostazione predefinita, tutti gli indirizzi hanno il valore 0x0 che è uguale a 0x0000000000000000000000000000000000000000. Questo è il valore degli indirizzi prima che tu dia loro un valore.
Stringhe e Byte
Stringhe e Byte memorizzano le stesse informazioni. La differenza è che i Byte consentono di memorizzare ulteriori Byte grezzi mentre le stringhe sono utilizzate solo per il testo.
È inoltre possibile utilizzare byte1, byte2, byte3 fino a byte32. Questi sono usati per lo stesso scopo, per la memorizzazione di dati di testo e di byte ma usano meno gas, il che è ottimo per gli utenti perché dovranno pagare meno ether per interagire con quelle variabili.
le variabili byte32 sono limitate a 32 caratteri.
In breve: si utilizza bytes32 nel 99% delle situazioni perché è il modo più efficiente per archiviare il testo rispetto alle stringhe. Tuttavia, sono di dimensioni limitate, quindi se desideri memorizzare una grande quantità di testo, devi necessariamente utilizzare la stringhe.
pragma solidity 0.5.12;
contract Prova {uint256 provaNumero;
address indirizzo_proprietario;
bytes32 nome = "Giovanni";
string articolo = "testo dell’articolo di grandezza variabile";
function modificaNumero (uint256 _value) {
provaNumero = _value; }
}
Boolean
Questo è il tipo più semplice di variabile. Può essere vero o falso. Per impostazione predefinita, tutti i booleani sono falsi, quindi se non si assegna alcun valore a un valore booleano, sarà falso. Ecco come le definisci:
bool isTrue;
La denominazione dei booleani di solito inizia con “is” per motivi di leggibilità. In questo modo puoi capire velocemente che è un booleano.
Mapping
Sono un tipo speciale di variabili, consentono di memorizzare informazioni illimitate, ad esempio:
Nome: Giovanni, Età: 22
Nome: Dario, Età: 32
Nome: Luigi, Età: 25
Potresti usare una mappa come questa:
mapping (string = uint256) etaPersone;
Si utilizzano delle parole chiave e quindi si definiscono i tipi. Le informazioni saranno memorizzate in questo modo:
Giovanni = 35
Dario = 31
Luigi = 25
E sarai in grado di accedere alle informazioni come in un array:
etaPersone ["Giovanni"]; // Restituirà 35
Puoi aggiungere voci illimitate alle mappe ed è possibile creare mappe di mappe:
mapping (string = mapping (string = uint256)) etaPersone;
Come un array multidimensionale (questa è solo una rappresentazione):
Dario = Giovanni = 35
Luigi = 25
Mario = 31
In realtà, accederai a queste informazioni con questa sintassi:
etaPersone ["Dario"] ["Luigi"]; // Restituirà 25
etaPersone ["Dario"] ["Mario"]; // Restituisce 31
Ricorda che il nome della mappa è alla fine della dichiarazione (mapping), in questo caso si chiama etaPersone ma puoi usare qualsiasi nome tu voglia. I nomi delle variabili in Solidity usano lo stile camelCase in cui ogni termine successivo al primo è in maiuscolo. Proprio come in Javascript. Le mappe sono molto potenti per memorizzare enormi quantità di informazioni, ma non è possibile accedervi in ordine. Se hai una mappa di stringhe su uint256 non sarai in grado di vedere ogni record individualmente come in un array perché devi prima conoscere la stringa per ottenere il valore. Ciò significa che non sarà possibile eseguire il ciclo tra il primo valore e l’ultimo perché non esiste un ultimo valore. Di default tutti gli uint sono 0 e gli indirizzi sono 0x0 che è zero in esadecimale. Se si desidera eseguire il ciclo su una mappa, sarà necessario creare una matrice che memorizzi la chiave della mappa.
Struct
Struct significa struttura. Le strutture ti consentono di creare oggetti con attributi. È come un oggetto in Javascript in cui è possibile definire proprietà o “variabili interne”. È un po’ complicato da spiegare, quindi vediamo un esempio:
struct persone {
uint256 id;
string nome;
uint256 anni;
}
Hai appena definito una struttura chiamata persone con ID, nome ed età. Ora puoi creare istanze in questo modo:
persone inserisciPersona = persone (1, "Giovanni", 35);
In genere si desidera archiviare le strutture in mappe o in matrici poiché si desidera creare diverse istanze di mappa. Ricorda che ogni proprietà della struttura, deve terminare con un punto e virgola. Puoi aggiungere tutte le proprietà che vuoi, anche array e mappe. Nota inoltre che la struttura in sé non ha un valore predefinito.
Array
Puoi creare una matrice di qualsiasi cosa tranne i mapping aggiungendo le parentesi alla fine della parola chiave variabile. Per esempio:
uint256[]
myNumbers;
bytes32[]
myStrings;
string[]
myTexts;
Tree[]
myTrees;// La struttura ad albero è una struttura che abbiamo definito in precedenza e questa matrice contiene istanze di tali strutture
È possibile eseguire il loop attraverso di essi con un ciclo for o while facilmente poiché i valori sono ordinati e hanno sempre un ultimo valore. Puoi accedere a ciascun valore con:
myNumbers[3]; // 93
myStrings[5]; // Laura
Esistono 2 tipi di array. Gli array di dimensioni fisse e gli array di dimensioni variabili. Ecco come funzionano:
– Array di dimensioni fisse: sono array di dimensioni limitate. Ad esempio, un array di 5 stringhe:
string[5] myNames;
Per aggiungere valori a questo array, utilizza il numero dell’elemento da modificare. La funzione push non funziona in array di dimensioni fisse:
myNames[2] = ‘Dario’; // Ok
myNames.push(‘Luigi’); // Da errore, questo non funziona con questo tipo di array
– Array di dimensioni dinamiche: hanno dimensioni illimitate, quindi puoi continuare ad aggiungere elementi per tutto il tempo che desideri. È necessario utilizzare la
funzione push per aggiungere nuovi elementi:
myNames.push(‘Dario’); // Ok
myNames[40] = ‘Carlo’; // Non funzionerà a meno che quell’elemento non sia già stato modificato con push
Queste sono praticamente tutte le variabili che vedrai in uno Smart Contract. Esistono altri tipi come byte e int ma non sono molto utilizzati. Int è per la memorizzazione di numeri negativi e positivi.
Variabili Globali
In ogni Smart Contract ci sono variabili globali:
– now o block.timestamp: entrambe restituiscono lo stesso valore, il valore unix dell’ora corrente, un valore di 10 numeri. È molto utile memorizzare data ed ora in cui è stata
intrapresa un’azione specifica. Ricorda che tutto il codice viene eseguito quando un blocco viene estratto in modo che i miner definiscano data ed ora (timing) nel blocco. Ciò
significa che l’ora non sarà esattamente l’ora corrente, sarà sempre un pò inferiore. Tienilo a mente.
– mgs.sender, msg.gas e msg.value: il messaggio del mittente contiene l’indirizzo dell’utente che ha eseguito quella funzione, msg gas il gas rimanente disponibile in quel
punto della funzione e il valore msg è la quantità di Ether inviata a quella funzione in wei. Un wei è solo la più piccola unità di ether. Ad esempio, 1 Ether è 1 * 10
^ 18 wei.
– days, seconds, minutes, hours, weeks e years: Sono solo unità per definire valori temporali. Per esempio, 1 minuto equivale a 60 secondi. Tutte queste variabili restituiranno valori espressi in secondi. Vediamo un esempio:
uint256 myTime = 25 days;
uint256 mySecondTime = 1 minutes;
– this: restituisce l’indirizzo dello Smart Contract corrente.
Puoi anche usare this.balance per ottenere quanto ether questo contratto ha il valore verrà restituito in wei.
Tutte queste informazioni sono inutili se non vengono applicate in un esempio del mondo reale. Facciamolo. Ti guiderò attraverso i passaggi per creare un semplice Smart Contract che memorizzerà delle cose da fare. Cose da fare, le cose che devono essere fatte oggi o nel breve periodo.
Riepilogo delle principali variabili in Solidity
Le variabili in Solidity possono essere:
– Numeri. Per impostazione predefinita, tutti i numeri sono 0 e se vanno in ‘overflow’, si resettano a zero:
Positivi: uint, uint8,… uint256.
Positivi e negativi: int, int8,… int256.
– Stringhe o testo. Le stringhe per impostazione predefinita sono null, non hanno alcun valore. Il modo per verificare se una stringa è vuota è convertirla in byte e
verificarne il primo valore:
Bytes: bytes, bytes8,… bytes32. Bytes32 è il modo più efficiente di memorizzare il testo anche se è limitato a 32 caratteri diversamente dalle stringhe.
Strings: (String) è il modo migliore per archiviare grandi quantità di testo.
– Address: hanno 42 caratteri, senza virgolette e puoi accedere all’indirizzo della persona che ha eseguito il contratto con msg.sender. Per impostazione predefinita, sono
0x0 che è 0x seguito da 40 zeri. Li definisci con l’indirizzo della parola chiave.
– Booleans: sono veri o falsi. Per impostazione predefinita, sono falsi. Li definisci con la parola chiave bool.
– Structs: consentono di creare oggetti o elementi ordinati con diverse proprietà. Possono contenere numeri, stringhe, mappe, array, indirizzi, valori booleani e byte. Li definisci con la parola chiave struct e non hanno alcun valore predefinito. Devi usare la memoria delle parole chiave davanti alla struttura se stai creando un’istanza temporanea. Entreremo nel dettaglio su come e quando utilizzare la memoria delle parole chiave.
– Array: Conservano grandi quantità di informazioni. Può essere di qualsiasi tipo di variabile tranne le strutture e le mappature. Esistono 2 tipi di array:
– Array a dimensione fissa: hanno dimensioni predefinite. Non puoi usare push() perché non puoi aggiungere più elementi a loro e devi modificarli in base al loro
valore. Ad esempio: bool [5] areTrue = false;
– Array a dimensioni variabili: questi array sono di dimensioni illimitate e devi usare la funzione push per aggiungere nuovi elementi. Non è possibile accedere direttamente agli elementi che non sono già stati creati con push. Ad esempio: bool [] areTrue;
– Mapping: Sono simili agli array, ma collegano tipi di variabili. Puoi accedere a qualsiasi elemento della mappa liberamente. Ad esempio:
mapping (string = address) myAddresses;
Smart Contract project: Cose da fare
Mettiamo in pratica le nuove conoscenze acquisite in un progetto concreto.
Tutti i progetti dovrebbero iniziare con una chiara specifica di ciò che vogliamo ottenere perché altrimenti perderai tempo ad aggiungere funzionalità non necessarie e a fare le cose in modo diverso dall’obiettivo iniziale.
Analizziamo per un secondo le specifiche per capire cosa dobbiamo fare:
– Le note sulle cose da fare sono limitate a 32 lettere. Ciò significa che utilizzeremo byte32 per il contenuto della nota poiché è il modo migliore per salvarle.
– Le note devono contenere la data di creazione. Utilizzeremo una variabile globale per ottenere l’ora corrente.
– Le note devono contenere l’indirizzo del proprietario che ha creato quella nota. Useremo msg.sender per ottenere l’indirizzo di quell’utente e memorizzarlo nella
mappa.
– Una funzione per contrassegnare le cose da fare come completate. Ciò significa che dovremo creare una struttura Note con le informazioni richieste e creeremo una funzione
per aggiornare lo stato di ciascuna cosa da fare.
– Solo il proprietario sarà in grado di modificare le note. Lo faremo con un nuovo tipo di funzione chiamata modifier che ci consente di effettuare controlli prima di
eseguire qualsiasi calcolo. Lo useremo per confrontare l’indirizzo del mittente con l’indirizzo del proprietario della nota.
Iniziamo creando una cartella sul desktop chiamata cose-da-fare-dapp e quindi un file chiamato CoseDaFare.sol. Questo sarà il contratto con tutta la logica. Per interagire con il contratto dall’esterno, creeremo un’app Web, Web3.js.
All’interno di CoseDaFare.sol, crea il layout di base dello Smart Contract:
pragma solidity 0.5.12;
contract CoseDaFare {
}
Ora potresti chiederti. Da dove comincio con questa applicazione? Bene, il componente principale di questo contratto è l’elemento Note. Che è solo una struttura con diverse variabili. Creiamola:
pragma solidity 0.5.12;
contract CoseDaFare {
struct Note {
bytes32 content;
address owner;
bool isCompleted;
uint256 timestamp;
} }
Timestamp è la data di creazione della nota. Gli altri campi si basano sulle specifiche. Ora abbiamo bisogno di un modo per memorizzare quelle note. Potremmo usare un array o una mappa. In questo caso useremo entrambe perché ogni persona, ogni indirizzo avrà diverse note e ciò può essere realizzato con un array. Utilizziamo una mappa perché ci consente di ottenere tutte le note di un utente con solo il suo indirizzo senza loop.
pragma solidity 0.5.12;
contract CoseDaFare {
struct Note {
uint256 id;
bytes32 content;
address owner;
bool isCompleted;
uint256 timestamp;
}
uint256 public constant maxAmountOfNotes = 100;
// Owner = Note
mapping(address = Note[maxAmountOfNotes]) public note;
// Owner = id ultima nota
mapping(address = uint256) public lastIds;
}
Si noti che è possibile aggiungere commenti con una doppia barra // per i commenti di riga o con una barra con asterisco / ** / per i commenti di blocco. Ecco cosa ho appena fatto:
– Ho definito una variabile chiamata maxAmountOfNotes che viene utilizzata per limitare la quantità di cose da fare che ogni utente può avere. Ciò è necessario per evitare che il numero di note create da un utente cresca all’infinito poiché abbiamo limiti di gas.
– Note è dove verranno memorizzate le note per ciascun indirizzo utente.
– LastIds è solo un modo per tenere traccia dell’ultimo ID utilizzato per ciascun utente, necessario per aggiungere nuove note poiché stiamo utilizzando un array di dimensioni fisse nella mappa note. Mi piace aggiungere un commento sopra ogni mappa per indicare esattamente cosa significano le variabili all’interno, al fine di migliorare la chiarezza del codice. È molto importante commentare il codice. Ti aiuterà a capire ed eseguire il debug più velocemente. Tieni presente che questa non è la migliore soluzione possibile per questa specifica. È solo il mio modo di fare le cose. È possibile leggere le specifiche e archiviare le note in un singolo array in modo efficiente. Prova tu stesso senza copiare il codice e vedrai cosa puoi fare da solo. A questo punto possiamo iniziare a creare le funzioni per questa applicazione. Avremo bisogno di un modo per aggiungere note alla mappa delle note. Ecco come ho fatto:
pragma solidity 0.5.12;
contract CoseDaFare {
struct Note {
uint256 id;
bytes32 content;
address owner;
bool isCompleted;
uint256 timestamp;
}
uint256 public constant maxAmountOfNote = 100;
// Owner = Note
mapping(address = Note[maxAmountOfNote]) public note;
// Owner = id ultima nota
mapping(address = uint256) public lastIds;
modifier onlyOwner(address _owner) {
require(msg.sender == _owner);
_;
}
// Aggiungi note alla lista
function addNote(bytes32 _content) public {
Note memory myNote = Note(lastIds[msg.sender], _content, msg.sender, false, now);
note[msg.sender][lastIds[msg.sender]] = myNote;
if(lastIds[msg.sender] = maxAmountOfNote)
lastIds[msg.sender] = 0;
else lastIds[msg.sender]++;
}
}
Prosegui ora tu in autonomia, hai tutti gli elementi e le nozioni per realizzarlo.
Se desideri approfondire ulteriormente l’argomento, ho scritto un libro su Solidity, disponibile su Amazon.