Browse Source

Separation of code & data compiling.

cl-refactor
Gav Wood 11 years ago
parent
commit
1713329d22
  1. 22
      alethzero/MainWin.cpp
  2. 2
      alethzero/MainWin.h
  3. 4
      eth/main.cpp
  4. 8
      libethereum/AddressState.cpp
  5. 29
      libethereum/AddressState.h
  6. 13
      libethereum/Client.cpp
  7. 4
      libethereum/Client.h
  8. 9
      libethereum/CommonData.h
  9. 11
      libethereum/ExtVMFace.h
  10. 262
      libethereum/Instruction.cpp
  11. 46
      libethereum/Instruction.h
  12. 8
      libethereum/RLP.h
  13. 116
      libethereum/State.cpp
  14. 31
      libethereum/State.h
  15. 57
      libethereum/VM.h
  16. 51
      test/vm.cpp
  17. 6
      walleth/MainWin.cpp
  18. 3
      walleth/MainWin.h

22
alethzero/MainWin.cpp

@ -395,17 +395,19 @@ void Main::on_blocks_currentItemChanged()
s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>";
auto ss = tx.safeSender();
s << "<br/>From: <b>" << pretty(ss).toStdString() << "</b> " << ss;
if (tx.isCreation)
if (tx.isCreation())
s << "<br/>Creates: <b>" << pretty(right160(th)).toStdString() << "</b> " << right160(th);
else
s << "<br/>To: <b>" << pretty(tx.receiveAddress).toStdString() << "</b> " << tx.receiveAddress;
s << "<br/>Value: <b>" << formatBalance(tx.value) << "</b>";
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce << "</b>";
s << "<br/>Gas price: <b>" << formatBalance(tx.gasPrice) << "</b>";
if (tx.isCreation)
if (tx.isCreation())
{
s << "<br/>Storage:&nbsp;&emsp;&nbsp;";
s << "</br>" << disassemble(tx.storage);
s << "<br/>Init:";
s << "<br/>" << disassemble(tx.init);
s << "<br/>Code:";
s << "<br/>" << disassemble(tx.data);
}
else
{
@ -524,10 +526,10 @@ void Main::on_data_textChanged()
if (isCreation())
{
string code = ui->data->toPlainText().toStdString();
m_storage = code[0] == '(' ? compileLisp(code, true) : assemble(code, true);
ui->code->setPlainText(QString::fromStdString(disassemble(m_storage)));
ui->gas->setValue((qint64)state().createGas(m_storage.size()));
ui->gas->setEnabled(false);
m_data = compileLisp(code, true, m_init);
ui->code->setPlainText(QString::fromStdString(disassemble(m_data)) + "\n; Init:" + QString::fromStdString(disassemble(m_init)));
ui->gas->setMinimum((qint64)state().createGas(m_data.size() + m_init.size()));
ui->gas->setEnabled(true);
}
else
{
@ -659,9 +661,9 @@ void Main::on_send_clicked()
m_client->unlock();
Secret s = i.secret();
if (isCreation())
m_client->transact(s, value(), gasPrice(), m_storage);
m_client->transact(s, value(), gasPrice(), ui->gas->value(), m_data, m_init);
else
m_client->transact(s, value(), gasPrice(), fromString(ui->destination->text()), ui->gas->value(), m_data);
m_client->transact(s, value(), gasPrice(), ui->gas->value(), fromString(ui->destination->text()), m_data);
refresh();
return;
}

2
alethzero/MainWin.h

@ -83,8 +83,8 @@ private:
QStringList m_servers;
QVector<eth::KeyPair> m_myKeys;
bool m_keysChanged = false;
eth::u256s m_storage;
eth::bytes m_data;
eth::bytes m_init;
eth::Address m_nameReg;
QNetworkAccessManager m_webCtrl;

4
eth/main.cpp

@ -515,7 +515,7 @@ int main(int argc, char** argv)
Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(rechex));
bytes data;
c.transact(secret, amount, gasPrice, dest, gas, data);
c.transact(secret, amount, gasPrice, gas, dest, data);
}
else if (cmd == "send")
{
@ -526,7 +526,7 @@ int main(int argc, char** argv)
cin >> rechex >> amount >> gasPrice >> gas;
Address dest = h160(fromHex(rechex));
c.transact(us.secret(), amount, gasPrice, dest, gas, bytes());
c.transact(us.secret(), amount, gasPrice, gas, dest, bytes());
}
else if (cmd == "inspect")
{

8
libethereum/AddressState.cpp

@ -20,6 +20,14 @@
*/
#include "AddressState.h"
#include "CommonEth.h"
using namespace std;
using namespace eth;
AddressState::AddressState(u256 _balance, u256 _nonce, bytesConstRef _code):
m_type(AddressType::Contract),
m_balance(_balance),
m_nonce(_nonce),
m_isComplete(true),
m_code(_code.toBytes())
{}

29
libethereum/AddressState.h

@ -37,14 +37,10 @@ enum class AddressType
class AddressState
{
public:
AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0), m_haveMemory(false) {}
AddressState(u256 _balance, u256 _nonce, AddressType _type = AddressType::Normal): m_type(_type), m_balance(_balance), m_nonce(_nonce), m_haveMemory(true) {}
AddressState(u256 _balance, u256 _nonce, h256 _contractRoot): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(false), m_contractRoot(_contractRoot) {}
AddressState(u256 _balance, u256 _nonce, u256s _memory): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(true)
{
for (unsigned i = 0; i < _memory.size(); ++i)
m_memory[(u256)i] = _memory[i];
}
AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0), m_isComplete(false) {}
AddressState(u256 _balance, u256 _nonce, AddressType _type = AddressType::Normal): m_type(_type), m_balance(_balance), m_nonce(_nonce), m_isComplete(true) {}
AddressState(u256 _balance, u256 _nonce, h256 _contractRoot, h256 _codeHash): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_isComplete(false), m_contractRoot(_contractRoot), m_codeHash(_codeHash) {}
AddressState(u256 _balance, u256 _nonce, bytesConstRef _code);
void incNonce() { m_nonce++; }
void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); }
@ -55,20 +51,25 @@ public:
u256 const& balance() const { return m_balance; }
u256& nonce() { return m_nonce; }
u256 const& nonce() const { return m_nonce; }
bool haveMemory() const { return m_haveMemory; }
std::map<u256, u256>& setHaveMemory() { assert(m_type == AddressType::Contract); m_haveMemory = true; m_contractRoot = h256(); return m_memory; }
h256 oldRoot() const { assert(!haveMemory()); return m_contractRoot; }
std::map<u256, u256>& memory() { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
bool isComplete() const { return m_isComplete; }
std::map<u256, u256>& setIsComplete(bytesConstRef _code) { assert(m_type == AddressType::Contract); m_isComplete = true; m_contractRoot = h256(); m_code = _code.toBytes(); return m_memory; }
h256 oldRoot() const { assert(!isComplete()); return m_contractRoot; }
h256 codeHash() const { assert(m_codeHash); return m_codeHash; }
std::map<u256, u256>& memory() { assert(m_type == AddressType::Contract && isComplete()); return m_memory; }
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && isComplete()); return m_memory; }
bytes const& code() const { assert(m_type == AddressType::Contract && isComplete()); return m_code; }
bool freshCode() const { return !m_codeHash && m_isComplete; }
private:
AddressType m_type;
u256 m_balance;
u256 m_nonce;
bool m_haveMemory;
bool m_isComplete;
h256 m_contractRoot;
h256 m_codeHash; // if 0 and m_isComplete, has been created and needs to be inserted.
// TODO: change to unordered_map.
std::map<u256, u256> m_memory;
bytes m_code;
};
}

