2014-01-19 14:42:02 +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
2014-02-06 18:53:46 +00:00
the Free Software Foundation , either version 3 of the License , or
2014-01-19 14:42:02 +00:00
( at your option ) any later version .
2014-02-16 10:20:55 +00:00
cpp - ethereum is distributed in the hope that it will be useful ,
2014-01-19 14:42:02 +00:00
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
2014-02-16 10:41:15 +00:00
along with cpp - ethereum . If not , see < http : //www.gnu.org/licenses/>.
2014-01-19 14:42:02 +00:00
*/
/** @file state.cpp
2014-10-29 16:25:02 +00:00
* @ author Christoph Jentzsch < cj @ ethdev . com >
2014-01-19 14:42:02 +00:00
* @ date 2014
* State test functions .
*/
2014-10-31 08:41:02 +00:00
# define FILL_TESTS
2014-02-19 22:16:20 +00:00
# include <boost/filesystem/operations.hpp>
2014-10-29 16:25:02 +00:00
# include <boost/test/unit_test.hpp>
# include "JsonSpiritHeaders.h"
# include <libdevcore/CommonIO.h>
2014-04-23 14:08:11 +00:00
# include <libethereum/BlockChain.h>
# include <libethereum/State.h>
2014-10-29 16:25:02 +00:00
# include <libethereum/ExtVM.h>
2014-04-23 14:08:11 +00:00
# include <libethereum/Defaults.h>
2014-10-29 16:25:02 +00:00
# include <libevm/VM.h>
# include "TestHelper.h"
2014-01-19 14:42:02 +00:00
using namespace std ;
2014-10-29 16:25:02 +00:00
using namespace json_spirit ;
2014-09-05 15:09:58 +00:00
using namespace dev ;
using namespace dev : : eth ;
2014-10-29 16:25:02 +00:00
using namespace dev : : eth : : test ;
2014-01-19 14:42:02 +00:00
2014-10-29 16:25:02 +00:00
class FakeState : public State
2014-01-19 14:42:02 +00:00
{
2014-01-19 20:15:07 +00:00
2014-10-29 16:25:02 +00:00
} ;
2014-01-19 20:15:07 +00:00
2014-01-21 15:51:57 +00:00
2014-10-29 16:25:02 +00:00
namespace dev { namespace eth { namespace test {
2014-01-21 15:51:57 +00:00
2014-01-20 18:43:11 +00:00
2014-10-29 16:25:02 +00:00
void doStateTests ( json_spirit : : mValue & v , bool _fillin )
{
for ( auto & i : v . get_obj ( ) )
{
cnote < < i . first ;
mObject & o = i . second . get_obj ( ) ;
BOOST_REQUIRE ( o . count ( " env " ) > 0 ) ;
BOOST_REQUIRE ( o . count ( " pre " ) > 0 ) ;
BOOST_REQUIRE ( o . count ( " exec " ) > 0 ) ;
2014-10-31 08:41:02 +00:00
ImportTest importer ( o , _fillin ) ;
if ( _fillin )
{
importer . code = importer . m_statePre . code ( importer . m_environment . myAddress ) ;
importer . m_environment . code = & importer . code ;
}
2014-10-29 16:25:02 +00:00
ExtVM evm ( importer . m_statePre , importer . m_environment . myAddress ,
importer . m_environment . caller , importer . m_environment . origin ,
importer . m_environment . value , importer . m_environment . gasPrice ,
importer . m_environment . data , importer . m_environment . code ,
importer . getManifest ( ) ) ;
bytes output ;
VM vm ( importer . gasExec ) ;
try
{
output = vm . go ( evm , Executive : : simpleTrace ( ) ) . toVector ( ) ;
}
catch ( Exception const & _e )
{
cnote < < " VM did throw an exception: " < < diagnostic_information ( _e ) ;
//BOOST_ERROR("Failed VM Test with Exception: " << e.what());
}
catch ( std : : exception const & _e )
{
cnote < < " VM did throw an exception: " < < _e . what ( ) ;
//BOOST_ERROR("Failed VM Test with Exception: " << e.what());
}
2014-10-31 08:41:02 +00:00
if ( _fillin )
importer . exportTest ( output , vm . gas ( ) , evm . state ( ) ) ;
else
{
BOOST_REQUIRE ( o . count ( " post " ) > 0 ) ;
//BOOST_REQUIRE(o.count("callcreates") > 0);
BOOST_REQUIRE ( o . count ( " out " ) > 0 ) ;
BOOST_REQUIRE ( o . count ( " gas " ) > 0 ) ;
// check output
int j = 0 ;
if ( o [ " out " ] . type ( ) = = 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 ( ) ) ) ;
BOOST_CHECK_EQUAL ( toInt ( o [ " gas " ] ) , vm . gas ( ) ) ;
auto expectedAddrs = importer . m_statePost . addresses ( ) ;
auto resultAddrs = evm . state ( ) . addresses ( ) ;
for ( auto & expectedPair : expectedAddrs )
{
auto & expectedAddr = expectedPair . first ;
auto resultAddrIt = resultAddrs . find ( expectedAddr ) ;
if ( resultAddrIt = = resultAddrs . end ( ) )
BOOST_ERROR ( " Missing expected address " < < expectedAddr ) ;
else
{
BOOST_CHECK_MESSAGE ( importer . m_statePost . balance ( expectedAddr ) = = evm . state ( ) . balance ( expectedAddr ) , expectedAddr < < " : incorrect balance " < < evm . state ( ) . balance ( expectedAddr ) < < " , expected " < < importer . m_statePost . balance ( expectedAddr ) ) ;
BOOST_CHECK_MESSAGE ( importer . m_statePost . transactionsFrom ( expectedAddr ) = = evm . state ( ) . transactionsFrom ( expectedAddr ) , expectedAddr < < " : incorrect txCount " < < evm . state ( ) . transactionsFrom ( expectedAddr ) < < " , expected " < < importer . m_statePost . transactionsFrom ( expectedAddr ) ) ;
BOOST_CHECK_MESSAGE ( importer . m_statePost . code ( expectedAddr ) = = evm . state ( ) . code ( expectedAddr ) , expectedAddr < < " : incorrect code " ) ;
auto & & expectedStore = importer . m_statePost . storage ( expectedAddr ) ;
auto & & resultStore = evm . state ( ) . storage ( 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-10-29 16:25:02 +00:00
2014-10-31 08:41:02 +00:00
for ( auto & resultPair : resultAddrs )
2014-10-29 16:25:02 +00:00
{
2014-10-31 08:41:02 +00:00
auto & resultAddr = resultPair . first ;
auto expectedAddrIt = expectedAddrs . find ( resultAddr ) ;
if ( expectedAddrIt = = expectedAddrs . end ( ) )
BOOST_ERROR ( " Missing result address " < < resultAddr ) ;
2014-10-29 16:25:02 +00:00
}
2014-10-31 08:41:02 +00:00
BOOST_CHECK ( evm . state ( ) . addresses ( ) = = importer . m_statePost . addresses ( ) ) ; // Just to make sure nothing missed
//BOOST_CHECK(evm.callcreates == importer.callcreates);
}
2014-01-21 15:51:57 +00:00
2014-10-29 16:25:02 +00:00
}
}
2014-01-21 15:51:57 +00:00
2014-01-19 20:15:07 +00:00
2014-10-29 16:25:02 +00:00
void executeStateTests ( const string & _name )
{
const char * ptestPath = getenv ( " ETHEREUM_TEST_PATH " ) ;
string testPath ;
2014-01-20 18:43:11 +00:00
2014-10-29 16:25:02 +00:00
if ( ptestPath = = NULL )
2014-01-19 20:15:07 +00:00
{
2014-10-29 16:25:02 +00:00
cnote < < " could not find environment variable ETHEREUM_TEST_PATH \n " ;
testPath = " ../../../tests " ;
2014-01-19 20:15:07 +00:00
}
2014-10-29 16:25:02 +00:00
else
testPath = ptestPath ;
2014-01-19 20:15:07 +00:00
2014-10-31 08:41:02 +00:00
testPath + = " /statetests " ;
2014-01-20 18:43:11 +00:00
2014-10-29 16:25:02 +00:00
# ifdef FILL_TESTS
try
{
cnote < < " Populating VM 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 " ) ) ;
2014-10-31 08:41:02 +00:00
BOOST_REQUIRE_MESSAGE ( s . length ( ) > 0 , " Contents of " + dir . string ( ) + " / " + _name + " Filler.json is empty. " ) ;
2014-10-29 16:25:02 +00:00
json_spirit : : read_string ( s , v ) ;
2014-10-31 08:41:02 +00:00
doStateTests ( v , true ) ;
2014-10-29 16:25:02 +00:00
writeFile ( testPath + " / " + _name + " .json " , asBytes ( json_spirit : : write_string ( v , true ) ) ) ;
}
catch ( Exception const & _e )
{
BOOST_ERROR ( " Failed VM Test with Exception: " < < diagnostic_information ( _e ) ) ;
}
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed VM Test with Exception: " < < _e . what ( ) ) ;
}
# endif
2014-01-21 15:51:57 +00:00
2014-10-29 16:25:02 +00:00
try
{
cnote < < " Testing VM... " < < _name ;
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 ) ;
doStateTests ( v , false ) ;
}
catch ( Exception const & _e )
{
BOOST_ERROR ( " Failed VM Test with Exception: " < < diagnostic_information ( _e ) ) ;
}
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed VM Test with Exception: " < < _e . what ( ) ) ;
}
2014-01-21 15:51:57 +00:00
2014-10-29 16:25:02 +00:00
}
} } } // Namespace Close
2014-01-19 17:17:05 +00:00
2014-10-29 16:25:02 +00:00
BOOST_AUTO_TEST_CASE ( vmSystemOperationsTest )
2014-10-31 08:41:02 +00:00
{
dev : : eth : : test : : executeStateTests ( " stSystemOperationsTest " ) ;
}
BOOST_AUTO_TEST_CASE ( tmp )
2014-10-29 16:25:02 +00:00
{
std : : cout < < " Doing systemoperationsTest in state \n " ;
int currentVerbosity = g_logVerbosity ;
g_logVerbosity = 12 ;
2014-10-31 08:41:02 +00:00
dev : : eth : : test : : executeStateTests ( " tmp " ) ;
2014-10-29 16:25:02 +00:00
g_logVerbosity = currentVerbosity ;
2014-01-19 14:42:02 +00:00
}