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>
2015-02-09 16:31:04 +00:00
2014-11-03 15:33:02 +00:00
# include <boost/filesystem/path.hpp>
2015-03-25 12:47:28 +00:00
# include <boost/assign.hpp>
2015-02-09 16:31:04 +00:00
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
}
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 { } ;
bigint const c_max256plus1 = bigint ( 1 ) < < 256 ;
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 ( ) ) ;
2015-03-25 12:47:28 +00:00
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
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
void ImportTest : : importState ( json_spirit : : mObject & _o , State & _state )
{
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-12 08:16:32 +00:00
assert ( o . count ( " balance " ) > 0 ) ;
assert ( o . count ( " nonce " ) > 0 ) ;
assert ( o . count ( " storage " ) > 0 ) ;
assert ( o . count ( " code " ) > 0 ) ;
2014-10-29 16:25:02 +00:00
2015-02-10 10:07:31 +00:00
if ( bigint ( o [ " balance " ] . get_str ( ) ) > = c_max256plus1 )
2015-02-07 11:23:17 +00:00
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " State 'balance' is equal or greater than 2**256 " ) ) ;
2015-02-10 10:07:31 +00:00
if ( bigint ( o [ " nonce " ] . get_str ( ) ) > = c_max256plus1 )
2015-02-07 11:23:17 +00:00
BOOST_THROW_EXCEPTION ( ValueTooLarge ( ) < < errinfo_comment ( " State 'nonce' is equal or greater than 2**256 " ) ) ;
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
bytes code = importCode ( o ) ;
2014-11-05 17:30:38 +00:00
if ( code . size ( ) )
2014-10-29 16:25:02 +00:00
{
2014-11-03 15:33:02 +00:00
_state . m_cache [ address ] = Account ( toInt ( o [ " 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
_state . m_cache [ address ] = Account ( toInt ( o [ " balance " ] ) , Account : : NormalCreation ) ;
2014-10-29 16:25:02 +00:00
2014-12-12 20:21:18 +00:00
for ( auto const & j : o [ " storage " ] . get_obj ( ) )
_state . setStorage ( address , toInt ( j . first ) , toInt ( j . second ) ) ;
2014-11-03 15:33:02 +00:00
for ( int i = 0 ; i < toInt ( o [ " nonce " ] ) ; + + i )
_state . noteSending ( address ) ;
2014-10-31 08:41:02 +00:00
2014-11-03 15:33:02 +00:00
_state . ensureCached ( address , false , false ) ;
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 ( ) ) ;
m_transaction = Transaction ( transactionRLP . data ( ) , CheckSignature : : Sender ) ;
}
2014-10-29 16:25:02 +00:00
}
2015-03-25 12:47:28 +00:00
bool ImportTest : : compareStates ( State const & _stateExpect , State const & _statePost )
2015-03-24 18:36:04 +00:00
{
//TestNet Addresses
2015-03-25 12:47:28 +00:00
static Addresses testNetAddressList = boost : : assign : : list_of
( Address ( " 0000000000000000000000000000000000000001 " ) )
( Address ( " 0000000000000000000000000000000000000002 " ) )
( Address ( " 0000000000000000000000000000000000000003 " ) )
( Address ( " 0000000000000000000000000000000000000004 " ) )
( Address ( " 1a26338f0d905e295fccb71fa9ea849ffa12aaf4 " ) )
( Address ( " 2ef47100e0787b915105fd5e3f4ff6752079d5cb " ) )
( Address ( " 6c386a4b26f73c802f34673f7248bb118f97424a " ) )
( Address ( " b9c015918bdaba24b4ff057a92a3873d6eb201be " ) )
( Address ( " cd2a3d9f938e13cd947ec05abc7fe734df8dd826 " ) )
( Address ( " dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6 " ) )
( Address ( " e4157b34ea9615cfbde6b4fda419828124b70c78 " ) )
( Address ( " e6716f9544a56c530d868e4bfbacb172315bdead " ) ) ;
for ( auto const & a : _stateExpect . addresses ( ) )
2015-03-24 18:36:04 +00:00
{
2015-03-25 12:47:28 +00:00
bool bFound = false ; //do not count default addresses as it's not in addressInUse
for ( auto const & it : testNetAddressList )
2015-03-24 18:36:04 +00:00
{
2015-03-25 12:47:28 +00:00
if ( it = = a . first )
2015-03-24 18:36:04 +00:00
{
2015-03-25 12:47:28 +00:00
bFound = true ;
break ;
2015-03-24 18:36:04 +00:00
}
2015-03-25 12:47:28 +00:00
}
if ( bFound )
continue ;
2015-03-24 18:36:04 +00:00
2015-03-25 12:47:28 +00:00
BOOST_CHECK_MESSAGE ( _statePost . addressInUse ( a . first ) , " Filling Test Error: " < < a . first < < " expected address not in use! " ) ;
if ( _statePost . addressInUse ( a . first ) )
{
BOOST_CHECK_MESSAGE ( _stateExpect . balance ( a . first ) = = _statePost . balance ( a . first ) ,
" Filling Test Error: " < < a . first < < " : incorrect balance " < < _statePost . balance ( a . first ) < < " , expected " < < _stateExpect . balance ( a . first ) ) ;
BOOST_CHECK_MESSAGE ( _stateExpect . transactionsFrom ( a . first ) = = _statePost . transactionsFrom ( a . first ) ,
" Filling Test Error: " < < a . first < < " : incorrect nonce " < < _statePost . transactionsFrom ( a . first ) < < " , expected " < < _stateExpect . transactionsFrom ( a . first ) ) ;
2015-03-24 18:36:04 +00:00
2015-03-25 12:47:28 +00:00
map < u256 , u256 > stateStorage = _statePost . storage ( a . first ) ;
for ( auto const & s : _stateExpect . storage ( a . first ) )
2015-03-24 18:36:04 +00:00
{
2015-03-25 12:47:28 +00:00
BOOST_CHECK_MESSAGE ( stateStorage [ s . first ] = = s . second ,
" Filling Test Error: " < < a . first < < " : incorrect storage [ " < < s . first < < " ] = " < < toHex ( stateStorage [ s . first ] ) < < " , expected [ " < < s . first < < " ] = " < < toHex ( s . second ) ) ;
2015-03-24 18:36:04 +00:00
}
2015-03-25 12:47:28 +00:00
BOOST_CHECK_MESSAGE ( _stateExpect . code ( a . first ) = = _statePost . code ( a . first ) ,
" Filling Test Error: " < < a . first < < " : incorrect code ' " < < toHex ( _statePost . code ( a . first ) ) < < " ', expected ' " < < toHex ( _stateExpect . code ( a . first ) ) < < " ' " ) ;
}
2015-03-24 18:36:04 +00:00
}
2015-03-25 12:47:28 +00:00
return true ;
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
m_TestObject [ " out " ] = " 0x " + toHex ( _output ) ;
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 )
{
State expectState ;
importState ( m_TestObject [ " expect " ] . get_obj ( ) , expectState ) ;
compareStates ( expectState , _statePost ) ;
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-03-02 20:19:36 +00:00
m_TestObject [ " postStateRoot " ] = toHex ( _statePost . rootHash ( ) . asBytes ( ) ) ;
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 ) ;
}
json_spirit : : mObject fillJsonWithState ( State _state )
{
// export pre state
json_spirit : : mObject oState ;
2014-11-05 19:21:33 +00:00
2015-03-09 09:28:48 +00:00
for ( auto const & a : _state . addresses ( ) )
2014-11-05 19:21:33 +00:00
{
json_spirit : : mObject o ;
2015-03-09 09:28:48 +00:00
o [ " balance " ] = toString ( _state . balance ( a . first ) ) ;
o [ " nonce " ] = toString ( _state . transactionsFrom ( a . first ) ) ;
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 ) )
2014-11-05 19:21:33 +00:00
store [ " 0x " + toHex ( toCompactBigEndian ( s . first ) ) ] = " 0x " + toHex ( toCompactBigEndian ( s . second ) ) ;
o [ " storage " ] = store ;
}
2015-03-09 09:28:48 +00:00
o [ " code " ] = " 0x " + toHex ( _state . code ( a . first ) ) ;
2014-11-05 19:21:33 +00:00
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
}
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-12-05 18:26:32 +00:00
json_spirit : : mArray exportLog ( eth : : LogEntries _logs )
2014-12-01 21:04:09 +00:00
{
2014-12-05 18:26:32 +00:00
json_spirit : : mArray ret ;
2014-12-01 21:44:31 +00:00
if ( _logs . size ( ) = = 0 ) return ret ;
for ( LogEntry const & l : _logs )
{
json_spirit : : mObject o ;
o [ " address " ] = toString ( l . address ) ;
json_spirit : : mArray topics ;
for ( auto const & t : l . topics )
topics . push_back ( toString ( t ) ) ;
o [ " topics " ] = topics ;
o [ " data " ] = " 0x " + toHex ( l . data ) ;
2014-12-05 18:26:32 +00:00
o [ " bloom " ] = toString ( l . bloom ( ) ) ;
ret . push_back ( o ) ;
2014-12-01 21:44:31 +00:00
}
return ret ;
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 ( ) ) ;
}
}
2014-11-10 16:37:55 +00:00
void userDefinedTest ( string testTypeFlag , std : : function < void ( json_spirit : : mValue & , bool ) > doTests )
{
for ( int i = 1 ; i < boost : : unit_test : : framework : : master_test_suite ( ) . argc ; + + i )
{
2014-11-10 17:30:35 +00:00
string arg = boost : : unit_test : : framework : : master_test_suite ( ) . argv [ i ] ;
2014-11-10 16:37:55 +00:00
if ( arg = = testTypeFlag )
{
2014-11-20 21:21:08 +00:00
if ( boost : : unit_test : : framework : : master_test_suite ( ) . argc < = i + 2 )
2014-11-10 16:37:55 +00:00
{
2014-11-20 19:41:35 +00:00
cnote < < " Missing filename \n Usage: testeth " < < testTypeFlag < < " <filename> <testname> \n " ;
2014-11-10 16:37:55 +00:00
return ;
}
string filename = boost : : unit_test : : framework : : master_test_suite ( ) . argv [ i + 1 ] ;
2014-11-20 19:41:35 +00:00
string testname = boost : : unit_test : : framework : : master_test_suite ( ) . argv [ i + 2 ] ;
2014-11-10 16:37:55 +00:00
int currentVerbosity = g_logVerbosity ;
g_logVerbosity = 12 ;
try
{
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 ) ;
2014-11-20 19:41:35 +00:00
json_spirit : : mObject oSingleTest ;
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 ;
}
else
oSingleTest [ pos - > first ] = pos - > second ;
json_spirit : : mValue v_singleTest ( oSingleTest ) ;
doTests ( v_singleTest , false ) ;
2014-11-10 16:37:55 +00:00
}
catch ( Exception const & _e )
{
BOOST_ERROR ( " Failed Test with Exception: " < < diagnostic_information ( _e ) ) ;
2014-11-10 17:30:35 +00:00
g_logVerbosity = currentVerbosity ;
2014-11-10 16:37:55 +00:00
}
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed Test with Exception: " < < _e . what ( ) ) ;
2014-11-10 17:30:35 +00:00
g_logVerbosity = currentVerbosity ;
2014-11-10 16:37:55 +00:00
}
g_logVerbosity = currentVerbosity ;
}
}
}
2014-11-03 15:33:02 +00:00
void executeTests ( const string & _name , const string & _testPathAppendix , std : : function < void ( json_spirit : : mValue & , bool ) > doTests )
{
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__ ) ;
boost : : filesystem : : path dir = p . parent_path ( ) ;
string s = asString ( dev : : contents ( dir . string ( ) + " / " + _name + " Filler.json " ) ) ;
BOOST_REQUIRE_MESSAGE ( s . length ( ) > 0 , " Contents of " + dir . string ( ) + " / " + _name + " Filler.json is empty. " ) ;
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
{
2015-03-12 10:55:00 +00:00
jit = true ;
2014-12-12 10:48:15 +00:00
eth : : VMFactory : : setKind ( eth : : VMKind : : JIT ) ;
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-03-25 11:13:44 +00:00
else if ( arg . compare ( 0 , 7 , " --stats " ) = = 0 )
{
2015-03-13 10:19:26 +00:00
stats = true ;
2015-03-25 11:13:44 +00:00
if ( arg . size ( ) > 7 )
statsOutFile = arg . substr ( 8 ) ; // skip '=' char
}
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 ;
else if ( arg = = " --all " )
{
performance = true ;
quadratic = true ;
memory = true ;
inputLimits = true ;
bigData = true ;
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