@ -22,6 +22,7 @@
*/
# include <string>
# include <tuple>
# include <boost/test/unit_test.hpp>
# include <libethereum/State.h>
# include <libethereum/Executive.h>
@ -41,36 +42,72 @@ class ExecutionFramework
public :
ExecutionFramework ( ) { g_logVerbosity = 0 ; }
bytes const & compileAndRun ( std : : st ring const & _sourceCode )
bytes const & compileAndRun ( string const & _sourceCode )
{
bytes code = dev : : solidity : : CompilerStack : : compile ( _sourceCode ) ;
bytes code = dev : : solidity : : CompilerStack : : stati cC ompile( _sourceCode ) ;
sendMessage ( code , true ) ;
BOOST_REQUIRE ( ! m_output . empty ( ) ) ;
return m_output ;
}
bytes const & callFunction ( byte _index , bytes const & _data )
bytes const & callContract Function ( byte _index , bytes const & _data = bytes ( ) )
{
sendMessage ( bytes ( 1 , _index ) + _data , false ) ;
return m_output ;
}
bytes const & callFunction ( byte _index , u256 const & _argument1 )
template < class . . . Args >
bytes const & callContractFunction ( byte _index , Args const & . . . _arguments )
{
return callFunction ( _index , toBigEndian ( _argument1 ) ) ;
return callContract Function ( _index , argsToBigEndian ( _arguments . . . ) ) ;
}
bool testSolidityAgainstCpp ( byte _index , std : : function < u256 ( u256 ) > const & _cppfun , u256 const & _argument1 )
template < class CppFunction , class . . . Args >
void testSolidityAgainstCpp ( byte _index , CppFunction const & _cppFunction , Args const & . . . _arguments )
{
return toBigEndian ( _cppfun ( _argument1 ) ) = = callFunction ( _index , toBigEndian ( _argument1 ) ) ;
bytes solidityResult = callContractFunction ( _index , _arguments . . . ) ;
bytes cppResult = callCppAndEncodeResult ( _cppFunction , _arguments . . . ) ;
BOOST_CHECK_MESSAGE ( solidityResult = = cppResult , " Computed values do not match. "
" \n Solidity: " + toHex ( solidityResult ) + " \n C++: " + toHex ( cppResult ) ) ;
}
bool testSolidityAgainstCpp ( byte _index , std : : function < u256 ( ) > const & _cppfun )
template < class CppFunction , class . . . Args >
void testSolidityAgainstCppOnRange ( byte _index , CppFunction const & _cppFunction ,
u256 const & _rangeStart , u256 const & _rangeEnd )
{
return toBigEndian ( _cppfun ( ) ) = = callFunction ( _index , bytes ( ) ) ;
for ( u256 argument = _rangeStart ; argument < _rangeEnd ; + + argument )
{
bytes solidityResult = callContractFunction ( _index , argument ) ;
bytes cppResult = callCppAndEncodeResult ( _cppFunction , argument ) ;
BOOST_CHECK_MESSAGE ( solidityResult = = cppResult , " Computed values do not match. "
" \n Solidity: " + toHex ( solidityResult ) + " \n C++: " + toHex ( cppResult ) +
" \n Argument: " + toHex ( toBigEndian ( argument ) ) ) ;
}
}
private :
template < class FirstArg , class . . . Args >
bytes argsToBigEndian ( FirstArg const & _firstArg , Args const & . . . _followingArgs ) const
{
return toBigEndian ( _firstArg ) + argsToBigEndian ( _followingArgs . . . ) ;
}
bytes argsToBigEndian ( ) const { return bytes ( ) ; }
template < class CppFunction , class . . . Args >
auto callCppAndEncodeResult ( CppFunction const & _cppFunction , Args const & . . . _arguments )
- > typename enable_if < is_void < decltype ( _cppFunction ( _arguments . . . ) ) > : : value , bytes > : : type
{
_cppFunction ( _arguments . . . ) ;
return bytes ( ) ;
}
template < class CppFunction , class . . . Args >
auto callCppAndEncodeResult ( CppFunction const & _cppFunction , Args const & . . . _arguments )
- > typename enable_if < ! is_void < decltype ( _cppFunction ( _arguments . . . ) ) > : : value , bytes > : : type
{
return toBigEndian ( _cppFunction ( _arguments . . . ) ) ;
}
void sendMessage ( bytes const & _data , bool _isCreation )
{
eth : : Executive executive ( m_state ) ;
@ -91,7 +128,10 @@ private:
BOOST_REQUIRE ( m_state . addressHasCode ( m_contractAddress ) ) ;
}
else
{
BOOST_REQUIRE ( m_state . addressHasCode ( m_contractAddress ) ) ;
BOOST_REQUIRE ( ! executive . call ( m_contractAddress , Address ( ) , 0 , m_gasPrice , & _data , m_gas , Address ( ) ) ) ;
}
BOOST_REQUIRE ( executive . go ( ) ) ;
executive . finalize ( ) ;
m_output = executive . out ( ) . toVector ( ) ;
@ -112,8 +152,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
" function f(uint a) returns(uint d) { return a * 7; } \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
u256 a = 0x200030004 ;
BOOST_CHECK ( callFunction ( 0 , a ) = = toBigEndian ( a * 7 ) ) ;
testSolidityAgainstCppOnRange ( 0 , [ ] ( u256 const & a ) - > u256 { return a * 7 ; } , 0 , 100 ) ;
}
BOOST_AUTO_TEST_CASE ( empty_contract )
@ -121,7 +160,7 @@ BOOST_AUTO_TEST_CASE(empty_contract)
char const * sourceCode = " contract test { \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
BOOST_CHECK ( callFunction ( 0 , bytes ( ) ) . empty ( ) ) ;
BOOST_CHECK ( callContract Function ( 0 , bytes ( ) ) . empty ( ) ) ;
}
BOOST_AUTO_TEST_CASE ( recursive_calls )
@ -133,7 +172,7 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
" } \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
std : : function < u256 ( u256 ) > recursive_calls_cpp = [ & recursive_calls_cpp ] ( u256 const & n ) - > u256
function < u256 ( u256 ) > recursive_calls_cpp = [ & recursive_calls_cpp ] ( u256 const & n ) - > u256
{
if ( n < = 1 )
return 1 ;
@ -141,11 +180,23 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
return n * recursive_calls_cpp ( n - 1 ) ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , recursive_calls_cpp , u256 ( 0 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , recursive_calls_cpp , u256 ( 1 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , recursive_calls_cpp , u256 ( 2 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , recursive_calls_cpp , u256 ( 3 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , recursive_calls_cpp , u256 ( 4 ) ) ) ;
testSolidityAgainstCppOnRange ( 0 , recursive_calls_cpp , 0 , 5 ) ;
}
BOOST_AUTO_TEST_CASE ( multiple_functions )
{
char const * sourceCode = " contract test { \n "
" function a() returns(uint n) { return 0; } \n "
" function b() returns(uint n) { return 1; } \n "
" function c() returns(uint n) { return 2; } \n "
" function f() returns(uint n) { return 3; } \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
BOOST_CHECK ( callContractFunction ( 0 , bytes ( ) ) = = toBigEndian ( u256 ( 0 ) ) ) ;
BOOST_CHECK ( callContractFunction ( 1 , bytes ( ) ) = = toBigEndian ( u256 ( 1 ) ) ) ;
BOOST_CHECK ( callContractFunction ( 2 , bytes ( ) ) = = toBigEndian ( u256 ( 2 ) ) ) ;
BOOST_CHECK ( callContractFunction ( 3 , bytes ( ) ) = = toBigEndian ( u256 ( 3 ) ) ) ;
BOOST_CHECK ( callContractFunction ( 4 , bytes ( ) ) = = bytes ( ) ) ;
}
BOOST_AUTO_TEST_CASE ( while_loop )
@ -169,11 +220,7 @@ BOOST_AUTO_TEST_CASE(while_loop)
return nfac ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , while_loop_cpp , u256 ( 0 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , while_loop_cpp , u256 ( 1 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , while_loop_cpp , u256 ( 2 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , while_loop_cpp , u256 ( 3 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , while_loop_cpp , u256 ( 4 ) ) ) ;
testSolidityAgainstCppOnRange ( 0 , while_loop_cpp , 0 , 5 ) ;
}
BOOST_AUTO_TEST_CASE ( break_outside_loop )
@ -184,9 +231,8 @@ BOOST_AUTO_TEST_CASE(break_outside_loop)
" break; continue; return 2; \n "
" } \n "
" } \n " ;
ExecutionFramework framework ;
framework . compileAndRun ( sourceCode ) ;
BOOST_CHECK ( framework . callFunction ( 0 , u256 ( 0 ) ) = = toBigEndian ( u256 ( 2 ) ) ) ;
compileAndRun ( sourceCode ) ;
testSolidityAgainstCpp ( 0 , [ ] ( u256 const & ) - > u256 { return 2 ; } , u256 ( 0 ) ) ;
}
BOOST_AUTO_TEST_CASE ( nested_loops )
@ -209,8 +255,7 @@ BOOST_AUTO_TEST_CASE(nested_loops)
" return x; \n "
" } \n "
" } \n " ;
ExecutionFramework framework ;
framework . compileAndRun ( sourceCode ) ;
compileAndRun ( sourceCode ) ;
auto nested_loops_cpp = [ ] ( u256 n ) - > u256
{
@ -236,18 +281,7 @@ BOOST_AUTO_TEST_CASE(nested_loops)
return n ;
} ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 0 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 1 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 2 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 3 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 4 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 5 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 6 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 7 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 8 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 9 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 10 ) ) ) ;
BOOST_CHECK ( framework . testSolidityAgainstCpp ( 0 , nested_loops_cpp , u256 ( 11 ) ) ) ;
testSolidityAgainstCppOnRange ( 0 , nested_loops_cpp , 0 , 12 ) ;
}
BOOST_AUTO_TEST_CASE ( calling_other_functions )
@ -279,7 +313,8 @@ BOOST_AUTO_TEST_CASE(calling_other_functions)
return 3 * n + 1 ;
} ;
auto collatz_cpp = [ & evenStep_cpp , & oddStep_cpp ] ( u256 n ) - > u256 {
auto collatz_cpp = [ & evenStep_cpp , & oddStep_cpp ] ( u256 n ) - > u256
{
u256 y ;
while ( ( y = n ) > 1 )
{
@ -291,11 +326,11 @@ BOOST_AUTO_TEST_CASE(calling_other_functions)
return y ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 0 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 1 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 2 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 8 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 127 ) ) ) ;
testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 0 ) ) ;
testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 1 ) ) ;
testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 2 ) ) ;
testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 8 ) ) ;
testSolidityAgainstCpp ( 2 , collatz_cpp , u256 ( 127 ) ) ;
}
BOOST_AUTO_TEST_CASE ( many_local_variables )
@ -308,8 +343,15 @@ BOOST_AUTO_TEST_CASE(many_local_variables)
" } \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
BOOST_CHECK ( callFunction ( 0 , toBigEndian ( u256 ( 0x1000 ) ) + toBigEndian ( u256 ( 0x10000 ) ) + toBigEndian ( u256 ( 0x100000 ) ) )
= = toBigEndian ( u256 ( 0x121121 ) ) ) ;
auto f = [ ] ( u256 const & x1 , u256 const & x2 , u256 const & x3 ) - > u256
{
u256 a = 0x1 ;
u256 b = 0x10 ;
u256 c = 0x100 ;
u256 y = a + b + c + x1 + x2 + x3 ;
return y + b + x2 ;
} ;
testSolidityAgainstCpp ( 0 , f , u256 ( 0x1000 ) , u256 ( 0x10000 ) , u256 ( 0x100000 ) ) ;
}
BOOST_AUTO_TEST_CASE ( packing_unpacking_types )
@ -322,7 +364,7 @@ BOOST_AUTO_TEST_CASE(packing_unpacking_types)
" } \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
BOOST_CHECK ( callFunction ( 0 , fromHex ( " 01 " " 0f0f0f0f " " f0f0f0f0f0f0f0f0 " ) )
BOOST_CHECK ( callContract Function ( 0 , fromHex ( " 01 " " 0f0f0f0f " " f0f0f0f0f0f0f0f0 " ) )
= = fromHex ( " 00000000000000000000000000000000000000 " " 01 " " f0f0f0f0 " " 0f0f0f0f0f0f0f0f " ) ) ;
}
@ -334,7 +376,7 @@ BOOST_AUTO_TEST_CASE(multiple_return_values)
" } \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
BOOST_CHECK ( callFunction ( 0 , bytes ( 1 , 1 ) + toBigEndian ( u256 ( 0xcd ) ) )
BOOST_CHECK ( callContract Function ( 0 , bytes ( 1 , 1 ) + toBigEndian ( u256 ( 0xcd ) ) )
= = toBigEndian ( u256 ( 0xcd ) ) + bytes ( 1 , 1 ) + toBigEndian ( u256 ( 0 ) ) ) ;
}
@ -354,8 +396,7 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
return n ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , short_circuiting_cpp , u256 ( 0 ) ) ) ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , short_circuiting_cpp , u256 ( 1 ) ) ) ;
testSolidityAgainstCppOnRange ( 0 , short_circuiting_cpp , 0 , 2 ) ;
}
BOOST_AUTO_TEST_CASE ( high_bits_cleaning )
@ -375,7 +416,7 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning)
return 0 ;
return x ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , high_bits_cleaning_cpp ) ) ;
testSolidityAgainstCpp ( 0 , high_bits_cleaning_cpp ) ;
}
BOOST_AUTO_TEST_CASE ( sign_extension )
@ -395,7 +436,7 @@ BOOST_AUTO_TEST_CASE(sign_extension)
return 0 ;
return u256 ( x ) * - 1 ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , sign_extension_cpp ) ) ;
testSolidityAgainstCpp ( 0 , sign_extension_cpp ) ;
}
BOOST_AUTO_TEST_CASE ( small_unsigned_types )
@ -412,7 +453,7 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types)
uint32_t x = uint32_t ( 0xffffff ) * 0xffffff ;
return x / 0x100 ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , small_unsigned_types_cpp ) ) ;
testSolidityAgainstCpp ( 0 , small_unsigned_types_cpp ) ;
}
BOOST_AUTO_TEST_CASE ( small_signed_types )
@ -427,7 +468,7 @@ BOOST_AUTO_TEST_CASE(small_signed_types)
{
return - int32_t ( 10 ) * - int64_t ( 20 ) ;
} ;
BOOST_CHECK ( testSolidityAgainstCpp ( 0 , small_signed_types_cpp ) ) ;
testSolidityAgainstCpp ( 0 , small_signed_types_cpp ) ;
}
BOOST_AUTO_TEST_CASE ( state_smoke_test )
@ -445,14 +486,14 @@ BOOST_AUTO_TEST_CASE(state_smoke_test)
" } \n "
" } \n " ;
compileAndRun ( sourceCode ) ;
BOOST_CHECK ( callFunction ( 0 , bytes ( 1 , 0x00 ) ) = = toBigEndian ( u256 ( 0 ) ) ) ;
BOOST_CHECK ( callFunction ( 0 , bytes ( 1 , 0x01 ) ) = = toBigEndian ( u256 ( 0 ) ) ) ;
BOOST_CHECK ( callFunction ( 1 , bytes ( 1 , 0x00 ) + toBigEndian ( u256 ( 0x1234 ) ) ) = = bytes ( ) ) ;
BOOST_CHECK ( callFunction ( 1 , bytes ( 1 , 0x01 ) + toBigEndian ( u256 ( 0x8765 ) ) ) = = bytes ( ) ) ;
BOOST_CHECK ( callFunction ( 0 , bytes ( 1 , 0x00 ) ) = = toBigEndian ( u256 ( 0x1234 ) ) ) ;
BOOST_CHECK ( callFunction ( 0 , bytes ( 1 , 0x01 ) ) = = toBigEndian ( u256 ( 0x8765 ) ) ) ;
BOOST_CHECK ( callFunction ( 1 , bytes ( 1 , 0x00 ) + toBigEndian ( u256 ( 0x3 ) ) ) = = bytes ( ) ) ;
BOOST_CHECK ( callFunction ( 0 , bytes ( 1 , 0x00 ) ) = = toBigEndian ( u256 ( 0x3 ) ) ) ;
BOOST_CHECK ( callContract Function ( 0 , bytes ( 1 , 0x00 ) ) = = toBigEndian ( u256 ( 0 ) ) ) ;
BOOST_CHECK ( callContract Function ( 0 , bytes ( 1 , 0x01 ) ) = = toBigEndian ( u256 ( 0 ) ) ) ;
BOOST_CHECK ( callContract Function ( 1 , bytes ( 1 , 0x00 ) + toBigEndian ( u256 ( 0x1234 ) ) ) = = bytes ( ) ) ;
BOOST_CHECK ( callContract Function ( 1 , bytes ( 1 , 0x01 ) + toBigEndian ( u256 ( 0x8765 ) ) ) = = bytes ( ) ) ;
BOOST_CHECK ( callContract Function ( 0 , bytes ( 1 , 0x00 ) ) = = toBigEndian ( u256 ( 0x1234 ) ) ) ;
BOOST_CHECK ( callContract Function ( 0 , bytes ( 1 , 0x01 ) ) = = toBigEndian ( u256 ( 0x8765 ) ) ) ;
BOOST_CHECK ( callContract Function ( 1 , bytes ( 1 , 0x00 ) + toBigEndian ( u256 ( 0x3 ) ) ) = = bytes ( ) ) ;
BOOST_CHECK ( callContract Function ( 0 , bytes ( 1 , 0x00 ) ) = = toBigEndian ( u256 ( 0x3 ) ) ) ;
}
BOOST_AUTO_TEST_SUITE_END ( )