Browse Source

More VM implementation stuff.

cl-refactor
Gav Wood 11 years ago
parent
commit
dd20b143ad
  1. 2
      libethereum/Common.h
  2. 24
      libethereum/RLP.h
  3. 425
      libethereum/VirtualMachine.cpp
  4. 68
      libethereum/VirtualMachine.h

2
libethereum/Common.h

@ -61,7 +61,7 @@ inline std::string toBigEndianString(u256 _val)
{ {
std::string ret; std::string ret;
ret.resize(32); ret.resize(32);
for (int i = 0; i <32; ++i, _val >>= 8) for (int i = 0; i < 32; ++i, _val >>= 8)
ret[31 - i] = (char)(uint8_t)_val; ret[31 - i] = (char)(uint8_t)_val;
return ret; return ret;
} }

24
libethereum/RLP.h

@ -59,6 +59,9 @@ public:
/// Fits only into eth::u256 type. Use only toFatInt() or toBigInt() to read. /// Fits only into eth::u256 type. Use only toFatInt() or toBigInt() to read.
bool isFatInt() const { assert(!isNull()); return m_data[0] >= 0x20 && m_data[0] < 0x38; } bool isFatInt() const { assert(!isNull()); return m_data[0] >= 0x20 && m_data[0] < 0x38; }
/// Fits into eth::u256 type, though might fit into eth::uint type.
bool isFixedInt() const { assert(!isNull()); return m_data[0] < 0x38; }
/// Fits only into eth::bigint type. Use only toBigInt() to read. /// Fits only into eth::bigint type. Use only toBigInt() to read.
bool isBigInt() const { assert(!isNull()); return m_data[0] >= 0x38 && m_data[0] < 0x40; } bool isBigInt() const { assert(!isNull()); return m_data[0] >= 0x38 && m_data[0] < 0x40; }
@ -95,23 +98,23 @@ public:
return payload().cropped(0, items()).toString(); return payload().cropped(0, items()).toString();
} }
template <class _T = uint> _T toInt(_T _def = 0) const template <class _T = uint> _T toInt() const
{ {
if (!isInt()) if (!isString() && !isInt())
return _def; return 0;
if (isDirectValueInt()) if (isDirectValueInt())
return m_data[0]; return m_data[0];
_T ret = 0; _T ret = 0;
auto s = intSize() - intLengthSize(); auto s = isInt() ? intSize() - lengthSize() : isString() ? items() : 0;
uint o = intLengthSize() + 1; uint o = lengthSize() + 1;
for (uint i = 0; i < s; ++i) for (uint i = 0; i < s; ++i)
ret = (ret << 8) | m_data[i + o]; ret = (ret << 8) | m_data[i + o];
return ret; return ret;
} }
uint toSlimInt(uint _def = 0) const { return toInt<uint>(_def); } uint toSlimInt() const { return toInt<uint>(); }
u256 toFatInt(u256 _def = 0) const { return toInt<u256>(_def); } u256 toFatInt() const { return toInt<u256>(); }
bigint toBigInt(bigint _def = 0) const { return toInt<bigint>(_def); } bigint toBigInt() const { return toInt<bigint>(); }
RLPs toList() const RLPs toList() const
{ {
@ -159,9 +162,9 @@ private:
return 0; return 0;
} }
uint intLengthSize() const { return isIndirectAddressedInt() ? m_data[0] - 0x37 : 0; } uint intSize() const { return (!isInt() || isDirectValueInt()) ? 0 : isIndirectAddressedInt() ? lengthSize() + items() : (m_data[0] - 0x17); }
uint intSize() const { return (!isInt() || isDirectValueInt()) ? 0 : isIndirectAddressedInt() ? intLengthSize() + items() : (m_data[0] - 0x17); }
uint lengthSize() const { auto n = (m_data[0] & 0x3f); return n > 0x37 ? n - 0x37 : 0; }
uint items() const uint items() const
{ {
auto n = (m_data[0] & 0x3f); auto n = (m_data[0] & 0x3f);
@ -219,6 +222,7 @@ public:
RLPStream& operator<<(char const* _s) { append(std::string(_s)); return *this; } RLPStream& operator<<(char const* _s) { append(std::string(_s)); return *this; }
RLPStream& operator<<(std::string const& _s) { append(_s); return *this; } RLPStream& operator<<(std::string const& _s) { append(_s); return *this; }
RLPStream& operator<<(RLPList _l) { appendList(_l.count); return *this; } RLPStream& operator<<(RLPList _l) { appendList(_l.count); return *this; }
template <class _T> RLPStream& operator<<(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
bytes const& out() const { return m_out; } bytes const& out() const { return m_out; }
std::string str() const { return std::string((char const*)m_out.data(), (char const*)(m_out.data() + m_out.size())); } std::string str() const { return std::string((char const*)m_out.data(), (char const*)(m_out.data() + m_out.size())); }

425
libethereum/VirtualMachine.cpp

@ -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();

68
libethereum/VirtualMachine.h

@ -80,65 +80,47 @@ struct BlockInfo
class State class State
{ {
public: public:
State() {} explicit State(u256 _minerAddress): m_minerAddress(_minerAddress) {}
bool transact(bytes const& _rlp);
private:
bool isContractAddress(u256 _address) const { return m_contractMemory.count(_address); }
u256 balance(u256 _id) const { auto it = m_balance.find(_id); return it == m_balance.end() ? 0 : it->second; }
void addBalance(u256 _id, u256 _amount) { auto it = m_balance.find(_id); if (it == m_balance.end()) it->second = _amount; else it->second += _amount; }
// bigint as we don't want any accidental problems with -ve numbers.
bool subBalance(u256 _id, bigint _amount) { auto it = m_balance.find(_id); if (it == m_balance.end() || (bigint)it->second < _amount) return false; it->second = (u256)((bigint)it->second - _amount); return true; }
u256 memory(u256 _contract, u256 _memory) const u256 memory(u256 _contract, u256 _memory) const
{ {
auto m = m_memory.find(_contract); auto m = m_contractMemory.find(_contract);
if (m == m_memory.end()) if (m == m_contractMemory.end())
return 0; return 0;
auto i = m->second.find(_memory); auto i = m->second.find(_memory);
return i == m->second.end() ? 0 : i->second; return i == m->second.end() ? 0 : i->second;
} }
std::map<u256, u256>& memory(u256 _contract) u256 transactionsFrom(u256 _address) { return 0; } // TODO
{
return m_memory[_contract];
}
u256 balance(u256 _id) const { return 0; }
bool transact(u256 _src, u256 _dest, u256 _amount, u256 _fee, u256s const& _data) { return false; }
private:
std::map<u256, std::map<u256, u256>> m_memory;
};
class VirtualMachine
{
public:
VirtualMachine(State& _s): m_state(&_s) {}
~VirtualMachine();
void execute(u256 _myAddress, u256 _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* _totalFee);
void initMemory(RLP _contract); std::map<u256, u256>& ensureMemory(u256 _contract) { return m_contractMemory[_contract]; }
void setMemory(RLP _state);
void go(); std::map<u256, std::map<u256, u256>> m_contractMemory;
std::map<u256, u256> m_balance; // for now - might end up using Trie?
private:
State* m_state;
std::vector<u256> m_stack;
u256 m_stepCount;
u256 m_totalFee;
u256 m_stepFee;
u256 m_dataFee;
u256 m_memoryFee;
u256 m_extroFee;
u256 m_minerFee;
u256 m_voidFee;
u256 m_myAddress;
u256 m_txSender;
u256 m_txValue;
u256 m_txFee;
std::vector<u256> m_txData;
BlockInfo m_previousBlock; BlockInfo m_previousBlock;
BlockInfo m_currentBlock; BlockInfo m_currentBlock;
u256 m_minerAddress;
static const u256 c_stepFee;
static const u256 c_dataFee;
static const u256 c_memoryFee;
static const u256 c_extroFee;
static const u256 c_cryptoFee;
static const u256 c_newContractFee;
}; };
} }

Loading…
Cancel
Save