@ -1,5 +1,6 @@
# pragma once
# pragma once
# include <exception>
# include <array>
# include <array>
# include <map>
# include <map>
# include <unordered_map>
# include <unordered_map>
@ -13,7 +14,7 @@ namespace eth
enum class Instruction : uint8_t
enum class Instruction : uint8_t
{
{
STOP = 0x00 , ///< halts execution
STOP = 0x00 , ///< halts execution
ADD = 0x10 , ///< Rx Ry Rz - sets Rz <- Rx + Ry mod 2^256
ADD , ///< Rx Ry Rz - sets Rz <- Rx + Ry mod 2^256
SUB , ///< Rx Ry Rz - sets Rz <- Rx - Ry mod 2^256
SUB , ///< Rx Ry Rz - sets Rz <- Rx - Ry mod 2^256
MUL , ///< Rx Ry Rz - sets Rz <- Rx * Ry mod 2^256
MUL , ///< Rx Ry Rz - sets Rz <- Rx * Ry mod 2^256
DIV , ///< Rx Ry Rz - sets Rz <- floor(Rx / Ry)
DIV , ///< Rx Ry Rz - sets Rz <- floor(Rx / Ry)
@ -22,34 +23,51 @@ enum class Instruction: uint8_t
SMOD , ///< Rx Ry Rz - like MOD, but for signed values just like SDIV (using Python's convention with negative numbers)
SMOD , ///< Rx Ry Rz - like MOD, but for signed values just like SDIV (using Python's convention with negative numbers)
EXP , ///< Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256
EXP , ///< Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256
NEG , ///< Rx Ry - sets Ry <- 2^256 - Rx
NEG , ///< Rx Ry - sets Ry <- 2^256 - Rx
LT = 0x2 0 , ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0
LT = 0x1 0 , ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0
LE , ///< Rx Ry Rz - sets Rz <- 1 if Rx <= Ry else 0
LE , ///< Rx Ry Rz - sets Rz <- 1 if Rx <= Ry else 0
GT , ///< Rx Ry Rz - sets Rz <- 1 if Rx > Ry else 0
GT , ///< Rx Ry Rz - sets Rz <- 1 if Rx > Ry else 0
GE , ///< Rx Ry Rz - sets Rz <- 1 if Rx >= Ry else 0
GE , ///< Rx Ry Rz - sets Rz <- 1 if Rx >= Ry else 0
EQ , ///< Rx Ry Rz - sets Rz <- 1 if Rx = Ry else 0
EQ , ///< Rx Ry Rz - sets Rz <- 1 if Rx = Ry else 0
NOT , ///< Rx Ry - sets Ry <- 1 if Rx = 0 else 0
NOT , ///< Rx Ry - sets Ry <- 1 if Rx = 0 else 0
SHA256 = 0x30 , ///< Rx Ry - sets Ry <- SHA256(Rx)
MYADDRESS = 0x20 , ///< Rx - sets Rx to the contract's own address
MYCREATOR , ///< Rx - sets Rx to the contract's own address
TXSENDER , ///< pushes the transaction sender
TXVALUE , ///< pushes the transaction value
TXFEE , ///< pushes the transaction fee
TXDATAN , ///< pushes the number of data items
TXDATA , ///< pops one item and pushes data item S[-1], or zero if index out of range
BLK_PREVHASH , ///< pushes the hash of the previous block (NOT the current one since that's impossible!)
BLK_COINBASE , ///< pushes the coinbase of the current block
BLK_TIMESTAMP , ///< pushes the timestamp of the current block
BLK_NUMBER , ///< pushes the current block number
BLK_DIFFICULTY , ///< pushes the difficulty of the current block
SHA256 = 0x30 , ///< sets Ry <- SHA256(Rx)
RIPEMD160 , ///< Rx Ry - sets Ry <- RIPEMD160(Rx)
RIPEMD160 , ///< Rx Ry - sets Ry <- RIPEMD160(Rx)
ECMUL , ///< Rx Ry Rz Ra Rb - sets (Ra, Rb) = Rz * (Rx, Ry) in secp256k1, using (0,0) for the point at infinity
ECMUL , ///< Rx Ry Rz Ra Rb - sets (Ra, Rb) = Rz * (Rx, Ry) in secp256k1, using (0,0) for the point at infinity
ECADD , ///< Rx Ry Rz Ra Rb Rc - sets (Rb, Rc) = (Rx, Ry) + (Ra, Rb)
ECADD , ///< Rx Ry Rz Ra Rb Rc - sets (Rb, Rc) = (Rx, Ry) + (Ra, Rb)
SIGN , ///< Rx Ry Rz Ra Rb - sets(Rz, Ra, Rb)as the(r,s,prefix)values of an Electrum-style RFC6979 deterministic signature ofRxwith private keyRy`
ECSIGN , ///< Rx Ry Rz Ra Rb - sets(Rz, Ra, Rb)as the(r,s,prefix)values of an Electrum-style RFC6979 deterministic signature ofRxwith private keyRy`
RECOVER , ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
ECRECOVER , ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
COPY = 0x40 , ///< Rx Ry - copies Ry <- Rx
ECVALID , ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
ST , ///< Rx Ry - sets M[Ry] <- Rx
PUSH = 0x40 ,
LD , ///< Rx Ry - sets Ry <- M[Rx]
POP ,
SET , ///< Rx V1 V2 V3 V4 - sets Rx <- V1 + 2^8*V2 + 2^16*V3 + 2^24*V4 (where 0 <= V[i] <= 255)
DUP ,
DUPN ,
SWAP ,
SWAPN ,
LOAD ,
STORE ,
JMP = 0x50 , ///< Rx - sets the index pointer to the value at Rx
JMP = 0x50 , ///< Rx - sets the index pointer to the value at Rx
JMPI , ///< Rx Ry - if Rx != 0, sets the index pointer to Ry
JMPI , ///< Rx Ry - if Rx != 0, sets the index pointer to Ry
IND , ///< Rx - sets Rx to the index pointer.
IND , ///< pushes the index pointer.
EXTRO = 0x60 , ///< Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz
EXTRO = 0x60 , ///< Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz
BALANCE , ///< Rx - returns the ether balance of address Rx
BALANCE , ///< Rx - returns the ether balance of address Rx
MKTX = 0x70 , ///< Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract.
MKTX = 0x70 , ///< Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract.
DATA = 0x80 , ///< Rx Ry - sets Ry to data item index Rx if possible, otherwise zero
DATAN , ///< Rx - sets Rx to the number of data items
MYADDRESS = 0x90 , ///< Rx - sets Rx to the contract's own address
SUICIDE = 0xff ///< Rx - destroys the contract and clears all memory, sending the entire balance plus the negative fee from clearing memory minus TXFEE to the address
SUICIDE = 0xff ///< Rx - destroys the contract and clears all memory, sending the entire balance plus the negative fee from clearing memory minus TXFEE to the address
} ;
} ;
class BadInstruction : public std : : exception { } ;
class StackTooSmall : public std : : exception { public : StackTooSmall ( uint _req , uint _got ) : req ( _req ) , got ( _got ) { } uint req ; uint got ; } ;
class VirtualMachine
class VirtualMachine
{
{
public :
public :
@ -58,16 +76,21 @@ public:
void initMemory ( RLP _contract ) ;
void initMemory ( RLP _contract ) ;
void setMemory ( RLP _state ) ;
void setMemory ( RLP _state ) ;
void go ( ) ;
private :
private :
std : : map < u256 , u256 > m_memory ;
std : : map < u256 , u256 > m_memory ;
std : : array < u256 , 256 > m_registers ;
std : : vector < u256 > m_stack ;
bigint m_stepCount ;
u256 m_pc ;
bigint m_totalFee ;
u256 m_stepCount ;
bigint m_stepFee ;
u256 m_totalFee ;
bigint m_dataFee ;
u256 m_stepFee ;
bigint m_memoryFee ;
u256 m_dataFee ;
bigint m_extroFee ;
u256 m_memoryFee ;
u256 m_extroFee ;
u256 m_minerFee ;
u256 m_voidFee ;
} ;
} ;
}
}