13
libethereum/Client.cpp

@ -140,16 +140,15 @@ void Client::stopMining()
m_doMine = false;
}
void Client::transact(Secret _secret, u256 _value, u256 _gasPrice, Address _dest, u256 _gas, bytes _data)
void Client::transact(Secret _secret, u256 _value, u256 _gasPrice, u256 _gas, Address _dest, bytes const& _data)
{
lock_guard<recursive_mutex> l(m_lock);
Transaction t;
t.isCreation = false;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.receiveAddress = _dest;
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.receiveAddress = _dest;
t.data = _data;
t.sign(_secret);
cnote << "New transaction " << t;
@ -157,15 +156,17 @@ void Client::transact(Secret _secret, u256 _value, u256 _gasPrice, Address _dest
m_changed = true;
}
void Client::transact(Secret _secret, u256 _endowment, u256 _gasPrice, u256s _storage)
void Client::transact(Secret _secret, u256 _endowment, u256 _gasPrice, u256 _gas, bytes const& _code, bytes const& _init)
{
lock_guard<recursive_mutex> l(m_lock);
Transaction t;
t.isCreation = true;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.value = _endowment;
t.gasPrice = _gasPrice;
t.storage = _storage;
t.gas = _gas;
t.receiveAddress = Address();
t.data = _code;
t.init = _init;
t.sign(_secret);
cnote << "New transaction " << t;
m_tq.attemptImport(t.rlp());

4
libethereum/Client.h

@ -84,10 +84,10 @@ public:
~Client();
/// Submits the given transaction.
void transact(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());
void transact(Secret _secret, u256 _value, u256 _gasPrice, u256 _gas, Address _dest, bytes const& _data);
/// Submits a new contract.
void transact(Secret _secret, u256 _endowment, u256 _gasPrice, u256s _storage = u256s());
void transact(Secret _secret, u256 _endowment, u256 _gasPrice, u256 _gas, bytes const& _code, bytes const& _init);
/// Makes the given call. Nothing is recorded into the state. TODO
// bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());

9
libethereum/CommonData.h

@ -143,6 +143,15 @@ std::string randomWord();
// General datatype convenience functions.
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class _T>
inline uint bytesRequired(_T _i)
{
uint i = 0;
for (; _i != 0; ++i, _i >>= 8) {}
return i;
}
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
template <class _T>

11
libethereum/ExtVMFace.h

@ -41,12 +41,13 @@ public:
currentNumber(_currentNumber)
{}
ExtVMFace(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
ExtVMFace(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
myAddress(_myAddress),
txSender(_txSender),
txValue(_txValue),
gasPrice(_gasPrice),
txData(_txData),
code(_code),
previousBlock(_previousBlock),
currentBlock(_currentBlock),
currentNumber(_currentNumber)
@ -57,13 +58,14 @@ public:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
u256 store(u256 _n) { return 0; }
void setStore(u256 _n, u256 _v) {}
byte getCode(u256 _n) const { return _n < code.size() ? code[(unsigned)_n] : 0; }
u256 store(u256 _n) { return 0; }
void setStore(u256 _n, u256 _v) {}
u256 balance(Address _a) { return 0; }
void subBalance(u256 _a) {}
u256 txCount(Address _a) { return 0; }
void suicide(Address _a) {}
h160 create(u256 _endowment, vector_ref<h256 const> _storage) { return h160(); }
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init) { return h160(); }
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _tx) { return false; }
#pragma GCC diagnostic pop
@ -74,6 +76,7 @@ public:
u256 txValue;
u256 gasPrice;
bytesConstRef txData;
bytesConstRef code;
BlockInfo previousBlock; ///< The current block's information.
BlockInfo currentBlock; ///< The current block's information.
uint currentNumber;

262
libethereum/Instruction.cpp

@ -63,7 +63,6 @@ const std::map<std::string, Instruction> eth::c_instructions =
{ "NUMBER", Instruction::NUMBER },
{ "DIFFICULTY", Instruction::DIFFICULTY },
{ "GASLIMIT", Instruction::GASLIMIT },
{ "PUSH", Instruction::PUSH },
{ "POP", Instruction::POP },
{ "DUP", Instruction::DUP },
{ "SWAP", Instruction::SWAP },
@ -77,6 +76,38 @@ const std::map<std::string, Instruction> eth::c_instructions =
{ "PC", Instruction::PC },
{ "MEMSIZE", Instruction::MEMSIZE },
{ "GAS", Instruction::GAS },
{ "PUSH1", Instruction::PUSH1 },
{ "PUSH2", Instruction::PUSH2 },
{ "PUSH3", Instruction::PUSH3 },
{ "PUSH4", Instruction::PUSH4 },
{ "PUSH5", Instruction::PUSH5 },
{ "PUSH6", Instruction::PUSH6 },
{ "PUSH7", Instruction::PUSH7 },
{ "PUSH8", Instruction::PUSH8 },
{ "PUSH9", Instruction::PUSH9 },
{ "PUSH10", Instruction::PUSH10 },
{ "PUSH11", Instruction::PUSH11 },
{ "PUSH12", Instruction::PUSH12 },
{ "PUSH13", Instruction::PUSH13 },
{ "PUSH14", Instruction::PUSH14 },
{ "PUSH15", Instruction::PUSH15 },
{ "PUSH16", Instruction::PUSH16 },
{ "PUSH17", Instruction::PUSH17 },
{ "PUSH18", Instruction::PUSH18 },
{ "PUSH19", Instruction::PUSH19 },
{ "PUSH20", Instruction::PUSH20 },
{ "PUSH21", Instruction::PUSH21 },
{ "PUSH22", Instruction::PUSH22 },
{ "PUSH23", Instruction::PUSH23 },
{ "PUSH24", Instruction::PUSH24 },
{ "PUSH25", Instruction::PUSH25 },
{ "PUSH26", Instruction::PUSH26 },
{ "PUSH27", Instruction::PUSH27 },
{ "PUSH28", Instruction::PUSH28 },
{ "PUSH29", Instruction::PUSH29 },
{ "PUSH30", Instruction::PUSH30 },
{ "PUSH31", Instruction::PUSH31 },
{ "PUSH32", Instruction::PUSH32 },
{ "CREATE", Instruction::CREATE },
{ "CALL", Instruction::CALL },
{ "RETURN", Instruction::RETURN },
@ -118,7 +149,6 @@ const std::map<Instruction, InstructionInfo> eth::c_instructionInfo =
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1 } },
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1 } },
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1 } },
{ Instruction::PUSH, { "PUSH", 1, 0, 1 } },
{ Instruction::POP, { "POP", 0, 1, 0 } },
{ Instruction::DUP, { "DUP", 0, 1, 2 } },
{ Instruction::SWAP, { "SWAP", 0, 2, 2 } },
@ -132,6 +162,38 @@ const std::map<Instruction, InstructionInfo> eth::c_instructionInfo =
{ Instruction::PC, { "PC", 0, 0, 1 } },
{ Instruction::MEMSIZE, { "MEMSIZE", 0, 0, 1 } },
{ Instruction::GAS, { "GAS", 0, 0, 1 } },
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1 } },
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1 } },
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1 } },
{ Instruction::PUSH4, { "PUSH4", 4, 0, 1 } },
{ Instruction::PUSH5, { "PUSH5", 5, 0, 1 } },
{ Instruction::PUSH6, { "PUSH6", 6, 0, 1 } },
{ Instruction::PUSH7, { "PUSH7", 7, 0, 1 } },
{ Instruction::PUSH8, { "PUSH8", 8, 0, 1 } },
{ Instruction::PUSH9, { "PUSH9", 9, 0, 1 } },
{ Instruction::PUSH10, { "PUSH10", 10, 0, 1 } },
{ Instruction::PUSH11, { "PUSH11", 11, 0, 1 } },
{ Instruction::PUSH12, { "PUSH12", 12, 0, 1 } },
{ Instruction::PUSH13, { "PUSH13", 13, 0, 1 } },
{ Instruction::PUSH14, { "PUSH14", 14, 0, 1 } },
{ Instruction::PUSH15, { "PUSH15", 15, 0, 1 } },
{ Instruction::PUSH16, { "PUSH16", 16, 0, 1 } },
{ Instruction::PUSH17, { "PUSH17", 17, 0, 1 } },
{ Instruction::PUSH18, { "PUSH18", 18, 0, 1 } },
{ Instruction::PUSH19, { "PUSH19", 19, 0, 1 } },
{ Instruction::PUSH20, { "PUSH20", 20, 0, 1 } },
{ Instruction::PUSH21, { "PUSH21", 21, 0, 1 } },
{ Instruction::PUSH22, { "PUSH22", 22, 0, 1 } },
{ Instruction::PUSH23, { "PUSH23", 23, 0, 1 } },
{ Instruction::PUSH24, { "PUSH24", 24, 0, 1 } },
{ Instruction::PUSH25, { "PUSH25", 25, 0, 1 } },
{ Instruction::PUSH26, { "PUSH26", 26, 0, 1 } },
{ Instruction::PUSH27, { "PUSH27", 27, 0, 1 } },
{ Instruction::PUSH28, { "PUSH28", 28, 0, 1 } },
{ Instruction::PUSH29, { "PUSH29", 29, 0, 1 } },
{ Instruction::PUSH30, { "PUSH30", 30, 0, 1 } },
{ Instruction::PUSH31, { "PUSH31", 31, 0, 1 } },
{ Instruction::PUSH32, { "PUSH32", 32, 0, 1 } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } },
{ Instruction::CALL, { "CALL", 0, 7, 1 } },
{ Instruction::RETURN, { "RETURN", 0, 2, 0 } },
@ -174,9 +236,9 @@ static u256 readNumeric(string _v, bool _quiet)
return 0;
}
u256s eth::assemble(std::string const& _code, bool _quiet)
bytes eth::assemble(std::string const& _code, bool _quiet)
{
u256s ret;
bytes ret;
map<string, unsigned> known;
map<unsigned, string> req;
char const* d = _code.data();
@ -184,11 +246,11 @@ u256s eth::assemble(std::string const& _code, bool _quiet)
while (d != e)
{
// skip to next token
for (; d != e && !isalnum(*d) && *d != '_' && *d != ':' && *d != '"'; ++d) {}
for (; d != e && !isalnum(*d) && *d != '_' /*&& *d != ':' && *d != '"'*/; ++d) {}
if (d == e)
break;
if (*d == '"')
/* if (*d == '"')
{
string s = readQuoted(d, e);
if (s.size() > 32)
@ -202,15 +264,15 @@ u256s eth::assemble(std::string const& _code, bool _quiet)
memset(valHash.data() + s.size(), 0, 32 - s.size());
ret.push_back((u256)valHash);
}
else
else*/
{
char const* s = d;
for (; d != e && (isalnum(*d) || *d == '_' || *d == ':' || *d == '"'); ++d) {}
for (; d != e && (isalnum(*d) || *d == '_'/* || *d == ':' || *d == '"'*/); ++d) {}
string t = string(s, d - s);
if (isdigit(t[0]))
ret.push_back(readNumeric(t, _quiet));
else if (t.back() == ':')
ret.push_back((byte)readNumeric(t, _quiet));
/* else if (t.back() == ':')
known[t.substr(0, t.size() - 1)] = (unsigned)ret.size();
else
{
@ -222,7 +284,7 @@ u256s eth::assemble(std::string const& _code, bool _quiet)
req[(unsigned)ret.size()] = t;
ret.push_back(0);
}
}
}*/
}
}
for (auto i: req)
@ -235,12 +297,41 @@ u256s eth::assemble(std::string const& _code, bool _quiet)
return ret;
}
static void appendCode(u256s& o_code, vector<unsigned>& o_locs, u256s _code, vector<unsigned>& _locs)
/// @returns the number of addition bytes required for the PUSH.
static void increaseLocation(bytes& o_code, unsigned _pos, unsigned _inc)
{
assert(o_code[_pos] == (byte)Instruction::PUSH4);
bytesRef r(&o_code[1 + _pos], 4);
toBigEndian(fromBigEndian<uint32_t>(bytesConstRef(&o_code[1 + _pos], 4)) + _inc, r);
}
static void pushLocation(bytes& o_code, uint32_t _locationValue)
{
o_code.push_back((byte)Instruction::PUSH4);
o_code.resize(o_code.size() + 4);
bytesRef r(&o_code[o_code.size() - 4], 4);
toBigEndian(_locationValue, r);
}
static unsigned pushLiteral(bytes& o_code, u256 _literalValue)
{
unsigned br = max<unsigned>(1, bytesRequired(_literalValue));
o_code.push_back((byte)Instruction::PUSH1 + br - 1);
o_code.resize(o_code.size() + br);
for (unsigned i = 0; i < br; ++i)
{
o_code[o_code.size() - 1 - i] = (byte)(_literalValue & 0xff);
_literalValue <<= 8;
}
return br + 1;
}
static void appendCode(bytes& o_code, vector<unsigned>& o_locs, bytes _code, vector<unsigned>& _locs)
{
o_locs.reserve(o_locs.size() + _locs.size());
for (auto i: _locs)
{
_code[i] += (u256)o_code.size();
increaseLocation(_code, i, (unsigned)o_code.size());
o_locs.push_back(i + (unsigned)o_code.size());
}
o_code.reserve(o_code.size() + _code.size());
@ -248,7 +339,7 @@ static void appendCode(u256s& o_code, vector<unsigned>& o_locs, u256s _code, vec
o_code.push_back(i);
}
static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s& o_code, vector<unsigned>& o_locs)
static int compileLispFragment(char const*& d, char const* e, bool _quiet, bytes& o_code, vector<unsigned>& o_locs)
{
std::map<std::string, Instruction> const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD } };
std::map<std::string, pair<Instruction, bool>> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } };
@ -321,7 +412,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
bool bareLoad = true;
if (exec)
{
u256s codes;
bytes codes;
vector<unsigned> locs;
if (compileLispFragment(d, e, _quiet, codes, locs))
{
@ -332,10 +423,9 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
bareLoad = false;
}
}
o_code.push_back(Instruction::PUSH);
o_code.push_back(literalValue);
pushLiteral(o_code, literalValue);
if (exec)
o_code.push_back(bareLoad ? Instruction::SLOAD : Instruction::SSTORE);
o_code.push_back(bareLoad ? (byte)Instruction::SLOAD : (byte)Instruction::SSTORE);
}
else
{
@ -343,7 +433,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
if (t == "IF")
{
// Compile all the code...
u256s codes[4];
bytes codes[4];
vector<unsigned> locs[4];
for (int i = 0; i < 3; ++i)
{
@ -360,36 +450,34 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
appendCode(o_code, o_locs, codes[0], locs[0]);
// Push the positive location.
o_code.push_back(Instruction::PUSH);
unsigned posLocation = (unsigned)o_code.size();
o_locs.push_back(posLocation);
o_code.push_back(0);
pushLocation(o_code, 0);
// Jump to negative if false.
o_code.push_back(Instruction::JUMPI);
o_code.push_back((byte)Instruction::JUMPI);
// Second fragment - negative.
appendCode(o_code, o_locs, codes[2], locs[2]);
// Jump to end after negative.
o_code.push_back(Instruction::PUSH);
unsigned endLocation = (unsigned)o_code.size();
o_locs.push_back(endLocation);
o_code.push_back(0);
o_code.push_back(Instruction::JUMP);
pushLocation(o_code, 0);
o_code.push_back((byte)Instruction::JUMP);
// Third fragment - positive.
o_code[posLocation] = o_code.size();
increaseLocation(o_code, posLocation, o_code.size());
appendCode(o_code, o_locs, codes[1], locs[1]);
// At end now.
o_code[endLocation] = o_code.size();
increaseLocation(o_code, endLocation, o_code.size());
}
else if (t == "WHEN" || t == "UNLESS")
{
outs = 0;
// Compile all the code...
u256s codes[3];
bytes codes[3];
vector<unsigned> locs[3];
for (int i = 0; i < 2; ++i)
{
@ -398,7 +486,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
return false;
if (i == 1)
for (int j = 0; j < o; ++j)
codes[i].push_back(Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on).
codes[i].push_back((byte)Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on).
}
if (compileLispFragment(d, e, _quiet, codes[2], locs[2]) != -1)
return false;
@ -407,27 +495,26 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
appendCode(o_code, o_locs, codes[0], locs[0]);
// Push the positive location.
o_code.push_back(Instruction::PUSH);
unsigned endLocation = (unsigned)o_code.size();
o_locs.push_back(endLocation);
o_code.push_back(0);
pushLocation(o_code, 0);
// Jump to end...
if (t == "WHEN")
o_code.push_back(Instruction::NOT);
o_code.push_back(Instruction::JUMPI);
o_code.push_back((byte)Instruction::NOT);
o_code.push_back((byte)Instruction::JUMPI);
// Second fragment - negative.
appendCode(o_code, o_locs, codes[1], locs[1]);
// At end now.
o_code[endLocation] = o_code.size();
increaseLocation(o_code, endLocation, o_code.size());
}
else if (t == "FOR")
{
outs = 0;
// Compile all the code...
u256s codes[3];
bytes codes[3];
vector<unsigned> locs[3];
for (int i = 0; i < 2; ++i)
{
@ -436,7 +523,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
return false;
if (i == 1)
for (int j = 0; j < o; ++j)
codes[i].push_back(Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on).
codes[i].push_back((byte)Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on).
}
if (compileLispFragment(d, e, _quiet, codes[2], locs[2]) != -1)
return false;
@ -447,39 +534,37 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
appendCode(o_code, o_locs, codes[0], locs[0]);
// Push the positive location.
o_code.push_back(Instruction::PUSH);
unsigned endInsertion = (unsigned)o_code.size();
o_locs.push_back(endInsertion);
o_code.push_back(0);
pushLocation(o_code, 0);
// Jump to positive if true.
o_code.push_back(Instruction::NOT);
o_code.push_back(Instruction::JUMPI);
o_code.push_back((byte)Instruction::NOT);
o_code.push_back((byte)Instruction::JUMPI);
// Second fragment - negative.
appendCode(o_code, o_locs, codes[1], locs[1]);
// Jump to end after negative.
o_code.push_back(Instruction::PUSH);
o_locs.push_back((unsigned)o_code.size());
o_code.push_back(startLocation);
o_code.push_back(Instruction::JUMP);
pushLocation(o_code, startLocation);
o_code.push_back((byte)Instruction::JUMP);
// At end now.
o_code[endInsertion] = o_code.size();
increaseLocation(o_code, endInsertion, o_code.size());
}
else if (t == "SEQ")
{
while (d != e)
{
u256s codes;
bytes codes;
vector<unsigned> locs;
outs = 0;
int o;
if ((o = compileLispFragment(d, e, _quiet, codes, locs)) > -1)
{
for (int i = 0; i < outs; ++i)
o_code.push_back(Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on).
o_code.push_back((byte)Instruction::POP); // pop additional items off stack for the previous item (final item's returns get left on).
outs = o;
appendCode(o_code, o_locs, codes, locs);
}
@ -491,14 +576,14 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
{
if (exec)
{
vector<pair<u256s, vector<unsigned>>> codes(1);
vector<pair<bytes, vector<unsigned>>> codes(1);
int totalArgs = 0;
while (d != e)
{
int o = compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second);
if (o < 1)
break;
codes.push_back(pair<u256s, vector<unsigned>>());
codes.push_back(pair<bytes, vector<unsigned>>());
totalArgs += o;
}
if (totalArgs < 2)
@ -513,12 +598,9 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
{
appendCode(o_code, o_locs, it->first, it->second);
if (i == datan)
{
o_code.push_back(Instruction::PUSH);
o_code.push_back(datan);
}
pushLocation(o_code, datan);
}
o_code.push_back(Instruction::CALL);
o_code.push_back((byte)Instruction::CALL);
outs = 0;
}
}
@ -526,7 +608,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
{
while (d != e)
{
u256s codes;
bytes codes;
vector<unsigned> locs;
outs = 0;
int o;
@ -541,7 +623,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
}
else if (t == "AND")
{
vector<u256s> codes;
vector<bytes> codes;
vector<vector<unsigned>> locs;
while (d != e)
{
@ -567,8 +649,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
if (codes.size() > 1)
{
o_code.push_back(Instruction::PUSH);
o_code.push_back(0);
pushLiteral(o_code, 0);
for (unsigned i = 1; i < codes.size(); ++i)
{
@ -576,16 +657,15 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]);
// Push the false location.
o_code.push_back(Instruction::PUSH);
ends.push_back((unsigned)o_code.size());
o_locs.push_back(ends.back());
o_code.push_back(0);
pushLocation(o_code, 0);
// Jump to end...
o_code.push_back(Instruction::NOT);
o_code.push_back(Instruction::JUMPI);
o_code.push_back((byte)Instruction::NOT);
o_code.push_back((byte)Instruction::JUMPI);
}
o_code.push_back(Instruction::POP);
o_code.push_back((byte)Instruction::POP);
}
// Check if true - predicate
@ -593,11 +673,11 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
// At end now.
for (auto i: ends)
o_code[i] = o_code.size();
increaseLocation(o_code, i, o_code.size());
}
else if (t == "OR")
{
vector<u256s> codes;
vector<bytes> codes;
vector<vector<unsigned>> locs;
while (d != e)
{
@ -621,8 +701,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
if (codes.size() > 1)
{
o_code.push_back(Instruction::PUSH);
o_code.push_back(1);
pushLiteral(o_code, 1);
for (unsigned i = 1; i < codes.size(); ++i)
{
@ -630,15 +709,14 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]);
// Push the false location.
o_code.push_back(Instruction::PUSH);
ends.push_back((unsigned)o_code.size());
o_locs.push_back(ends.back());
o_code.push_back(0);
pushLocation(o_code, 0);
// Jump to end...
o_code.push_back(Instruction::JUMPI);
o_code.push_back((byte)Instruction::JUMPI);
}
o_code.push_back(Instruction::POP);
o_code.push_back((byte)Instruction::POP);
}
// Check if true - predicate
@ -646,7 +724,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
// At end now.
for (auto i: ends)
o_code[i] = o_code.size();
increaseLocation(o_code, i, o_code.size());
}
else
{
@ -655,14 +733,14 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
{
if (exec)
{
vector<pair<u256s, vector<unsigned>>> codes(1);
vector<pair<bytes, vector<unsigned>>> codes(1);
int totalArgs = 0;
while (d != e)
{
int o = compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second);
if (o < 1)
break;
codes.push_back(pair<u256s, vector<unsigned>>());
codes.push_back(pair<bytes, vector<unsigned>>());
totalArgs += o;
}
int ea = c_instructionInfo.at(it->second).args;
@ -674,13 +752,13 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
for (auto it = codes.rbegin(); it != codes.rend(); ++it)
appendCode(o_code, o_locs, it->first, it->second);
o_code.push_back((u256)it->second);
o_code.push_back((byte)it->second);
outs = c_instructionInfo.at(it->second).ret;
}
else
{
o_code.push_back(Instruction::PUSH);
o_code.push_back(it->second);
o_code.push_back((byte)Instruction::PUSH1);
o_code.push_back((byte)it->second);
}
}
else
@ -691,7 +769,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
int i = 0;
while (d != e)
{
u256s codes;
bytes codes;
vector<unsigned> locs;
int o = compileLispFragment(d, e, _quiet, codes, locs);
if (o == -1)
@ -708,7 +786,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
appendCode(o_code, o_locs, codes, locs);
i += o;
for (; i > 1; --i)
o_code.push_back((u256)it->second);
o_code.push_back((byte)it->second);
}
}
else
@ -716,14 +794,14 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
auto it = c_binary.find(t);
if (it != c_binary.end())
{
vector<pair<u256s, vector<unsigned>>> codes(1);
vector<pair<bytes, vector<unsigned>>> codes(1);
int totalArgs = 0;
while (d != e)
{
int o = compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second);
if (o < 1)
break;
codes.push_back(pair<u256s, vector<unsigned>>());
codes.push_back(pair<bytes, vector<unsigned>>());
totalArgs += o;
}
codes.pop_back();
@ -736,15 +814,15 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
for (auto jt = codes.rbegin(); jt != codes.rend(); ++jt)
appendCode(o_code, o_locs, jt->first, jt->second);
if (it->second.second)
o_code.push_back(Instruction::EQ);
o_code.push_back((u256)it->second.first);
o_code.push_back((byte)Instruction::EQ);
o_code.push_back((byte)it->second.first);
}
else
{
auto it = c_unary.find(t);
if (it != c_unary.end())
{
vector<pair<u256s, vector<unsigned>>> codes(1);
vector<pair<bytes, vector<unsigned>>> codes(1);
int totalArgs = 0;
while (d != e)
{
@ -752,7 +830,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
if (o == -1)
break;
totalArgs += o;
codes.push_back(pair<u256s, vector<unsigned>>());
codes.push_back(pair<bytes, vector<unsigned>>());
}
codes.pop_back();
// int i = (int)codes.size();
@ -763,7 +841,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
}
for (auto it = codes.rbegin(); it != codes.rend(); ++it)
appendCode(o_code, o_locs, it->first, it->second);
o_code.push_back(it->second);
o_code.push_back((byte)it->second);
}
else if (!_quiet)
cwarn << "Unknown assembler token" << t;
@ -781,25 +859,27 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
return -1;
}
u256s eth::compileLisp(std::string const& _code, bool _quiet)
bytes eth::compileLisp(std::string const& _code, bool _quiet, bytes& _init)
{
char const* d = _code.data();
char const* e = _code.data() + _code.size();
u256s ret;
bytes ret;
vector<unsigned> locs;
compileLispFragment(d, e, _quiet, ret, locs);
locs.clear();
compileLispFragment(d, e, _quiet, _init, locs);
return ret;
}
string eth::disassemble(u256s const& _mem)
string eth::disassemble(bytes const& _mem)
{
stringstream ret;
uint numerics = 0;
for (auto it = _mem.begin(); it != _mem.end(); ++it)
{
u256 n = *it;
auto iit = c_instructionInfo.find((Instruction)(uint)n);
if (numerics || iit == c_instructionInfo.end() || (u256)(uint)iit->first != n) // not an instruction or expecting an argument...
byte n = *it;
auto iit = c_instructionInfo.find((Instruction)n);
if (numerics || iit == c_instructionInfo.end() || (byte)iit->first != n) // not an instruction or expecting an argument...
{
if (numerics)
numerics--;

46
libethereum/Instruction.h

@ -69,8 +69,7 @@ enum class Instruction: uint8_t
DIFFICULTY,
GASLIMIT,
PUSH = 0x50,
POP,
POP = 0x50,
DUP,
SWAP,
MLOAD,
@ -84,10 +83,43 @@ enum class Instruction: uint8_t
MEMSIZE,
GAS,
CREATE = 0x60,
PUSH1 = 0x60,
PUSH2,
PUSH3,
PUSH4,
PUSH5,
PUSH6,
PUSH7,
PUSH8,
PUSH9,
PUSH10,
PUSH11,
PUSH12,
PUSH13,
PUSH14,
PUSH15,
PUSH16,
PUSH17,
PUSH18,
PUSH19,
PUSH20,
PUSH21,
PUSH22,
PUSH23,
PUSH24,
PUSH25,
PUSH26,
PUSH27,
PUSH28,
PUSH29,
PUSH30,
PUSH31,
PUSH32,
CREATE = 0xf0,
CALL,
RETURN,
SUICIDE = 0x7f
SUICIDE = 0xff
};
/// Information structure for a particular instruction.
@ -106,12 +138,12 @@ extern const std::map<Instruction, InstructionInfo> c_instructionInfo;
extern const std::map<std::string, Instruction> c_instructions;
/// Convert from simple EVM assembly language to EVM code.
u256s assemble(std::string const& _code, bool _quiet = false);
bytes assemble(std::string const& _code, bool _quiet = false);
/// Convert from EVM code to simple EVM assembly language.
std::string disassemble(u256s const& _mem);
std::string disassemble(bytes const& _mem);
/// Compile a Low-level Lisp-like Language program into EVM-code.
u256s compileLisp(std::string const& _code, bool _quiet = false);
bytes compileLisp(std::string const& _code, bool _quiet, bytes& _init);
}

8
libethereum/RLP.h

@ -325,14 +325,6 @@ private:
*(b--) = (byte)_i;
}
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class _T> static uint bytesRequired(_T _i)
{
uint i = 0;
for (; _i != 0; ++i, _i >>= 8) {}
return i;
}
/// Our output byte stream.
bytes m_out;

