(Articolo pubblicato in italiano col permesso di Md Zaryab Afser, l’originale in inglese è disponibile sul suo sito)

Solidity ha appena rilasciato la nuova versione di Solidity, la 0.8.20.

E, come sempre, insieme a questa versione sono state introdotte molte nuove modifiche, miglioramenti, correzioni di bug, ecc. Tuttavia, c'è un aggiornamento fondamentale in questa versione di cui gli sviluppatori di smart contract devono essere a conoscenza. Si tratta dell'inclusione di un nuovo opcode chiamato PUSH0.


The new compiler switches the default target EVM version to Shanghai, which means that the generated bytecode will include PUSH0 opcodes.

— Solidity Team

Prima di tutto, cos'è esattamente PUSH0?

L'opcode PUSH0 è in realtà piuttosto semplice.

Si tratta di un'istruzione che ha un compito specifico, ovvero quello di inserire il valore costante ZERO nello stack. Tutto qui, credetemi.

Sebbene PUSH0 sia stato recentemente incluso nella versione 0.8.20 di Solidity, la sua importanza è evidente fin dal 2021, con la nascita dell'EIP-3855.

Nelle sezioni seguenti, approfondiremo il significato di questo opcode apparentemente semplice ed esploreremo le sue implicazioni cruciali.

Se si dà una rapida occhiata agli opcode relativi alle operazioni PUSH che abbiamo avuto finora (istruzioni da 0x60 a 0x7f), ci si rende conto che avevamo opcode da PUSH1 a PUSH32.

Ciò significa che abbiamo la possibilità di inserire nello stack qualsiasi elemento da 1 byte a 32 byte, utilizzando il rispettivo opcode in base alle nostre esigenze.

PUSH1  = 0x60, // Place 1 byte item on stack.
PUSH2  = 0x61, // Place 2 byte item on stack.
PUSH3  = 0x62, // Place 3 byte item on stack.
PUSH4  = 0x63, // Place 4 byte item on stack.
PUSH5  = 0x64, // Place 5 byte item on stack.
PUSH6  = 0x65, // Place 6 byte item on stack.
PUSH7  = 0x66, // Place 7 byte item on stack.
PUSH8  = 0x67, // Place 8 byte item on stack.
PUSH9  = 0x68, // Place 9 byte item on stack.
PUSH10 = 0x69, // Place 10 byte item on stack.
....
PUSH31 = 0x7e, // Place 31 byte item on stack.
PUSH32 = 0x7f, // Place 32 byte item on stack.

Perché dovremmo voler INSERIRE il valore ZERO nello stack?

💡Se vi state chiedendo perché dovremmo inserire il valore ZERO nello stack, dovreste dare un'occhiata a EIP3855 per maggiori dettagli, dato che ci sono molti casi in cui ZERO è richiesto nello stack per effettuare operazioni importanti.

 

Tuttavia, non avevamo un modo adeguato per inserire ZERO nello stack.

Pertanto, per inserire il valore ZERO nello stack, abbiamo finora trovato delle scorciatoie come:

  • "PUSH1 00": utilizzando l'opcode PUSH1 per inserire gli zeri nello stack,

  • l'uso di più istruzioni DUP per duplicare gli zeri e metterli in pila, ecc.

Sebbene le soluzioni di cui sopra abbiano svolto il loro compito, non erano comunque adeguate.

L'uso di "PUSH1 00", ad esempio, è codificato come due byte e tecnicamente consuma più gas di quanto dovrebbe per mettere uno zero sullo stack.

Inoltre, l'uso di più istruzioni DUP potrebbe far lievitare le dimensioni del codice del contratto e non è un approccio ottimizzato. Come accennato in precedenza, questo nuovo opcode potrebbe sembrare piuttosto semplice, ma risolve tutti questi problemi che sono stati ignorati per molto tempo.

Una parte della documentazione dell'EIP3855 dice:

To put the “waste” into perspective, across existing accounts 340,557,331 bytes are wasted on PUSH1 00 instructions, which means 68,111,466,200 gas was spent to deploy them.In practice, a lot of these accounts share identical bytecode with others, so their total stored size in clients is lower, however, the deploy time cost must have been paid nevertheless.

— EIP3855

E questo già dimostra quanto poco efficiente sia stato finora l’uso o abuso delle tecniche precedentemente adottate.

Introduciamo l'opcode PUSH0

Ora, con l'inclusione di PUSH0, saremo in grado di risolvere tutti questi problemi in un colpo solo.

L'opcode PUSH0 ci consentirà di inserire direttamente un valore costante 0 nello stack senza dover utilizzare più istruzioni DUP o una combinazione di altri opcode.

Con il nuovo opcode PUSH0, ora abbiamo:

  • Un meccanismo adeguato per inserire lo zero sullo stack,

  • Riduzione della dimensione del bytecode del contratto, poiché possiamo sostituire molti opcode con il solo PUSH0,

  • Riduzione al minimo dell'uso delle istruzioni DUP per duplicare gli zeri sullo stack, ecc.

  • Tempo di verifica

Siamo in Web3, quindi 👇

Dont’ trust, verify

Proviamo a verificare tutti i dettagli di cui sopra sull'opcode PUSH0 con un esempio e vediamo se fa effettivamente la magia. 🪄

Prendiamo come esempio questo piccolo contratto,

contratto PushZero_Test{

uint256 public num;

funzione set(uint256 _n) public{

num = _n;

}

}

Compiliamo e distribuiamo questo contratto.

Per prima cosa, utilizzare le versioni precedenti, come la 0.8.19 o la 0.8.16, ecc. poi si usa l'ultima versione, la 0.8.20.

Risultati? 🤔

Dimensione del codice del contratto

➡️ Dimensione del bytecode del contratto utilizzando la versione precedente = ~678 caratteri

➡️ Dimensione del bytecode del contratto utilizzando la versione 0.8.20 = ~646 caratteri

Costo di distribuzione del gas ⛽️

➡️ Costo di implementazione del contratto usando le vecchie versioni = ~61511 gas

➡️ Costo di distribuzione del contratto usando le versioni 0.8.20 = ~58909 gas

Come risultato di questo breve esperimento, possiamo chiaramente verificare che con l'inclusione dell'opcode PUSH0, ora abbiamo:

  • Riduzione della dimensione del codice del contratto e

  • Riduzione del costo del gas di distribuzione del contratto

L'opcode quindi svolge egregiamente il suo compito. 🧐

Se avete sottomano truffle, hardhat o remix non limitatevi a leggere. Provate e verificate anche voi

☢️ Avvertenza importante per gli sviluppatori di Solidity

Sebbene l'opcode PUSH0 sia ora incluso nell'ultimo compilatore Solidity, è necessario fare attenzione quando lo si utilizza su catene diverse da ETH mainnet.

Ci sono ancora altre blockchain EVM o L2 che non riconoscono l'opcode PUSH0. Pertanto, se si tenta di utilizzare l'ultimo compilatore per distribuire il proprio contratto su una catena che non supporta questo opcode, la distribuzione del contratto fallirà.

Si potrebbe ottenere un errore che assomiglia a questo 👇


Distribuzione fallita durante l'utilizzo della versione 0.8.20 su Polygon Mumbai

Pertanto, in questi casi, è necessario assicurarsi di aver selezionato la versione EVM corretta. Per saperne di più sulla selezione della versione EVM corretta da utilizzare, vai QUI.

Bene sviluppatore solidity, spero che sia stato utile.

A più tardi. 👋🏻