Debug delle Transazioni
(si veda anche la pagina di accompagnamento di questa: il tour del Debugger)
Esistono due modi per avviare una sessione di debug, ognuno dei quali corrisponde a un caso d’uso diverso.
Caso d’uso 1: per eseguire il debug di una transazione effettuata in Remix, fare clic sul pulsante Debug nel registro delle transazioni nel Terminale di Remix.
Caso d’uso 2: per il debug di una transazione in cui si dispone di un”hash di transazione da un contratto verificato o in cui si dispone dell’hash di transazione e del codice sorgente compilato con le stesse impostazioni di compilazione del contratto distribuito.
Avviare il debug dal registro delle transazioni nel Terminale
Cominciamo con un contratto di base (o sostituisci il contratto qui sotto con il tuo)
pragma solidity >=0.5.1 <0.6.0;
contract Donation {
address owner;
event fundMoved(address _to, uint _amount);
modifier onlyowner { if (msg.sender == owner) _; }
address[] _giver;
uint[] _values;
constructor() public {
owner = msg.sender;
}
function donate() public payable {
addGiver(msg.value);
}
function moveFund(address payable _to, uint _amount) onlyowner public {
uint balance = address(this).balance;
uint amount = _amount;
if (amount <= balance) {
if (_to.send(balance)) {
emit fundMoved(_to, amount);
} else {
revert();
}
} else {
revert();
}
}
function addGiver(uint _amount) internal {
_giver.push(msg.sender);
_values.push(_amount);
}
}
Crea un nuovo file in Remix e copiaci dentro il codice di cui sopra.
Compila il codice.
Vai al modulo Esegui & Distribuisci.
Per lo scopo di questa esercitazione, eseguiremo la Remix VM
.
Distribuisci il contratto:
Fare clic sul pulsante Distribuisci
Si vedrà l’istanza distribuita (alias udapp).
Open it up (by clicking the caret).
Invocheremo la funzione Dona
e invieremo 2 Ether.
Per farlo: nella casella di inserimento del valore immettere 2 e selezionare Ether come unità (NON LASCIARE L’UNITÀ DI DEFAULT come gwei o la modifica sarà difficile da rilevare).
Quindi clicca sul pulsante Dona
.
Questo invierà l’Ether alla funzione.
Because we are using the Remix VM
, everything happens almost instantly. (If we had been using Injected Web 3, then we would have needed to approve the transaction, pay for gas and wait for the transaction to get mined.)
Remix visualizza le informazioni relative a ciascun risultato della transazione nel terminale.
Controlla nel terminale dove è registrata la transazione appena effettuata.
Clicca sul pulsante di debug.
Ma prima di passare allo strumento di debug vero e proprio, la prossima sezione mostra come avviare una sessione di debug direttamente dal Debugger.
Avviare il debug dal Debugger
Fai clic sull’icona del bug nel pannello delle icone per accedere al debugger nel pannello laterale.
Se non si vede l’icona del bug, vai nel gestore dei plugin e attiva il debugger.
È possibile avviare una sessione di debug fornendo un hash di transazione
.
Per trovare un hash di transazione:
Vai a una transazione nel terminale.
Fai clic su una riga con una transazione - per espandere il registro.
L’hash di transazione è lì: copialo.
Quindi fai clic nel debugger per incollare l’hash e premi il pulsante Avvia il debug
.
Utilizzare il debugger
Il debugger consente di visualizzare informazioni dettagliate sull’esecuzione della transazione. Esso utilizza l’editor per visualizzare la posizione nel codice sorgente in cui si trova l’esecuzione attuale.
La parte di navigazione contiene un cursore e dei pulsanti che possono essere utilizzati per procedere con l’esecuzione della transazione.
11 pannelli forniscono informazioni dettagliate sull’esecuzione:
Istruzioni
Il pannello Istruzioni visualizza il bytecode del contratto in esecuzione, con il passaggio attuale evidenziato.
Nota importante: quando questo pannello è nascosto, il cursore avrà una granularità più grossolana e si fermerà solo ai confini delle espressioni, anche se queste sono compilate in più istruzioni EVM. Quando il pannello è visualizzato, sarà possibile passare sopra ogni istruzione, anche quelle che fanno riferimento alla stessa espressione.
Solidity Locals
Il pannello «Solidity Locals» visualizza le variabili locali associate al contesto attuale.
Stato di Solidity
Il pannello Stato di Solidity visualizza le variabili di stato del contratto in esecuzione.
Pannelli di basso livello
Questi pannelli mostrano informazioni di basso livello sull’esecuzione:
Stack
Modifiche dell’Archiviazione
Memoria
Dati d’Invocazione
Pila d’Invocazione
Valore Restituito (solo se il passaggio corrente è un codice operativo RETURN)
Full Storages Changes (only at the end of the execution & it displays all the storage changes)
Transazione Stornata
Una transazione può essere stornata
(a causa di un’eccezione carburante esaurito, di un’istruzione revert
di Solidity o di un’eccezione di basso livello).
È importante essere consapevoli dell’eccezione e individuare la posizione dell’eccezione nel codice sorgente.
Remix ti avviserà quando l’esecuzione genera un’eccezione. Il pulsante di avvertimento salta all’ultimo codice operativo prima che si verificasse l’eccezione.
Punti di interruzione
Gli ultimi due pulsanti dell’area di navigazione servono per tornare al punto di interruzione precedente o per passare al punto di interruzione successivo.
I punti di interruzione possono essere aggiunti e rimossi facendo clic sul numero di riga nell’Editor**.
Quando si utilizza una sessione di debug con punti d’interruzione, l’esecuzione salta al primo punto d’interruzione incontrato.
Nota importante: se si aggiunge un punto d’interruzione a una riga che dichiara una variabile, questo potrebbe essere attivato due volte: una prima volta per inizializzare la variabile a zero e una seconda volta per assegnare il valore effettivo.
Ecco un esempio di questo problema. Se stai facendo debug del seguente contratto:
pragma solidity >=0.5.1 <0.6.0;
contract ctr {
function hid() public {
uint p = 45;
uint m;
m = 89;
uint l = 34;
}
}
E punti d’interruzione sono impostati per le linee
uint p = 45;
m = 89;
uint l = 34;
allora, facendo clic sul pulsante Salta al prossimo punto di interruzione
, si fermerà alle righe seguenti nell’ordine indicato:
uint p = 45;
(dichiarazione di p)
uint l = 34;
(dichiarazione di l)
uint p = 45;
(45 assegnato a p)
m = 89;
(89 assegnato a m)
uint l = 34;
(34 assegnato a l)