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