@ -1,177 +1,370 @@
# include "sha256.h"
# include <secp256k1.h>
# include <secp256k1.h>
# include <random>
# include "sha256.h"
# include "VirtualMachine.h"
# include "VirtualMachine.h"
using namespace std ;
using namespace std ;
using namespace eth ;
using namespace eth ;
VirtualMachine : : ~ VirtualMachine ( )
u256 const State : : c_stepFee = 0 ;
u256 const State : : c_dataFee = 0 ;
u256 const State : : c_memoryFee = 0 ;
u256 const State : : c_extroFee = 0 ;
u256 const State : : c_cryptoFee = 0 ;
u256 const State : : c_newContractFee = 0 ;
u256 extractSender ( u256 _v , u256 _r , u256 _s )
{
{
// TODO...
return _s ;
}
}
template < class _T >
inline _T low160 ( _T const & _t )
{
return _t & ( ( ( ( _T ) 1 ) < < 160 ) - 1 ) ;
}
void VirtualMachine : : go ( )
bool State : : transact ( bytes const & _rlp )
{
{
u256 curPC = 0 ;
RLP rlp ( _rlp ) ;
u256 nextPC = 1 ;
if ( ! rlp . isList ( ) )
auto & memory = m_state - > memory ( m_myAddress ) ;
return false ;
RLPs items = rlp . toList ( ) ;
// if (!items[0].isFixedInt())
// return false;
if ( ! items [ 0 ] . isString ( ) )
return false ;
u256 nonce = items [ 0 ] . toFatInt ( ) ;
// if (!(items[1].isEmpty() || items[1].isFixedInt()))
// return false;
if ( ! items [ 1 ] . isString ( ) )
return false ;
u256 address = items [ 1 ] . toFatInt ( ) ;
if ( ! items [ 2 ] . isFixedInt ( ) )
return false ;
u256 value = items [ 2 ] . toFatInt ( ) ;
if ( ! items [ 3 ] . isFixedInt ( ) )
return false ;
u256 fee = items [ 3 ] . toFatInt ( ) ;
if ( ! items [ 4 ] . isList ( ) )
return false ;
u256s data ;
data . reserve ( items [ 4 ] . itemCount ( ) ) ;
for ( auto const & i : items [ 4 ] . toList ( ) )
if ( i . isFixedInt ( ) )
data . push_back ( i . toFatInt ( ) ) ;
else
return false ;
if ( ! items [ 5 ] . isString ( ) )
return false ;
u256 v = items [ 5 ] . toFatInt ( ) ;
if ( ! items [ 6 ] . isString ( ) )
return false ;
u256 r = items [ 6 ] . toFatInt ( ) ;
if ( ! items [ 7 ] . isString ( ) )
return false ;
u256 s = items [ 7 ] . toFatInt ( ) ;
u256 sender ;
try
{
sender = extractSender ( v , r , s ) ;
}
catch ( . . . )
{
// Invalid signiture.
// Error reporting?
return false ;
}
if ( nonce ! = transactionsFrom ( sender ) )
{
// Nonce is wrong.
// Error reporting?
return false ;
}
if ( balance ( sender ) < value + fee )
{
// Sender balance too low.
// Error reporting?
return false ;
}
if ( address )
{
assert ( subBalance ( sender , value ) ) ;
addBalance ( address , value ) ;
if ( isContractAddress ( address ) )
{
bool ret = true ;
u256 minerFee = 0 ;
try
{
execute ( address , sender , value , fee , data , & minerFee ) ;
}
catch ( . . . )
{
// Execution error.
// Error reporting?
ret = false ;
}
addBalance ( m_minerAddress , minerFee ) ;
return ret ;
}
else
return true ;
}
else
{
if ( fee < data . size ( ) * c_memoryFee + c_newContractFee )
{
// Fee too small.
// Error reporting?
return false ;
}
u256 newAddress = low160 ( sha256 ( _rlp ) ) ;
if ( isContractAddress ( newAddress ) )
{
// Contract collision.
// Error reporting?
return false ;
}
auto & mem = m_contractMemory [ newAddress ] ;
for ( uint i = 0 ; i < data . size ( ) ; + + i )
mem [ i ] = data [ i ] ;
assert ( subBalance ( sender , value ) ) ;
addBalance ( newAddress , value ) ;
return true ;
}
}
void State : : execute ( u256 _myAddress , u256 _txSender , u256 _txValue , u256 _txFee , u256s const & _txData , u256 * _totalFee )
{
std : : vector < u256 > stack ;
auto & myMemory = ensureMemory ( _myAddress ) ;
auto require = [ & ] ( u256 _n )
auto require = [ & ] ( u256 _n )
{
{
if ( m_stack . size ( ) < _n )
if ( stack . size ( ) < _n )
throw StackTooSmall ( _n , m_stack . size ( ) ) ;
throw StackTooSmall ( _n , stack . size ( ) ) ;
} ;
} ;
auto mem = [ & ] ( u256 _n )
auto mem = [ & ] ( u256 _n ) - > u256
{
{
auto i = memory . find ( _n ) ;
auto i = myMemory . find ( _n ) ;
return i = = memory . end ( ) ? 0 : i - > second ;
return i = = myMemory . end ( ) ? 0 : i - > second ;
} ;
auto setMem = [ & ] ( u256 _n , u256 _v )
{
if ( _v )
myMemory [ _n ] = _v ;
else
myMemory . erase ( _n ) ;
} ;
} ;
u256 curPC = 0 ;
u256 nextPC = 1 ;
u256 stepCount = 0 ;
for ( bool stopped = false ; ! stopped ; curPC = nextPC , nextPC = curPC + 1 )
for ( bool stopped = false ; ! stopped ; curPC = nextPC , nextPC = curPC + 1 )
{
{
stepCount + + ;
bigint minerFee = stepCount > 16 ? c_stepFee : 0 ;
bigint voidFee = 0 ;
auto rawInst = mem ( curPC ) ;
auto rawInst = mem ( curPC ) ;
if ( rawInst > 0xff )
if ( rawInst > 0xff )
throw BadInstruction ( ) ;
throw BadInstruction ( ) ;
Instruction inst = ( Instruction ) ( uint8_t ) rawInst ;
Instruction inst = ( Instruction ) ( uint8_t ) rawInst ;
switch ( inst )
{
case Instruction : : STORE :
require ( 2 ) ;
if ( ! mem ( stack . back ( ) ) & & stack [ stack . size ( ) - 2 ] )
voidFee + = c_memoryFee ;
if ( mem ( stack . back ( ) ) & & ! stack [ stack . size ( ) - 2 ] )
voidFee - = c_memoryFee ;
// continue on to...
case Instruction : : LOAD :
minerFee + = c_dataFee ;
break ;
case Instruction : : EXTRO :
case Instruction : : BALANCE :
minerFee + = c_extroFee ;
break ;
case Instruction : : SHA256 :
case Instruction : : RIPEMD160 :
case Instruction : : ECMUL :
case Instruction : : ECADD :
case Instruction : : ECSIGN :
case Instruction : : ECRECOVER :
case Instruction : : ECVALID :
minerFee + = c_cryptoFee ;
break ;
default :
break ;
}
if ( minerFee + voidFee > balance ( _myAddress ) )
return ;
subBalance ( _myAddress , minerFee + voidFee ) ;
* _totalFee + = ( u256 ) minerFee ;
switch ( inst )
switch ( inst )
{
{
case Instruction : : ADD :
case Instruction : : ADD :
//pops two items and pushes S[-1] + S[-2] mod 2^256.
//pops two items and pushes S[-1] + S[-2] mod 2^256.
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] + = m_stack . back ( ) ;
stack [ stack . size ( ) - 2 ] + = stack . back ( ) ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : MUL :
case Instruction : : MUL :
//pops two items and pushes S[-1] * S[-2] mod 2^256.
//pops two items and pushes S[-1] * S[-2] mod 2^256.
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] * = m_stack . back ( ) ;
stack [ stack . size ( ) - 2 ] * = stack . back ( ) ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : SUB :
case Instruction : : SUB :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) - m_stack [ m_stack . size ( ) - 2 ] ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) - stack [ stack . size ( ) - 2 ] ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : DIV :
case Instruction : : DIV :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) / m_stack [ m_stack . size ( ) - 2 ] ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) / stack [ stack . size ( ) - 2 ] ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : SDIV :
case Instruction : : SDIV :
require ( 2 ) ;
require ( 2 ) ;
( s256 & ) m_stack [ m_stack . size ( ) - 2 ] = ( s256 & ) m_stack . back ( ) / ( s256 & ) m_stack [ m_stack . size ( ) - 2 ] ;
( s256 & ) stack [ stack . size ( ) - 2 ] = ( s256 & ) stack . back ( ) / ( s256 & ) stack [ stack . size ( ) - 2 ] ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : MOD :
case Instruction : : MOD :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) % m_stack [ m_stack . size ( ) - 2 ] ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) % stack [ stack . size ( ) - 2 ] ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : SMOD :
case Instruction : : SMOD :
require ( 2 ) ;
require ( 2 ) ;
( s256 & ) m_stack [ m_stack . size ( ) - 2 ] = ( s256 & ) m_stack . back ( ) % ( s256 & ) m_stack [ m_stack . size ( ) - 2 ] ;
( s256 & ) stack [ stack . size ( ) - 2 ] = ( s256 & ) stack . back ( ) % ( s256 & ) stack [ stack . size ( ) - 2 ] ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : EXP :
case Instruction : : EXP :
{
{
// TODO: better implementation?
// TODO: better implementation?
require ( 2 ) ;
require ( 2 ) ;
auto n = m_stack . back ( ) ;
auto n = stack . back ( ) ;
auto x = m_stack [ m_stack . size ( ) - 2 ] ;
auto x = stack [ stack . size ( ) - 2 ] ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
for ( u256 i = 0 ; i < x ; + + i )
for ( u256 i = 0 ; i < x ; + + i )
n * = n ;
n * = n ;
m_stack . back ( ) = n ;
stack . back ( ) = n ;
break ;
break ;
}
}
case Instruction : : NEG :
case Instruction : : NEG :
require ( 1 ) ;
require ( 1 ) ;
m_stack . back ( ) = ~ ( m_stack . back ( ) - 1 ) ;
stack . back ( ) = ~ ( stack . back ( ) - 1 ) ;
break ;
break ;
case Instruction : : LT :
case Instruction : : LT :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) < m_stack [ m_stack . size ( ) - 2 ] ? 1 : 0 ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) < stack [ stack . size ( ) - 2 ] ? 1 : 0 ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : LE :
case Instruction : : LE :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) < = m_stack [ m_stack . size ( ) - 2 ] ? 1 : 0 ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) < = stack [ stack . size ( ) - 2 ] ? 1 : 0 ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : GT :
case Instruction : : GT :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) > m_stack [ m_stack . size ( ) - 2 ] ? 1 : 0 ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) > stack [ stack . size ( ) - 2 ] ? 1 : 0 ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : GE :
case Instruction : : GE :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) > = m_stack [ m_stack . size ( ) - 2 ] ? 1 : 0 ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) > = stack [ stack . size ( ) - 2 ] ? 1 : 0 ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : EQ :
case Instruction : : EQ :
require ( 2 ) ;
require ( 2 ) ;
m_stack [ m_stack . size ( ) - 2 ] = m_stack . back ( ) = = m_stack [ m_stack . size ( ) - 2 ] ? 1 : 0 ;
stack [ stack . size ( ) - 2 ] = stack . back ( ) = = stack [ stack . size ( ) - 2 ] ? 1 : 0 ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : NOT :
case Instruction : : NOT :
require ( 1 ) ;
require ( 1 ) ;
m_stack . back ( ) = m_stack . back ( ) ? 0 : 1 ;
stack . back ( ) = stack . back ( ) ? 0 : 1 ;
m_stack . pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : MYADDRESS :
case Instruction : : MYADDRESS :
m_stack . push_back ( m_myAddress ) ;
stack . push_back ( _myAddress ) ;
break ;
break ;
case Instruction : : TXSENDER :
case Instruction : : TXSENDER :
m_stack . push_back ( m_txSender ) ;
stack . push_back ( _txSender ) ;
break ;
break ;
case Instruction : : TXVALUE :
case Instruction : : TXVALUE :
m_stack . push_back ( m_txValue ) ;
stack . push_back ( _txValue ) ;
break ;
break ;
case Instruction : : TXFEE :
case Instruction : : TXFEE :
m_stack . push_back ( m_txFee ) ;
stack . push_back ( _txFee ) ;
break ;
break ;
case Instruction : : TXDATAN :
case Instruction : : TXDATAN :
m_stack . push_back ( m_txData . size ( ) ) ;
stack . push_back ( _txData . size ( ) ) ;
break ;
break ;
case Instruction : : TXDATA :
case Instruction : : TXDATA :
require ( 1 ) ;
require ( 1 ) ;
m_stack . back ( ) = m_stack . back ( ) < m_txData . size ( ) ? m_txData [ ( uint ) m_stack . back ( ) ] : 0 ;
stack . back ( ) = stack . back ( ) < _txData . size ( ) ? _txData [ ( uint ) stack . back ( ) ] : 0 ;
break ;
break ;
case Instruction : : BLK_PREVHASH :
case Instruction : : BLK_PREVHASH :
m_stack . push_back ( m_previousBlock . hash ) ;
stack . push_back ( m_previousBlock . hash ) ;
break ;
break ;
case Instruction : : BLK_COINBASE :
case Instruction : : BLK_COINBASE :
m_ stack. push_back ( m_currentBlock . coinbase ) ;
stack . push_back ( m_currentBlock . coinbase ) ;
break ;
break ;
case Instruction : : BLK_TIMESTAMP :
case Instruction : : BLK_TIMESTAMP :
m_ stack. push_back ( m_currentBlock . timestamp ) ;
stack . push_back ( m_currentBlock . timestamp ) ;
break ;
break ;
case Instruction : : BLK_NUMBER :
case Instruction : : BLK_NUMBER :
m_ stack. push_back ( m_currentBlock . number ) ;
stack . push_back ( m_currentBlock . number ) ;
break ;
break ;
case Instruction : : BLK_DIFFICULTY :
case Instruction : : BLK_DIFFICULTY :
m_ stack. push_back ( m_currentBlock . difficulty ) ;
stack . push_back ( m_currentBlock . difficulty ) ;
break ;
break ;
case Instruction : : SHA256 :
case Instruction : : SHA256 :
case Instruction : : RIPEMD160 :
case Instruction : : RIPEMD160 :
{
{
uint s = ( uint ) min ( m_ stack. back ( ) , ( u256 ) ( m_ stack. size ( ) - 1 ) * 32 ) ;
uint s = ( uint ) min ( stack . back ( ) , ( u256 ) ( stack . size ( ) - 1 ) * 32 ) ;
bytes b ( s ) ;
bytes b ( s ) ;
uint i = 0 ;
uint i = 0 ;
for ( ; s ; s = ( s > = 32 ? s - 32 : 0 ) , i + = 32 )
for ( ; s ; s = ( s > = 32 ? s - 32 : 0 ) , i + = 32 )
{
{
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
u256 v = m_ stack. back ( ) ;
u256 v = stack . back ( ) ;
int sz = ( int ) min < u256 > ( 32 , s ) - 1 ; // sz is one fewer than the number of bytes we're interested in.
int sz = ( int ) min < u256 > ( 32 , s ) - 1 ; // sz is one fewer than the number of bytes we're interested in.
v > > = ( ( 31 - sz ) * 8 ) ; // kill unused low-order bytes.
v > > = ( ( 31 - sz ) * 8 ) ; // kill unused low-order bytes.
for ( int j = 0 ; j < = sz ; + + j , v > > = 8 ) // cycle through bytes, starting at low-order end.
for ( int j = 0 ; j < = sz ; + + j , v > > = 8 ) // cycle through bytes, starting at low-order end.
b [ i + sz - j ] = ( byte ) ( v & 0xff ) ; // set each 32-byte (256-bit) chunk in reverse - (i.e. we want to put low-order last).
b [ i + sz - j ] = ( byte ) ( v & 0xff ) ; // set each 32-byte (256-bit) chunk in reverse - (i.e. we want to put low-order last).
}
}
if ( inst = = Instruction : : SHA256 )
if ( inst = = Instruction : : SHA256 )
m_ stack. back ( ) = sha256 ( b ) ;
stack . back ( ) = sha256 ( b ) ;
else
else
// NOTE: this aligns to right of 256-bit container (low-order bytes). This won't work if they're treated as byte-arrays and thus left-aligned in a 256-bit container.
// NOTE: this aligns to right of 256-bit container (low-order bytes). This won't work if they're treated as byte-arrays and thus left-aligned in a 256-bit container.
m_ stack. back ( ) = ripemd160 ( & b ) ;
stack . back ( ) = ripemd160 ( & b ) ;
break ;
break ;
}
}
case Instruction : : ECMUL :
case Instruction : : ECMUL :
@ -183,117 +376,143 @@ void VirtualMachine::go()
break ;
break ;
case Instruction : : PUSH :
case Instruction : : PUSH :
{
{
m_ stack. push_back ( mem ( curPC + 1 ) ) ;
stack . push_back ( mem ( curPC + 1 ) ) ;
nextPC = curPC + 2 ;
nextPC = curPC + 2 ;
break ;
break ;
}
}
case Instruction : : POP :
case Instruction : : POP :
require ( 1 ) ;
require ( 1 ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : DUP :
case Instruction : : DUP :
require ( 1 ) ;
require ( 1 ) ;
m_ stack. push_back ( m_ stack. back ( ) ) ;
stack . push_back ( stack . back ( ) ) ;
break ;
break ;
case Instruction : : DUPN :
case Instruction : : DUPN :
{
{
auto s = mem ( curPC + 1 ) ;
auto s = mem ( curPC + 1 ) ;
if ( s = = 0 | | s > m_ stack. size ( ) )
if ( s = = 0 | | s > stack . size ( ) )
throw OperandOutOfRange ( 1 , m_ stack. size ( ) , s ) ;
throw OperandOutOfRange ( 1 , stack . size ( ) , s ) ;
m_ stack. push_back ( m_ stack[ m_ stack. size ( ) - ( uint ) s ] ) ;
stack . push_back ( stack [ stack . size ( ) - ( uint ) s ] ) ;
nextPC = curPC + 2 ;
nextPC = curPC + 2 ;
break ;
break ;
}
}
case Instruction : : SWAP :
case Instruction : : SWAP :
{
{
require ( 2 ) ;
require ( 2 ) ;
auto d = m_ stack. back ( ) ;
auto d = stack . back ( ) ;
m_ stack. back ( ) = m_ stack[ m_ stack. size ( ) - 2 ] ;
stack . back ( ) = stack [ stack . size ( ) - 2 ] ;
m_ stack[ m_ stack. size ( ) - 2 ] = d ;
stack [ stack . size ( ) - 2 ] = d ;
break ;
break ;
}
}
case Instruction : : SWAPN :
case Instruction : : SWAPN :
{
{
require ( 1 ) ;
require ( 1 ) ;
auto d = m_ stack. back ( ) ;
auto d = stack . back ( ) ;
auto s = mem ( curPC + 1 ) ;
auto s = mem ( curPC + 1 ) ;
if ( s = = 0 | | s > m_ stack. size ( ) )
if ( s = = 0 | | s > stack . size ( ) )
throw OperandOutOfRange ( 1 , m_ stack. size ( ) , s ) ;
throw OperandOutOfRange ( 1 , stack . size ( ) , s ) ;
m_ stack. back ( ) = m_ stack[ m_ stack. size ( ) - ( uint ) s ] ;
stack . back ( ) = stack [ stack . size ( ) - ( uint ) s ] ;
m_ stack[ m_ stack. size ( ) - ( uint ) s ] = d ;
stack [ stack . size ( ) - ( uint ) s ] = d ;
nextPC = curPC + 2 ;
nextPC = curPC + 2 ;
break ;
break ;
}
}
case Instruction : : LOAD :
case Instruction : : LOAD :
require ( 1 ) ;
require ( 1 ) ;
m_ stack. back ( ) = mem ( m_ stack. back ( ) ) ;
stack . back ( ) = mem ( stack . back ( ) ) ;
break ;
break ;
case Instruction : : STORE :
case Instruction : : STORE :
require ( 2 ) ;
require ( 2 ) ;
mem ( m_ stack. back ( ) ) = m_ stack[ m_ stack. size ( ) - 2 ] ;
setMem ( stack . back ( ) , stack [ stack . size ( ) - 2 ] ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : JMP :
case Instruction : : JMP :
require ( 1 ) ;
require ( 1 ) ;
nextPC = m_ stack. back ( ) ;
nextPC = stack . back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : JMPI :
case Instruction : : JMPI :
require ( 2 ) ;
require ( 2 ) ;
if ( m_ stack. back ( ) )
if ( stack . back ( ) )
nextPC = m_ stack[ m_ stack. size ( ) - 2 ] ;
nextPC = stack [ stack . size ( ) - 2 ] ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
break ;
break ;
case Instruction : : IND :
case Instruction : : IND :
m_ stack. push_back ( curPC ) ;
stack . push_back ( curPC ) ;
break ;
break ;
case Instruction : : EXTRO :
case Instruction : : EXTRO :
{
{
require ( 2 ) ;
require ( 2 ) ;
auto memoryAddress = m_ stack. back ( ) ;
auto memoryAddress = stack . back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
auto contractAddress = m_ stack. back ( ) ;
auto contractAddress = stack . back ( ) ;
m_ stack. back ( ) = m_state - > memory ( contractAddress , memoryAddress ) ;
stack . back ( ) = memory ( contractAddress , memoryAddress ) ;
break ;
break ;
}
}
case Instruction : : BALANCE :
case Instruction : : BALANCE :
{
{
require ( 1 ) ;
require ( 1 ) ;
m_ stack. back ( ) = m_state - > balance ( m_ stack. back ( ) ) ;
stack . back ( ) = balance ( stack . back ( ) ) ;
break ;
break ;
}
}
case Instruction : : MKTX :
case Instruction : : MKTX :
{
{
require ( 4 ) ;
require ( 4 ) ;
auto dest = m_ stack. back ( ) ;
auto dest = stack . back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
auto amount = m_ stack. back ( ) ;
auto value = stack . back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
auto fee = m_ stack. back ( ) ;
auto fee = stack . back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
auto itemCount = m_ stack. back ( ) ;
auto itemCount = stack . back ( ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
if ( m_ stack. size ( ) < itemCount )
if ( stack . size ( ) < itemCount )
throw OperandOutOfRange ( 0 , m_ stack. size ( ) , itemCount ) ;
throw OperandOutOfRange ( 0 , stack . size ( ) , itemCount ) ;
u256s data ;
u256s data ;
data . reserve ( ( uint ) itemCount ) ;
data . reserve ( ( uint ) itemCount ) ;
for ( auto i = 0 ; i < itemCount ; + + i )
for ( auto i = 0 ; i < itemCount ; + + i )
{
{
data . push_back ( m_ stack. back ( ) ) ;
data . push_back ( stack . back ( ) ) ;
m_ stack. pop_back ( ) ;
stack . pop_back ( ) ;
}
}
m_state - > transact ( m_myAddress , dest , amount , fee , data ) ;
u256 nonce = transactionsFrom ( _myAddress ) ;
u256 v = 42 ; // TODO: turn our address into a v/r/s signature?
u256 r = 42 ;
u256 s = _myAddress ;
// v/r/s are required to make the transaction hash (via the RLP serialisation) and thus are required in the creation of a contract.
RLPStream rlp ;
if ( nonce )
rlp < < nonce ;
else
rlp < < " " ;
if ( dest )
rlp < < toBigEndianString ( dest ) ;
else
rlp < < " " ;
rlp < < value < < fee < < data < < toBigEndianString ( v ) < < toBigEndianString ( r ) < < toBigEndianString ( s ) ;
transact ( rlp . out ( ) ) ;
break ;
break ;
}
}
case Instruction : : SUICIDE :
case Instruction : : SUICIDE :
// TODO: Suicide...
{
require ( 1 ) ;
auto dest = stack . back ( ) ;
u256 minusVoidFee = m_contractMemory [ _myAddress ] . size ( ) * c_memoryFee ;
addBalance ( dest , balance ( _myAddress ) + minusVoidFee - _txFee ) ;
m_balance . erase ( _myAddress ) ;
m_contractMemory . erase ( _myAddress ) ;
// ...follow through to...
}
case Instruction : : STOP :
case Instruction : : STOP :
// TODO: Cleanups...
return ;
return ;
default :
default :
throw BadInstruction ( ) ;
throw BadInstruction ( ) ;