diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 5e3fb4cf6..a6a1b9b1f 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -395,17 +395,19 @@ void Main::on_blocks_currentItemChanged()
s << "
" << h << "[" << txi << "]
";
auto ss = tx.safeSender();
s << "
From: " << pretty(ss).toStdString() << " " << ss;
- if (tx.isCreation)
+ if (tx.isCreation())
s << "
Creates: " << pretty(right160(th)).toStdString() << " " << right160(th);
else
s << "
To: " << pretty(tx.receiveAddress).toStdString() << " " << tx.receiveAddress;
s << "
Value: " << formatBalance(tx.value) << "";
s << " #" << tx.nonce << "";
s << "
Gas price: " << formatBalance(tx.gasPrice) << "";
- if (tx.isCreation)
+ if (tx.isCreation())
{
- s << "
Storage: ";
- s << "" << disassemble(tx.storage);
+ s << "
Init:";
+ s << "
" << disassemble(tx.init);
+ s << "
Code:";
+ s << "
" << 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;
}
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index 00a16c7b3..91840dd08 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -83,8 +83,8 @@ private:
QStringList m_servers;
QVector 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;
diff --git a/eth/main.cpp b/eth/main.cpp
index cebcfb9ec..c9412248e 100644
--- a/eth/main.cpp
+++ b/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")
{
diff --git a/libethereum/AddressState.cpp b/libethereum/AddressState.cpp
index a61b6b881..97000521f 100644
--- a/libethereum/AddressState.cpp
+++ b/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())
+{}
diff --git a/libethereum/AddressState.h b/libethereum/AddressState.h
index 1b26bbc3c..d4f37c555 100644
--- a/libethereum/AddressState.h
+++ b/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& 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& memory() { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
- std::map const& memory() const { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
+ bool isComplete() const { return m_isComplete; }
+ std::map& 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& memory() { assert(m_type == AddressType::Contract && isComplete()); return m_memory; }
+ std::map 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 m_memory;
+ bytes m_code;
};
}
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 795ad5293..9c50e7e83 100644
--- a/libethereum/Client.cpp
+++ b/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 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 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());
diff --git a/libethereum/Client.h b/libethereum/Client.h
index d5686065d..39fb7f5d7 100644
--- a/libethereum/Client.h
+++ b/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());
diff --git a/libethereum/CommonData.h b/libethereum/CommonData.h
index ca1fad1a6..260fb3c2a 100644
--- a/libethereum/CommonData.h
+++ b/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
+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
diff --git a/libethereum/ExtVMFace.h b/libethereum/ExtVMFace.h
index 3dc44d6ba..92310e7f1 100644
--- a/libethereum/ExtVMFace.h
+++ b/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 _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;
diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp
index f4273994e..265c284e1 100644
--- a/libethereum/Instruction.cpp
+++ b/libethereum/Instruction.cpp
@@ -63,7 +63,6 @@ const std::map 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 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 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 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 known;
map 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& o_locs, u256s _code, vector& _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(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(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& o_locs, bytes _code, vector& _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& 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& o_locs)
+static int compileLispFragment(char const*& d, char const* e, bool _quiet, bytes& o_code, vector& o_locs)
{
std::map const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD } };
std::map> 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 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 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 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 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 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>> codes(1);
+ vector>> 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>());
+ codes.push_back(pair>());
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 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 codes;
+ vector codes;
vector> 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 codes;
+ vector codes;
vector> 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>> codes(1);
+ vector>> 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>());
+ codes.push_back(pair>());
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 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>> codes(1);
+ vector>> 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>());
+ codes.push_back(pair>());
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>> codes(1);
+ vector>> 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>());
+ codes.push_back(pair>());
}
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 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--;
diff --git a/libethereum/Instruction.h b/libethereum/Instruction.h
index 9b842e6e8..d4396bbf2 100644
--- a/libethereum/Instruction.h
+++ b/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 c_instructionInfo;
extern const std::map 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);
}
diff --git a/libethereum/RLP.h b/libethereum/RLP.h
index e1606b366..29783e1e9 100644
--- a/libethereum/RLP.h
+++ b/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 static uint bytesRequired(_T _i)
- {
- uint i = 0;
- for (; _i != 0; ++i, _i >>= 8) {}
- return i;
- }
-
/// Our output byte stream.
bytes m_out;
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 173e17621..c1a7acf7b 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -137,16 +137,16 @@ void State::ensureCached(std::map& _cache, Address _a, bo
else if (state.itemCount() == 2)
s = AddressState(state[0].toInt(), state[1].toInt());
else
- s = AddressState(state[0].toInt(), state[1].toInt(), state[2].toHash());
+ s = AddressState(state[0].toInt(), state[1].toInt(), state[2].toHash(), state[3].toHash());
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 memdb(const_cast(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :)
- map& mem = it->second.setHaveMemory();
+ map& mem = it->second.setIsComplete(bytesConstRef(m_db.lookup(it->second.codeHash())));
for (auto const& i: memdb)
mem[i.first] = RLP(i.second).toInt();
}
@@ -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 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 _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;
}
diff --git a/libethereum/State.h b/libethereum/State.h
index a4e3c14fa..a1707fb0a 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -46,6 +46,8 @@ std::map const& genesisState();
static const std::map 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 if no contract exists at that address.
std::map 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 _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 _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 const& _cache, DB& _db, TrieDB memdb(&_db);
memdb.init();
@@ -374,9 +381,17 @@ void commit(std::map const& _cache, DB& _db, TrieDB 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 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 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*)(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);
diff --git a/test/vm.cpp b/test/vm.cpp
index bab4b3553..959b0c692 100644
--- a/test/vm.cpp
+++ b/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 _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 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 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 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>> addresses;
+ map, 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());
o["env"] = fev.exportEnv();
o["pre"] = fev.exportState();
fev.setTransaction(toAddress(sha3("sender")), ether, finney, bytes());
diff --git a/walleth/MainWin.cpp b/walleth/MainWin.cpp
index f6e950428..c456b6d77 100644
--- a/walleth/MainWin.cpp
+++ b/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 _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) :
diff --git a/walleth/MainWin.h b/walleth/MainWin.h
index dc180c4b7..54f8e4d93 100644
--- a/walleth/MainWin.h
+++ b/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 _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);