
Introduzione
Per risolvere questi problemi, sono state create diverse soluzioni Layer 2, come Base, che funzionano grazie alla scalabilità e a costi di gas più bassi. Anche se le soluzioni L2 hanno costi molto più bassi rispetto alla mainnet di Ethereum, chi sviluppa smart contract non può ignorare l'ottimizzazione del gas durante lo sviluppo.
Questo tutorial ti aiuterà a migliorare la tua esperienza e a creare app decentralizzate più competitive usando strategie avanzate che riducono il costo del gas sugli smart contract che verranno testati. Gli esempi che ti danno sono simulati con contratti semplici e tengono conto soprattutto dei prezzi del gas durante l'esecuzione, dato che i costi di implementazione variano molto a seconda delle dimensioni di un contratto.
L'ottimizzazione del gas è importante per gli sviluppatori, gli utenti e il successo a lungo termine del progetto. Usare in modo intelligente il gas degli smart contract può rendere i protocolli più convenienti e scalabili e meno esposti a minacce alla sicurezza come gli attacchi denial of service.
L'uso pratico degli smart contract richiede un controllo completo e sistematico di ogni singolo smart contract.
L'importanza dell'ottimizzazione del gas Solidity
L'ottimizzazione del gas permette agli smart contract, ai protocolli e ai progetti di funzionare anche quando le reti sono congestionate, rendendoli economici ed efficienti. Migliorando il codice dei contratti, si possono scoprire possibili vulnerabilità e i protocolli e gli utenti si sentono più sicuri.
Anche l'ottimizzazione del gas è un punto importante dello sviluppo. Non è solo una cosa carina da avere, ma è fondamentale per il successo e la sicurezza a lungo termine degli smart contract. Il fatto che si possa costruire su L2 con commissioni relativamente basse non vuol dire che le commissioni del gas non saranno molto più alte rispetto alla concorrenza.
Tutti i test usano Foundry e Solidity versione 0.8.13, il nodo blockchain locale Anvil, i comandi di test forge e 100 esecuzioni di ottimizzazione.
Le società di revisione professionali dovrebbero essere coinvolte nei controlli di sicurezza completi, questa guida dovrebbe essere solo un aiuto.
Riduci i dati sulla catena
I token non fungibili (NFT) sono diventati popolari nel 2021 e hanno attirato l'interesse verso gli NFT completamente on-chain. Gli NFT on-chain, rispetto a quelli tradizionali che usano dati off-chain, come metadati e riferimenti alle immagini, mettono tutte le informazioni direttamente sulla blockchain.
Questi token sono notoriamente costosi da usare e le soluzioni ibride sono la scelta più comune quando gli utenti devono pagare delle commissioni. Che tu stia creando NFT, giochi o protocolli DeFi, dovresti sempre pensare a quali dati servono davvero sulla blockchain e ai pro e contro di entrambe le opzioni.
Riduci di molto l'uso di gas salvando le informazioni fuori dalla catena, così avrai bisogno di meno spazio per le variabili. Un modo per farlo è usare gli eventi per salvare i dati fuori dalla catena invece che nella memoria effettiva della catena.
I costi del gas delle transazioni aumentano a causa delle funzioni di emissione aggiuntive generate dagli eventi; ma le informazioni non vengono memorizzate sulla catena, quindi i risparmi di solito superano i costi.
Pensa a uno smart contract che permette agli utenti di votare vero o falso. Il primo è quello che salva i voti degli utenti in strutture on-chain. Una dimostrazione del test della funzione di voto con Foundry con oltre 100 iterazioni mostra determinati costi del gas.
Confronta con uno smart contract che non memorizzerebbe le informazioni sulla catena, ma emetterebbe un evento quando viene richiamata la funzione di voto. Un test che coinvolge Foundry più di 100 volte nella nuova funzionalità di voto fornisce i risultati.
I dati ridotti sulla catena hanno tagliato il gas medio del 90,34%.
Per poter accedere ai dati off-chain on-chain, le funzioni Chainlink e le soluzioni di supporto sono disponibili per l'integrazione con le reti L2 più popolari, come Base.
Usa le mappature sugli array
Ci sono due tipi principali di dati in Solidity: array e mappature.
- •Gli array servono per memorizzare insiemi di elementi che sono collegati a determinati indici
- •Le mappature chiave-valore sono strutture di dati che permettono di accedere direttamente ai dati usando chiavi uniche
Anche se gli array potrebbero essere utili per memorizzare vettori e altri dati simili, di solito si preferiscono le mappature perché consumano meno gas. Sono particolarmente adatte a situazioni in cui servono dati su richiesta, per esempio per nome, indirizzo del portafoglio o saldo del conto.
Per capire quanto gas si usa quando si usano array o mappature, potresti dover controllare il gas usato dagli opcode EVM associati. Gli opcode sono istruzioni di basso livello che la Ethereum Virtual Machine esegue durante l'esecuzione degli smart contract, e ogni opcode ha un costo in gas.
Per accedere ai valori dell'array, bisogna pagare per ogni unità di gas usata dagli opcode EVM. Per memorizzare gli indirizzi degli utenti e i saldi corrispondenti nell'array, bisogna fare un ciclo su tutti gli elementi dell'array, controllare se l'indirizzo utente e l'argomento fornito corrispondono e, in caso di corrispondenza, restituire il saldo.
Passando direttamente al saldo specifico dell'utente, non serve più controllare tutti gli elementi dell'array. Una volta sostituiti gli array con le mappature, si è usato l'89% di gas in meno per accedere ai dati.
Confronto sul consumo di gas: array vs mappature
| Metodo | Prima dell'ottimizzazione | Dopo l'ottimizzazione | Risparmio di carburante |
|---|---|---|---|
| Accesso ai dati | 30.586 | 3.081 | 89% |
| Aggiunta di dati | - | - | 93% |
Usa costanti e immutabili per ridurre i costi del gas degli smart contract
Un altro consiglio per ottimizzare è usare costanti e variabili immutabili. Quando dici che le variabili sono immutabili o costanti, i loro valori vengono forniti solo al momento della creazione del contratto e non più in seguito.
Non occupano spazio di archiviazione nell'EVM rispetto ad altre variabili. È possibile codificare direttamente i valori nel bytecode smart contract, il che significa che il costo di archiviazione dei dati è ridotto dal fatto che variabili come maxSupply e owner non hanno le parole chiave costanti o immutabili.
Quando i test vengono eseguiti 100 volte, il costo medio del gas è di 112.222 unità. Dato che maxSupply e owner sono valori noti che non devono essere cambiati, dichiarare la fornitura massima e il proprietario che non usano spazio di archiviazione è la scelta migliore.
I test sulle variabili costanti o immutabili hanno portato a un risparmio medio del 35,89% (da 112.222 a 71.940 unità di gas).
Ottimizza le variabili che non usi
È ovvio che per ottimizzare il gas bisogna ottimizzare le variabili negli smart contract. Le variabili che non servono, però, nella maggior parte dei casi vengono mantenute durante l'esecuzione del contratto, portando a un uso inutile di gas.
Togliendo le variabili che non usi puoi risparmiare sui costi, in media il 18%, soprattutto se pensi ai contratti con variabili inutilizzate definite e modificate nelle funzioni ma mai chiamate altrove.
Risultati dell'ottimizzazione delle variabili inutilizzate
| Fase di ottimizzazione | Consumo di gas | Risparmi |
|---|---|---|
| Prima dell'ottimizzazione | 32.513 | - |
| Dopo l'ottimizzazione | 27.429 | 18% |
Rimborso Solidity Gas: eliminare le variabili che non usi
Eliminare le variabili che non si usano è un modo per dare dei valori predefiniti alle variabili dopo che sono state calcolate completamente senza che i dati vengano salvati nella memoria. Per esempio, il valore predefinito delle variabili del tipo uint è 0.
Non distruggendo le variabili della funzione al termine delle funzioni, il costo medio del gas è di 100.300 unità per assegnare le variabili ai dati. Risparmio medio di gas del 19% usando il tasto Canc per rimuovere le variabili dei dati (per impostare le variabili a 0).
Usa array di dimensioni fisse invece di array dinamici per ridurre al minimo i costi del gas degli smart contract.
Usa le mappature quando puoi per ridurre i costi del gas degli smart contract. Comunque, quando servono gli array, quelli di dimensione fissa sono più economici in termini di gas rispetto a quelli di dimensione dinamica, perché questi ultimi possono essere allargati all'infinito e quindi costano di più.
Gli array dinamici possono essere ampliati, quindi l'EVM deve tenere d'occhio le lunghezze e aggiornarle quando si aggiungono nuovi elementi.
Pensa a un codice che definisce array di dimensioni dinamiche e li aggiorna con funzioni updateArray. Le istruzioni Require assicurano che gli indici forniti siano all'interno di un intervallo di array di dimensioni fisse. Quando si eseguono 100 ripetizioni di un test, la quantità media di gas utilizzata è 12.541.
Cambiare gli array in dimensione fissa 5 crea array di dimensione fissa di lunghezza 5, tipo uint256. L'EVM sa che fixedArray con variabile di stato dimensione 5 ha 5 slot e la lunghezza non viene salvata nella memoria. Sostituire gli array dinamici con quelli fissi fa risparmiare il 17,99% di gas.
Ottimizza oggi stesso i tuoi contratti intelligenti
Inizia a usare queste tecniche di ottimizzazione del gas per ridurre i costi fino al 90% su Base e altre catene L2.
Usa uint8 al posto di uint256
Questo è meno efficiente e può essere più costoso da usare rispetto a uint256 a causa del funzionamento dell'EVM. L'EVM ha dimensioni di parola a 256 bit. Le operazioni con numeri interi a 256 bit (uint256) tendono ad essere le più efficienti, perché si adattano alla dimensione delle parole dell'EVM, mentre i tipi più piccoli (come uint8) richiedono al compilatore Solidity di creare operazioni aggiuntive per adattare i tipi più piccoli in un singolo slot di memoria a 256 bit.
In generale, anche se i tipi piccoli come uint8 possono essere utili per lo spazio di archiviazione (un sacco di tipi piccoli possono essere messi in un'unica operazione con uno slot di archiviazione a 256 bit), si è visto che i tipi più piccoli aiutano solo con lo spazio di archiviazione. Il risparmio di spazio può essere annullato convertendo da e verso uint256 per fare i calcoli.
Combinazione di variabili inferiori a 256 bit
Combinare variabili di dimensioni inferiori a 256 bit di solito non è efficiente come usare variabili a 256 bit. Ma a volte, quando non c'è interoperabilità, bisogna usare tipi meno potenti in dimensioni più piccole, tipo i booleani che occupano 1 byte o 8 bit per essere memorizzati.
Quando si usano tipi meno potenti, puoi dichiarare variabili di stato tenendo conto dello spazio di archiviazione, e Solidity può raggrupparle e memorizzarle usando lo stesso slot di archiviazione. Il vantaggio del raggruppamento delle variabili viene di solito considerato nelle operazioni di archiviazione, piuttosto che nelle operazioni di memoria o di stack.
Dato che le dimensioni delle combinazioni bidirezionali sono di 16 bit, ovvero 240 bit in meno rispetto alla capacità di memorizzare un singolo slot di archiviazione, Solidity può essere usato per raggruppare le variabili nello stesso slot e ridurre al minimo l'utilizzo di gas di distribuzione, senza bisogno di tanti slot per memorizzare le variabili di stato.
Riorganizzare le dichiarazioni delle variabili permette di ottimizzare in media il 13% del gas.
Risultati del confezionamento delle variabili
| Fase | Consumo di gas | Risparmi |
|---|---|---|
| Pre-ottimizzazione | 1.678 | - |
| Post-ottimizzazione | 1.447 | 13% |
Seleziona il modificatore di visibilità esterna
Per ottimizzare il gas degli smart contract, è meglio scegliere la giusta visibilità delle funzioni. I modificatori di visibilità esterni potrebbero essere più efficienti nell'uso del gas rispetto a quelli pubblici, per come una funzione pubblica gestisce i suoi argomenti e per come i dati vengono trasferiti alle funzioni.
Le funzioni esterne possono accedere a calldata, che è uno spazio temporaneo di sola lettura nell'EVM che contiene i parametri di una chiamata di funzione. Le funzioni pubbliche possono essere chiamate:
- •Esternamente (quando vengono chiamati esternamente da una transazione usando calldata)
- •Internamente (quando vengono chiamati all'interno di un contratto usando calldata)
Dato che le funzioni sono pubbliche, devono ricevere array in memoria che possono essere costosi in termini di gas se sono grandi. Passare le funzioni all'esterno permette di ricevere array nei calldata, che è più conveniente quando si ha a che fare con array grandi, risparmiando in media lo 0,3% di unità di gas per chiamata.
Memorizzazione per rileggere lo stesso valore
Un buon trucco per risparmiare gas è non leggere più volte lo stesso valore nella memoria. Leggere dalla memoria costa di più che leggere dalla RAM. Rileggere più volte le stesse variabili nella memoria e scrivere nella memoria quando non serve può essere uno spreco di gas negli smart contract.
Questo può essere evitato definendo variabili che sono in memoria all'inizio delle funzioni e assegnando loro valori di variabili numeriche.
Questo fa risparmiare il 17% del gas usato dalle funzioni sumNumbers, ma più grande è l'array, più grandi saranno i numeri di iterazione e il gas usato.
Variabili di cache Risultati
| Fase | Consumo di gas | Risparmi |
|---|---|---|
| Prima dell'ottimizzazione | 3.527 | - |
| Dopo l'ottimizzazione | 2.905 | 17% |
Non impostare le variabili con i valori predefiniti
Quando dichiari variabili di stato senza inizializzarle (cioè senza assegnare loro un valore iniziale), queste variabili vengono automaticamente inizializzate con valori predefiniti:
- •uint: 0
- •bool: false
- •indirizzo: indirizzo(0)
Quest'ultimo è più economico rispetto alla dichiarazione dei valori come predefiniti e al loro semplice aggiornamento quando l'utente interagisce con il sistema, che non è efficiente in termini di gas. Senza l'inizializzazione delle variabili, l'ottimizzazione indica un risparmio medio di gas del 4%.
Supporta l'ottimizzazione del compilatore Solidity
Solidity ha dei compilatori con impostazioni facili da cambiare per ottimizzare il codice compilato. La compilazione ottimizzata viene eseguita centinaia di volte, ottimizzando il codice e trasformandolo in forme più economiche che richiedono meno gas per funzionare.
I compilatori possono essere regolati per trovare il giusto equilibrio tra i costi di implementazione e quelli di esecuzione. Definire il numero stimato di contratti da eseguire usando i comandi di esecuzione:
- •Livelli più alti sono migliori in termini di prezzi bassi del gas quando si applica il contratto
- •Meno numeri sono meglio in termini di riduzione dei costi del gas nell'implementazione del contratto
Ottimizza i flag più il valore di run=200 dice ai compilatori di ottimizzare il codice per risparmiare gas quando si eseguono le funzioni incrementCount 200 volte. Classifica queste impostazioni in base ai requisiti specifici dell'applicazione.
Bonus Ottimizzazione del gas Solidity: Assemblaggio
Quando scrivi smart contract in Solidity, questi vengono compilati in bytecode, una sequenza di codici operativi EVM. Tramite l'assembly, puoi semplicemente scrivere codice che gira a livelli più compatibili con i codici operativi e, in alcuni casi, la possibilità di ottimizzare manualmente i codici operativi offre un vantaggio rispetto al bytecode Solidity.
Anche se scrivere codice a un livello così basso non è proprio una passeggiata, ha il vantaggio di permettere di ottimizzare manualmente gli opcode, quindi in generale è meglio rispetto al bytecode Solidity. Questo livello di ottimizzazione lo rende più efficiente ed efficace nell'esecuzione del contratto.
Anche nei casi più semplici, tipo quando le due funzioni devono sommare due numeri, le versioni in Solidity e Assembly avranno qualche differenza, ma le versioni Assembly costano meno.
Fare progetti su L2 come Base significa che gli utenti spenderanno meno per usare i protocolli, ma gli sviluppatori devono assicurarsi di usare le tecniche di ottimizzazione del gas. Questi consigli possono far risparmiare un sacco sui costi delle transazioni, aggiungere scalabilità e migliorare l'efficienza del contratto in generale.
L'Assembly può essere usato per ottimizzare l'esecuzione degli smart contract usando il gas, ma a volte le versioni Assembly possono creare codice non sicuro. È una buona idea coinvolgere esperti di sicurezza degli smart contract nella revisione dei contratti prima che vengano implementati.