116
libethereum/State.cpp

@ -137,16 +137,16 @@ void State::ensureCached(std::map<Address, AddressState>& _cache, Address _a, bo
else if (state.itemCount() == 2)
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>());
else
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>());
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>(), state[3].toHash<h256>());
bool ok;
tie(it, ok) = _cache.insert(make_pair(_a, s));
}
if (_requireMemory && !it->second.haveMemory())
if (_requireMemory && !it->second.isComplete())
{
// Populate memory.
assert(it->second.type() == AddressType::Contract);
TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :)
map<u256, u256>& mem = it->second.setHaveMemory();
map<u256, u256>& mem = it->second.setIsComplete(bytesConstRef(m_db.lookup(it->second.codeHash())));
for (auto const& i: memdb)
mem[i.first] = RLP(i.second).toInt<u256>();
}
@ -572,7 +572,7 @@ u256 State::contractMemory(Address _id, u256 _memory) const
auto it = m_cache.find(_id);
if (it == m_cache.end() || it->second.type() != AddressType::Contract)
return 0;
else if (it->second.haveMemory())
else if (it->second.isComplete())
{
auto mit = it->second.memory().find(_memory);
if (mit == it->second.memory().end())
@ -593,6 +593,14 @@ map<u256, u256> const& State::contractMemory(Address _contract) const
return m_cache[_contract].memory();
}
bytes const& State::contractCode(Address _contract) const
{
if (!isContractAddress(_contract))
return EmptyBytes;
ensureCached(_contract, true, true);
return m_cache[_contract].code();
}
void State::execute(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.
@ -617,23 +625,15 @@ void State::execute(bytesConstRef _rlp)
// Entry point for a contract-originated transaction.
u256 gasCost;
if (t.isCreation)
{
unsigned nonZero = 0;
for (auto i: t.storage)
if (i)
nonZero++;
gasCost = nonZero * c_sstoreGas + c_createGas;
t.gas = gasCost;
}
if (t.isCreation())
gasCost = (t.init.size() + t.data.size()) * c_txDataGas + c_createGas;
else
{
gasCost = t.data.size() * c_txDataGas + c_callGas;
if (t.gas < gasCost)
{
clog(StateChat) << "Not enough gas to pay for the transaction.";
throw OutOfGas();
}
if (t.gas < gasCost)
{
clog(StateChat) << "Not enough gas to pay for the transaction.";
throw OutOfGas();
}
u256 cost = t.value + t.gas * t.gasPrice;
@ -654,21 +654,13 @@ void State::execute(bytesConstRef _rlp)
cnote << "Paying" << formatBalance(cost) << "from sender (includes" << t.gas << "gas at" << formatBalance(t.gasPrice) << ")";
subBalance(sender, cost);
if (t.isCreation)
if (t.isCreation())
{
Address newAddress = right160(t.sha3());
while (isContractAddress(newAddress) || isNormalAddress(newAddress))
newAddress = (u160)newAddress + 1;
// Set up new account...
m_cache[newAddress] = AddressState(t.value, 0, AddressType::Contract);
auto& mem = m_cache[newAddress].memory();
for (uint i = 0; i < t.storage.size(); ++i)
mem[i] = t.storage[i];
create(t, sender, &gas);
}
else
{
cnote << "Giving" << formatBalance(t.value) << "to receiver";
cnote << "Passing" << formatBalance(t.value) << "to receiver";
addBalance(t.receiveAddress, t.value);
if (isContractAddress(t.receiveAddress))
@ -693,7 +685,7 @@ void State::execute(bytesConstRef _rlp)
bool State::call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out)
{
VM vm(*_gas);
ExtVM evm(*this, _myAddress, _txSender, _txValue, _gasPrice, _txData);
ExtVM evm(*this, _myAddress, _txSender, _txValue, _gasPrice, _txData, &contractCode(_myAddress));
bool revert = false;
try
@ -728,27 +720,69 @@ bool State::call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gas
return !revert;
}
h160 State::create(Address _txSender, u256 _endowment, u256 _gasPrice, vector_ref<h256 const> _storage)
h160 State::create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, bytesConstRef _init)
{
Transaction t;
for (auto const& i: _storage)
t.storage.push_back((u256)i);
t.value = _endowment;
t.gasPrice = _gasPrice;
t.gas = *_gas;
t.nonce = transactionsFrom(_txSender);
Address newAddress = right160(t.sha3());
t.init = _init.toBytes();
t.data = _code.toBytes();
return create(t, _txSender, _gas);
}
Address State::create(Transaction const& _t, Address _sender, u256* _gas)
{
Address newAddress = right160(_t.sha3(false));
while (isContractAddress(newAddress) || isNormalAddress(newAddress))
newAddress = (u160)newAddress + 1;
// Set up new account...
m_cache[newAddress] = AddressState(0, 0, &_t.data);
// Execute _init.
VM vm(*_gas);
ExtVM evm(*this, newAddress, _sender, _t.value, _t.gasPrice, bytesConstRef(), &_t.init);
bool revert = false;
// Increment associated nonce for sender.
noteSending(_txSender);
noteSending(_sender);
// Set up new account...
m_cache[newAddress] = AddressState(_endowment, 0, AddressType::Contract);
auto& mem = m_cache[newAddress].memory();
for (uint i = 0; i < _storage.size(); ++i)
mem[i] = (u256)_storage[i];
try
{
/*auto out =*/ vm.go(evm);
// Don't do anything with the output (yet).
//memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
}
catch (OutOfGas const& /*_e*/)
{
clog(StateChat) << "Out of Gas! Reverting.";
revert = true;
}
catch (VMException const& _e)
{
clog(StateChat) << "VM Exception: " << _e.description();
}
catch (Exception const& _e)
{
clog(StateChat) << "Exception in VM: " << _e.description();
}
catch (std::exception const& _e)
{
clog(StateChat) << "std::exception in VM: " << _e.what();
}
// Write state out only in the case of a non-excepted transaction.
if (revert)
{
evm.revert();
m_cache.erase(newAddress);
newAddress = Address();
}
*_gas = vm.gas();
return newAddress;
}

31
libethereum/State.h

@ -46,6 +46,8 @@ std::map<Address, AddressState> const& genesisState();
static const std::map<u256, u256> EmptyMapU256U256;
static const bytes EmptyBytes;
struct StateChat: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 4; };
class ExtVM;
@ -151,6 +153,10 @@ public:
/// @returns std::map<u256, u256> if no contract exists at that address.
std::map<u256, u256> const& contractMemory(Address _contract) const;
/// Get the code of a contract.
/// @returns bytes() if no contract exists at that address.
bytes const& contractCode(Address _contract) const;
/// Note that the given address is sending a transaction and thus increment the associated ticker.
void noteSending(Address _id);
@ -201,7 +207,8 @@ private:
// We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction.
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, vector_ref<h256 const> _storage);
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, bytesConstRef _init);
h160 create(Transaction const& _t, Address _sender, u256* _gas);
/// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
@ -246,8 +253,8 @@ private:
class ExtVM: public ExtVMFace
{
public:
ExtVM(State& _s, Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData):
ExtVMFace(_myAddress, _txSender, _txValue, _gasPrice, _txData, _s.m_previousBlock, _s.m_currentBlock, _s.m_currentNumber), m_s(_s), m_origCache(_s.m_cache)
ExtVM(State& _s, Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, bytesConstRef _code):
ExtVMFace(_myAddress, _txSender, _txValue, _gasPrice, _txData, _code, _s.m_previousBlock, _s.m_currentBlock, _s.m_currentNumber), m_s(_s), m_origCache(_s.m_cache)
{
m_s.ensureCached(_myAddress, true, true);
m_store = &(m_s.m_cache[_myAddress].memory());
@ -266,9 +273,9 @@ public:
m_store->erase(_n);
}
h160 create(u256 _endowment, vector_ref<h256 const> _storage)
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init)
{
return m_s.create(myAddress, _endowment, gasPrice, _storage);
return m_s.create(myAddress, _endowment, gasPrice, _gas, _code, _init);
}
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out)
@ -332,7 +339,7 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
_out << (d.count(i.first) ? "[ ! " : "[ * ") << (i.second.type() == AddressType::Contract ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << i.second.nonce() << "@" << i.second.balance();
if (i.second.type() == AddressType::Contract)
{
if (i.second.haveMemory())
if (i.second.isComplete())
{
_out << std::endl << i.second.memory();
}
@ -366,7 +373,7 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
s << i.second.balance() << i.second.nonce();
if (i.second.type() == AddressType::Contract)
{
if (i.second.haveMemory())
if (i.second.isComplete())
{
TrieDB<h256, DB> memdb(&_db);
memdb.init();
@ -374,9 +381,17 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
if (j.second)
memdb.insert(j.first, rlp(j.second));
s << memdb.root();
if (i.second.freshCode())
{
h256 ch = sha3(i.second.code());
_db.insert(ch, &i.second.code());
s << ch;
}
else
s << i.second.codeHash();
}
else
s << i.second.oldRoot();
s << i.second.oldRoot() << i.second.codeHash();
}
_state.insert(i.first, &s.out());
}

57
libethereum/VM.h

@ -84,10 +84,7 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
m_stepCount++;
// INSTRUCTION...
auto rawInst = _ext.store(m_curPC);
if (rawInst > 0xff)
throw BadInstruction();
Instruction inst = (Instruction)(uint8_t)rawInst;
Instruction inst = (Instruction)_ext.getCode(m_curPC);
// FEES...
bigint runGas = c_stepGas;
@ -349,10 +346,44 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::GASLIMIT:
m_stack.push_back(1000000);
break;
case Instruction::PUSH:
case Instruction::PUSH1:
case Instruction::PUSH2:
case Instruction::PUSH3:
case Instruction::PUSH4:
case Instruction::PUSH5:
case Instruction::PUSH6:
case Instruction::PUSH7:
case Instruction::PUSH8:
case Instruction::PUSH9:
case Instruction::PUSH10:
case Instruction::PUSH11:
case Instruction::PUSH12:
case Instruction::PUSH13:
case Instruction::PUSH14:
case Instruction::PUSH15:
case Instruction::PUSH16:
case Instruction::PUSH17:
case Instruction::PUSH18:
case Instruction::PUSH19:
case Instruction::PUSH20:
case Instruction::PUSH21:
case Instruction::PUSH22:
case Instruction::PUSH23:
case Instruction::PUSH24:
case Instruction::PUSH25:
case Instruction::PUSH26:
case Instruction::PUSH27:
case Instruction::PUSH28:
case Instruction::PUSH29:
case Instruction::PUSH30:
case Instruction::PUSH31:
case Instruction::PUSH32:
{
m_stack.push_back(_ext.store(m_curPC + 1));
m_nextPC = m_curPC + 2;
int i = (int)inst - (int)Instruction::PUSH1 + 1;
m_nextPC = m_curPC + 1;
m_stack.push_back(0);
for (; i--; m_nextPC++)
m_stack.back() = (m_stack.back() << 8) | _ext.getCode(m_nextPC);
break;
}
case Instruction::POP:
@ -447,19 +478,23 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
break;
case Instruction::CREATE:
{
require(3);
require(5);
u256 endowment = m_stack.back();
m_stack.pop_back();
unsigned inOff = (unsigned)m_stack.back();
unsigned codeOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned inSize = (unsigned)m_stack.back();
unsigned codeSize = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned initOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned initSize = (unsigned)m_stack.back();
m_stack.pop_back();
if (_ext.balance(_ext.myAddress) >= endowment)
{
_ext.subBalance(endowment);
m_stack.push_back((u160)_ext.create(endowment, vector_ref<h256 const>((h256 const*)(m_temp.data() + inOff), inSize / 32)));
m_stack.push_back((u160)_ext.create(endowment, &m_gas, bytesConstRef(m_temp.data() + codeOff, codeSize), bytesConstRef(m_temp.data() + initOff, initSize)));
}
else
m_stack.push_back(0);

51
test/vm.cpp

@ -40,7 +40,7 @@ public:
FakeExtVM()
{}
FakeExtVM(BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
ExtVMFace(Address(), Address(), 0, 1, bytesConstRef(), _previousBlock, _currentBlock, _currentNumber)
ExtVMFace(Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _currentNumber)
{}
u256 store(u256 _n)
@ -69,15 +69,14 @@ public:
txs.push_back(_t);
}
}
h160 create(u256 _endowment, vector_ref<h256 const> _storage)
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init)
{
Transaction t;
t.value = _endowment;
t.isCreation = true;
t.storage.reserve(_storage.size());
for (auto i: _storage)
t.storage.push_back(i);
t.gasPrice = gasPrice;
t.gas = *_gas;
t.data = _code.toBytes();
t.init = _init.toBytes();
txs.push_back(t);
return right160(t.sha3(false));
}
@ -85,11 +84,10 @@ public:
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _txOut)
{
Transaction t;
t.isCreation = false;
t.value = _txValue;
t.data = _txData.toVector();
t.gas = *_gas;
t.gasPrice = gasPrice;
t.gas = *_gas;
t.data = _txData.toVector();
t.receiveAddress = _receiveAddress;
txs.push_back(t);
(void)_txOut;
@ -103,18 +101,25 @@ public:
txData = &_txData;
gasPrice = _gasPrice;
}
void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s const& _storage)
void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, bytes const& _code, map<u256, u256> const& _storage)
{
myAddress = _myAddress;
set(myAddress, _myBalance, _myNonce, _storage);
set(myAddress, _myBalance, _myNonce, _code, _storage);
}
void set(Address _a, u256 _myBalance, u256 _myNonce, u256s const& _storage)
void set(Address _a, u256 _myBalance, u256 _myNonce, bytes const& _code, map<u256, u256> const& _storage)
{
get<0>(addresses[_a]) = _myBalance;
get<1>(addresses[_a]) = _myNonce;
get<2>(addresses[_a]) = 0;
for (unsigned i = 0; i < _storage.size(); ++i)
get<3>(addresses[_a])[i] = _storage[i];
get<3>(addresses[_a]) = _storage;
get<4>(addresses[_a]) = _code;
}
void reset(u256 _myBalance, u256 _myNonce, map<u256, u256> const& _storage)
{
txs.clear();
addresses.clear();
set(myAddress, _myBalance, _myNonce, get<4>(addresses[myAddress]), _storage);
}
mObject exportEnv()
@ -235,9 +240,9 @@ public:
}
if (o.count("code"))
{
u256s d = compileLisp(o["code"].get_str());
for (unsigned i = 0; i < d.size(); ++i)
get<3>(a)[(u256)i] = d[i];
bytes e;
bytes d = compileLisp(o["code"].get_str(), false, e);
get<4>(a) = d;
}
}
}
@ -299,14 +304,7 @@ public:
}
}
void reset(u256 _myBalance, u256 _myNonce, u256s _myData)
{
txs.clear();
addresses.clear();
set(myAddress, _myBalance, _myNonce, _myData);
}
map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses;
map<Address, tuple<u256, u256, u256, map<u256, u256>, bytes>> addresses;
Transactions txs;
bytes thisTxData;
};
@ -409,7 +407,8 @@ public:
cb.timestamp = 1;
cb.coinbaseAddress = toAddress(sha3("coinbase"));
FakeExtVM fev(pb, cb, 0);
fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))"));
bytes init;
fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))", false, init), map<u256, u256>());
o["env"] = fev.exportEnv();
o["pre"] = fev.exportState();
fev.setTransaction(toAddress(sha3("sender")), ether, finney, bytes());

