@ -45,42 +45,12 @@ static array<InstructionMetric, 256> metrics()
return s_ret ;
return s_ret ;
}
}
bytesConstRef VM : : execImpl ( u256 & io_gas , ExtVMFace & _ext , OnOpFunc const & _onOp )
void VM : : checkRequirements ( u256 & io_gas , ExtVMFace & _ext , OnOpFunc const & _onOp , Instruction _inst )
{
// Reset leftovers from possible previous run
m_curPC = 0 ;
m_jumpDests . clear ( ) ;
m_stack . reserve ( ( unsigned ) c_stackLimit ) ;
unique_ptr < CallParameters > callParams ;
static const array < InstructionMetric , 256 > c_metrics = metrics ( ) ;
auto memNeed = [ ] ( u256 _offset , dev : : u256 _size ) { return _size ? ( bigint ) _offset + _size : ( bigint ) 0 ; } ;
auto gasForMem = [ ] ( bigint _size ) - > bigint
{
{
bigint s = _size / 32 ;
static const auto c_metrics = metrics ( ) ;
return ( bigint ) c_memoryGas * s + s * s / c_quadCoeffDiv ;
auto & metric = c_metrics [ static_cast < size_t > ( _inst ) ] ;
} ;
if ( m_jumpDests . empty ( ) )
if ( metric . gasPriceTier = = InvalidTier )
for ( unsigned i = 0 ; i < _ext . code . size ( ) ; + + i )
{
if ( _ext . code [ i ] = = ( byte ) Instruction : : JUMPDEST )
m_jumpDests . push_back ( i ) ;
else if ( _ext . code [ i ] > = ( byte ) Instruction : : PUSH1 & & _ext . code [ i ] < = ( byte ) Instruction : : PUSH32 )
i + = _ext . code [ i ] - ( unsigned ) Instruction : : PUSH1 + 1 ;
}
u256 nextPC = m_curPC + 1 ;
for ( uint64_t steps = 0 ; true ; m_curPC = nextPC , nextPC = m_curPC + 1 , + + steps )
{
// INSTRUCTION...
Instruction inst = ( Instruction ) _ext . getCode ( m_curPC ) ;
auto metric = c_metrics [ ( int ) inst ] ;
int gasPriceTier = metric . gasPriceTier ;
if ( gasPriceTier = = InvalidTier )
BOOST_THROW_EXCEPTION ( BadInstruction ( ) ) ;
BOOST_THROW_EXCEPTION ( BadInstruction ( ) ) ;
// FEES...
// FEES...
@ -96,10 +66,12 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
auto onOperation = [ & ] ( )
auto onOperation = [ & ] ( )
{
{
if ( _onOp )
if ( _onOp )
_onOp ( steps , inst , newTempSize > m_temp . size ( ) ? ( newTempSize - m_temp . size ( ) ) / 32 : bigint ( 0 ) , runGas , io_gas , this , & _ext ) ;
_onOp ( m_ steps, _ inst, newTempSize > m_temp . size ( ) ? ( newTempSize - m_temp . size ( ) ) / 32 : bigint ( 0 ) , runGas , io_gas , this , & _ext ) ;
} ;
} ;
switch ( inst )
auto memNeed = [ ] ( u256 _offset , dev : : u256 _size ) { return _size ? ( bigint ) _offset + _size : ( bigint ) 0 ; } ;
switch ( _inst )
{
{
case Instruction : : SSTORE :
case Instruction : : SSTORE :
if ( ! _ext . store ( m_stack . back ( ) ) & & m_stack [ m_stack . size ( ) - 2 ] )
if ( ! _ext . store ( m_stack . back ( ) ) & & m_stack [ m_stack . size ( ) - 2 ] )
@ -157,7 +129,7 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
case Instruction : : LOG3 :
case Instruction : : LOG3 :
case Instruction : : LOG4 :
case Instruction : : LOG4 :
{
{
unsigned n = ( unsigned ) inst - ( unsigned ) Instruction : : LOG0 ;
unsigned n = ( unsigned ) _ inst - ( unsigned ) Instruction : : LOG0 ;
runGas = c_logGas + c_logTopicGas * n + ( bigint ) c_logDataGas * m_stack [ m_stack . size ( ) - 2 ] ;
runGas = c_logGas + c_logTopicGas * n + ( bigint ) c_logDataGas * m_stack [ m_stack . size ( ) - 2 ] ;
newTempSize = memNeed ( m_stack [ m_stack . size ( ) - 1 ] , m_stack [ m_stack . size ( ) - 2 ] ) ;
newTempSize = memNeed ( m_stack [ m_stack . size ( ) - 1 ] , m_stack [ m_stack . size ( ) - 2 ] ) ;
break ;
break ;
@ -166,7 +138,7 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
case Instruction : : CALL :
case Instruction : : CALL :
case Instruction : : CALLCODE :
case Instruction : : CALLCODE :
runGas = ( bigint ) c_callGas + m_stack [ m_stack . size ( ) - 1 ] ;
runGas = ( bigint ) c_callGas + m_stack [ m_stack . size ( ) - 1 ] ;
if ( inst ! = Instruction : : CALLCODE & & ! _ext . exists ( asAddress ( m_stack [ m_stack . size ( ) - 2 ] ) ) )
if ( _ inst ! = Instruction : : CALLCODE & & ! _ext . exists ( asAddress ( m_stack [ m_stack . size ( ) - 2 ] ) ) )
runGas + = c_callNewAccountGas ;
runGas + = c_callNewAccountGas ;
if ( m_stack [ m_stack . size ( ) - 3 ] > 0 )
if ( m_stack [ m_stack . size ( ) - 3 ] > 0 )
runGas + = c_callValueTransferGas ;
runGas + = c_callValueTransferGas ;
@ -188,6 +160,12 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
default : ;
default : ;
}
}
auto gasForMem = [ ] ( bigint _size ) - > bigint
{
bigint s = _size / 32 ;
return ( bigint ) c_memoryGas * s + s * s / c_quadCoeffDiv ;
} ;
newTempSize = ( newTempSize + 31 ) / 32 * 32 ;
newTempSize = ( newTempSize + 31 ) / 32 * 32 ;
if ( newTempSize > m_temp . size ( ) )
if ( newTempSize > m_temp . size ( ) )
runGas + = gasForMem ( newTempSize ) - gasForMem ( m_temp . size ( ) ) ;
runGas + = gasForMem ( newTempSize ) - gasForMem ( m_temp . size ( ) ) ;
@ -202,6 +180,32 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
if ( newTempSize > m_temp . size ( ) )
if ( newTempSize > m_temp . size ( ) )
m_temp . resize ( ( size_t ) newTempSize ) ;
m_temp . resize ( ( size_t ) newTempSize ) ;
}
bytesConstRef VM : : execImpl ( u256 & io_gas , ExtVMFace & _ext , OnOpFunc const & _onOp )
{
// Reset leftovers from possible previous run
m_curPC = 0 ;
m_jumpDests . clear ( ) ;
m_stack . reserve ( ( unsigned ) c_stackLimit ) ;
unique_ptr < CallParameters > callParams ;
if ( m_jumpDests . empty ( ) )
for ( unsigned i = 0 ; i < _ext . code . size ( ) ; + + i )
{
if ( _ext . code [ i ] = = ( byte ) Instruction : : JUMPDEST )
m_jumpDests . push_back ( i ) ;
else if ( _ext . code [ i ] > = ( byte ) Instruction : : PUSH1 & & _ext . code [ i ] < = ( byte ) Instruction : : PUSH32 )
i + = _ext . code [ i ] - ( unsigned ) Instruction : : PUSH1 + 1 ;
}
u256 nextPC = m_curPC + 1 ;
for ( m_steps = 0 ; true ; m_curPC = nextPC , nextPC = m_curPC + 1 , + + m_steps )
{
// INSTRUCTION...
Instruction inst = ( Instruction ) _ext . getCode ( m_curPC ) ;
checkRequirements ( io_gas , _ext , _onOp , inst ) ;
// EXECUTE...
// EXECUTE...
switch ( inst )
switch ( inst )