diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 01bd22d4f..1d8f410df 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -65,6 +65,23 @@ Main::~Main() writeSettings(); } +QString Main::render(eth::Address _a) const +{ + static const Address c_nameContract(fromUserHex("f28e4d396cfc7bae483e464221b0d2bd3c27f21f")); + if (h256 n = m_client->state().contractMemory(c_nameContract, (h256)(u256)(u160)_a)) + { + std::string s((char const*)n.data(), 32); + s.resize(s.find_first_of('\0')); + return QString::fromStdString(s + " (" + _a.abridged() + ")"); + } + return QString::fromStdString(_a.abridged()); +} + +Address Main::fromString(QString const& _a) const +{ + return _a.size() ? Address(fromUserHex(_a.toStdString())) : Address(); +} + void Main::on_about_triggered() { QMessageBox::about(this, "About AlethZero PoC-3", "AlethZero/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM) "\nBy Gav Wood, 2014.\nBased on a design by Vitalik Buterin.\n\nTeam Ethereum++ includes: Eric Lombrozo, Marko Simovic, Alex Leverington, Tim Hughes and several others."); @@ -153,10 +170,10 @@ void Main::refresh() ui->contracts->clear(); for (auto i: acs) { - (new QListWidgetItem(QString("%1 [%3] @ %2").arg(formatBalance(i.second).c_str()).arg(i.first.abridged().c_str()).arg((unsigned)m_client->state().transactionsFrom(i.first)), ui->accounts)) + (new QListWidgetItem(QString("%1 [%3] @ %2").arg(formatBalance(i.second).c_str()).arg(render(i.first)).arg((unsigned)m_client->state().transactionsFrom(i.first)), ui->accounts)) ->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size)); if (m_client->state().isContractAddress(i.first)) - (new QListWidgetItem(QString("%1 [%3] @ %2").arg(formatBalance(i.second).c_str()).arg(i.first.abridged().c_str()).arg((unsigned)m_client->state().transactionsFrom(i.first)), ui->contracts)) + (new QListWidgetItem(QString("%1 [%3] @ %2").arg(formatBalance(i.second).c_str()).arg(render(i.first)).arg((unsigned)m_client->state().transactionsFrom(i.first)), ui->contracts)) ->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size)); } @@ -472,7 +489,7 @@ void Main::on_send_clicked() { m_client->unlock(); Secret s = i.secret(); - Address r = ui->destination->text().size() ? Address(fromUserHex(ui->destination->text().toStdString())) : Address(); + Address r = fromString(ui->destination->text()); m_client->transact(s, r, value(), m_data); refresh(); return; diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 7f1fd6cd0..8c71492ae 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -47,6 +47,9 @@ private slots: void refreshNetwork(); private: + QString render(eth::Address _a) const; + eth::Address fromString(QString const& _a) const; + void updateFee(); void readSettings(); void writeSettings(); diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index a801c852f..a396a176b 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -22,9 +22,46 @@ #include "Instruction.h" #include +#include "Common.h" using namespace std; using namespace eth; +static string readQuoted(char const*& o_d, char const* _e) +{ + string ret; + bool escaped = 0; + for (++o_d; o_d != _e && (escaped || *o_d != '"'); ++o_d) + if (!escaped && *o_d == '\\') + escaped = true; + else + ret.push_back(*o_d); + if (o_d != _e) + ++o_d; // skip last " + return ret; +} + +static u256 readNumeric(string _v, bool _quiet) +{ + u256 x = 1; + for (auto const& i: units()) + if (boost::algorithm::ends_with(_v, i.second)) + { + _v = _v.substr(0, _v.size() - i.second.size()); + x = i.first; + break; + } + try + { + return x * u256(_v); + } + catch (...) + { + if (!_quiet) + cwarn << "Invalid numeric" << _v; + } + return 0; +} + u256s eth::assemble(std::string const& _code, bool _quiet) { u256s ret; @@ -35,34 +72,44 @@ u256s eth::assemble(std::string const& _code, bool _quiet) while (d != e) { // skip to next token - for (; d != e && !isalnum(*d) && *d != '_' && *d != ':'; ++d) {} + for (; d != e && !isalnum(*d) && *d != '_' && *d != ':' && *d != '"'; ++d) {} if (d == e) break; - char const* s = d; - for (; d != e && (isalnum(*d) || *d == '_' || *d == ':'); ++d) {} - - string t = string(s, d - s); - if (isdigit(t[0])) - try - { - ret.push_back(u256(t)); - } - catch (...) + if (*d == '"') + { + string s = readQuoted(d, e); + if (s.size() > 32) { - cwarn << "Invalid numeric" << t; + if (!_quiet) + cwarn << "String literal > 32 characters. Cropping."; + s.resize(32); } - else if (t.back() == ':') - known[t.substr(0, t.size() - 1)] = ret.size(); + h256 valHash; + memcpy(valHash.data(), s.data(), s.size()); + memset(valHash.data() + s.size(), 0, 32 - s.size()); + ret.push_back((u256)valHash); + } else { - auto it = c_instructions.find(boost::algorithm::to_upper_copy(t)); - if (it != c_instructions.end()) - ret.push_back((u256)it->second); + char const* s = 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() == ':') + known[t.substr(0, t.size() - 1)] = ret.size(); else { - req[ret.size()] = t; - ret.push_back(0); + auto it = c_instructions.find(boost::algorithm::to_upper_copy(t)); + if (it != c_instructions.end()) + ret.push_back((u256)it->second); + else + { + req[ret.size()] = t; + ret.push_back(0); + } } } } @@ -70,7 +117,8 @@ u256s eth::assemble(std::string const& _code, bool _quiet) if (known.count(i.second)) ret[i.first] = known[i.second]; else - cwarn << "Unknown assembler token" << i.second << "at address" << i.first; + if (!_quiet) + cwarn << "Unknown assembler token" << i.second << "at address" << i.first; return ret; } @@ -95,7 +143,7 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 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 != '"'; ++d) {} if (d == e) break; @@ -116,11 +164,38 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 return false; default: { - char const* s = d; - for (; d != e && (isalnum(*d) || *d == '_'); ++d) {} + bool haveLiteral = false; + u256 literalValue = 0; + string t; - string t(s, d - s); - if (isdigit(t[0])) + if (*d == '"') + { + string s = readQuoted(d, e); + if (s.size() > 32) + { + if (!_quiet) + cwarn << "String literal > 32 characters. Cropping."; + s.resize(32); + } + h256 valHash; + memcpy(valHash.data(), s.data(), s.size()); + memset(valHash.data() + s.size(), 0, 32 - s.size()); + literalValue = (u256)valHash; + haveLiteral = true; + } + else + { + char const* s = d; + for (; d != e && (isalnum(*d) || *d == '_'); ++d) {} + t = string(s, d - s); + if (isdigit(t[0])) + { + literalValue = readNumeric(t, _quiet); + haveLiteral = true; + } + } + + if (haveLiteral) { bool bareLoad = true; if (exec) @@ -131,19 +206,13 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 { appendCode(o_code, o_locs, codes, locs); while (compileLispFragment(d, e, _quiet, codes, locs)) - cwarn << "Additional items in bare store. Ignoring."; + if (!_quiet) + cwarn << "Additional items in bare store. Ignoring."; bareLoad = false; } } o_code.push_back(Instruction::PUSH); - try - { - o_code.push_back(u256(t)); - } - catch (...) - { - cwarn << "Invalid numeric" << t; - } + o_code.push_back(literalValue); if (exec) o_code.push_back(bareLoad ? Instruction::SLOAD : Instruction::SSTORE); } @@ -190,7 +259,38 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 // At end now. o_code[endLocation] = o_code.size(); } - if (t == "FOR") + else if (t == "WHEN" || t == "UNLESS") + { + // Compile all the code... + u256s codes[3]; + vector locs[3]; + for (int i = 0; i < 2; ++i) + if (!compileLispFragment(d, e, _quiet, codes[i], locs[i])) + return false; + if (compileLispFragment(d, e, _quiet, codes[2], locs[2])) + return false; + + // Push the positive location. + o_code.push_back(Instruction::PUSH); + unsigned endLocation = o_code.size(); + o_locs.push_back(endLocation); + o_code.push_back(0); + + // First fragment - predicate + appendCode(o_code, o_locs, codes[0], locs[0]); + + // Jump to end... + if (t == "WHEN") + o_code.push_back(Instruction::NOT); + o_code.push_back(Instruction::JMPI); + + // Second fragment - negative. + appendCode(o_code, o_locs, codes[1], locs[1]); + + // At end now. + o_code[endLocation] = o_code.size(); + } + else if (t == "FOR") { // Compile all the code... u256s codes[3]; @@ -257,14 +357,7 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 else { o_code.push_back(Instruction::PUSH); - try - { - o_code.push_back((u256)it->second); - } - catch (...) - { - cwarn << "Invalid numeric" << t; - } + o_code.push_back(it->second); } } else if (!_quiet) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 6dd5e1c03..7f0affcae 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -603,7 +603,8 @@ u256 State::contractMemory(Address _id, u256 _memory) const } // Memory not cached - just grab one item from the DB rather than cache the lot. TrieDB memdb(const_cast(&m_db), it->second.oldRoot()); // promise we won't change the overlay! :) - return RLP(memdb.at(_memory)).toInt(); // TODO: CHECK: check if this is actually an RLP decode + string ret = memdb.at(_memory); + return ret.size() ? RLP(ret).toInt() : 0; } map const& State::contractMemory(Address _contract) const