2014-03-26 05:01:17 +00:00
/*
This file is part of cpp - ethereum .
cpp - ethereum is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
cpp - ethereum is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with cpp - ethereum . If not , see < http : //www.gnu.org/licenses/>.
*/
/** @file TestHelper.cpp
* @ author Marko Simovic < markobarko @ gmail . com >
* @ date 2014
*/
2014-09-05 15:09:58 +00:00
# include "TestHelper.h"
2014-03-26 05:01:17 +00:00
# include <thread>
# include <chrono>
2014-04-23 14:08:11 +00:00
# include <libethereum/Client.h>
2014-10-29 16:25:02 +00:00
# include <liblll/Compiler.h>
2014-12-12 10:48:15 +00:00
# include <libevm/VMFactory.h>
2015-03-25 11:13:44 +00:00
# include "Stats.h"
2014-10-29 16:25:02 +00:00
using namespace std ;
2014-11-03 15:33:02 +00:00
using namespace dev : : eth ;
2014-03-26 05:01:17 +00:00
2014-09-05 15:09:58 +00:00
namespace dev
{
2014-03-26 05:01:17 +00:00
namespace eth
{
void mine ( Client & c , int numBlocks )
{
auto startBlock = c . blockChain ( ) . details ( ) . number ;
c . startMining ( ) ;
while ( c . blockChain ( ) . details ( ) . number < startBlock + numBlocks )
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 100 ) ) ;
c . stopMining ( ) ;
}
2014-04-03 15:01:03 +00:00
void connectClients ( Client & c1 , Client & c2 )
{
2014-09-30 14:53:15 +00:00
( void ) c1 ;
( void ) c2 ;
2014-09-16 12:09:48 +00:00
// TODO: Move to WebThree. eth::Client no longer handles networking.
2014-09-15 19:49:52 +00:00
#if 0
2014-04-03 15:01:03 +00:00
short c1Port = 20000 ;
short c2Port = 21000 ;
c1 . startNetwork ( c1Port ) ;
c2 . startNetwork ( c2Port ) ;
c2 . connect ( " 127.0.0.1 " , c1Port ) ;
2014-09-15 19:49:52 +00:00
# endif
2014-04-03 15:01:03 +00:00
}
2015-04-13 16:12:05 +00:00
void mine ( State & s , BlockChain const & _bc )
{
s . commitToMine ( _bc ) ;
GenericFarm < ProofOfWork > f ;
bool completed = false ;
f . onSolutionFound ( [ & ] ( ProofOfWork : : Solution sol )
{
return completed = s . completeMine < ProofOfWork > ( sol ) ;
} ) ;
f . setWork ( s . info ( ) ) ;
f . startCPU ( ) ;
while ( ! completed )
this_thread : : sleep_for ( chrono : : milliseconds ( 20 ) ) ;
}
void mine ( BlockInfo & _bi )
{
GenericFarm < ProofOfWork > f ;
bool completed = false ;
f . onSolutionFound ( [ & ] ( ProofOfWork : : Solution sol )
{
ProofOfWork : : assignResult ( sol , _bi ) ;
return completed = true ;
} ) ;
f . setWork ( _bi ) ;
f . startCPU ( ) ;
while ( ! completed )
this_thread : : sleep_for ( chrono : : milliseconds ( 20 ) ) ;
}
2014-11-03 15:33:02 +00:00
}
2014-04-03 15:01:03 +00:00
2014-10-29 16:25:02 +00:00
namespace test
{
2015-02-10 19:53:38 +00:00
struct ValueTooLarge : virtual Exception { } ;
2015-04-07 21:31:30 +00:00
struct MissingFields : virtual Exception { } ;
2015-02-10 19:53:38 +00:00
bigint const c_max256plus1 = bigint ( 1 ) < < 256 ;
2015-04-09 18:30:00 +00:00
2015-04-05 19:08:22 +00:00
ImportTest : : ImportTest ( json_spirit : : mObject & _o , bool isFiller ) :
m_statePre ( OverlayDB ( ) , eth : : BaseState : : Empty , Address ( _o [ " env " ] . get_obj ( ) [ " currentCoinbase " ] . get_str ( ) ) ) ,
m_statePost ( OverlayDB ( ) , eth : : BaseState : : Empty , Address ( _o [ " env " ] . get_obj ( ) [ " currentCoinbase " ] . get_str ( ) ) ) ,
m_TestObject ( _o )
2014-10-29 16:25:02 +00:00
{
importEnv ( _o [ " env " ] . get_obj ( ) ) ;
importState ( _o [ " pre " ] . get_obj ( ) , m_statePre ) ;
2014-11-03 15:33:02 +00:00
importTransaction ( _o [ " transaction " ] . get_obj ( ) ) ;
2014-10-29 16:25:02 +00:00
if ( ! isFiller )
{
importState ( _o [ " post " ] . get_obj ( ) , m_statePost ) ;
2014-12-05 18:26:32 +00:00
m_environment . sub . logs = importLog ( _o [ " logs " ] . get_array ( ) ) ;
2014-10-29 16:25:02 +00:00
}
2014-03-26 05:01:17 +00:00
}
2014-10-29 16:25:02 +00:00
2015-04-09 18:30:00 +00:00
json_spirit : : mObject & ImportTest : : makeAllFieldsHex ( json_spirit : : mObject & _o )
{
2015-04-15 23:03:26 +00:00
static const set < string > hashes { " bloom " , " coinbase " , " hash " , " mixHash " , " parentHash " , " receiptTrie " ,
" stateRoot " , " transactionsTrie " , " uncleHash " , " currentCoinbase " ,
2015-04-17 16:41:27 +00:00
" previousHash " , " to " , " address " , " caller " , " origin " , " secretKey " , " data " } ;
2015-04-13 13:33:42 +00:00
2015-04-15 23:03:26 +00:00
for ( auto & i : _o )
2015-04-09 18:30:00 +00:00
{
2015-04-15 23:03:26 +00:00
std : : string key = i . first ;
if ( hashes . count ( key ) )
2015-04-09 18:30:00 +00:00
continue ;
2015-04-13 13:33:42 +00:00
std : : string str ;
2015-04-15 23:03:26 +00:00
json_spirit : : mValue value = i . second ;
2015-04-09 23:13:54 +00:00
if ( value . type ( ) = = json_spirit : : int_type )
str = toString ( value . get_int ( ) ) ;
else if ( value . type ( ) = = json_spirit : : str_type )
str = value . get_str ( ) ;
else continue ;
2015-04-27 21:30:28 +00:00
_o [ key ] = ( str . substr ( 0 , 2 ) = = " 0x " ) ? str : toCompactHex ( toInt ( str ) , HexPrefix : : Add , 1 ) ;
2015-04-09 18:30:00 +00:00
}
return _o ;
}
2014-10-29 16:25:02 +00:00
void ImportTest : : importEnv ( json_spirit : : mObject & _o )
{
2015-03-12 08:16:32 +00:00
assert ( _o . count ( " previousHash " ) > 0 ) ;
assert ( _o . count ( " currentGasLimit " ) > 0 ) ;
assert ( _o . count ( " currentDifficulty " ) > 0 ) ;
assert ( _o . count ( " currentTimestamp " ) > 0 ) ;
assert ( _o . count ( " currentCoinbase " ) > 0 ) ;
assert ( _o . count ( " currentNumber " ) > 0 ) ;
2014-10-29 16:25:02 +00:00
2015-04-05 20:13:24 +00:00
m_environment . currentBlock . parentHash = h256 ( _o [ " previousHash " ] . get_str ( ) ) ;
2014-10-29 16:25:02 +00:00
m_environment . currentBlock . number = toInt ( _o [ " currentNumber " ] ) ;
m_environment . currentBlock . gasLimit = toInt ( _o [ " currentGasLimit " ] ) ;
m_environment . currentBlock . difficulty = toInt ( _o [ " currentDifficulty " ] ) ;
m_environment . currentBlock . timestamp = toInt ( _o [ " currentTimestamp " ] ) ;
m_environment . currentBlock . coinbaseAddress = Address ( _o [ " currentCoinbase " ] . get_str ( ) ) ;
2014-10-31 08:41:02 +00:00
m_statePre . m_previousBlock = m_environment . previousBlock ;
m_statePre . m_currentBlock = m_environment . currentBlock ;
2014-09-05 15:09:58 +00:00
}
2014-10-29 16:25:02 +00:00
2015-03-26 22:05:45 +00:00
// import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which fields were defined in json
void ImportTest : : importState ( json_spirit : : mObject & _o , State & _state , stateOptionsMap & _stateOptionsMap )
2014-10-29 16:25:02 +00:00
{
2014-10-31 08:41:02 +00:00
for ( auto & i : _o )
2014-10-29 16:25:02 +00:00
{
json_spirit : : mObject o = i . second . get_obj ( ) ;
2015-03-26 22:05:45 +00:00
ImportStateOptions stateOptions ;
2015-04-06 19:38:52 +00:00
u256 balance = 0 ;
u256 nonce = 0 ;
2014-10-29 16:25:02 +00:00
2015-03-26 22:05:45 +00:00
if ( o . count ( " balance " ) > 0 )
{
stateOptions . m_bHasBalance = true ;
if ( bigint ( o [ " balance " ] . get_str ( ) ) > = c_max256plus1 )
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " State 'balance' is equal or greater than 2**256 " ) ) ;
2015-04-06 14:40:01 +00:00
balance = toInt ( o [ " balance " ] ) ;
2015-03-26 22:05:45 +00:00
}
2014-10-29 16:25:02 +00:00
2015-03-26 22:05:45 +00:00
if ( o . count ( " nonce " ) > 0 )
{
stateOptions . m_bHasNonce = true ;
if ( bigint ( o [ " nonce " ] . get_str ( ) ) > = c_max256plus1 )
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " State 'nonce' is equal or greater than 2**256 " ) ) ;
2015-04-06 14:40:01 +00:00
nonce = toInt ( o [ " nonce " ] ) ;
2015-03-26 22:05:45 +00:00
}
2015-01-31 18:00:35 +00:00
2014-10-29 16:25:02 +00:00
Address address = Address ( i . first ) ;
2014-11-03 15:33:02 +00:00
2015-03-26 22:05:45 +00:00
bytes code ;
if ( o . count ( " code " ) > 0 )
{
code = importCode ( o ) ;
stateOptions . m_bHasCode = true ;
}
2014-11-03 15:33:02 +00:00
2014-11-05 17:30:38 +00:00
if ( code . size ( ) )
2014-10-29 16:25:02 +00:00
{
2015-04-06 14:40:01 +00:00
_state . m_cache [ address ] = Account ( balance , Account : : ContractConception ) ;
2015-01-20 19:33:33 +00:00
_state . m_cache [ address ] . setCode ( code ) ;
2014-10-29 16:25:02 +00:00
}
2014-11-03 15:33:02 +00:00
else
2015-04-06 14:40:01 +00:00
_state . m_cache [ address ] = Account ( balance , Account : : NormalCreation ) ;
2014-10-29 16:25:02 +00:00
2015-03-26 22:05:45 +00:00
if ( o . count ( " storage " ) > 0 )
{
stateOptions . m_bHasStorage = true ;
for ( auto const & j : o [ " storage " ] . get_obj ( ) )
_state . setStorage ( address , toInt ( j . first ) , toInt ( j . second ) ) ;
}
2014-12-12 20:21:18 +00:00
2015-04-06 14:40:01 +00:00
for ( int i = 0 ; i < nonce ; + + i )
2014-11-03 15:33:02 +00:00
_state . noteSending ( address ) ;
2014-10-31 08:41:02 +00:00
2014-11-03 15:33:02 +00:00
_state . ensureCached ( address , false , false ) ;
2015-03-26 22:05:45 +00:00
_stateOptionsMap [ address ] = stateOptions ;
}
}
void ImportTest : : importState ( json_spirit : : mObject & _o , State & _state )
{
stateOptionsMap importedMap ;
importState ( _o , _state , importedMap ) ;
2015-04-07 21:31:30 +00:00
for ( auto & stateOptionMap : importedMap )
{
//check that every parameter was declared in state object
if ( ! stateOptionMap . second . isAllSet ( ) )
BOOST_THROW_EXCEPTION ( MissingFields ( ) < < errinfo_comment ( " Import State: Missing state fields! " ) ) ;
2014-10-29 16:25:02 +00:00
}
}
2014-11-03 15:33:02 +00:00
void ImportTest : : importTransaction ( json_spirit : : mObject & _o )
2015-02-26 15:51:06 +00:00
{
2015-02-26 16:02:56 +00:00
if ( _o . count ( " secretKey " ) > 0 )
2015-02-26 15:51:06 +00:00
{
2015-03-12 08:16:32 +00:00
assert ( _o . count ( " nonce " ) > 0 ) ;
assert ( _o . count ( " gasPrice " ) > 0 ) ;
assert ( _o . count ( " gasLimit " ) > 0 ) ;
assert ( _o . count ( " to " ) > 0 ) ;
assert ( _o . count ( " value " ) > 0 ) ;
assert ( _o . count ( " data " ) > 0 ) ;
2015-02-26 15:51:06 +00:00
if ( bigint ( _o [ " nonce " ] . get_str ( ) ) > = c_max256plus1 )
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " Transaction 'nonce' is equal or greater than 2**256 " ) ) ;
if ( bigint ( _o [ " gasPrice " ] . get_str ( ) ) > = c_max256plus1 )
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " Transaction 'gasPrice' is equal or greater than 2**256 " ) ) ;
if ( bigint ( _o [ " gasLimit " ] . get_str ( ) ) > = c_max256plus1 )
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " Transaction 'gasLimit' is equal or greater than 2**256 " ) ) ;
if ( bigint ( _o [ " value " ] . get_str ( ) ) > = c_max256plus1 )
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " Transaction 'value' is equal or greater than 2**256 " ) ) ;
m_transaction = _o [ " to " ] . get_str ( ) . empty ( ) ?
Transaction ( toInt ( _o [ " value " ] ) , toInt ( _o [ " gasPrice " ] ) , toInt ( _o [ " gasLimit " ] ) , importData ( _o ) , toInt ( _o [ " nonce " ] ) , Secret ( _o [ " secretKey " ] . get_str ( ) ) ) :
Transaction ( toInt ( _o [ " value " ] ) , toInt ( _o [ " gasPrice " ] ) , toInt ( _o [ " gasLimit " ] ) , Address ( _o [ " to " ] . get_str ( ) ) , importData ( _o ) , toInt ( _o [ " nonce " ] ) , Secret ( _o [ " secretKey " ] . get_str ( ) ) ) ;
}
else
{
RLPStream transactionRLPStream = createRLPStreamFromTransactionFields ( _o ) ;
RLP transactionRLP ( transactionRLPStream . out ( ) ) ;
2015-04-08 00:42:51 +00:00
m_transaction = Transaction ( transactionRLP . data ( ) , CheckTransaction : : Everything ) ;
2015-02-26 15:51:06 +00:00
}
2014-10-29 16:25:02 +00:00
}
2015-04-02 15:33:28 +00:00
void ImportTest : : checkExpectedState ( State const & _stateExpect , State const & _statePost , stateOptionsMap const _expectedStateOptions , WhenError _throw )
2015-03-26 00:12:25 +00:00
{
2015-04-03 20:40:51 +00:00
# define CHECK(a,b) \
{ \
if ( _throw = = WhenError : : Throw ) \
BOOST_CHECK_MESSAGE ( a , b ) ; \
else \
BOOST_WARN_MESSAGE ( a , b ) ; \
}
2015-03-25 12:47:28 +00:00
for ( auto const & a : _stateExpect . addresses ( ) )
2015-03-24 18:36:04 +00:00
{
2015-03-26 00:12:25 +00:00
CHECK ( _statePost . addressInUse ( a . first ) , " Filling Test: " < < a . first < < " missing expected address! " ) ;
2015-03-25 12:47:28 +00:00
if ( _statePost . addressInUse ( a . first ) )
{
2015-03-26 22:05:45 +00:00
ImportStateOptions addressOptions ( true ) ;
if ( _expectedStateOptions . size ( ) )
{
try
{
addressOptions = _expectedStateOptions . at ( a . first ) ;
}
2015-05-06 11:18:52 +00:00
catch ( std : : out_of_range const & )
2015-03-26 22:05:45 +00:00
{
BOOST_ERROR ( " expectedStateOptions map does not match expectedState in checkExpectedState! " ) ;
break ;
}
}
2015-03-24 18:36:04 +00:00
2015-03-26 22:05:45 +00:00
if ( addressOptions . m_bHasBalance )
CHECK ( _stateExpect . balance ( a . first ) = = _statePost . balance ( a . first ) ,
" Check State: " < < a . first < < " : incorrect balance " < < _statePost . balance ( a . first ) < < " , expected " < < _stateExpect . balance ( a . first ) ) ;
2015-03-24 18:36:04 +00:00
2015-03-26 22:05:45 +00:00
if ( addressOptions . m_bHasNonce )
CHECK ( _stateExpect . transactionsFrom ( a . first ) = = _statePost . transactionsFrom ( a . first ) ,
" Check State: " < < a . first < < " : incorrect nonce " < < _statePost . transactionsFrom ( a . first ) < < " , expected " < < _stateExpect . transactionsFrom ( a . first ) ) ;
if ( addressOptions . m_bHasStorage )
{
2015-05-07 07:51:06 +00:00
unordered_map < u256 , u256 > stateStorage = _statePost . storage ( a . first ) ;
2015-03-26 22:05:45 +00:00
for ( auto const & s : _stateExpect . storage ( a . first ) )
CHECK ( stateStorage [ s . first ] = = s . second ,
" Check State: " < < a . first < < " : incorrect storage [ " < < s . first < < " ] = " < < toHex ( stateStorage [ s . first ] ) < < " , expected [ " < < s . first < < " ] = " < < toHex ( s . second ) ) ;
2015-03-27 21:48:51 +00:00
//Check for unexpected storage values
stateStorage = _stateExpect . storage ( a . first ) ;
for ( auto const & s : _statePost . storage ( a . first ) )
CHECK ( stateStorage [ s . first ] = = s . second ,
" Check State: " < < a . first < < " : incorrect storage [ " < < s . first < < " ] = " < < toHex ( s . second ) < < " , expected [ " < < s . first < < " ] = " < < toHex ( stateStorage [ s . first ] ) ) ;
2015-03-26 22:05:45 +00:00
}
if ( addressOptions . m_bHasCode )
2015-04-03 20:40:51 +00:00
CHECK ( _stateExpect . code ( a . first ) = = _statePost . code ( a . first ) ,
2015-03-26 22:05:45 +00:00
" Check State: " < < a . first < < " : incorrect code ' " < < toHex ( _statePost . code ( a . first ) ) < < " ', expected ' " < < toHex ( _stateExpect . code ( a . first ) ) < < " ' " ) ;
2015-03-25 12:47:28 +00:00
}
2015-03-24 18:36:04 +00:00
}
}
2015-02-28 17:57:01 +00:00
void ImportTest : : exportTest ( bytes const & _output , State const & _statePost )
2014-10-29 16:25:02 +00:00
{
2014-10-31 08:41:02 +00:00
// export output
2015-04-23 00:42:45 +00:00
m_TestObject [ " out " ] = toHex ( _output , 2 , HexPrefix : : Add ) ;
2014-10-31 08:41:02 +00:00
2014-12-01 21:44:31 +00:00
// export logs
m_TestObject [ " logs " ] = exportLog ( _statePost . pending ( ) . size ( ) ? _statePost . log ( 0 ) : LogEntries ( ) ) ;
2014-12-01 21:04:09 +00:00
2015-03-24 18:36:04 +00:00
// compare expected state with post state
2015-03-25 12:47:28 +00:00
if ( m_TestObject . count ( " expect " ) > 0 )
{
2015-03-26 22:05:45 +00:00
stateOptionsMap stateMap ;
2015-04-06 14:40:01 +00:00
State expectState ( OverlayDB ( ) , eth : : BaseState : : Empty ) ;
2015-03-26 22:05:45 +00:00
importState ( m_TestObject [ " expect " ] . get_obj ( ) , expectState , stateMap ) ;
checkExpectedState ( expectState , _statePost , stateMap , Options : : get ( ) . checkState ? WhenError : : Throw : WhenError : : DontThrow ) ;
2015-03-25 12:47:28 +00:00
m_TestObject . erase ( m_TestObject . find ( " expect " ) ) ;
}
2014-11-05 19:21:33 +00:00
2015-03-24 18:36:04 +00:00
// export post state
2015-03-09 09:28:48 +00:00
m_TestObject [ " post " ] = fillJsonWithState ( _statePost ) ;
2015-04-23 10:09:23 +00:00
m_TestObject [ " postStateRoot " ] = toHex ( _statePost . rootHash ( ) . asBytes ( ) ) ;
2015-03-02 20:19:36 +00:00
2014-11-05 19:21:33 +00:00
// export pre state
2015-03-09 09:28:48 +00:00
m_TestObject [ " pre " ] = fillJsonWithState ( m_statePre ) ;
2015-04-09 18:30:00 +00:00
m_TestObject [ " env " ] = makeAllFieldsHex ( m_TestObject [ " env " ] . get_obj ( ) ) ;
m_TestObject [ " transaction " ] = makeAllFieldsHex ( m_TestObject [ " transaction " ] . get_obj ( ) ) ;
2015-03-09 09:28:48 +00:00
}
2015-04-21 20:10:55 +00:00
json_spirit : : mObject fillJsonWithTransaction ( Transaction _txn )
{
json_spirit : : mObject txObject ;
2015-04-27 21:30:28 +00:00
txObject [ " nonce " ] = toCompactHex ( _txn . nonce ( ) , HexPrefix : : Add , 1 ) ;
2015-04-23 00:42:45 +00:00
txObject [ " data " ] = toHex ( _txn . data ( ) , 2 , HexPrefix : : Add ) ;
2015-04-27 21:30:28 +00:00
txObject [ " gasLimit " ] = toCompactHex ( _txn . gas ( ) , HexPrefix : : Add , 1 ) ;
txObject [ " gasPrice " ] = toCompactHex ( _txn . gasPrice ( ) , HexPrefix : : Add , 1 ) ;
txObject [ " r " ] = toCompactHex ( _txn . signature ( ) . r , HexPrefix : : Add , 1 ) ;
txObject [ " s " ] = toCompactHex ( _txn . signature ( ) . s , HexPrefix : : Add , 1 ) ;
txObject [ " v " ] = toCompactHex ( _txn . signature ( ) . v + 27 , HexPrefix : : Add , 1 ) ;
2015-04-22 23:43:35 +00:00
txObject [ " to " ] = _txn . isCreation ( ) ? " " : toString ( _txn . receiveAddress ( ) ) ;
2015-04-27 21:30:28 +00:00
txObject [ " value " ] = toCompactHex ( _txn . value ( ) , HexPrefix : : Add , 1 ) ;
2015-04-21 20:10:55 +00:00
return txObject ;
}
2015-03-09 09:28:48 +00:00
json_spirit : : mObject fillJsonWithState ( State _state )
{
json_spirit : : mObject oState ;
for ( auto const & a : _state . addresses ( ) )
2014-11-05 19:21:33 +00:00
{
json_spirit : : mObject o ;
2015-04-27 21:30:28 +00:00
o [ " balance " ] = toCompactHex ( _state . balance ( a . first ) , HexPrefix : : Add , 1 ) ;
o [ " nonce " ] = toCompactHex ( _state . transactionsFrom ( a . first ) , HexPrefix : : Add , 1 ) ;
2014-11-05 19:21:33 +00:00
{
json_spirit : : mObject store ;
2015-03-09 09:28:48 +00:00
for ( auto const & s : _state . storage ( a . first ) )
2015-04-27 21:30:28 +00:00
store [ toCompactHex ( s . first , HexPrefix : : Add , 1 ) ] = toCompactHex ( s . second , HexPrefix : : Add , 1 ) ;
2014-11-05 19:21:33 +00:00
o [ " storage " ] = store ;
}
2015-04-23 00:42:45 +00:00
o [ " code " ] = toHex ( _state . code ( a . first ) , 2 , HexPrefix : : Add ) ;
2015-03-09 09:28:48 +00:00
oState [ toString ( a . first ) ] = o ;
2014-11-05 19:21:33 +00:00
}
2015-03-09 09:28:48 +00:00
return oState ;
2014-10-31 08:41:02 +00:00
}
2015-04-21 20:10:55 +00:00
json_spirit : : mArray exportLog ( eth : : LogEntries _logs )
{
json_spirit : : mArray ret ;
if ( _logs . size ( ) = = 0 ) return ret ;
for ( LogEntry const & l : _logs )
{
json_spirit : : mObject o ;
2015-04-22 23:43:35 +00:00
o [ " address " ] = toString ( l . address ) ;
2015-04-21 20:10:55 +00:00
json_spirit : : mArray topics ;
for ( auto const & t : l . topics )
topics . push_back ( toString ( t ) ) ;
o [ " topics " ] = topics ;
2015-04-23 00:42:45 +00:00
o [ " data " ] = toHex ( l . data , 2 , HexPrefix : : Add ) ;
2015-04-22 23:43:35 +00:00
o [ " bloom " ] = toString ( l . bloom ( ) ) ;
2015-04-21 20:10:55 +00:00
ret . push_back ( o ) ;
}
return ret ;
}
2014-10-29 16:25:02 +00:00
u256 toInt ( json_spirit : : mValue const & _v )
{
switch ( _v . type ( ) )
{
case json_spirit : : str_type : return u256 ( _v . get_str ( ) ) ;
case json_spirit : : int_type : return ( u256 ) _v . get_uint64 ( ) ;
case json_spirit : : bool_type : return ( u256 ) ( uint64_t ) _v . get_bool ( ) ;
case json_spirit : : real_type : return ( u256 ) ( uint64_t ) _v . get_real ( ) ;
default : cwarn < < " Bad type for scalar: " < < _v . type ( ) ;
}
return 0 ;
}
byte toByte ( json_spirit : : mValue const & _v )
{
switch ( _v . type ( ) )
{
case json_spirit : : str_type : return ( byte ) stoi ( _v . get_str ( ) ) ;
case json_spirit : : int_type : return ( byte ) _v . get_uint64 ( ) ;
case json_spirit : : bool_type : return ( byte ) _v . get_bool ( ) ;
case json_spirit : : real_type : return ( byte ) _v . get_real ( ) ;
default : cwarn < < " Bad type for scalar: " < < _v . type ( ) ;
}
return 0 ;
}
2015-01-23 20:03:29 +00:00
bytes importByteArray ( std : : string const & _str )
2015-01-05 22:39:02 +00:00
{
2015-03-20 15:47:54 +00:00
return fromHex ( _str . substr ( 0 , 2 ) = = " 0x " ? _str . substr ( 2 ) : _str , WhenError : : Throw ) ;
2015-01-05 22:39:02 +00:00
}
2014-11-05 17:30:38 +00:00
bytes importData ( json_spirit : : mObject & _o )
2014-11-03 15:33:02 +00:00
{
bytes data ;
if ( _o [ " data " ] . type ( ) = = json_spirit : : str_type )
2015-01-23 20:03:29 +00:00
data = importByteArray ( _o [ " data " ] . get_str ( ) ) ;
2014-11-03 15:33:02 +00:00
else
for ( auto const & j : _o [ " data " ] . get_array ( ) )
data . push_back ( toByte ( j ) ) ;
return data ;
}
2014-11-05 17:30:38 +00:00
bytes importCode ( json_spirit : : mObject & _o )
2014-11-03 15:33:02 +00:00
{
bytes code ;
if ( _o [ " code " ] . type ( ) = = json_spirit : : str_type )
if ( _o [ " code " ] . get_str ( ) . find_first_of ( " 0x " ) ! = 0 )
code = compileLLL ( _o [ " code " ] . get_str ( ) , false ) ;
else
code = fromHex ( _o [ " code " ] . get_str ( ) . substr ( 2 ) ) ;
else if ( _o [ " code " ] . type ( ) = = json_spirit : : array_type )
{
code . clear ( ) ;
for ( auto const & j : _o [ " code " ] . get_array ( ) )
code . push_back ( toByte ( j ) ) ;
}
return code ;
}
2014-12-05 18:26:32 +00:00
LogEntries importLog ( json_spirit : : mArray & _a )
2014-12-01 21:04:09 +00:00
{
2014-12-01 21:44:31 +00:00
LogEntries logEntries ;
2014-12-05 18:26:32 +00:00
for ( auto const & l : _a )
2014-12-01 21:44:31 +00:00
{
2014-12-05 18:26:32 +00:00
json_spirit : : mObject o = l . get_obj ( ) ;
2014-12-01 21:44:31 +00:00
// cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest)
assert ( o . count ( " address " ) > 0 ) ;
assert ( o . count ( " topics " ) > 0 ) ;
assert ( o . count ( " data " ) > 0 ) ;
2014-12-05 18:26:32 +00:00
assert ( o . count ( " bloom " ) > 0 ) ;
2014-12-01 21:44:31 +00:00
LogEntry log ;
log . address = Address ( o [ " address " ] . get_str ( ) ) ;
for ( auto const & t : o [ " topics " ] . get_array ( ) )
2014-12-02 19:09:00 +00:00
log . topics . push_back ( h256 ( t . get_str ( ) ) ) ;
2014-12-01 21:44:31 +00:00
log . data = importData ( o ) ;
logEntries . push_back ( log ) ;
}
return logEntries ;
2014-12-01 21:04:09 +00:00
}
2014-11-05 17:30:38 +00:00
void checkOutput ( bytes const & _output , json_spirit : : mObject & _o )
2014-11-03 15:33:02 +00:00
{
int j = 0 ;
if ( _o [ " out " ] . type ( ) = = json_spirit : : array_type )
for ( auto const & d : _o [ " out " ] . get_array ( ) )
{
BOOST_CHECK_MESSAGE ( _output [ j ] = = toInt ( d ) , " Output byte [ " < < j < < " ] different! " ) ;
+ + j ;
}
else if ( _o [ " out " ] . get_str ( ) . find ( " 0x " ) = = 0 )
BOOST_CHECK ( _output = = fromHex ( _o [ " out " ] . get_str ( ) . substr ( 2 ) ) ) ;
else
BOOST_CHECK ( _output = = fromHex ( _o [ " out " ] . get_str ( ) ) ) ;
}
void checkStorage ( map < u256 , u256 > _expectedStore , map < u256 , u256 > _resultStore , Address _expectedAddr )
{
for ( auto & & expectedStorePair : _expectedStore )
{
auto & expectedStoreKey = expectedStorePair . first ;
auto resultStoreIt = _resultStore . find ( expectedStoreKey ) ;
if ( resultStoreIt = = _resultStore . end ( ) )
BOOST_ERROR ( _expectedAddr < < " : missing store key " < < expectedStoreKey ) ;
else
{
auto & expectedStoreValue = expectedStorePair . second ;
auto & resultStoreValue = resultStoreIt - > second ;
BOOST_CHECK_MESSAGE ( expectedStoreValue = = resultStoreValue , _expectedAddr < < " : store[ " < < expectedStoreKey < < " ] = " < < resultStoreValue < < " , expected " < < expectedStoreValue ) ;
}
}
2014-12-12 20:21:18 +00:00
BOOST_CHECK_EQUAL ( _resultStore . size ( ) , _expectedStore . size ( ) ) ;
2014-12-17 16:56:54 +00:00
for ( auto & & resultStorePair : _resultStore )
{
2014-12-11 19:46:05 +00:00
if ( ! _expectedStore . count ( resultStorePair . first ) )
BOOST_ERROR ( _expectedAddr < < " : unexpected store key " < < resultStorePair . first ) ;
2014-12-17 16:56:54 +00:00
}
2014-11-03 15:33:02 +00:00
}
2014-11-19 13:30:42 +00:00
void checkLog ( LogEntries _resultLogs , LogEntries _expectedLogs )
{
BOOST_REQUIRE_EQUAL ( _resultLogs . size ( ) , _expectedLogs . size ( ) ) ;
for ( size_t i = 0 ; i < _resultLogs . size ( ) ; + + i )
{
2014-11-21 06:42:41 +00:00
BOOST_CHECK_EQUAL ( _resultLogs [ i ] . address , _expectedLogs [ i ] . address ) ;
BOOST_CHECK_EQUAL ( _resultLogs [ i ] . topics , _expectedLogs [ i ] . topics ) ;
2014-11-19 13:30:42 +00:00
BOOST_CHECK ( _resultLogs [ i ] . data = = _expectedLogs [ i ] . data ) ;
}
}
2015-01-13 14:47:36 +00:00
void checkCallCreates ( eth : : Transactions _resultCallCreates , eth : : Transactions _expectedCallCreates )
{
BOOST_REQUIRE_EQUAL ( _resultCallCreates . size ( ) , _expectedCallCreates . size ( ) ) ;
for ( size_t i = 0 ; i < _resultCallCreates . size ( ) ; + + i )
{
BOOST_CHECK ( _resultCallCreates [ i ] . data ( ) = = _expectedCallCreates [ i ] . data ( ) ) ;
BOOST_CHECK ( _resultCallCreates [ i ] . receiveAddress ( ) = = _expectedCallCreates [ i ] . receiveAddress ( ) ) ;
BOOST_CHECK ( _resultCallCreates [ i ] . gas ( ) = = _expectedCallCreates [ i ] . gas ( ) ) ;
BOOST_CHECK ( _resultCallCreates [ i ] . value ( ) = = _expectedCallCreates [ i ] . value ( ) ) ;
}
}
2015-05-08 09:00:17 +00:00
void userDefinedTest ( std : : function < void ( json_spirit : : mValue & , bool ) > doTests )
2014-11-10 16:37:55 +00:00
{
2015-05-08 09:00:17 +00:00
if ( ! Options : : get ( ) . singleTest )
2015-05-12 07:37:39 +00:00
return ;
2015-04-21 08:37:47 +00:00
2015-05-12 07:37:39 +00:00
if ( Options : : get ( ) . singleTestFile . empty ( ) | | Options : : get ( ) . singleTestName . empty ( ) )
2014-11-10 16:37:55 +00:00
{
2015-05-08 09:00:17 +00:00
cnote < < " Missing user test specification \n Usage: testeth --singletest <filename> <testname> \n " ;
return ;
}
2014-11-20 19:41:35 +00:00
2015-05-08 09:00:17 +00:00
auto & filename = Options : : get ( ) . singleTestFile ;
auto & testname = Options : : get ( ) . singleTestName ;
int currentVerbosity = g_logVerbosity ;
g_logVerbosity = 12 ;
try
2014-11-10 16:37:55 +00:00
{
2015-05-08 09:00:17 +00:00
cnote < < " Testing user defined test: " < < filename ;
json_spirit : : mValue v ;
string s = asString ( contents ( filename ) ) ;
BOOST_REQUIRE_MESSAGE ( s . length ( ) > 0 , " Contents of " + filename + " is empty. " ) ;
json_spirit : : read_string ( s , v ) ;
json_spirit : : mObject oSingleTest ;
2014-11-20 19:41:35 +00:00
2015-05-08 09:00:17 +00:00
json_spirit : : mObject : : const_iterator pos = v . get_obj ( ) . find ( testname ) ;
if ( pos = = v . get_obj ( ) . end ( ) )
{
cnote < < " Could not find test: " < < testname < < " in " < < filename < < " \n " ;
return ;
2014-11-10 16:37:55 +00:00
}
2015-05-08 09:00:17 +00:00
else
oSingleTest [ pos - > first ] = pos - > second ;
json_spirit : : mValue v_singleTest ( oSingleTest ) ;
doTests ( v_singleTest , false ) ;
}
catch ( Exception const & _e )
{
BOOST_ERROR ( " Failed Test with Exception: " < < diagnostic_information ( _e ) ) ;
g_logVerbosity = currentVerbosity ;
2014-11-10 16:37:55 +00:00
}
2015-05-08 09:00:17 +00:00
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed Test with Exception: " < < _e . what ( ) ) ;
g_logVerbosity = currentVerbosity ;
2014-11-10 16:37:55 +00:00
}
2015-05-08 09:00:17 +00:00
g_logVerbosity = currentVerbosity ;
2014-11-10 16:37:55 +00:00
}
2015-04-20 20:48:53 +00:00
void executeTests ( const string & _name , const string & _testPathAppendix , const boost : : filesystem : : path _pathToFiller , std : : function < void ( json_spirit : : mValue & , bool ) > doTests )
2014-11-03 15:33:02 +00:00
{
string testPath = getTestPath ( ) ;
testPath + = _testPathAppendix ;
2015-03-25 11:13:44 +00:00
if ( Options : : get ( ) . stats )
Listener : : registerListener ( Stats : : get ( ) ) ;
2015-03-12 10:55:00 +00:00
if ( Options : : get ( ) . fillTests )
2014-11-03 15:33:02 +00:00
{
2015-03-12 10:55:00 +00:00
try
2014-11-11 21:25:21 +00:00
{
2015-03-12 10:55:00 +00:00
cnote < < " Populating tests... " ;
json_spirit : : mValue v ;
boost : : filesystem : : path p ( __FILE__ ) ;
2015-04-20 20:48:53 +00:00
string s = asString ( dev : : contents ( _pathToFiller . string ( ) + " / " + _name + " Filler.json " ) ) ;
BOOST_REQUIRE_MESSAGE ( s . length ( ) > 0 , " Contents of " + _pathToFiller . string ( ) + " / " + _name + " Filler.json is empty. " ) ;
2015-03-12 10:55:00 +00:00
json_spirit : : read_string ( s , v ) ;
doTests ( v , true ) ;
writeFile ( testPath + " / " + _name + " .json " , asBytes ( json_spirit : : write_string ( v , true ) ) ) ;
}
catch ( Exception const & _e )
{
BOOST_ERROR ( " Failed filling test with Exception: " < < diagnostic_information ( _e ) ) ;
}
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed filling test with Exception: " < < _e . what ( ) ) ;
2014-11-11 21:25:21 +00:00
}
2014-11-03 15:33:02 +00:00
}
try
{
2015-03-13 12:10:38 +00:00
std : : cout < < " TEST " < < _name < < " : \n " ;
2014-11-03 15:33:02 +00:00
json_spirit : : mValue v ;
string s = asString ( dev : : contents ( testPath + " / " + _name + " .json " ) ) ;
BOOST_REQUIRE_MESSAGE ( s . length ( ) > 0 , " Contents of " + testPath + " / " + _name + " .json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path? " ) ;
json_spirit : : read_string ( s , v ) ;
2015-03-25 11:13:44 +00:00
Listener : : notifySuiteStarted ( _name ) ;
2014-11-03 15:33:02 +00:00
doTests ( v , false ) ;
}
catch ( Exception const & _e )
{
BOOST_ERROR ( " Failed test with Exception: " < < diagnostic_information ( _e ) ) ;
}
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed test with Exception: " < < _e . what ( ) ) ;
}
}
2014-10-29 16:25:02 +00:00
2015-02-11 15:36:00 +00:00
RLPStream createRLPStreamFromTransactionFields ( json_spirit : : mObject & _tObj )
2015-02-06 22:43:49 +00:00
{
//Construct Rlp of the given transaction
RLPStream rlpStream ;
2015-02-11 15:36:00 +00:00
rlpStream . appendList ( _tObj . size ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " nonce " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " nonce " ] . get_str ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " gasPrice " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " gasPrice " ] . get_str ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " gasLimit " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " gasLimit " ] . get_str ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " to " ) )
2015-02-11 15:36:00 +00:00
{
if ( _tObj [ " to " ] . get_str ( ) . empty ( ) )
rlpStream < < " " ;
else
rlpStream < < importByteArray ( _tObj [ " to " ] . get_str ( ) ) ;
}
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " value " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " value " ] . get_str ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " data " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < importData ( _tObj ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " v " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " v " ] . get_str ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " r " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " r " ] . get_str ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " s " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " s " ] . get_str ( ) ) ;
2015-02-16 10:04:05 +00:00
if ( _tObj . count ( " extrafield " ) )
2015-02-11 15:36:00 +00:00
rlpStream < < bigint ( _tObj [ " extrafield " ] . get_str ( ) ) ;
2015-02-06 22:43:49 +00:00
2015-02-11 15:36:00 +00:00
return rlpStream ;
2015-02-06 22:43:49 +00:00
}
2015-03-12 10:55:00 +00:00
Options : : Options ( )
2014-12-12 10:48:15 +00:00
{
auto argc = boost : : unit_test : : framework : : master_test_suite ( ) . argc ;
auto argv = boost : : unit_test : : framework : : master_test_suite ( ) . argv ;
2015-03-12 10:55:00 +00:00
for ( auto i = 0 ; i < argc ; + + i )
2014-12-12 10:48:15 +00:00
{
2015-03-12 10:55:00 +00:00
auto arg = std : : string { argv [ i ] } ;
if ( arg = = " --jit " )
2014-12-12 10:48:15 +00:00
eth : : VMFactory : : setKind ( eth : : VMKind : : JIT ) ;
2015-05-06 11:18:52 +00:00
else if ( arg = = " --vm=smart " )
eth : : VMFactory : : setKind ( eth : : VMKind : : Smart ) ;
2015-03-12 10:55:00 +00:00
else if ( arg = = " --vmtrace " )
vmtrace = true ;
2015-03-12 15:53:00 +00:00
else if ( arg = = " --filltests " )
fillTests = true ;
2015-05-05 15:15:26 +00:00
else if ( arg = = " --stats " & & i + 1 < argc )
2015-03-25 11:13:44 +00:00
{
2015-03-13 10:19:26 +00:00
stats = true ;
2015-05-05 15:15:26 +00:00
statsOutFile = argv [ i + 1 ] ;
2015-03-25 11:13:44 +00:00
}
2015-03-12 10:55:00 +00:00
else if ( arg = = " --performance " )
performance = true ;
else if ( arg = = " --quadratic " )
quadratic = true ;
else if ( arg = = " --memory " )
memory = true ;
else if ( arg = = " --inputlimits " )
inputLimits = true ;
else if ( arg = = " --bigdata " )
bigData = true ;
2015-03-26 00:12:25 +00:00
else if ( arg = = " --checkstate " )
checkState = true ;
2015-03-12 10:55:00 +00:00
else if ( arg = = " --all " )
{
performance = true ;
quadratic = true ;
memory = true ;
inputLimits = true ;
bigData = true ;
2014-12-12 10:48:15 +00:00
}
2015-05-05 15:15:26 +00:00
else if ( arg = = " --singletest " & & i + 1 < argc )
2015-05-05 13:46:01 +00:00
{
2015-05-05 15:15:26 +00:00
singleTest = true ;
2015-05-12 07:37:39 +00:00
auto name1 = std : : string { argv [ i + 1 ] } ;
if ( i + 1 < argc ) // two params
{
auto name2 = std : : string { argv [ i + 2 ] } ;
if ( name2 [ 0 ] = = ' - ' ) // not param, another option
singleTestName = std : : move ( name1 ) ;
else
{
singleTestFile = std : : move ( name1 ) ;
singleTestName = std : : move ( name2 ) ;
}
}
else
singleTestName = std : : move ( name1 ) ;
2015-05-05 13:46:01 +00:00
}
2014-12-12 10:48:15 +00:00
}
}
2015-03-12 10:55:00 +00:00
Options const & Options : : get ( )
{
static Options instance ;
return instance ;
}
2015-03-13 10:19:26 +00:00
2015-01-09 09:58:32 +00:00
LastHashes lastHashes ( u256 _currentBlockNumber )
{
LastHashes ret ;
for ( u256 i = 1 ; i < = 256 & & i < = _currentBlockNumber ; + + i )
ret . push_back ( sha3 ( toString ( _currentBlockNumber - i ) ) ) ;
return ret ;
}
2015-03-13 10:19:26 +00:00
namespace
{
Listener * g_listener ;
}
void Listener : : registerListener ( Listener & _listener )
{
g_listener = & _listener ;
}
2015-03-25 11:13:44 +00:00
void Listener : : notifySuiteStarted ( std : : string const & _name )
{
if ( g_listener )
g_listener - > suiteStarted ( _name ) ;
}
2015-03-13 10:19:26 +00:00
void Listener : : notifyTestStarted ( std : : string const & _name )
{
if ( g_listener )
g_listener - > testStarted ( _name ) ;
}
void Listener : : notifyTestFinished ( )
{
if ( g_listener )
g_listener - > testFinished ( ) ;
}
2014-11-03 15:33:02 +00:00
} } // namespaces