2016-04-13 18 views
6

Ho una funzione su un contratto Solidità che esegue un lancio. Per esempio.Qual è il modello per la gestione del tiro su un contratto Solidity nei test

function do(x,y) { 
     if (msg.sender != owner) 
      throw; 
     // ... 
    } 

Nell'ambiente Tartufo ho qualcosa un test js come:

//.... part of a promise chain 
     .then(
      function (_bool0) { 
       assert.isTrue(_bool0,"whoops - should be true"); 
       return contract.do("okdoke" , {from: accounts[1]}); 
      }).then(
      function (tx_id) { 
       //.. 
       done(); 
      } 
    // ... 

Il contract.do ritorno() fa sì che la condizione che si traduce nel lancio. Che produce il seguente nella Tartufo di prova uscita per questo test:

Error: VM Exception while executing transaction: invalid JUMP 

Qual è il linguaggio per la gestione di un lancio da una funzione contratto in un test come questo? Il tiro è il comportamento corretto.

+0

Caveat per chiunque seguendo il "controllo se si utilizza tutto il gas" approccio: Questo cambierà in futuro, dato che il lancio viene deprecato a favore di "revert()". Revert() NON consumerà tutto il gas, solo il gas che è stato utilizzato fino al punto in cui è stato chiamato revert(). – TripleSpeeder

+0

Questo problema mi crea ancora problemi, soprattutto dal momento che sto usando revert(). Sono stato in grado di individuare errori su TestRPC ma ora che sono in corso, le transazioni restituite dalla rete di test sono state restituite come se avessero avuto successo. eventuali aggiornamenti dalla tua parte? – okwme

risposta

3

La soluzione "più corretta" a questo problema che ho avuto modo di verificare è che tutto il gas inviato è stato speso, che è ciò che accade in un lancio, ma c'è un'ulteriore ruga per rendere la soluzione lavoro su entrambi i TestRPC (che suppongo tu stia usando, dato l'errore reale che viene lanciato) e Geth. Quando si verifica un lancio in Geth, viene ancora creata una transazione, spendendo tutto il gas, ma non si verificano cambiamenti di stato. TestRPC effettivamente genera l'errore, che è utile per scopi di debug.

//Somewhere where global functions can be defined 
    function checkAllGasSpent(gasAmount, gasPrice, account, prevBalance){ 
     var newBalance = web3.eth.getBalance(account); 
     assert.equal(prevBalance.minus(newBalance).toNumber(), gasAmount*gasPrice, 'Incorrect amount of gas used'); 
    } 

    function ifUsingTestRPC(){ 
     return; 
    } 

    //Some default values for gas 
    var gasAmount = 3000000; 
    var gasPrice = 20000000000; 

    .... 

    //Back in your actual test 
    it('should fail ', function (done) { 
     var prevBalance; 

    .... 

    .then(function (_bool0) { 
     assert.isTrue(_bool0,"whoops - should be true"); 
     prevBalance = web3.eth.getBalance(accounts[1]); 
     return contract.do("okdoke" , {from: accounts[1], gasPrice:gasPrice, gas:gasAmount }); 
     }) 
    .catch(ifUsingTestRPC) 
    .then(function(){ 
     checkAllGasSpent(gasAmount, gasPrice, accounts[1], prevBalance); 
    }) 
    .then(done) 
    .catch(done); 

Sarei felice di implementare una soluzione più semplice se ne viene visualizzato un altro.

NB Se si spende tutto il gas con una transazione che è accidentalmente valida, questo non lo rileverà - presumerà che il gas è stato speso a causa di un lancio all'interno della VM.

+0

grazie per averci dedicato del tempo per pensarci, ma stavo cercando più come gestire il lancio. L'eccezione VM sembra spezzare tutto ma speravo in una tecnica try/catch per mantenere il controllo. Piuttosto che tutto crolla. – Interition

0

Giusto per far sapere a tutti, mi sono imbattuto in questo problema come bene e hanno utilizzato il seguente:

function getTransactionError(func) { 
    return Promise.resolve().then(func) 
    .then(function(txid) { 
     var tx = web3.eth.getTransaction(txid); 
     var txr = web3.eth.getTransactionReceipt(txid); 
     if (txr.gasUsed === tx.gas) throw new Error("all gas used"); 
    }) 
    .catch(function(err) { 
     return err; 
    }); 
} 

Su Geth si utilizza la transazione ID per ottenere disponibili gas e gas utilizzato e restituisce un errore di caso è stato utilizzato tutto il gas. Su testrpc cattura semplicemente l'eccezione generata e la restituisce. Lo sto usando in un test come segue:

return getTransactionError(function() { 
    return contract.doSomething(); 
}).then(function(err) { 
    assert.isDefined(err, "transaction should have thrown"); 
}); 

Naturalmente si può anche lasciare fuori il fermo, nel qual caso la promessa semplicemente esito negativo con un errore se è stato gettato.

2

Il progetto Zeppelin come un modo fantastico per fare proprio questo:

it("should fail to withdraw", async() => { 
    try { 
     await receiver.withdrawToken(0x0); 
     assert.fail('should have thrown before'); 
    } catch(error) { 
     assertJump(error); 
    } 
    }); 

function assertJump(error) { 
    assert.isAbove(error.message.search('invalid opcode'), -1, 'Invalid opcode error must be returned'); 
} 

https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/Ownable.js Per vedere un esempio completo

Problemi correlati