From 0ca84e5a0d78f0eb286b165eb777aeebeaeccb1b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 9 Jan 2015 00:22:06 +0100 Subject: [PATCH] Basic logging in Solidity (though no tests yet). --- alethzero/MainWin.cpp | 87 +++++++++++++++++------------- alethzero/MainWin.h | 2 + libsolidity/CompilerStack.cpp | 8 +++ libsolidity/CompilerStack.h | 7 ++- libsolidity/ExpressionCompiler.cpp | 55 +++++++++++++++++++ libsolidity/GlobalContext.cpp | 55 +++++++++++++------ libsolidity/InterfaceHandler.cpp | 25 +++++++++ libsolidity/InterfaceHandler.h | 1 + libsolidity/Types.h | 2 +- 9 files changed, 187 insertions(+), 55 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b73a2cd0d..8b7acf26e 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -105,9 +105,9 @@ static QString contentsOfQResource(std::string const& res) return in.readAll(); } -Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); -Address c_newConfig = Address("d5f9d8d94886e70b06e474c3fb14fd43e2f23970"); -Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1"); +//Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); +Address c_newConfig = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); +//Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1"); Main::Main(QWidget *parent) : QMainWindow(parent), @@ -265,22 +265,32 @@ void Main::uninstallWatch(unsigned _w) void Main::installWatches() { - installWatch(dev::eth::LogFilter().address(c_config), [=]() { installNameRegWatch(); }); - installWatch(dev::eth::LogFilter().address(c_config), [=]() { installCurrenciesWatch(); }); + installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installNameRegWatch(); }); + installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installCurrenciesWatch(); }); installWatch(dev::eth::PendingChangedFilter, [=](){ onNewPending(); }); installWatch(dev::eth::ChainChangedFilter, [=](){ onNewBlock(); }); } +Address Main::getNameReg() const +{ + return abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); +} + +Address Main::getCurrencies() const +{ + return abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)2))); +} + void Main::installNameRegWatch() { uninstallWatch(m_nameRegFilter); - m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); }); + m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](){ onNameRegChange(); }); } void Main::installCurrenciesWatch() { uninstallWatch(m_currenciesFilter); - m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); }); + m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](){ onCurrenciesChange(); }); } void Main::installBalancesWatch() @@ -288,7 +298,9 @@ void Main::installBalancesWatch() dev::eth::LogFilter tf; vector
altCoins; - Address coinsAddr = right160(ethereum()->stateAt(c_config, 1)); + Address coinsAddr = getCurrencies(); + + // TODO: Update for new currencies reg. for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i) altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1))); for (auto i: m_myKeys) @@ -450,37 +462,37 @@ static Public stringToPublic(QString const& _a) return Public(); } -static Address g_newNameReg; +//static Address g_newNameReg; QString Main::pretty(dev::Address _a) const { - static std::map s_memos; +/* static std::map s_memos; if (!s_memos.count(_a)) - { - if (!g_newNameReg) - g_newNameReg = abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); + {*/ +// if (!g_newNameReg) + auto g_newNameReg = getNameReg(); if (g_newNameReg) { QString s = QString::fromStdString(toString(abiOut(ethereum()->call(g_newNameReg, abiIn(2, _a))))); - s_memos[_a] = s; +// s_memos[_a] = s; if (s.size()) return s; } - } +/* } else if (s_memos[_a].size()) - return s_memos[_a]; + return s_memos[_a];*/ h256 n; - +/* if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0)) n = ethereum()->stateAt(nameReg, (u160)(_a)); if (!n) n = ethereum()->stateAt(m_nameReg, (u160)(_a)); - +*/ return fromRaw(n); } @@ -505,21 +517,21 @@ Address Main::fromString(QString const& _n) const if (_n == "(Create Contract)") return Address(); - static std::map s_memos; +/* static std::map s_memos; if (!s_memos.count(_n)) - { - if (!g_newNameReg) - g_newNameReg = abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); + {*/ +// if (!g_newNameReg) + auto g_newNameReg = abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); if (g_newNameReg) { Address a = abiOut
(ethereum()->call(g_newNameReg, abiIn(0, ::fromString(_n.toStdString())))); - s_memos[_n] = a; +// s_memos[_n] = a; if (a) return a; } - } +/* } else if (s_memos[_n]) return s_memos[_n]; @@ -532,14 +544,13 @@ Address Main::fromString(QString const& _n) const memset(n.data() + sn.size(), 0, 32 - sn.size()); if (_n.size()) { - if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0)) if (h256 a = ethereum()->stateAt(nameReg, n)) return right160(a); if (h256 a = ethereum()->stateAt(m_nameReg, n)) return right160(a); - } + }*/ if (_n.size() == 40) return Address(fromHex(_n.toStdString())); @@ -566,8 +577,9 @@ QString Main::lookup(QString const& _a) const */ h256 ret; - if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0)) - ret = ethereum()->stateAt(dnsReg, n); + // TODO: fix with the new DNSreg contract +// if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0)) +// ret = ethereum()->stateAt(dnsReg, n); /* if (!ret) if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0, 0)) ret = ethereum()->stateAt(nameReg, n2); @@ -861,8 +873,8 @@ void Main::refreshBalances() // update all the balance-dependent stuff. ui->ourAccounts->clear(); u256 totalBalance = 0; - map> altCoins; - Address coinsAddr = right160(ethereum()->stateAt(c_config, 1)); +/* map> altCoins; + Address coinsAddr = getCurrencies(); for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i) { auto n = ethereum()->stateAt(coinsAddr, i + 1); @@ -872,7 +884,7 @@ void Main::refreshBalances() denom = 1; // cdebug << n << addr << denom << sha3(h256(n).asBytes()); altCoins[addr] = make_tuple(fromRaw(n), 0, denom); - } + }*/ for (auto i: m_myKeys) { u256 b = ethereum()->balanceAt(i.address()); @@ -880,18 +892,18 @@ void Main::refreshBalances() ->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); totalBalance += b; - for (auto& c: altCoins) - get<1>(c.second) += (u256)ethereum()->stateAt(c.first, (u160)i.address()); +// for (auto& c: altCoins) +// get<1>(c.second) += (u256)ethereum()->stateAt(c.first, (u160)i.address()); } QString b; - for (auto const& c: altCoins) +/* for (auto const& c: altCoins) if (get<1>(c.second)) { stringstream s; s << setw(toString(get<2>(c.second) - 1).size()) << setfill('0') << (get<1>(c.second) % get<2>(c.second)); b += QString::fromStdString(toString(get<1>(c.second) / get<2>(c.second)) + "." + s.str() + " ") + get<0>(c.second).toUpper() + " | "; - } + }*/ ui->balance->setText(b + QString::fromStdString(formatBalance(totalBalance))); } @@ -1619,12 +1631,15 @@ void Main::on_data_textChanged() { m_data = fromHex(src); } - else if (src.substr(0, 8) == "contract") // improve this heuristic + else if (src.substr(0, 8) == "contract" || src.substr(0, 2) == "/*") // improve this heuristic { dev::solidity::CompilerStack compiler; try { m_data = compiler.compile(src, m_enableOptimizer); + solidity = "

