Browse Source

Virtual machine and switch to Boost's big num type for 256-bit ints.

cl-refactor
Gav Wood 11 years ago
parent
commit
306de204e3
  1. 6
      Common.h
  2. 6
      PatriciaTree.h
  3. 2
      RLP.h
  4. 95
      VirtualMachine.cpp
  5. 65
      VirtualMachine.h
  6. 4
      sha256.cpp
  7. 2
      sha256.h

6
Common.h

@ -5,7 +5,6 @@
#include <cstdint>
#include <boost/multiprecision/cpp_int.hpp>
#include "foreign.h"
#include "uint256_t.h"
namespace eth
{
@ -16,8 +15,9 @@ using bytes = std::vector<byte>;
using fBytes = foreign<byte>;
using fConstBytes = foreign<byte const>;
using bigint = boost::multiprecision::cpp_int;
using u256 = uint256_t;
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using uint = uint64_t;
using sint = int64_t;

6
PatriciaTree.h

@ -116,8 +116,10 @@ inline u256 hash256(StringMap const& _s)
if (_s.empty())
return 0;
HexMap hexMap;
for (auto const& i: _s)
hexMap[toHex(i.first)] = i.second;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second;
// for (auto const& i: _s)
// hexMap[toHex(i.first)] = i.second;
return hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0);
}

2
RLP.h

@ -239,7 +239,7 @@ private:
void appendNumeric(u256 _i)
{
if (_i < 0x18)
m_out.push_back(_i);
m_out.push_back((byte)_i);
else
{
auto br = bytesRequired(_i);

95
VirtualMachine.cpp

@ -1,3 +1,4 @@
#include "uint256_t.h"
#include "VirtualMachine.h"
using namespace std;
using namespace eth;
@ -11,3 +12,97 @@ VirtualMachine::~VirtualMachine()
}
void VirtualMachine::go()
{
bool stopped = false;
while (!stopped)
{
auto rawInst = m_memory[m_pc];
if (rawInst > 0xff)
throw BadInstruction();
Instruction inst = (Instruction)(uint8_t)rawInst;
auto require = [&](uint _n)
{
if (m_stack.size() < _n)
throw StackTooSmall(_n, m_stack.size());
};
switch (inst)
{
case Instruction::ADD:
//pops two items and pushes S[-1] + S[-2] mod 2^256.
require(2);
m_stack[m_stack.size() - 2] += m_stack.back();
m_stack.pop_back();
case Instruction::MUL:
//pops two items and pushes S[-1] * S[-2] mod 2^256.
require(2);
m_stack[m_stack.size() - 2] *= m_stack.back();
m_stack.pop_back();
case Instruction::SUB:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2];
m_stack.pop_back();
case Instruction::DIV:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2];
m_stack.pop_back();
case Instruction::SDIV:
require(2);
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2];
m_stack.pop_back();
case Instruction::MOD:
case Instruction::SMOD:
case Instruction::EXP:
case Instruction::NEG:
case Instruction::LT:
case Instruction::LE:
case Instruction::GT:
case Instruction::GE:
case Instruction::EQ:
case Instruction::NOT:
case Instruction::MYADDRESS:
case Instruction::MYCREATOR:
case Instruction::TXSENDER:
case Instruction::TXVALUE:
case Instruction::TXFEE:
case Instruction::TXDATAN:
case Instruction::TXDATA:
case Instruction::BLK_PREVHASH:
case Instruction::BLK_COINBASE:
case Instruction::BLK_TIMESTAMP:
case Instruction::BLK_NUMBER:
case Instruction::BLK_DIFFICULTY:
case Instruction::SHA256:
case Instruction::RIPEMD160:
case Instruction::ECMUL:
case Instruction::ECADD:
case Instruction::ECSIGN:
case Instruction::ECRECOVER:
case Instruction::ECVALID:
case Instruction::PUSH:
case Instruction::POP:
case Instruction::DUP:
case Instruction::DUPN:
case Instruction::SWAP:
case Instruction::SWAPN:
case Instruction::LOAD:
case Instruction::STORE:
case Instruction::JMP:
case Instruction::JMPI:
case Instruction::IND:
case Instruction::EXTRO:
case Instruction::BALANCE:
case Instruction::MKTX:
break;
case Instruction::SUICIDE:
// TODO: Suicide...
case Instruction::STOP:
// TODO: Cleanups...
return;
default:
throw BadInstruction();
}
}
}

65
VirtualMachine.h

@ -1,5 +1,6 @@
#pragma once
#include <exception>
#include <array>
#include <map>
#include <unordered_map>
@ -13,7 +14,7 @@ namespace eth
enum class Instruction: uint8_t
{
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
MUL, ///< Rx Ry Rz - sets Rz <- Rx * Ry mod 2^256
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)
EXP, ///< Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256
NEG, ///< Rx Ry - sets Ry <- 2^256 - Rx
LT = 0x20, ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0
LT = 0x10, ///< 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
GE, ///< 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
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)
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)
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`
RECOVER, ///< 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
ST, ///< Rx Ry - sets M[Ry] <- Rx
LD, ///< Rx Ry - sets Ry <- M[Rx]
SET, ///< Rx V1 V2 V3 V4 - sets Rx <- V1 + 2^8*V2 + 2^16*V3 + 2^24*V4 (where 0 <= V[i] <= 255)
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`
ECRECOVER, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
ECVALID, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
PUSH = 0x40,
POP,
DUP,
DUPN,
SWAP,
SWAPN,
LOAD,
STORE,
JMP = 0x50, ///< Rx - sets the index pointer to the value at Rx
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
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.
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
};
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
{
public:
@ -58,16 +76,21 @@ public:
void initMemory(RLP _contract);
void setMemory(RLP _state);
void go();
private:
std::map<u256, u256> m_memory;
std::array<u256, 256> m_registers;
bigint m_stepCount;
bigint m_totalFee;
bigint m_stepFee;
bigint m_dataFee;
bigint m_memoryFee;
bigint m_extroFee;
std::vector<u256> m_stack;
u256 m_pc;
u256 m_stepCount;
u256 m_totalFee;
u256 m_stepFee;
u256 m_dataFee;
u256 m_memoryFee;
u256 m_extroFee;
u256 m_minerFee;
u256 m_voidFee;
};
}

4
sha256.cpp

@ -181,9 +181,9 @@ std::string eth::sha256(std::string const& _input, bool _hex)
return std::string(buf);
}
uint256_t eth::sha256(bytes const& _input)
u256 eth::sha256(bytes const& _input)
{
uint256_t ret = 0;
u256 ret = 0;
SHA256 ctx = SHA256();
ctx.init();

2
sha256.h

@ -27,7 +27,7 @@ protected:
};
std::string sha256(std::string const& input, bool _hex);
uint256_t sha256(bytes const& input);
u256 sha256(bytes const& input);
#define SHA2_SHFR(x, n) (x >> n)
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))

Loading…
Cancel
Save