6
walleth/MainWin.cpp

@ -174,14 +174,14 @@ unsigned QEthereum::peerCount() const
return (unsigned)client()->peerCount();
}
void QEthereum::transact(Secret _secret, u256 _amount, u256 _gasPrice, QVector<u256> _storage)
void QEthereum::transact(Secret _secret, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _code, QByteArray _init)
{
return client()->transact(_secret, _amount, _gasPrice, _storage.toStdVector());
client()->transact(_secret, _amount, _gasPrice, _gas, bytes(_code.data(), _code.data() + _code.size()), bytes(_init.data(), _init.data() + _init.size()));
}
void QEthereum::transact(Secret _secret, Address _dest, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _data)
{
client()->transact(_secret, _amount, _gasPrice, _dest, _gas, bytes(_data.data(), _data.data() + _data.size()));
client()->transact(_secret, _amount, _gasPrice, _gas, _dest, bytes(_data.data(), _data.data() + _data.size()));
}
Main::Main(QWidget *parent) :

3
walleth/MainWin.h

@ -141,8 +141,7 @@ public:
public slots:
void transact(eth::Secret _secret, eth::Address _dest, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _data);
void transact(eth::Secret _secret, eth::u256 _amount, eth::u256 _gasPrice, QVector<eth::u256> _storage);
void transact(eth::Secret _secret, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _code, QByteArray _init);
void setCoinbase(eth::Address);
void setMining(bool _l);

Loading…
Cancel
Save