Solidity

"; + solidity += "
" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "
"; + solidity += "
" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
"; } catch (dev::Exception const& exception) { diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index ed5d275eb..55d4c2173 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -170,6 +170,8 @@ private: QString prettyU256(dev::u256 _n) const; QString lookup(QString const& _n) const; + dev::Address getNameReg() const; + dev::Address getCurrencies() const; void populateDebugger(dev::bytesConstRef r); void initDebugger(); diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 79716fdec..1c883a7f6 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -143,6 +143,11 @@ string const& CompilerStack::getInterface(string const& _contractName) const return getJsonDocumentation(_contractName, DocumentationType::ABI_INTERFACE); } +string const& CompilerStack::getSolidityInterface(string const& _contractName) const +{ + return getJsonDocumentation(_contractName, DocumentationType::ABI_SOLIDITY_INTERFACE); +} + string const& CompilerStack::getJsonDocumentation(string const& _contractName, DocumentationType _type) const { if (!m_parseSuccessful) @@ -162,6 +167,9 @@ string const& CompilerStack::getJsonDocumentation(string const& _contractName, D case DocumentationType::ABI_INTERFACE: doc = &contract.interface; break; + case DocumentationType::ABI_SOLIDITY_INTERFACE: + doc = &contract.solidityInterface; + break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index e7143b7bb..d6378ea1e 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -43,7 +43,8 @@ enum class DocumentationType: uint8_t { NATSPEC_USER = 1, NATSPEC_DEV, - ABI_INTERFACE + ABI_INTERFACE, + ABI_SOLIDITY_INTERFACE }; /** @@ -81,6 +82,9 @@ public: /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. std::string const& getInterface(std::string const& _contractName = "") const; + /// Returns a string representing the contract interface in JSON. + /// Prerequisite: Successful call to parse or compile. + std::string const& getSolidityInterface(std::string const& _contractName = "") const; /// Returns a string representing the contract's documentation in JSON. /// Prerequisite: Successful call to parse or compile. /// @param type The type of the documentation to get. @@ -118,6 +122,7 @@ private: bytes bytecode; std::shared_ptr interfaceHandler; mutable std::unique_ptr interface; + mutable std::unique_ptr solidityInterface; mutable std::unique_ptr userDocumentation; mutable std::unique_ptr devDocumentation; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index aa7406132..ec66b69af 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -256,6 +256,61 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) CompilerUtils(m_context).storeInMemory(0); m_context << u256(32) << u256(0) << eth::Instruction::SHA3; break; + case Location::LOG0: + arguments.front()->accept(*this); + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); + // @todo move this once we actually use memory + CompilerUtils(m_context).storeInMemory(0); + m_context << u256(32) << u256(0) << eth::Instruction::LOG0; + break; + case Location::LOG1: + arguments[1]->accept(*this); + arguments[0]->accept(*this); + appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true); + appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true); + // @todo move this once we actually use memory + CompilerUtils(m_context).storeInMemory(0); + m_context << u256(32) << u256(0) << eth::Instruction::LOG1; + break; + case Location::LOG2: + arguments[2]->accept(*this); + arguments[1]->accept(*this); + arguments[0]->accept(*this); + appendTypeConversion(*arguments[2]->getType(), *function.getParameterTypes()[2], true); + appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true); + appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true); + // @todo move this once we actually use memory + CompilerUtils(m_context).storeInMemory(0); + m_context << u256(32) << u256(0) << eth::Instruction::LOG2; + break; + case Location::LOG3: + arguments[3]->accept(*this); + arguments[2]->accept(*this); + arguments[1]->accept(*this); + arguments[0]->accept(*this); + appendTypeConversion(*arguments[3]->getType(), *function.getParameterTypes()[3], true); + appendTypeConversion(*arguments[2]->getType(), *function.getParameterTypes()[2], true); + appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true); + appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true); + // @todo move this once we actually use memory + CompilerUtils(m_context).storeInMemory(0); + m_context << u256(32) << u256(0) << eth::Instruction::LOG3; + break; + case Location::LOG4: + arguments[4]->accept(*this); + arguments[3]->accept(*this); + arguments[2]->accept(*this); + arguments[1]->accept(*this); + arguments[0]->accept(*this); + appendTypeConversion(*arguments[4]->getType(), *function.getParameterTypes()[4], true); + appendTypeConversion(*arguments[3]->getType(), *function.getParameterTypes()[3], true); + appendTypeConversion(*arguments[2]->getType(), *function.getParameterTypes()[2], true); + appendTypeConversion(*arguments[1]->getType(), *function.getParameterTypes()[1], true); + appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true); + // @todo move this once we actually use memory + CompilerUtils(m_context).storeInMemory(0); + m_context << u256(32) << u256(0) << eth::Instruction::LOG4; + break; case Location::ECRECOVER: case Location::SHA256: case Location::RIPEMD160: diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index f4805b1f7..bf2ed479c 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -33,33 +33,54 @@ namespace solidity { GlobalContext::GlobalContext(): +// TODO: make this cleaner. m_magicVariables(vector>{make_shared("block", make_shared(MagicType::Kind::BLOCK)), - make_shared("msg", make_shared(MagicType::Kind::MSG)), - make_shared("tx", make_shared(MagicType::Kind::TX)), - make_shared("suicide", + make_shared("msg", make_shared(MagicType::Kind::MSG)), + make_shared("tx", make_shared(MagicType::Kind::TX)), + make_shared("suicide", make_shared(TypePointers({std::make_shared(0, IntegerType::Modifier::ADDRESS)}), - TypePointers(), - FunctionType::Location::SUICIDE)), - make_shared("sha3", + TypePointers(), + FunctionType::Location::SUICIDE)), + make_shared("sha3", make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - FunctionType::Location::SHA3)), - make_shared("sha256", + TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + FunctionType::Location::SHA3)), + make_shared("log0", make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - FunctionType::Location::SHA256)), - make_shared("ecrecover", + TypePointers(), + FunctionType::Location::LOG0)), + make_shared("log1", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers(), + FunctionType::Location::LOG1)), + make_shared("log2", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers(), + FunctionType::Location::LOG2)), + make_shared("log3", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers(), + FunctionType::Location::LOG3)), + make_shared("log4", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers(), + FunctionType::Location::LOG4)), + make_shared("sha256", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + FunctionType::Location::SHA256)), + make_shared("ecrecover", make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(8, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(0, IntegerType::Modifier::ADDRESS)}), - FunctionType::Location::ECRECOVER)), - make_shared("ripemd160", + TypePointers({std::make_shared(0, IntegerType::Modifier::ADDRESS)}), + FunctionType::Location::ECRECOVER)), + make_shared("ripemd160", make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(160, IntegerType::Modifier::HASH)}), - FunctionType::Location::RIPEMD160))}) + TypePointers({std::make_shared(160, IntegerType::Modifier::HASH)}), + FunctionType::Location::RIPEMD160))}) { } diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 224234cbd..06b9824c9 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -2,6 +2,7 @@ #include #include #include +using namespace std; namespace dev { @@ -26,6 +27,8 @@ std::unique_ptr InterfaceHandler::getDocumentation(ContractDefiniti return getDevDocumentation(_contractDef); case DocumentationType::ABI_INTERFACE: return getABIInterface(_contractDef); + case DocumentationType::ABI_SOLIDITY_INTERFACE: + return getABISolidityInterface(_contractDef); } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); @@ -64,6 +67,28 @@ std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinitio return std::unique_ptr(new std::string(m_writer.write(methods))); } +unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef) +{ + string ret = "contract " + _contractDef.getName() + "{"; + for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions()) + { + auto populateParameters = [](vector> const& _vars) + { + string r = ""; + for (ASTPointer const& var: _vars) + r += (r.size() ? "," : "(") + var->getType()->toString() + " " + var->getName(); + return r.size() ? r + ")" : "()"; + }; + ret += "function " + f->getName() + populateParameters(f->getParameters()) + (f->isDeclaredConst() ? "constant " : ""); + if (f->getReturnParameters().size()) + ret += "returns" + populateParameters(f->getReturnParameters()); + else if (ret.back() == ' ') + ret.pop_back(); + ret += "{}"; + } + return unique_ptr(new string(ret + "}")); +} + std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef) { Json::Value doc; diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index c8399d71f..2b62cabdf 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -74,6 +74,7 @@ public: /// @return A unique pointer contained string with the json /// representation of the contract's ABI Interface std::unique_ptr getABIInterface(ContractDefinition const& _contractDef); + std::unique_ptr getABISolidityInterface(ContractDefinition const& _contractDef); /// Get the User documentation of the contract /// @param _contractDef The contract definition /// @return A unique pointer contained string with the json diff --git a/libsolidity/Types.h b/libsolidity/Types.h index a91a6c24e..b25d5d895 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -318,7 +318,7 @@ public: /// INTERNAL: jump tag, EXTERNAL: contract address + function index, /// BARE: contract address (non-abi contract call) /// OTHERS: special virtual function, nothing on the stack - enum class Location { INTERNAL, EXTERNAL, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160, BARE }; + enum class Location { INTERNAL, EXTERNAL, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160, LOG0, LOG1, LOG2, LOG3, LOG4, BARE }; virtual Category getCategory() const override { return Category::FUNCTION; } explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);