diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp index 6482b691d..821629906 100644 --- a/alethzero/DappLoader.cpp +++ b/alethzero/DappLoader.cpp @@ -72,20 +72,19 @@ DappLocation DappLoader::resolveAppUri(QString const& _uri) string32 name = ZeroString32; QByteArray utf8 = parts[partIndex].toUtf8(); std::copy(utf8.data(), utf8.data() + utf8.size(), name.data()); - address = abiOut
(web3()->ethereum()->call(address, abiIn("addr(string32)", name))); + address = abiOut
(web3()->ethereum()->call(address, abiIn("addr(string32)", name)).output); domainParts.append(parts[partIndex]); if (!address) { //we have the address of the last part, try to get content hash - contentHash = abiOut(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name))); + contentHash = abiOut(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)).output); if (!contentHash) throw dev::Exception() << errinfo_comment("Can't resolve address"); } ++partIndex; } - - string32 contentUrl = abiOut(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash))); + string32 contentUrl = abiOut(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)).output); QString domain = domainParts.join('/'); parts.erase(parts.begin(), parts.begin() + partIndex); QString path = parts.join('/'); diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 5d4f9770e..967bc6b56 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -284,12 +284,12 @@ void Main::installWatches() Address Main::getNameReg() const { - return abiOut
(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1))); + return abiOut
(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)).output); } Address Main::getCurrencies() const { - return abiOut
(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3))); + return abiOut
(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3)).output); } void Main::installNameRegWatch() @@ -470,7 +470,7 @@ QString Main::pretty(dev::Address _a) const if (g_newNameReg) { - QString s = QString::fromStdString(toString(abiOut(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a))))); + QString s = QString::fromStdString(toString(abiOut(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)).output))); if (s.size()) return s; } @@ -575,7 +575,7 @@ Address Main::fromString(QString const& _n) const auto g_newNameReg = getNameReg(); if (g_newNameReg) { - Address a = abiOut
(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString())))); + Address a = abiOut
(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))).output); if (a) return a; } @@ -818,7 +818,7 @@ void Main::on_importKeyFile_triggered() m_myKeys.push_back(KeyPair::create()); keysChanged(); } - ethereum()->transact(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice()); + ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice()); } else QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); @@ -1059,8 +1059,7 @@ void Main::refreshBlockCount() { cwatch << "refreshBlockCount()"; auto d = ethereum()->blockChain().details(); - auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty; - ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); + ui->blockCount->setText(QString("%4 #%1 PV%2 D%3 H%5").arg(d.number).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(c_ethashVersion)); } void Main::on_turboMining_triggered() @@ -1429,63 +1428,64 @@ void Main::on_blocks_currentItemChanged() s << "

" << h << "

"; s << "

#" << info.number; s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty); - s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << ""; - s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress; - s << "
Seed hash: " << info.seedHash() << ""; - s << "
Mix hash: " << info.mixHash << ""; - s << "
Nonce: " << info.nonce << ""; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << ""; - s << "
Difficulty: " << info.difficulty << ""; + s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "   Children: " << details.children.size() << ""; + s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Beneficiary: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress << "" << "
"; + s << "
Seed hash: " << info.seedHash() << "" << "
"; + s << "
Mix hash: " << info.mixHash << "" << "
"; + s << "
Nonce: " << info.nonce << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { auto e = Ethasher::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")"; - s << "
Parent: " << info.parentHash << ""; + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + s << "
Parent: " << info.parentHash << "" << "
"; } else { - s << "
Proof-of-Work: Phil has nothing to prove"; - s << "
Parent: It was a virgin birth"; + s << "
Proof-of-Work: Phil has nothing to prove
"; + s << "
Parent: It was a virgin birth
"; } -// s << "
Bloom: " << details.bloom << ""; +// s << "
Bloom: " << details.bloom << ""; if (!!info.logBloom) s << "
Log Bloom: " << info.logBloom << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << ""; - s << "
Receipts: @" << info.receiptsRoot << ":"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << ""; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); - char const* line = "
 "; - s << line << "Hash: " << uncle.hash << ""; - s << line << "Parent: " << uncle.parentHash << ""; - s << line << "Number: " << uncle.number << ""; - s << line << "Coinbase: " << pretty(uncle.coinbaseAddress).toHtmlEscaped().toStdString() << " " << uncle.coinbaseAddress; - s << line << "Seed hash: " << uncle.seedHash() << ""; - s << line << "Mix hash: " << uncle.mixHash << ""; - s << line << "Nonce: " << uncle.nonce << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << ""; - s << line << "Difficulty: " << uncle.difficulty << ""; + char const* line = "
 "; + s << line << "Hash: " << uncle.hash << "" << "
"; + s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Number: " << uncle.number << "" << ""; + s << line << "Coinbase: " << pretty(uncle.coinbaseAddress).toHtmlEscaped().toStdString() << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Seed hash: " << uncle.seedHash() << "" << ""; + s << line << "Mix hash: " << uncle.mixHash << "" << ""; + s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = Ethasher::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")"; + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << ""; + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; else - s << "
Pre: Nothing is before Phil"; + s << "
Pre: Nothing is before Phil" << "
"; + + s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << ""; - s << "
Dump: " Span(Mono) << toHex(block[0].data()) << ""; + s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } else @@ -1497,19 +1497,19 @@ void Main::on_blocks_currentItemChanged() TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi]; s << "

" << th << "

"; s << "

" << h << "[" << txi << "]

"; - s << "
From: " << pretty(ss).toHtmlEscaped().toStdString() << " " << ss; + s << "
From: " << pretty(ss).toHtmlEscaped().toStdString() << " " << ss << "" << "
"; if (tx.isCreation()) - s << "
Creates: " << pretty(right160(th)).toHtmlEscaped().toStdString() << " " << right160(th); + s << "
Creates: " << pretty(right160(th)).toHtmlEscaped().toStdString() << " " << right160(th) << "
"; else - s << "
To: " << pretty(tx.receiveAddress()).toHtmlEscaped().toStdString() << " " << tx.receiveAddress(); - s << "
Value: " << formatBalance(tx.value()) << ""; - s << "   #" << tx.nonce() << ""; - s << "
Gas price: " << formatBalance(tx.gasPrice()) << ""; - s << "
Gas: " << tx.gas() << ""; - s << "
V: " << hex << nouppercase << (int)tx.signature().v << " + 27"; - s << "
R: " << hex << nouppercase << tx.signature().r << ""; - s << "
S: " << hex << nouppercase << tx.signature().s << ""; - s << "
Msg: " << tx.sha3(eth::WithoutSignature) << ""; + s << "
To: " << pretty(tx.receiveAddress()).toHtmlEscaped().toStdString() << " " << tx.receiveAddress() << "
"; + s << "
Value: " << formatBalance(tx.value()) << "" << "
"; + s << "   #" << tx.nonce() << "" << ""; + s << "
Gas price: " << formatBalance(tx.gasPrice()) << "" << "
"; + s << "
Gas: " << tx.gas() << "" << "
"; + s << "
V: " << hex << nouppercase << (int)tx.signature().v << " + 27" << "
"; + s << "
R: " << hex << nouppercase << tx.signature().r << "" << "
"; + s << "
S: " << hex << nouppercase << tx.signature().s << "" << "
"; + s << "
Msg: " << tx.sha3(eth::WithoutSignature) << "" << "
"; if (!tx.data().empty()) { if (tx.isCreation()) @@ -1522,7 +1522,7 @@ void Main::on_blocks_currentItemChanged() if (!!receipt.bloom()) s << "
Log Bloom: " << receipt.bloom() << "
"; else - s << "
Log Bloom: Uneventful
"; + s << "
Log Bloom: Uneventful
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index a9023b2f2..2c77895ff 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -284,7 +284,7 @@ void Transact::on_send_clicked() { // If execution is a contract creation, add Natspec to // a local Natspec LEVELDB - ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); + ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice()); string src = ui->data->toPlainText().toStdString(); if (sourceIsSolidity(src)) try @@ -304,7 +304,7 @@ void Transact::on_send_clicked() return; } else - ethereum()->transact(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); + ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); return; } QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); diff --git a/eth/main.cpp b/eth/main.cpp index 3b97c561d..81e910716 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -659,7 +659,7 @@ int main(int argc, char** argv) { Secret secret = h256(fromHex(sechex)); Address dest = h160(fromHex(hexAddr)); - c->transact(secret, amount, dest, data, gas, gasPrice); + c->submitTransaction(secret, amount, dest, data, gas, gasPrice); } catch (BadHexCharacter& _e) { @@ -673,7 +673,7 @@ int main(int argc, char** argv) } } else - cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; + cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; } else if (c && cmd == "listcontracts") { @@ -721,7 +721,7 @@ int main(int argc, char** argv) try { Address dest = h160(fromHex(hexAddr, ThrowType::Throw)); - c->transact(us.secret(), amount, dest, bytes(), minGas); + c->submitTransaction(us.secret(), amount, dest, bytes(), minGas); } catch (BadHexCharacter& _e) { @@ -790,7 +790,7 @@ int main(int argc, char** argv) else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else - c->transact(us.secret(), endowment, init, gas, gasPrice); + c->submitTransaction(us.secret(), endowment, init, gas, gasPrice); } else cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX"; diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 14fca2cde..5ab394a80 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") @@ -22,7 +22,7 @@ if(LLVM_DIR OR APPLE) # local LLVM build message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") add_definitions(${LLVM_DEFINITIONS}) # TODO: bitwriter is needed only for evmcc - llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) + llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter ipo) else() # Workaround for Ubuntu broken LLVM package message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") diff --git a/evmjit/libevmjit-cpp/CMakeLists.txt b/evmjit/libevmjit-cpp/CMakeLists.txt index 53448332b..add132f2a 100644 --- a/evmjit/libevmjit-cpp/CMakeLists.txt +++ b/evmjit/libevmjit-cpp/CMakeLists.txt @@ -4,8 +4,9 @@ set(TARGET_NAME evmjit-cpp) find_package(Boost REQUIRED) set(SOURCES - Env.cpp + Env.cpp JitVM.cpp JitVM.h + Utils.h ) source_group("" FILES ${SOURCES}) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index 874993c84..fae320c28 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -62,23 +62,40 @@ extern "C" *o_address = {}; } - EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { auto value = llvm2eth(*_value); + auto receiveAddress = right160(*_receiveAddress); + auto codeAddress = right160(*_codeAddress); + const auto isCall = receiveAddress == codeAddress; // OPT: The same address pointer can be used if not CODECALL + + *io_gas -= _callGas; + if (*io_gas < 0) + return false; + + if (isCall && !_env->exists(receiveAddress)) + *io_gas -= static_cast(c_callNewAccountGas); // no underflow, *io_gas non-negative before + + if (value > 0) // value transfer + { + /*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible"); + *io_gas -= static_cast(c_callValueTransferGas); // no underflow + _callGas += static_cast(c_callStipend); // overflow possibility, but in the same time *io_gas < 0 + } + + if (*io_gas < 0) + return false; + + auto ret = false; + auto callGas = u256{_callGas}; if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) { _env->subBalance(value); - auto receiveAddress = right160(*_receiveAddress); - auto inRef = bytesConstRef{_inBeg, _inSize}; - auto outRef = bytesRef{_outBeg, _outSize}; - auto codeAddress = right160(*_codeAddress); - u256 gas = *io_gas; - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); - *io_gas = static_cast(gas); - return ret; + ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress); } - return false; + *io_gas += static_cast(callGas); // it is never more than initial _callGas + return ret; } EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index e28fcd39f..84cc41dd1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -69,8 +69,8 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) BOOST_THROW_EXCEPTION(BadJumpDestination()); case ReturnCode::OutOfGas: BOOST_THROW_EXCEPTION(OutOfGas()); - case ReturnCode::StackTooSmall: - BOOST_THROW_EXCEPTION(StackTooSmall()); + case ReturnCode::StackUnderflow: + BOOST_THROW_EXCEPTION(StackUnderflow()); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); case ReturnCode::LinkerWorkaround: // never happens diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index ddf06b463..f24626750 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -9,6 +9,7 @@ #include "Type.h" #include "Endianness.h" +#include "Utils.h" namespace dev { @@ -38,6 +39,8 @@ llvm::Function* Arith256::getMulFunc() { llvm::Type* argTypes[] = {Type::Word, Type::Word}; func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + func->setDoesNotThrow(); + func->setDoesNotAccessMemory(); auto x = &func->getArgumentList().front(); x->setName("x"); @@ -50,12 +53,16 @@ llvm::Function* Arith256::getMulFunc() auto i64 = Type::Size; auto i128 = m_builder.getIntNTy(128); auto i256 = Type::Word; + auto c64 = Constant::get(64); + auto c128 = Constant::get(128); + auto c192 = Constant::get(192); + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); - auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); - auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); - auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); - auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, c64), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, c64), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, c128), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, c128), i128); auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); @@ -67,13 +74,13 @@ llvm::Function* Arith256::getMulFunc() auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); auto p = m_builder.CreateZExt(t1, i256); - p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); - p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); - p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); - p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); - p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); - p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); - p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), c64)); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), c128)); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), c64)); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), c128)); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), c192)); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), c128)); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), c192)); m_builder.CreateRet(p); } return func; @@ -87,6 +94,8 @@ llvm::Function* Arith256::getMul512Func() auto i512 = m_builder.getIntNTy(512); llvm::Type* argTypes[] = {Type::Word, Type::Word}; func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); + func->setDoesNotThrow(); + func->setDoesNotAccessMemory(); auto x = &func->getArgumentList().front(); x->setName("x"); @@ -130,6 +139,8 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) auto retType = llvm::StructType::get(m_builder.getContext(), llvm::ArrayRef{argTypes}); auto funcName = _type == Type::Word ? "div" : "div512"; func = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, funcName, getModule()); + func->setDoesNotThrow(); + func->setDoesNotAccessMemory(); auto zero = llvm::ConstantInt::get(_type, 0); auto one = llvm::ConstantInt::get(_type, 1); @@ -221,6 +232,8 @@ llvm::Function* Arith256::getExpFunc() { llvm::Type* argTypes[] = {Type::Word, Type::Word}; m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); + m_exp->setDoesNotThrow(); + m_exp->setDoesNotAccessMemory(); auto base = &m_exp->getArgumentList().front(); base->setName("base"); @@ -289,6 +302,8 @@ llvm::Function* Arith256::getAddModFunc() auto i512Ty = m_builder.getIntNTy(512); llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; m_addmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "addmod", getModule()); + m_addmod->setDoesNotThrow(); + m_addmod->setDoesNotAccessMemory(); auto x = &m_addmod->getArgumentList().front(); x->setName("x"); @@ -318,6 +333,8 @@ llvm::Function* Arith256::getMulModFunc() { llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); + m_mulmod->setDoesNotThrow(); + m_mulmod->setDoesNotAccessMemory(); auto i512Ty = m_builder.getIntNTy(512); auto x = &m_mulmod->getArgumentList().front(); @@ -343,18 +360,49 @@ llvm::Function* Arith256::getMulModFunc() llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { + if (auto c1 = llvm::dyn_cast(_arg1)) + { + if (auto c2 = llvm::dyn_cast(_arg2)) + return Constant::get(c1->getValue() * c2->getValue()); + } + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) { - auto div = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 0, "div"); - auto mod = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 1, "mod"); + if (auto c1 = llvm::dyn_cast(_arg1)) + { + if (auto c2 = llvm::dyn_cast(_arg2)) + { + if (!c2->getValue()) + return std::make_pair(Constant::get(0), Constant::get(0)); + auto div = Constant::get(c1->getValue().udiv(c2->getValue())); + auto mod = Constant::get(c1->getValue().urem(c2->getValue())); + return std::make_pair(div, mod); + } + } + + auto r = createCall(getDivFunc(Type::Word), {_arg1, _arg2}); + auto div = m_builder.CreateExtractValue(r, 0, "div"); + auto mod = m_builder.CreateExtractValue(r, 1, "mod"); return std::make_pair(div, mod); } std::pair Arith256::sdiv(llvm::Value* _x, llvm::Value* _y) { + if (auto c1 = llvm::dyn_cast(_x)) + { + if (auto c2 = llvm::dyn_cast(_y)) + { + if (!c2->getValue()) + return std::make_pair(Constant::get(0), Constant::get(0)); + auto div = Constant::get(c1->getValue().sdiv(c2->getValue())); + auto mod = Constant::get(c1->getValue().srem(c2->getValue())); + return std::make_pair(div, mod); + } + } + auto xIsNeg = m_builder.CreateICmpSLT(_x, Constant::get(0)); auto xNeg = m_builder.CreateSub(Constant::get(0), _x); auto xAbs = m_builder.CreateSelect(xIsNeg, xNeg, _x); @@ -378,16 +426,73 @@ std::pair Arith256::sdiv(llvm::Value* _x, llvm::Valu llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) { + // while (e != 0) { + // if (e % 2 == 1) + // r *= b; + // b *= b; + // e /= 2; + // } + + if (auto c1 = llvm::dyn_cast(_arg1)) + { + if (auto c2 = llvm::dyn_cast(_arg2)) + { + auto b = c1->getValue(); + auto e = c2->getValue(); + auto r = llvm::APInt{256, 1}; + while (e != 0) + { + if (e[0]) + r *= b; + b *= b; + e = e.lshr(1); + } + return Constant::get(r); + } + } + return createCall(getExpFunc(), {_arg1, _arg2}); } llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) { + // FIXME: Disabled because of llvm::APInt::urem bug +// if (auto c1 = llvm::dyn_cast(_arg1)) +// { +// if (auto c2 = llvm::dyn_cast(_arg2)) +// { +// if (auto c3 = llvm::dyn_cast(_arg3)) +// { +// if (!c3->getValue()) +// return Constant::get(0); +// auto s = c1->getValue().zext(256+64) + c2->getValue().zext(256+64); +// auto r = s.urem(c3->getValue().zext(256+64)).trunc(256); +// return Constant::get(r); +// } +// } +// } + return createCall(getAddModFunc(), {_arg1, _arg2, _arg3}); } llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) { + // FIXME: Disabled because of llvm::APInt::urem bug +// if (auto c1 = llvm::dyn_cast(_arg1)) +// { +// if (auto c2 = llvm::dyn_cast(_arg2)) +// { +// if (auto c3 = llvm::dyn_cast(_arg3)) +// { +// if (!c3->getValue()) +// return Constant::get(0); +// auto p = c1->getValue().zext(512) * c2->getValue().zext(512); +// auto r = p.urem(c3->getValue().zext(512)).trunc(256); +// return Constant::get(r); +// } +// } +// } + return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } @@ -400,7 +505,7 @@ extern "C" { EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + DLOG(JIT) << "DEBUG " << std::dec << z << ": " //<< d << c << b << a << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; } } diff --git a/evmjit/libevmjit/Array.cpp b/evmjit/libevmjit/Array.cpp new file mode 100644 index 000000000..3266038db --- /dev/null +++ b/evmjit/libevmjit/Array.cpp @@ -0,0 +1,320 @@ +#include "Array.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Runtime.h" +#include "Utils.h" + +#include // DEBUG only + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +static const auto c_reallocStep = 1; +static const auto c_reallocMultipier = 2; + +llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args, llvm::Twine const& _name) +{ + if (!m_func) + m_func = m_creator(); + + return _builder.CreateCall(m_func, {_args.begin(), _args.size()}, _name); +} + +llvm::Function* Array::createArrayPushFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Word}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto value = arrayPtr->getNextNode(); + value->setName("value"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func); + auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func); + auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func); + + m_builder.SetInsertPoint(entryBB); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); + auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto size = m_builder.CreateLoad(sizePtr, "size"); + auto cap = m_builder.CreateLoad(capPtr, "cap"); + auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq"); + m_builder.CreateCondBr(reallocReq, reallocBB, pushBB); + + m_builder.SetInsertPoint(reallocBB); + auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap"); + //newCap = m_builder.CreateNUWMul(newCap, m_builder.getInt64(c_reallocMultipier)); + auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32 + auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes"); + auto newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes"); + auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData"); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateStore(newCap, capPtr); + m_builder.CreateBr(pushBB); + + m_builder.SetInsertPoint(pushBB); + auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi"); + dataPhi->addIncoming(data, entryBB); + dataPhi->addIncoming(newData, reallocBB); + auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr"); + m_builder.CreateStore(value, newElemPtr); + auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize"); + m_builder.CreateStore(newSize, sizePtr); + m_builder.CreateRetVoid(); + + return func; +} + +llvm::Function* Array::createArraySetFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto index = arrayPtr->getNextNode(); + index->setName("index"); + auto value = index->getNextNode(); + value->setName("value"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); + m_builder.CreateStore(value, valuePtr); + m_builder.CreateRetVoid(); + return func; +} + +llvm::Function* Array::createArrayGetFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "array.get", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto index = arrayPtr->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); + auto value = m_builder.CreateLoad(valuePtr, "value"); + m_builder.CreateRet(value); + return func; +} + +llvm::Function* Array::createGetPtrFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::PrivateLinkage, "array.getPtr", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto index = arrayPtr->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto bytePtr = m_builder.CreateGEP(data, index, "bytePtr"); + auto wordPtr = m_builder.CreateBitCast(bytePtr, Type::WordPtr, "wordPtr"); + m_builder.CreateRet(wordPtr); + return func; +} + +llvm::Function* Array::createFreeFunc() +{ + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule()); + freeFunc->setDoesNotThrow(); + freeFunc->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem"); + m_builder.CreateCall(freeFunc, mem); + m_builder.CreateRetVoid(); + return func; +} + +llvm::Function* Array::getReallocFunc() +{ + if (auto func = getModule()->getFunction("ext_realloc")) + return func; + + llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size}; + auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule()); + reallocFunc->setDoesNotThrow(); + reallocFunc->setDoesNotAlias(0); + reallocFunc->setDoesNotCapture(1); + return reallocFunc; +} + +llvm::Function* Array::createExtendFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.extend", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto newSize = arrayPtr->getNextNode(); + newSize->setName("newSize"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array + auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); + auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto size = m_builder.CreateLoad(sizePtr, "size"); + auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize"); + auto newData = m_reallocFunc.call(m_builder, {data, newSize}, "newData"); // TODO: Check realloc result for null + auto extPtr = m_builder.CreateGEP(newData, size, "extPtr"); + m_builder.CreateMemSet(extPtr, m_builder.getInt8(0), extSize, 16); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateStore(newSize, sizePtr); + m_builder.CreateStore(newSize, capPtr); + m_builder.CreateRetVoid(); + return func; +} + +llvm::Type* Array::getType() +{ + llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size}; + static auto arrayTy = llvm::StructType::create(elementTys, "Array"); + return arrayTy; +} + +Array::Array(llvm::IRBuilder<>& _builder, char const* _name) : + CompilerHelper(_builder), + m_pushFunc([this](){ return createArrayPushFunc(); }), + m_setFunc([this](){ return createArraySetFunc(); }), + m_getFunc([this](){ return createArrayGetFunc(); }), + m_freeFunc([this](){ return createFreeFunc(); }) +{ + m_array = m_builder.CreateAlloca(getType(), nullptr, _name); + m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array); +} + +Array::Array(llvm::IRBuilder<>& _builder, llvm::Value* _array) : + CompilerHelper(_builder), + m_array(_array), + m_pushFunc([this](){ return createArrayPushFunc(); }), + m_setFunc([this](){ return createArraySetFunc(); }), + m_getFunc([this](){ return createArrayGetFunc(); }), + m_freeFunc([this](){ return createFreeFunc(); }) +{ + m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array); +} + + +void Array::pop(llvm::Value* _count) +{ + auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr"); + auto size = m_builder.CreateLoad(sizePtr, "size"); + auto newSize = m_builder.CreateNUWSub(size, _count, "newSize"); + m_builder.CreateStore(newSize, sizePtr); +} + +llvm::Value* Array::size(llvm::Value* _array) +{ + auto sizePtr = m_builder.CreateStructGEP(_array ? _array : m_array, 1, "sizePtr"); + return m_builder.CreateLoad(sizePtr, "array.size"); +} + +void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size) +{ + assert(_arrayPtr->getType() == m_array->getType()); + assert(_size->getType() == Type::Size); + m_extendFunc.call(m_builder, {_arrayPtr, _size}); +} + +} +} +} + +namespace +{ + struct AllocatedMemoryWatchdog + { + std::set allocatedMemory; + + ~AllocatedMemoryWatchdog() + { + if (!allocatedMemory.empty()) + { + DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n"; + for (auto&& leak : allocatedMemory) + DLOG(mem) << "\t" << leak << "\n"; + } + } + }; + + AllocatedMemoryWatchdog watchdog; +} + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT void* ext_realloc(void* _data, size_t _size) noexcept + { + //std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl; + auto newData = std::realloc(_data, _size); + if (_data != newData) + { + DLOG(mem) << "REALLOC: " << newData << " <- " << _data << " [" << _size << "]\n"; + watchdog.allocatedMemory.erase(_data); + watchdog.allocatedMemory.insert(newData); + } + return newData; + } + + EXPORT void ext_free(void* _data) noexcept + { + std::free(_data); + if (_data) + { + DLOG(mem) << "FREE : " << _data << "\n"; + watchdog.allocatedMemory.erase(_data); + } + } + +} // extern "C" + diff --git a/evmjit/libevmjit/Array.h b/evmjit/libevmjit/Array.h new file mode 100644 index 000000000..41842f0c9 --- /dev/null +++ b/evmjit/libevmjit/Array.h @@ -0,0 +1,74 @@ +#pragma once + +#include + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class LazyFunction +{ +public: + using Creator = std::function; + + LazyFunction(Creator _creator) : + m_creator(_creator) + {} + + llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args, llvm::Twine const& _name = ""); + +private: + llvm::Function* m_func = nullptr; + Creator m_creator; +}; + +class Array : public CompilerHelper +{ +public: + Array(llvm::IRBuilder<>& _builder, char const* _name); + Array(llvm::IRBuilder<>& _builder, llvm::Value* _array); + + void push(llvm::Value* _value) { m_pushFunc.call(m_builder, {m_array, _value}); } + void set(llvm::Value* _index, llvm::Value* _value) { m_setFunc.call(m_builder, {m_array, _index, _value}); } + llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); } + void pop(llvm::Value* _count); + llvm::Value* size(llvm::Value* _array = nullptr); + void free() { m_freeFunc.call(m_builder, {m_array}); } + + void extend(llvm::Value* _arrayPtr, llvm::Value* _size); + llvm::Value* getPtr(llvm::Value* _arrayPtr, llvm::Value* _index) { return m_getPtrFunc.call(m_builder, {_arrayPtr, _index}); } + + llvm::Value* getPointerTo() const { return m_array; } + + static llvm::Type* getType(); + +private: + llvm::Value* m_array = nullptr; + + llvm::Function* createArrayPushFunc(); + llvm::Function* createArraySetFunc(); + llvm::Function* createArrayGetFunc(); + llvm::Function* createGetPtrFunc(); + llvm::Function* createFreeFunc(); + llvm::Function* createExtendFunc(); + llvm::Function* getReallocFunc(); + + LazyFunction m_pushFunc = {[this](){ return createArrayPushFunc(); }}; // TODO: If works on MSVC, remove form initialization list + LazyFunction m_setFunc; + LazyFunction m_getPtrFunc = {[this](){ return createGetPtrFunc(); }}; + LazyFunction m_getFunc; + LazyFunction m_freeFunc; + LazyFunction m_extendFunc = {[this](){ return createExtendFunc(); }}; + LazyFunction m_reallocFunc = {[this](){ return getReallocFunc(); }}; +}; + +} +} +} + + diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index c9e71be9a..93d73b991 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -11,6 +11,7 @@ #include "preprocessor/llvm_includes_end.h" #include "Type.h" +#include "Utils.h" namespace dev { @@ -136,32 +137,34 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) { auto blockTerminator = m_llvmBB->getTerminator(); assert(blockTerminator != nullptr); - m_builder.SetInsertPoint(blockTerminator); + if (blockTerminator->getOpcode() != llvm::Instruction::Ret) + { + // Not needed in case of ret instruction. Ret also invalidates the stack. + m_builder.SetInsertPoint(blockTerminator); - auto currIter = m_currentStack.begin(); - auto endIter = m_currentStack.end(); + auto currIter = m_currentStack.begin(); + auto endIter = m_currentStack.end(); - // Update (emit set()) changed values - for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; - currIter < endIter && idx >= 0; - ++currIter, --idx) - { - assert(static_cast(idx) < m_initialStack.size()); - if (*currIter != m_initialStack[idx]) // value needs update - _evmStack.set(static_cast(idx), *currIter); - } + // Update (emit set()) changed values + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; + currIter < endIter && idx >= 0; + ++currIter, --idx) + { + assert(static_cast(idx) < m_initialStack.size()); + if (*currIter != m_initialStack[idx]) // value needs update + _evmStack.set(static_cast(idx), *currIter); + } - if (m_tosOffset < 0) - { // Pop values - _evmStack.pop(static_cast(-m_tosOffset)); - } + if (m_tosOffset < 0) + _evmStack.pop(static_cast(-m_tosOffset)); - // Push new values - for (; currIter < endIter; ++currIter) - { - assert(*currIter != nullptr); - _evmStack.push(*currIter); + // Push new values + for (; currIter < endIter; ++currIter) + { + assert(*currIter != nullptr); + _evmStack.push(*currIter); + } } // Emit get() for all (used) values from the initial stack @@ -233,7 +236,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt) { auto predInfoEntry = cfg.find(*predIt); - if (predInfoEntry != cfg.end()) + if (predInfoEntry != cfg.end()) // FIXME: It is wrong - will skip entry block info.predecessors.push_back(&predInfoEntry->second); } } @@ -242,13 +245,12 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB bool valuesChanged = true; while (valuesChanged) { - if (getenv("EVMCC_DEBUG_BLOCKS")) + for (auto& pair : cfg) { - for (auto& pair : cfg) - std::cerr << pair.second.bblock.llvm()->getName().str() - << ": in " << pair.second.inputItems - << ", out " << pair.second.outputItems - << "\n"; + DLOG(bb) << pair.second.bblock.llvm()->getName().str() + << ": in " << pair.second.inputItems + << ", out " << pair.second.outputItems + << "\n"; } valuesChanged = false; @@ -256,6 +258,9 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB { auto& info = pair.second; + if (&info.bblock == basicBlocks.front()) + info.inputItems = 0; // we cannot use phi nodes for first block as it is a successor of entry block + if (info.predecessors.empty()) info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false @@ -340,6 +345,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) { if (val == nullptr) out << " ?"; + else if (llvm::isa(val)) + out << " " << val->getName(); else if (llvm::isa(val)) out << *val; else @@ -361,6 +368,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) { if (*val == nullptr) out << " ?"; + else if (llvm::isa(*val)) + out << " " << (*val)->getName(); else if (llvm::isa(*val)) out << **val; else diff --git a/evmjit/libevmjit/BuildInfo.h.in b/evmjit/libevmjit/BuildInfo.h.in index 204b4d89b..4b72144ed 100644 --- a/evmjit/libevmjit/BuildInfo.h.in +++ b/evmjit/libevmjit/BuildInfo.h.in @@ -8,3 +8,4 @@ #define LLVM_VERSION "${LLVM_PACKAGE_VERSION}" #define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}" +#define LLVM_DEBUG ${LLVM_DEBUG} diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index 943c64e42..7f4e763d7 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -1,9 +1,29 @@ set(TARGET_NAME evmjit) -file(GLOB SOURCES "*.cpp") -file(GLOB HEADERS "*.h") -set(INTERFACE_HEADERS interface.h) -source_group("" FILES ${HEADERS}) +set(SOURCES + Arith256.cpp Arith256.h + Array.cpp Array.h + BasicBlock.cpp BasicBlock.h + Cache.cpp Cache.h + Common.h + Compiler.cpp Compiler.h + CompilerHelper.cpp CompilerHelper.h + Endianness.cpp Endianness.h + ExecStats.cpp ExecStats.h + ExecutionEngine.cpp ExecutionEngine.h + Ext.cpp Ext.h + GasMeter.cpp GasMeter.h + Instruction.cpp Instruction.h + interface.cpp interface.h + Memory.cpp Memory.h + Optimizer.cpp Optimizer.h + Runtime.cpp Runtime.h + RuntimeData.h + RuntimeManager.cpp RuntimeManager.h + Stack.cpp Stack.h + Type.cpp Type.h + Utils.cpp Utils.h +) source_group("" FILES ${SOURCES}) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") @@ -48,11 +68,13 @@ else() set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) endif() + +string(COMPARE EQUAL "${LLVM_ENABLE_ASSERTIONS}" "ON" LLVM_DEBUG) configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") -add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) +add_library(${TARGET_NAME} SHARED ${SOURCES} gen/BuildInfo.gen.h) set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} FOLDER "libs") @@ -62,7 +84,4 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") - install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) -#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) \ No newline at end of file diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index fe226eefb..d3cda1098 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -1,8 +1,5 @@ #include "Cache.h" -#include -#include - #include "preprocessor/llvm_includes_start.h" #include #include @@ -14,6 +11,7 @@ #include "ExecutionEngine.h" #include "Utils.h" +#include "BuildInfo.gen.h" namespace dev { @@ -22,28 +20,54 @@ namespace eth namespace jit { -//#define CACHE_LOG std::cerr << "CACHE " -#define CACHE_LOG std::ostream(nullptr) - namespace { + CacheMode g_mode; llvm::MemoryBuffer* g_lastObject; ExecutionEngineListener* g_listener; + static const size_t c_versionStampLength = 32; + + llvm::StringRef getLibVersionStamp() + { + static auto version = llvm::SmallString{}; + if (version.empty()) + { + version = EVMJIT_VERSION_FULL; + version.resize(c_versionStampLength); + } + return version; + } } -ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) +ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener) { static ObjectCache objectCache; + g_mode = _mode; g_listener = _listener; return &objectCache; } +void Cache::clear() +{ + using namespace llvm::sys; + llvm::SmallString<256> cachePath; + path::system_temp_directory(false, cachePath); + path::append(cachePath, "evm_objs"); + + std::error_code err; + for (auto it = fs::directory_iterator{cachePath.str(), err}; it != fs::directory_iterator{}; it.increment(err)) + fs::remove(it->path()); +} + std::unique_ptr Cache::getObject(std::string const& id) { + if (g_mode != CacheMode::on && g_mode != CacheMode::read) + return nullptr; + if (g_listener) g_listener->stateChanged(ExecState::CacheLoad); - CACHE_LOG << id << ": search\n"; + DLOG(cache) << id << ": search\n"; if (!CHECK(!g_lastObject)) g_lastObject = nullptr; @@ -51,28 +75,21 @@ std::unique_ptr Cache::getObject(std::string const& id) llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); -#if defined(__GNUC__) && !defined(NDEBUG) - llvm::sys::fs::file_status st; - auto err = llvm::sys::fs::status(cachePath.str(), st); - if (err) - return nullptr; - auto mtime = st.getLastModificationTime().toEpochTime(); - - std::tm tm; - strptime(__DATE__ __TIME__, " %b %d %Y %H:%M:%S", &tm); - auto btime = (uint64_t)std::mktime(&tm); - if (btime > mtime) - return nullptr; -#endif - if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + { + auto& buf = r.get(); + auto objVersionStamp = buf->getBufferSize() >= c_versionStampLength ? llvm::StringRef{buf->getBufferEnd() - c_versionStampLength, c_versionStampLength} : llvm::StringRef{}; + if (objVersionStamp == getLibVersionStamp()) + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + else + DLOG(cache) << "Unmatched version: " << objVersionStamp.str() << ", expected " << getLibVersionStamp().str() << "\n"; + } else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) - std::cerr << r.getError().message(); // TODO: Add log + DLOG(cache) << r.getError().message(); // TODO: Add warning log if (g_lastObject) // if object found create fake module { - CACHE_LOG << id << ": found\n"; + DLOG(cache) << id << ": found\n"; auto&& context = llvm::getGlobalContext(); auto module = std::unique_ptr(new llvm::Module(id, context)); auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); @@ -81,13 +98,17 @@ std::unique_ptr Cache::getObject(std::string const& id) bb->getInstList().push_back(new llvm::UnreachableInst{context}); return module; } - CACHE_LOG << id << ": not found\n"; + DLOG(cache) << id << ": not found\n"; return nullptr; } void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { + // Only in "on" and "write" mode + if (g_mode != CacheMode::on && g_mode != CacheMode::write) + return; + if (g_listener) g_listener->stateChanged(ExecState::CacheWrite); @@ -97,19 +118,19 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::sys::path::append(cachePath, "evm_objs"); if (llvm::sys::fs::create_directory(cachePath.str())) - return; // TODO: Add log + DLOG(cache) << "Cannot create cache dir " << cachePath.str().str() << "\n"; llvm::sys::path::append(cachePath, id); - CACHE_LOG << id << ": write\n"; + DLOG(cache) << id << ": write\n"; std::string error; llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); - cacheFile << _object->getBuffer(); + cacheFile << _object->getBuffer() << getLibVersionStamp(); } llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { - CACHE_LOG << _module->getModuleIdentifier() << ": use\n"; + DLOG(cache) << _module->getModuleIdentifier() << ": use\n"; auto o = g_lastObject; g_lastObject = nullptr; return o; diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h index e8f01d38d..b0d26d080 100644 --- a/evmjit/libevmjit/Cache.h +++ b/evmjit/libevmjit/Cache.h @@ -12,6 +12,15 @@ namespace jit { class ExecutionEngineListener; +enum class CacheMode +{ + on, + off, + read, + write, + clear +}; + class ObjectCache : public llvm::ObjectCache { public: @@ -29,8 +38,11 @@ public: class Cache { public: - static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); + static ObjectCache* getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); + + /// Clears cache storage + static void clear(); }; } diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index 62731292f..028f0b3c5 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -1,11 +1,12 @@ #pragma once -#include #include #include #ifdef _MSC_VER -#define EXPORT __declspec(dllexport) +#define EXPORT __declspec(dllexport) +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() #else #define EXPORT #endif @@ -18,12 +19,9 @@ namespace jit { using byte = uint8_t; -using bytes = std::vector; using bytes_ref = std::tuple; using code_iterator = byte const*; -struct NoteChannel {}; // FIXME: Use some log library? - enum class ReturnCode { // Success codes @@ -33,7 +31,7 @@ enum class ReturnCode // Standard error codes OutOfGas = -1, - StackTooSmall = -2, + StackUnderflow = -2, BadJumpDestination = -3, BadInstruction = -4, Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index de48e8ef9..be3670874 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -6,13 +6,9 @@ #include #include "preprocessor/llvm_includes_start.h" -#include #include #include #include -#include -#include -#include #include "preprocessor/llvm_includes_end.h" #include "Instruction.h" @@ -93,7 +89,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn } } -llvm::BasicBlock* Compiler::getJumpTableBlock() +llvm::BasicBlock* Compiler::getJumpTableBlock(RuntimeManager& _runtimeManager) { if (!m_jumpTableBlock) { @@ -101,7 +97,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock() InsertPointGuard g{m_builder}; m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); auto dest = m_builder.CreatePHI(Type::Word, 8, "target"); - auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); + auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock(_runtimeManager)); for (auto&& p : m_basicBlocks) { if (p.second.isJumpDest()) @@ -111,21 +107,20 @@ llvm::BasicBlock* Compiler::getJumpTableBlock() return m_jumpTableBlock->llvm(); } -llvm::BasicBlock* Compiler::getBadJumpBlock() +llvm::BasicBlock* Compiler::getBadJumpBlock(RuntimeManager& _runtimeManager) { if (!m_badJumpBlock) { m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true)); InsertPointGuard g{m_builder}; m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + _runtimeManager.exit(ReturnCode::BadJumpDestination); } return m_badJumpBlock->llvm(); } std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) { - auto compilationStartTime = std::chrono::high_resolution_clock::now(); auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); // Create main function @@ -137,6 +132,17 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); m_builder.SetInsertPoint(entryBlock); + createBasicBlocks(_begin, _end); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder, _begin, _end); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager, memory); + Stack stack(m_builder, runtimeManager); + runtimeManager.setStack(stack); // Runtime Manager will free stack memory + Arith256 arith(m_builder); + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); @@ -149,24 +155,14 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); auto r = m_builder.CreateCall(setjmp, jmpBuf); auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); - - createBasicBlocks(_begin, _end); - - // Init runtime structures. - RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); - GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager, memory); - Stack stack(m_builder, runtimeManager); - Arith256 arith(m_builder); + runtimeManager.setJmpBuf(jmpBuf); // TODO: Create Stop basic block on demand m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); - auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); - m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, Type::expectTrue); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { @@ -180,10 +176,10 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera // Code for special blocks: // TODO: move to separate function. m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + runtimeManager.exit(ReturnCode::Stop); m_builder.SetInsertPoint(abortBB); - m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + runtimeManager.exit(ReturnCode::OutOfGas); removeDeadBlocks(); @@ -230,16 +226,6 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera dumpCFGifRequired("blocks-sync.dot"); - if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) - { - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - } - - auto compilationEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << "JIT: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count(); return module; } @@ -516,7 +502,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti auto val = stack.pop(); static_cast(val); // Generate a dummy use of val to make sure that a get(0) will be emitted at this point, - // so that StackTooSmall will be thrown + // so that StackUnderflow will be thrown // m_builder.CreateICmpEQ(val, val, "dummy"); break; } @@ -600,7 +586,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti auto&& c = constant->getValue(); auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; auto it = m_basicBlocks.find(targetIdx); - targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(); + targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(_runtimeManager); } // TODO: Improve; check for constants @@ -613,7 +599,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti else { _basicBlock.setJumpTarget(target); - m_builder.CreateBr(getJumpTableBlock()); + m_builder.CreateBr(getJumpTableBlock(_runtimeManager)); } } else // JUMPI @@ -629,7 +615,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti else { _basicBlock.setJumpTarget(target); - m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); + m_builder.CreateCondBr(cond, getJumpTableBlock(_runtimeManager), _nextBasicBlock); } } break; @@ -769,7 +755,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::CALL: case Instruction::CALLCODE: { - auto callGas256 = stack.pop(); + auto callGas = stack.pop(); auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); @@ -787,13 +773,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - auto gas = _runtimeManager.getGas(); - _gasMeter.count(callGas256); - auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas); - auto gasLeft = m_builder.CreateNSWSub(gas, callGas); - _runtimeManager.setGas(callGas); - auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gasLeft); + auto ret = _ext.call(callGas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.count(m_builder.getInt64(0), _runtimeManager.getJmpBuf(), _runtimeManager.getGasPtr()); stack.push(ret); break; } @@ -806,14 +787,14 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti _memory.require(index, size); _runtimeManager.registerReturnData(index, size); - m_builder.CreateRet(Constant::get(ReturnCode::Return)); + _runtimeManager.exit(ReturnCode::Return); break; } case Instruction::SUICIDE: { _runtimeManager.registerSuicide(stack.pop()); - m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); + _runtimeManager.exit(ReturnCode::Suicide); break; } diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index c9795fb99..4469389bb 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -38,9 +38,9 @@ private: void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); - llvm::BasicBlock* getJumpTableBlock(); + llvm::BasicBlock* getJumpTableBlock(RuntimeManager& _runtimeManager); - llvm::BasicBlock* getBadJumpBlock(); + llvm::BasicBlock* getBadJumpBlock(RuntimeManager& _runtimeManager); void removeDeadBlocks(); diff --git a/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp index 38f71560c..d36f4b7fa 100644 --- a/evmjit/libevmjit/Endianness.cpp +++ b/evmjit/libevmjit/Endianness.cpp @@ -2,6 +2,7 @@ #include "preprocessor/llvm_includes_start.h" #include +#include #include "preprocessor/llvm_includes_end.h" #include "Type.h" @@ -15,13 +16,7 @@ namespace jit llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { - union tester - { - unsigned int x; - unsigned char isLE; - }; - - if (tester{1}.isLE) + if (llvm::sys::IsLittleEndianHost) { // FIXME: Disabled because of problems with BYTE //if (auto constant = llvm::dyn_cast(_word)) diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index 684f6d39a..ff8c05307 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -67,6 +67,7 @@ char const* getExecStateName(ExecState _state) case ExecState::CacheLoad: return "CacheLoad"; case ExecState::CacheWrite: return "CacheWrite"; case ExecState::Compilation: return "Compilation"; + case ExecState::Optimization: return "Optimization"; case ExecState::CodeGen: return "CodeGen"; case ExecState::Execution: return "Execution"; case ExecState::Return: return "Return"; diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h index 1ac9b6995..0451ccb05 100644 --- a/evmjit/libevmjit/ExecStats.h +++ b/evmjit/libevmjit/ExecStats.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 1d2ff91b1..f9588fbea 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -1,8 +1,9 @@ #include "ExecutionEngine.h" #include -#include // env options +#include #include +#include #include "preprocessor/llvm_includes_start.h" #include @@ -12,10 +13,13 @@ #include #include #include +#include +#include #include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" +#include "Optimizer.h" #include "Cache.h" #include "ExecStats.h" #include "Utils.h" @@ -48,42 +52,58 @@ std::string codeHash(i256 const& _hash) return str; } -bool getEnvOption(char const* _name, bool _default) +void printVersion() { - auto var = std::getenv(_name); - if (!var) - return _default; - return std::strtol(var, nullptr, 10) != 0; + std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n" + << " EVMJIT version " << EVMJIT_VERSION << "\n" +#ifdef NDEBUG + << " Optimized build, " EVMJIT_VERSION_FULL "\n" +#else + << " DEBUG build, " EVMJIT_VERSION_FULL "\n" +#endif + << " Built " << __DATE__ << " (" << __TIME__ << ")\n" + << std::endl; } -bool showInfo() +namespace cl = llvm::cl; +cl::opt g_optimize{"O", cl::desc{"Optimize"}}; +cl::opt g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"}, + cl::values( + clEnumValN(CacheMode::on, "1", "Enabled"), + clEnumValN(CacheMode::off, "0", "Disabled"), + clEnumValN(CacheMode::read, "r", "Read only. No new objects are added to cache."), + clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."), + clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."), + clEnumValEnd)}; +cl::opt g_stats{"st", cl::desc{"Statistics"}}; +cl::opt g_dump{"dump", cl::desc{"Dump LLVM IR module"}}; + +void parseOptions() { - auto show = getEnvOption("EVMJIT_INFO", false); - if (show) - { - std::cout << "The Ethereum EVM JIT " EVMJIT_VERSION_FULL " LLVM " LLVM_VERSION << std::endl; - } - return show; + static llvm::llvm_shutdown_obj shutdownObj{}; + cl::AddExtraVersionPrinter(printVersion); + cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); } } + ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { - static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); - static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); - static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); - static auto infoShown = showInfo(); - (void) infoShown; + static std::once_flag flag; + std::call_once(flag, parseOptions); std::unique_ptr listener{new ExecStats}; listener->stateChanged(ExecState::Started); - auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; + auto objectCache = (g_cache != CacheMode::off && g_cache != CacheMode::clear) ? Cache::getObjectCache(g_cache, listener.get()) : nullptr; static std::unique_ptr ee; if (!ee) { + if (g_cache == CacheMode::clear) + Cache::clear(); + llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); @@ -91,7 +111,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) llvm::EngineBuilder builder(module.get()); builder.setEngineKind(llvm::EngineKind::JIT); builder.setUseMCJIT(true); - builder.setOptLevel(llvm::CodeGenOpt::None); + builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) @@ -108,9 +128,14 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static StatsCollector statsCollector; auto mainFuncName = codeHash(_data->codeHash); - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + m_runtime.init(_data, _env); + + EntryFuncPtr entryFuncPtr = nullptr; + static std::unordered_map funcCache; + auto it = funcCache.find(mainFuncName); + if (it != funcCache.end()) + entryFuncPtr = it->second; - auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); if (!entryFuncPtr) { auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; @@ -118,9 +143,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { listener->stateChanged(ExecState::Compilation); assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code? - module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName); + module = Compiler{{}}.compile(_data->code, _data->code + _data->codeSize, mainFuncName); + + if (g_optimize) + { + listener->stateChanged(ExecState::Optimization); + optimize(*module); + } } - if (debugDumpModule) + if (g_dump) module->dump(); ee->addModule(module.get()); @@ -131,18 +162,18 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (!CHECK(entryFuncPtr)) return ReturnCode::LLVMLinkError; + funcCache[mainFuncName] = entryFuncPtr; + listener->stateChanged(ExecState::Execution); - auto returnCode = entryFuncPtr(&runtime); + auto returnCode = entryFuncPtr(&m_runtime); listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) - { - returnData = runtime.getReturnData(); // Save reference to return data - std::swap(m_memory, runtime.getMemory()); // Take ownership of memory - } + returnData = m_runtime.getReturnData(); // Save reference to return data + listener->stateChanged(ExecState::Finished); - if (statsCollectingEnabled) + if (g_stats) statsCollector.stats.push_back(std::move(listener)); return returnCode; diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index 4c2965e58..26da6977c 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -2,7 +2,7 @@ #include -#include "RuntimeData.h" +#include "Runtime.h" namespace dev { @@ -17,6 +17,7 @@ enum class ExecState CacheLoad, CacheWrite, Compilation, + Optimization, CodeGen, Execution, Return, @@ -50,9 +51,7 @@ public: bytes_ref returnData; private: - /// After execution, if RETURN used, memory is moved there - /// to allow client copy the returned data - bytes m_memory; + Runtime m_runtime; }; } diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 38deef214..d35aebc68 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -41,7 +41,7 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, - FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::Gas, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, @@ -136,7 +136,7 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V return address; } -llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +llvm::Value* Ext::call(llvm::Value* _callGas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) { auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); auto inBeg = m_memoryMan.getBytePtr(_inOff); @@ -144,7 +144,11 @@ llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm:: auto outBeg = m_memoryMan.getBytePtr(_outOff); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); + auto callGas = m_builder.CreateSelect( + m_builder.CreateICmpULE(_callGas, m_builder.CreateZExt(Constant::gasMax, Type::Word)), + m_builder.CreateTrunc(_callGas, Type::Gas), + Constant::gasMax); + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), callGas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); return m_builder.CreateZExt(ret, Type::Word, "ret"); } diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index 1c0c0fc56..b0048d2e9 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -51,7 +51,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + llvm::Value* call(llvm::Value* _callGas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index ca21714e0..ffbd654e6 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -17,52 +17,113 @@ namespace jit namespace // Helper functions { -int64_t const c_stepGas = 1; -int64_t const c_balanceGas = 20; -int64_t const c_sha3Gas = 10; -int64_t const c_sha3WordGas = 10; -int64_t const c_sloadGas = 20; -int64_t const c_sstoreSetGas = 300; -int64_t const c_sstoreResetGas = 100; -int64_t const c_sstoreRefundGas = 100; -int64_t const c_createGas = 100; -int64_t const c_createDataGas = 5; -int64_t const c_callGas = 20; -int64_t const c_expGas = 1; -int64_t const c_expByteGas = 1; -int64_t const c_memoryGas = 1; -int64_t const c_txDataZeroGas = 1; -int64_t const c_txDataNonZeroGas = 5; -int64_t const c_txGas = 500; -int64_t const c_logGas = 32; -int64_t const c_logDataGas = 1; -int64_t const c_logTopicGas = 32; -int64_t const c_copyGas = 1; +int64_t const c_stepGas[] = {0, 2, 3, 5, 8, 10, 20}; +int64_t const c_expByteGas = 10; +int64_t const c_sha3Gas = 30; +int64_t const c_sha3WordGas = 6; +int64_t const c_sloadGas = 50; +int64_t const c_sstoreSetGas = 20000; +int64_t const c_sstoreResetGas = 5000; +int64_t const c_sstoreClearGas = 5000; +int64_t const c_jumpdestGas = 1; +int64_t const c_logGas = 375; +int64_t const c_logTopicGas = 375; +int64_t const c_logDataGas = 8; +int64_t const c_callGas = 40; +int64_t const c_createGas = 32000; +int64_t const c_memoryGas = 3; +int64_t const c_copyGas = 3; int64_t getStepCost(Instruction inst) { switch (inst) { - default: // Assumes instruction code is valid - return c_stepGas; - + // Tier 0 case Instruction::STOP: + case Instruction::RETURN: case Instruction::SUICIDE: case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() - return 0; - - case Instruction::EXP: return c_expGas; - - case Instruction::SLOAD: return c_sloadGas; - - case Instruction::SHA3: return c_sha3Gas; - - case Instruction::BALANCE: return c_balanceGas; - - case Instruction::CALL: - case Instruction::CALLCODE: return c_callGas; - - case Instruction::CREATE: return c_createGas; + return c_stepGas[0]; + + // Tier 1 + case Instruction::ADDRESS: + case Instruction::ORIGIN: + case Instruction::CALLER: + case Instruction::CALLVALUE: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::GASPRICE: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + case Instruction::POP: + case Instruction::PC: + case Instruction::MSIZE: + case Instruction::GAS: + return c_stepGas[1]; + + // Tier 2 + case Instruction::ADD: + case Instruction::SUB: + case Instruction::LT: + case Instruction::GT: + case Instruction::SLT: + case Instruction::SGT: + case Instruction::EQ: + case Instruction::ISZERO: + case Instruction::AND: + case Instruction::OR: + case Instruction::XOR: + case Instruction::NOT: + case Instruction::BYTE: + case Instruction::CALLDATALOAD: + case Instruction::CALLDATACOPY: + case Instruction::CODECOPY: + case Instruction::MLOAD: + case Instruction::MSTORE: + case Instruction::MSTORE8: + case Instruction::ANY_PUSH: + case Instruction::ANY_DUP: + case Instruction::ANY_SWAP: + return c_stepGas[2]; + + // Tier 3 + case Instruction::MUL: + case Instruction::DIV: + case Instruction::SDIV: + case Instruction::MOD: + case Instruction::SMOD: + case Instruction::SIGNEXTEND: + return c_stepGas[3]; + + // Tier 4 + case Instruction::ADDMOD: + case Instruction::MULMOD: + case Instruction::JUMP: + return c_stepGas[4]; + + // Tier 5 + case Instruction::EXP: + case Instruction::JUMPI: + return c_stepGas[5]; + + // Tier 6 + case Instruction::BALANCE: + case Instruction::EXTCODESIZE: + case Instruction::EXTCODECOPY: + case Instruction::BLOCKHASH: + return c_stepGas[6]; + + case Instruction::SHA3: + return c_sha3Gas; + + case Instruction::SLOAD: + return c_sloadGas; + + case Instruction::JUMPDEST: + return c_jumpdestGas; case Instruction::LOG0: case Instruction::LOG1: @@ -73,7 +134,16 @@ int64_t getStepCost(Instruction inst) auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } + + case Instruction::CALL: + case Instruction::CALLCODE: + return c_callGas; + + case Instruction::CREATE: + return c_createGas; } + + return 0; // TODO: Add UNREACHABLE macro } } @@ -82,34 +152,36 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) CompilerHelper(_builder), m_runtimeManager(_runtimeManager) { - auto module = getModule(); - - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); - InsertPointGuard guard(m_builder); + llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr}; + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule()); + m_gasCheckFunc->setDoesNotThrow(); + m_gasCheckFunc->setDoesNotCapture(1); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); - auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); - auto rt = &m_gasCheckFunc->getArgumentList().front(); - rt->setName("rt"); - auto cost = rt->getNextNode(); + auto gasPtr = &m_gasCheckFunc->getArgumentList().front(); + gasPtr->setName("gasPtr"); + auto cost = gasPtr->getNextNode(); cost->setName("cost"); + auto jmpBuf = cost->getNextNode(); + jmpBuf->setName("jmpBuf"); + InsertPointGuard guard(m_builder); m_builder.SetInsertPoint(checkBB); - auto gas = m_runtimeManager.getGas(); - gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); - auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions - m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); - - m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.abort(); - m_builder.CreateUnreachable(); + auto gas = m_builder.CreateLoad(gasPtr, "gas"); + auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions + m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue); m_builder.SetInsertPoint(updateBB); - m_runtimeManager.setGas(gas); + m_builder.CreateStore(gasUpdated, gasPtr); m_builder.CreateRetVoid(); + + m_builder.SetInsertPoint(outOfGasBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); } void GasMeter::count(Instruction _inst) @@ -117,13 +189,13 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getGasPtr(), llvm::UndefValue::get(Type::Gas), m_runtimeManager.getJmpBuf()}); } m_blockCost += getStepCost(_inst); } -void GasMeter::count(llvm::Value* _cost) +void GasMeter::count(llvm::Value* _cost, llvm::Value* _jmpBuf, llvm::Value* _gasPtr) { if (_cost->getType() == Type::Word) { @@ -134,7 +206,7 @@ void GasMeter::count(llvm::Value* _cost) } assert(_cost->getType() == Type::Gas); - createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); + createCall(m_gasCheckFunc, {_gasPtr ? _gasPtr : m_runtimeManager.getGasPtr(), _cost, _jmpBuf ? _jmpBuf : m_runtimeManager.getJmpBuf()}); } void GasMeter::countExp(llvm::Value* _exponent) @@ -145,25 +217,31 @@ void GasMeter::countExp(llvm::Value* _exponent) // OPT: Can gas update be done in exp algorithm? - auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); - auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); - count(sigBytes); + auto t = llvm::APInt{256, 1}; + auto c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(1), m_builder.getInt64(0)); + for (auto i = 2; i <= 32; ++i) + { + t <<= 8; + c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(i), c); + } + + // FIXME: Does not work because of LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=22304 +// auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); +// auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); +// auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); +// auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); +// auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); + count(m_builder.CreateNUWMul(c, m_builder.getInt64(c_expByteGas))); } void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) { auto oldValue = _ext.sload(_index); auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); - auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); - auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero"); auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); - auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); + static_assert(c_sstoreResetGas == c_sstoreClearGas, "Update SSTORE gas cost"); auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); count(cost); } @@ -171,8 +249,8 @@ void GasMeter::countLogData(llvm::Value* _dataLength) { assert(m_checkCall); assert(m_blockCost > 0); // LOGn instruction is already counted - static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter."); - count(_dataLength); + static_assert(c_logDataGas != 1, "Log data gas cost has changed. Update GasMeter."); + count(m_builder.CreateNUWMul(_dataLength, Constant::get(c_logDataGas))); // TODO: Use i64 } void GasMeter::countSha3Data(llvm::Value* _dataLength) @@ -213,16 +291,16 @@ void GasMeter::commitCostBlock() assert(m_blockCost == 0); } -void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) +void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords, llvm::Value* _jmpBuf, llvm::Value* _gasPtr) { - static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - count(_additionalMemoryInWords); + static_assert(c_memoryGas != 1, "Memory gas cost has changed. Update GasMeter."); + count(_additionalMemoryInWords, _jmpBuf, _gasPtr); } void GasMeter::countCopy(llvm::Value* _copyWords) { - static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter."); - count(_copyWords); + static_assert(c_copyGas != 1, "Copy gas cost has changed. Update GasMeter."); + count(m_builder.CreateNUWMul(_copyWords, m_builder.getInt64(c_copyGas))); } } diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h index 4056cd64d..aecc07315 100644 --- a/evmjit/libevmjit/GasMeter.h +++ b/evmjit/libevmjit/GasMeter.h @@ -20,7 +20,7 @@ public: void count(Instruction _inst); /// Count additional cost - void count(llvm::Value* _cost); + void count(llvm::Value* _cost, llvm::Value* _jmpBuf = nullptr, llvm::Value* _gasPtr = nullptr); /// Calculate & count gas cost for SSTORE instruction void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); @@ -41,7 +41,7 @@ public: void giveBack(llvm::Value* _gas); /// Generate code that checks the cost of additional memory used by program - void countMemory(llvm::Value* _additionalMemoryInWords); + void countMemory(llvm::Value* _additionalMemoryInWords, llvm::Value* _jmpBuf, llvm::Value* _gasPtr); /// Count addional gas cost for memory copy void countCopy(llvm::Value* _copyWords); diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index 647c5f26a..79a82a8ae 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -19,6 +19,7 @@ namespace jit Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_memory{getBuilder(), _runtimeManager.getMem()}, m_gasMeter(_gasMeter) {} @@ -27,20 +28,20 @@ llvm::Function* Memory::getRequireFunc() auto& func = m_require; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + llvm::Type* argTypes[] = {Array::getType()->getPointerTo(), Type::Word, Type::Word, Type::BytePtr, Type::GasPtr}; func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + func->setDoesNotThrow(); + + auto mem = &func->getArgumentList().front(); + mem->setName("mem"); + auto blkOffset = mem->getNextNode(); + blkOffset->setName("blkOffset"); + auto blkSize = blkOffset->getNextNode(); + blkSize->setName("blkSize"); + auto jmpBuf = blkSize->getNextNode(); + jmpBuf->setName("jmpBuf"); + auto gas = jmpBuf->getNextNode(); + gas->setName("gas"); auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); @@ -51,40 +52,38 @@ llvm::Function* Memory::getRequireFunc() // BB "Pre": Ignore checks with size 0 m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + m_builder.CreateCondBr(m_builder.CreateICmpNE(blkSize, Constant::get(0)), checkBB, returnBB, Type::expectTrue); // BB "Check" m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + static const auto c_inputMax = uint64_t(1) << 33; // max value of blkSize and blkOffset that will not result in integer overflow in calculations below + auto blkOffsetOk = m_builder.CreateICmpULE(blkOffset, Constant::get(c_inputMax), "blkOffsetOk"); + auto blkO = m_builder.CreateSelect(blkOffsetOk, m_builder.CreateTrunc(blkOffset, Type::Size), m_builder.getInt64(c_inputMax), "bklO"); + auto blkSizeOk = m_builder.CreateICmpULE(blkSize, Constant::get(c_inputMax), "blkSizeOk"); + auto blkS = m_builder.CreateSelect(blkSizeOk, m_builder.CreateTrunc(blkSize, Type::Size), m_builder.getInt64(c_inputMax), "bklS"); + + auto sizeReq0 = m_builder.CreateNUWAdd(blkO, blkS, "sizeReq0"); + auto sizeReq = m_builder.CreateAnd(m_builder.CreateNUWAdd(sizeReq0, m_builder.getInt64(31)), uint64_t(-1) << 5, "sizeReq"); // s' = ((s0 + 31) / 32) * 32 + auto sizeCur = m_memory.size(mem); + auto sizeOk = m_builder.CreateICmpULE(sizeReq, sizeCur, "sizeOk"); + + m_builder.CreateCondBr(sizeOk, returnBB, resizeBB, Type::expectTrue); // BB "Resize" m_builder.SetInsertPoint(resizeBB); // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - m_gasMeter.countMemory(newWords); + auto w1 = m_builder.CreateLShr(sizeReq, 5); + auto w1s = m_builder.CreateNUWMul(w1, w1); + auto c1 = m_builder.CreateAdd(m_builder.CreateNUWMul(w1, m_builder.getInt64(3)), m_builder.CreateLShr(w1s, 9)); + auto w0 = m_builder.CreateLShr(sizeCur, 5); + auto w0s = m_builder.CreateNUWMul(w0, w0); + auto c0 = m_builder.CreateAdd(m_builder.CreateNUWMul(w0, m_builder.getInt64(3)), m_builder.CreateLShr(w0s, 9)); + auto cc = m_builder.CreateNUWSub(c1, c0); + auto costOk = m_builder.CreateAnd(blkOffsetOk, blkSizeOk, "costOk"); + auto c = m_builder.CreateSelect(costOk, cc, m_builder.getInt64(std::numeric_limits::max()), "c"); + m_gasMeter.count(c, jmpBuf, gas); // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); + m_memory.extend(mem, sizeReq); m_builder.CreateBr(returnBB); // BB "Return" @@ -94,12 +93,12 @@ llvm::Function* Memory::getRequireFunc() return func; } -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType) { auto isWord = _valueType == Type::Word; - llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + llvm::Type* storeArgs[] = {Array::getType()->getPointerTo(), Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Array::getType()->getPointerTo(), Type::Word}; auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); @@ -107,28 +106,25 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet InsertPointGuard guard(m_builder); // Restores insert point at function exit m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto index = rt->getNextNode(); + auto mem = &func->getArgumentList().front(); + mem->setName("mem"); + auto index = mem->getNextNode(); index->setName("index"); - auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - this->require(index, Constant::get(valueSize)); - auto ptr = getBytePtr(index); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); if (_isStore) { - llvm::Value* value = index->getNextNode(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); - m_builder.CreateStore(value, ptr); + auto valueArg = index->getNextNode(); + valueArg->setName("value"); + auto value = isWord ? Endianness::toBE(m_builder, valueArg) : valueArg; + auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size)); + auto valuePtr = m_builder.CreateBitCast(memPtr, _valueType->getPointerTo(), "valuePtr"); + m_builder.CreateStore(value, valuePtr); m_builder.CreateRetVoid(); } else { - llvm::Value* ret = m_builder.CreateLoad(ptr); + auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size)); + llvm::Value* ret = m_builder.CreateLoad(memPtr); ret = Endianness::toNative(m_builder, ret); m_builder.CreateRet(ret); } @@ -140,7 +136,7 @@ llvm::Function* Memory::getLoadWordFunc() { auto& func = m_loadWord; if (!func) - func = createFunc(false, Type::Word, m_gasMeter); + func = createFunc(false, Type::Word); return func; } @@ -148,7 +144,7 @@ llvm::Function* Memory::getStoreWordFunc() { auto& func = m_storeWord; if (!func) - func = createFunc(true, Type::Word, m_gasMeter); + func = createFunc(true, Type::Word); return func; } @@ -156,39 +152,41 @@ llvm::Function* Memory::getStoreByteFunc() { auto& func = m_storeByte; if (!func) - func = createFunc(true, Type::Byte, m_gasMeter); + func = createFunc(true, Type::Byte); return func; } llvm::Value* Memory::loadWord(llvm::Value* _addr) { - return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); + require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8)); + return createCall(getLoadWordFunc(), {getRuntimeManager().getMem(), _addr}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); + require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8)); + createCall(getStoreWordFunc(), {getRuntimeManager().getMem(), _addr, _word}); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { + require(_addr, Constant::get(Type::Byte->getPrimitiveSizeInBits() / 8)); auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); + createCall(getStoreByteFunc(), {getRuntimeManager().getMem(), _addr, byte}); } llvm::Value* Memory::getData() { - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - return m_builder.CreateLoad(dataPtr, "data"); + auto memPtr = m_builder.CreateBitCast(getRuntimeManager().getMem(), Type::BytePtr->getPointerTo()); + auto data = m_builder.CreateLoad(memPtr, "data"); + assert(data->getType() == Type::BytePtr); + return data; } llvm::Value* Memory::getSize() { - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - return m_builder.CreateLoad(sizePtr, "size"); + return m_builder.CreateZExt(m_memory.size(), Type::Word, "msize"); // TODO: Allow placing i64 on stack } llvm::Value* Memory::getBytePtr(llvm::Value* _index) @@ -204,7 +202,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) if (!constant->getValue()) return; } - createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); + createCall(getRequireFunc(), {getRuntimeManager().getMem(), _offset, _size, getRuntimeManager().getJmpBuf(), getRuntimeManager().getGasPtr()}); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, @@ -233,28 +231,18 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize); auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes); - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner); + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner, "bytesToCopy"); + auto bytesToZero = m_builder.CreateNUWSub(reqBytes, bytesToCopy, "bytesToZero"); auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 - auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + auto padIdx = m_builder.CreateNUWAdd(dstIdx, bytesToCopy, "padIdx"); + auto dst = m_memory.getPtr(getRuntimeManager().getMem(), dstIdx); + auto pad = m_memory.getPtr(getRuntimeManager().getMem(), padIdx); m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); + m_builder.CreateMemSet(pad, m_builder.getInt8(0), bytesToZero, 0); } } } } - - -extern "C" -{ - using namespace dev::eth::jit; - - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR - { - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); - } -} diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h index e8edce735..beb535226 100644 --- a/evmjit/libevmjit/Memory.h +++ b/evmjit/libevmjit/Memory.h @@ -1,6 +1,6 @@ #pragma once -#include "CompilerHelper.h" +#include "Array.h" namespace dev { @@ -28,9 +28,11 @@ public: void require(llvm::Value* _offset, llvm::Value* _size); private: + Array m_memory; + GasMeter& m_gasMeter; - llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); + llvm::Function* createFunc(bool _isStore, llvm::Type* _type); llvm::Function* getRequireFunc(); llvm::Function* getLoadWordFunc(); diff --git a/evmjit/libevmjit/Optimizer.cpp b/evmjit/libevmjit/Optimizer.cpp new file mode 100644 index 000000000..84a7c3a6a --- /dev/null +++ b/evmjit/libevmjit/Optimizer.cpp @@ -0,0 +1,29 @@ +#include "Optimizer.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +bool optimize(llvm::Module& _module) +{ + auto pm = llvm::PassManager{}; + //pm.add(llvm::createFunctionInliningPass(2, 2)); // Produces invalid IR + pm.add(llvm::createCFGSimplificationPass()); + //pm.add(llvm::createInstructionCombiningPass()); // Produces invalid runtime results + pm.add(llvm::createAggressiveDCEPass()); + pm.add(llvm::createLowerSwitchPass()); + return pm.run(_module); +} + +} +} +} diff --git a/evmjit/libevmjit/Optimizer.h b/evmjit/libevmjit/Optimizer.h new file mode 100644 index 000000000..4a3147a7f --- /dev/null +++ b/evmjit/libevmjit/Optimizer.h @@ -0,0 +1,19 @@ +#pragma once + +namespace llvm +{ + class Module; +} + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +bool optimize(llvm::Module& _module); + +} +} +} diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp index 69937368c..7e9a7d52e 100644 --- a/evmjit/libevmjit/Runtime.cpp +++ b/evmjit/libevmjit/Runtime.cpp @@ -9,20 +9,29 @@ namespace eth namespace jit { -Runtime::Runtime(RuntimeData* _data, Env* _env) : - m_data(*_data), - m_env(*_env) -{} +void Runtime::init(RuntimeData* _data, Env* _env) +{ + m_data = _data; + m_env = _env; +} + +extern "C" void ext_free(void* _data) noexcept; + +Runtime::~Runtime() +{ + if (m_memData) + ext_free(m_memData); // Use helper free to check memory leaks +} bytes_ref Runtime::getReturnData() const { - auto data = m_data.callData; - auto size = static_cast(m_data.callDataSize); + auto data = m_data->callData; + auto size = static_cast(m_data->callDataSize); - if (data < m_memory.data() || data >= m_memory.data() + m_memory.size() || size == 0) + if (data < m_memData || data >= m_memData + m_memSize || size == 0) { assert(size == 0); // data can be an invalid pointer only if size is 0 - m_data.callData = nullptr; + m_data->callData = nullptr; return {}; } diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index 82be4a0c8..895128a59 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -9,30 +9,20 @@ namespace eth namespace jit { -using StackImpl = std::vector; -using MemoryImpl = bytes; - class Runtime { public: - Runtime(RuntimeData* _data, Env* _env); - - Runtime(const Runtime&) = delete; - Runtime& operator=(const Runtime&) = delete; - - StackImpl& getStack() { return m_stack; } - MemoryImpl& getMemory() { return m_memory; } + void init(RuntimeData* _data, Env* _env); + EXPORT ~Runtime(); bytes_ref getReturnData() const; private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. - byte* m_memoryData = nullptr; - i256 m_memorySize; - StackImpl m_stack; - MemoryImpl m_memory; + RuntimeData* m_data = nullptr; ///< Pointer to data. Expected by compiled contract. + Env* m_env = nullptr; ///< Pointer to environment proxy. Expected by compiled contract. + byte* m_memData = nullptr; + uint64_t m_memSize = 0; + uint64_t m_memCap = 0; }; } diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 0b5762fa2..d1ccaea8a 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -4,6 +4,9 @@ #include #include "preprocessor/llvm_includes_end.h" +#include "Stack.h" +#include "Utils.h" + namespace dev { namespace eth @@ -48,9 +51,7 @@ llvm::StructType* RuntimeManager::getRuntimeType() { Type::RuntimeDataPtr, // data Type::EnvPtr, // Env* - Type::BytePtr, // jmpbuf - Type::BytePtr, // memory data - Type::Word, // memory size + Array::getType() // memory }; type = llvm::StructType::create(elems, "Runtime"); } @@ -83,22 +84,21 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): CompilerHelper(_builder), - m_jmpBuf(_jmpBuf), m_codeBegin(_codeBegin), m_codeEnd(_codeEnd) { m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); - // save jmpBuf to be used in helper functions - auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); - m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt"); - // Unpack data auto rtPtr = getRuntimePtr(); m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); assert(m_dataPtr->getType() == Type::RuntimeDataPtr); + m_gasPtr = m_builder.CreateStructGEP(m_dataPtr, 0, "gas"); + assert(m_gasPtr->getType() == Type::Gas->getPointerTo()); + m_memPtr = m_builder.CreateStructGEP(rtPtr, 2, "mem"); + assert(m_memPtr->getType() == Array::getType()->getPointerTo()); m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); assert(m_envPtr->getType() == Type::EnvPtr); } @@ -150,7 +150,7 @@ void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value) void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size) { - auto memPtr = getBuilder().CreateStructGEP(getRuntimePtr(), 3); + auto memPtr = m_builder.CreateBitCast(getMem(), Type::BytePtr->getPointerTo()); auto mem = getBuilder().CreateLoad(memPtr, "memory"); auto idx = m_builder.CreateTrunc(_offset, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 // TODO: Report bug & fix to LLVM auto returnDataPtr = getBuilder().CreateGEP(mem, idx); @@ -165,6 +165,14 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } +void RuntimeManager::exit(ReturnCode _returnCode) +{ + if (m_stack) + m_stack->free(); + + m_builder.CreateRet(Constant::get(_returnCode)); +} + void RuntimeManager::abort(llvm::Value* _jmpBuf) { auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); @@ -213,12 +221,6 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBufExt() -{ - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); - return getBuilder().CreateLoad(ptr, "jmpBufExt"); -} - llvm::Value* RuntimeManager::getGas() { auto gas = get(RuntimeData::Gas); @@ -228,7 +230,14 @@ llvm::Value* RuntimeManager::getGas() llvm::Value* RuntimeManager::getGasPtr() { - return getPtr(RuntimeData::Gas); + assert(getMainFunction()); + return m_gasPtr; +} + +llvm::Value* RuntimeManager::getMem() +{ + assert(getMainFunction()); + return m_memPtr; } void RuntimeManager::setGas(llvm::Value* _gas) diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index 30c69ec88..eb8dadf6f 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -11,11 +11,12 @@ namespace eth { namespace jit { +class Stack; class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); + RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); @@ -32,11 +33,17 @@ public: llvm::Value* getJmpBuf() { return m_jmpBuf; } void setGas(llvm::Value* _gas); - void registerReturnData(llvm::Value* _index, llvm::Value* _size); + llvm::Value* getMem(); + + void registerReturnData(llvm::Value* _index, llvm::Value* _size); // TODO: Move to Memory. void registerSuicide(llvm::Value* _balanceAddress); + void exit(ReturnCode _returnCode); + void abort(llvm::Value* _jmpBuf); - void abort() { abort(getJmpBufExt()); } + + void setStack(Stack& _stack) { m_stack = &_stack; } + void setJmpBuf(llvm::Value* _jmpBuf) { m_jmpBuf = _jmpBuf; } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -44,15 +51,18 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; - llvm::Value* const m_jmpBuf; + llvm::Value* m_jmpBuf = nullptr; llvm::Value* m_dataPtr = nullptr; + llvm::Value* m_gasPtr = nullptr; + llvm::Value* m_memPtr = nullptr; llvm::Value* m_envPtr = nullptr; code_iterator m_codeBegin = {}; code_iterator m_codeEnd = {}; + + Stack* m_stack = nullptr; }; } diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 81a954991..3a686c766 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -6,6 +6,9 @@ #include "RuntimeManager.h" #include "Runtime.h" +#include "Utils.h" + +#include // DEBUG only namespace dev { @@ -16,20 +19,62 @@ namespace jit Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): CompilerHelper(_builder), - m_runtimeManager(_runtimeManager) + m_runtimeManager(_runtimeManager), + m_stack(_builder, "stack") +{} + +llvm::Function* Stack::getPushFunc() { - m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); + auto& func = m_push; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.push", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; + auto extPushFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_push", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto value = rt->getNextNode(); + value->setName("value"); - using namespace llvm; - using Linkage = GlobalValue::LinkageTypes; + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(entryBB); + auto a = m_builder.CreateAlloca(Type::Word); + m_builder.CreateStore(value, a); + createCall(extPushFunc, {rt, a}); + m_builder.CreateRetVoid(); + } + return func; +} - auto module = getModule(); +llvm::Function* Stack::getSetFunc() +{ + auto& func = m_set; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.set", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; + auto extSetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_set", getModule()); - llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; - m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto value = index->getNextNode(); + value->setName("value"); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(entryBB); + auto a = m_builder.CreateAlloca(Type::Word); + m_builder.CreateStore(value, a); + createCall(extSetFunc, {rt, index, a}); + m_builder.CreateRetVoid(); + } + return func; } llvm::Function* Stack::getPopFunc() @@ -73,16 +118,14 @@ llvm::Function* Stack::getGetFunc() auto& func = m_get; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; - func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); - llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; - auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + llvm::Type* argTypes[] = {Type::Size, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.require", getModule()); - auto rt = &func->getArgumentList().front(); - rt->setName("rt"); - auto index = rt->getNextNode(); + auto index = &func->getArgumentList().front(); index->setName("index"); - auto jmpBuf = index->getNextNode(); + auto size = index->getNextNode(); + size->setName("size"); + auto jmpBuf = size->getNextNode(); jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; @@ -91,46 +134,44 @@ llvm::Function* Stack::getGetFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); m_builder.SetInsertPoint(entryBB); - auto valuePtr = createCall(extGetFunc, {rt, index}); - auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); - m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + auto underflow = m_builder.CreateICmpUGE(index, size, "underflow"); + m_builder.CreateCondBr(underflow, underflowBB, returnBB); m_builder.SetInsertPoint(underflowBB); m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); - m_builder.CreateRet(valuePtr); + m_builder.CreateRetVoid(); } return func; } llvm::Value* Stack::get(size_t _index) { - auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); - return m_builder.CreateLoad(valuePtr); + createCall(getGetFunc(), {m_builder.getInt64(_index), m_stack.size(), m_runtimeManager.getJmpBuf()}); + auto value = m_stack.get(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1))); + //return m_builder.CreateLoad(valuePtr); + return value; } void Stack::set(size_t _index, llvm::Value* _value) { - m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); + m_stack.set(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1)), _value); } void Stack::pop(size_t _count) { - createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); + // FIXME: Pop does not check for stack underflow but looks like not needed + // We should place stack.require() check and begining of every BB + m_stack.pop(m_builder.getInt64(_count)); } void Stack::push(llvm::Value* _value) { - m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg); + m_stack.push(_value); } - -size_t Stack::maxStackSize = 0; - } } } @@ -139,41 +180,6 @@ extern "C" { using namespace dev::eth::jit; - EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) - { - auto& stack = _rt->getStack(); - if (stack.size() < _count) - return false; - - stack.erase(stack.end() - _count, stack.end()); - return true; - } - - EXPORT void stack_push(Runtime* _rt, i256 const* _word) - { - auto& stack = _rt->getStack(); - stack.push_back(*_word); - - if (stack.size() > Stack::maxStackSize) - Stack::maxStackSize = stack.size(); - } - - EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) - { - auto& stack = _rt->getStack(); - return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; - } - - EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) - { - auto& stack = _rt->getStack(); - assert(_index < stack.size()); - if (_index >= stack.size()) - return; - - *(stack.rbegin() + _index) = *_word; - } - EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) { // It asumes all indexes are less than 2^64 diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h index 4b6fa374f..3c526f0d3 100644 --- a/evmjit/libevmjit/Stack.h +++ b/evmjit/libevmjit/Stack.h @@ -1,6 +1,8 @@ #pragma once -#include "CompilerHelper.h" +#include + +#include "Array.h" namespace dev { @@ -19,21 +21,22 @@ public: void set(size_t _index, llvm::Value* _value); void pop(size_t _count); void push(llvm::Value* _value); - - static size_t maxStackSize; + void free() { m_stack.free(); } private: llvm::Function* getPopFunc(); + llvm::Function* getPushFunc(); llvm::Function* getGetFunc(); + llvm::Function* getSetFunc(); RuntimeManager& m_runtimeManager; llvm::Function* m_pop = nullptr; - llvm::Function* m_push; + llvm::Function* m_push = nullptr; llvm::Function* m_get = nullptr; - llvm::Function* m_set; + llvm::Function* m_set = nullptr; - llvm::Value* m_arg; + Array m_stack; }; diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 8e2bc13fc..00a143dea 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -1,4 +1,7 @@ #include "Type.h" + +#include + #include "RuntimeManager.h" namespace dev @@ -23,6 +26,7 @@ llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimePtr; llvm::ConstantInt* Constant::gasMax; +llvm::MDNode* Type::expectTrue; void Type::init(llvm::LLVMContext& _context) { @@ -46,6 +50,8 @@ void Type::init(llvm::LLVMContext& _context) RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); + + expectTrue = llvm::MDBuilder{_context}.createBranchWeights(1, 0); } } diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index b8a4a09eb..ffacc5407 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -40,6 +40,9 @@ struct Type static llvm::PointerType* RuntimeDataPtr; static llvm::PointerType* RuntimePtr; + // TODO: Redesign static LLVM objects + static llvm::MDNode* expectTrue; + static void init(llvm::LLVMContext& _context); }; diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp index bf3bf93b3..b010b1d96 100644 --- a/evmjit/libevmjit/Utils.cpp +++ b/evmjit/libevmjit/Utils.cpp @@ -1,13 +1,27 @@ #include "Utils.h" +#include + +#include "BuildInfo.gen.h" + +#if !defined(NDEBUG) // Debug + namespace dev { -namespace eth -{ -namespace jit +namespace evmjit { - +std::ostream& getLogStream(char const* _channel) +{ + static std::ostream nullStream{nullptr}; +#if LLVM_DEBUG + return (llvm::DebugFlag && llvm::isCurrentDebugType(_channel)) ? std::cerr : nullStream; +#else + return (void)_channel, nullStream; +#endif } + } } + +#endif diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h index aad975f5b..0caf5e1bd 100644 --- a/evmjit/libevmjit/Utils.h +++ b/evmjit/libevmjit/Utils.h @@ -2,23 +2,39 @@ #include -#include "Common.h" +// The same as assert, but expression is always evaluated and result returned +#define CHECK(expr) (assert(expr), expr) + +#if !defined(NDEBUG) // Debug namespace dev { -namespace eth -{ -namespace jit +namespace evmjit { -struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; +std::ostream& getLogStream(char const* _channel); + +} +} -//#define clog(CHANNEL) std::cerr -#define clog(CHANNEL) std::ostream(nullptr) +#define DLOG(CHANNEL) ::dev::evmjit::getLogStream(#CHANNEL) -// The same as assert, but expression is always evaluated and result returned -#define CHECK(expr) (assert(expr), expr) +#else // Release + +namespace dev +{ +namespace evmjit +{ + +struct Voider +{ + void operator=(std::ostream const&) {} +}; } } -} + + +#define DLOG(CHANNEL) true ? (void)0 : ::dev::evmjit::Voider{} = std::cerr + +#endif diff --git a/evmjit/libevmjit/interface.cpp b/evmjit/libevmjit/interface.cpp index 645f3d150..01f743a2e 100644 --- a/evmjit/libevmjit/interface.cpp +++ b/evmjit/libevmjit/interface.cpp @@ -5,11 +5,6 @@ extern "C" using namespace dev::eth::jit; -#ifdef _MSC_VER -#define _ALLOW_KEYWORD_MACROS -#define noexcept throw() -#endif - EXPORT void* evmjit_create() noexcept { // TODO: Make sure ExecutionEngine constructor does not throw diff --git a/libdevcore/Assertions.h b/libdevcore/Assertions.h new file mode 100644 index 000000000..7b4a4a765 --- /dev/null +++ b/libdevcore/Assertions.h @@ -0,0 +1,111 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @file Assertions.h + * @author Christian + * @date 2015 + * + * Assertion handling. + */ + +#pragma once + +#include "Exceptions.h" +#include "debugbreak.h" + +namespace dev +{ + +#if defined(_MSC_VER) +#define ETH_FUNC __FUNCSIG__ +#elif defined(__GNUC__) +#define ETH_FUNC __PRETTY_FUNCTION__ +#else +#define ETH_FUNC __func__ +#endif + +#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC) +#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC) + +inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func) +{ + bool ret = _a; + if (!ret) + { + std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; +#if ETH_DEBUG + debug_break(); +#endif + } + return !ret; +} + +template +inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func) +{ + bool ret = _a == _b; + if (!ret) + { + std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; + std::cerr << " Fail equality: " << _a << "==" << _b << std::endl; +#if ETH_DEBUG + debug_break(); +#endif + } + return !ret; +} + +/// Assertion that throws an exception containing the given description if it is not met. +/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); +/// Do NOT supply an exception object as the second parameter. +#define assertThrow(_condition, _ExceptionType, _description) \ + ::dev::assertThrowAux<_ExceptionType>(_condition, _description, __LINE__, __FILE__, ETH_FUNC) + +using errinfo_comment = boost::error_info; + +template +inline void assertThrowAux( + bool _condition, + ::std::string const& _errorDescription, + unsigned _line, + char const* _file, + char const* _function +) +{ + if (!_condition) + ::boost::throw_exception( + _ExceptionType() << + ::dev::errinfo_comment(_errorDescription) << + ::boost::throw_function(_function) << + ::boost::throw_file(_file) << + ::boost::throw_line(_line) + ); +} + +template +inline void assertThrowAux( + void const* _pointer, + ::std::string const& _errorDescription, + unsigned _line, + char const* _file, + char const* _function +) +{ + assertThrowAux<_ExceptionType>(_pointer != nullptr, _errorDescription, _line, _file, _function); +} + +} diff --git a/libdevcore/Common.h b/libdevcore/Common.h index bf9699b2f..5e778644d 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -44,7 +44,6 @@ #pragma warning(pop) #pragma GCC diagnostic pop #include "vector_ref.h" -#include "debugbreak.h" // CryptoPP defines byte in the global namespace, so must we. using byte = uint8_t; @@ -135,45 +134,4 @@ private: std::function m_f; }; -// Assertions... - -#if defined(_MSC_VER) -#define ETH_FUNC __FUNCSIG__ -#elif defined(__GNUC__) -#define ETH_FUNC __PRETTY_FUNCTION__ -#else -#define ETH_FUNC __func__ -#endif - -#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC) -#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC) - -inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func) -{ - bool ret = _a; - if (!ret) - { - std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; -#if ETH_DEBUG - debug_break(); -#endif - } - return !ret; -} - -template -inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func) -{ - bool ret = _a == _b; - if (!ret) - { - std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; - std::cerr << " Fail equality: " << _a << "==" << _b << std::endl; -#if ETH_DEBUG - debug_break(); -#endif - } - return !ret; -} - } diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index 09b525d59..17e393cbe 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -39,7 +39,7 @@ std::string dev::escaped(std::string const& _s, bool _all) ret += "\\\""; else if (i == '\\' && !_all) ret += "\\\\"; - else if (prettyEscapes.count(i)) + else if (prettyEscapes.count(i) && !_all) { ret += '\\'; ret += prettyEscapes.find(i)->second; diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 8398f9c7f..df9f36030 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -33,7 +33,7 @@ namespace dev // base class for all exceptions struct Exception: virtual std::exception, virtual boost::exception { - Exception(std::string _message = {}): m_message(std::move(_message)) {} + Exception(std::string _message = std::string()): m_message(std::move(_message)) {} const char* what() const noexcept override { return m_message.empty() ? std::exception::what() : m_message.c_str(); } private: diff --git a/libdevcore/StructuredLogger.cpp b/libdevcore/StructuredLogger.cpp index 5655b332d..f51ed310a 100644 --- a/libdevcore/StructuredLogger.cpp +++ b/libdevcore/StructuredLogger.cpp @@ -38,9 +38,10 @@ void StructuredLogger::outputJson(Json::Value const& _value, std::string const& { Json::Value event; static Mutex s_lock; + Json::FastWriter fastWriter; Guard l(s_lock); event[_name] = _value; - cout << event << endl << flush; + cout << fastWriter.write(event) << endl; } void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion) diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 79fd62262..ff22b9b45 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -20,6 +20,7 @@ */ #include +#include #include "ECDHE.h" #include "CryptoPP.h" diff --git a/libethash/CMakeLists.txt b/libethash/CMakeLists.txt index 7bc147af7..38fc821c0 100644 --- a/libethash/CMakeLists.txt +++ b/libethash/CMakeLists.txt @@ -2,7 +2,6 @@ set(LIBRARY ethash) if (CPPETHEREUM) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") -#else () endif () set(CMAKE_BUILD_TYPE Release) diff --git a/libethash/data_sizes.h b/libethash/data_sizes.h index ccdf554a8..3b747b3ea 100644 --- a/libethash/data_sizes.h +++ b/libethash/data_sizes.h @@ -20,8 +20,6 @@ * @date 2015 */ -// TODO: Update this after ~3.5 years - #pragma once #include @@ -33,213 +31,780 @@ extern "C" { #include -// 500 Epochs worth of tabulated DAG sizes (~3.5 Years) +// 2048 Epochs (~20 years) worth of tabulated DAG sizes // Generated with the following Mathematica Code: -// GetDataSizes[n_] := Module[{ -// DAGSizeBytesInit = 2^30, -// MixBytes = 128, -// DAGGrowth = 113000000, + +// GetCacheSizes[n_] := Module[{ +// CacheSizeBytesInit = 2^24, +// CacheGrowth = 2^17, +// HashBytes = 64, // j = 0}, -// Reap[ -// While[j < n, -// Module[{i = -// Floor[(DAGSizeBytesInit + DAGGrowth * j) / MixBytes]}, -// While[! PrimeQ[i], i--]; -// Sow[i*MixBytes]; j++]]]][[2]][[1]] - -static const size_t dag_sizes[] = { - 1073739904U, 1186739584U, 1299741568U, 1412741248U, 1525741696U, - 1638736768U, 1751741312U, 1864740736U, 1977740672U, 2090740864U, - 2203740544U, 2316741248U, 2429739392U, 2542740352U, 2655741824U, - 2768739712U, 2881740416U, 2994741632U, 3107740544U, 3220741504U, - 3333738112U, 3446741632U, 3559741312U, 3672740224U, 3785740928U, - 3898738304U, 4011741824U, 4124739712U, 4237735808U, 4350740864U, - 4463741824U, 4576741504U, 4689741184U, 4802739328U, 4915741568U, - 5028740224U, 5141740672U, 5254738304U, 5367741824U, 5480737664U, - 5593738112U, 5706741632U, 5819740544U, 5932734592U, 6045739904U, - 6158740096U, 6271740032U, 6384731776U, 6497732992U, 6610740352U, - 6723741056U, 6836741504U, 6949740416U, 7062740096U, 7175741824U, - 7288740224U, 7401741184U, 7514741632U, 7627741568U, 7740739712U, - 7853739136U, 7966740352U, 8079741568U, 8192739712U, 8305738624U, - 8418740864U, 8531740288U, 8644740736U, 8757735808U, 8870738816U, - 8983739264U, 9096740992U, 9209740928U, 9322739584U, 9435741824U, - 9548741504U, 9661739392U, 9774738304U, 9887741312U, 10000738688U, - 10113739136U, 10226741632U, 10339739776U, 10452741248U, 10565740928U, - 10678736512U, 10791734656U, 10904741248U, 11017738112U, 11130741632U, - 11243741312U, 11356739456U, 11469740416U, 11582734976U, 11695739008U, - 11808741248U, 11921734784U, 12034739072U, 12147741568U, 12260737408U, - 12373741696U, 12486738304U, 12599740544U, 12712740224U, 12825741184U, - 12938736256U, 13051741312U, 13164737408U, 13277738368U, 13390738048U, - 13503741824U, 13616741504U, 13729737088U, 13842740096U, 13955741312U, - 14068741504U, 14181740416U, 14294741632U, 14407739776U, 14520740224U, - 14633740928U, 14746736512U, 14859741824U, 14972740736U, 15085740928U, - 15198738304U, 15311732096U, 15424740736U, 15537739904U, 15650741632U, - 15763741568U, 15876737152U, 15989741696U, 16102740608U, 16215741056U, - 16328741248U, 16441740416U, 16554737792U, 16667740288U, 16780740992U, - 16893738112U, 17006741632U, 17119739008U, 17232735616U, 17345739392U, - 17458740352U, 17571736192U, 17684739712U, 17797739392U, 17910740096U, - 18023741312U, 18136740736U, 18249738112U, 18362738816U, 18475735424U, - 18588740224U, 18701738368U, 18814736768U, 18927737216U, 19040739968U, - 19153739648U, 19266736768U, 19379737984U, 19492739456U, 19605738368U, - 19718740352U, 19831741312U, 19944736384U, 20057741696U, 20170741376U, - 20283741824U, 20396737408U, 20509741696U, 20622741376U, 20735739008U, - 20848741504U, 20961740672U, 21074739328U, 21187740032U, 21300739456U, - 21413741696U, 21526740608U, 21639741824U, 21752737408U, 21865741696U, - 21978741376U, 22091741824U, 22204738432U, 22317740672U, 22430740096U, - 22543736704U, 22656741248U, 22769739904U, 22882739584U, 22995740288U, - 23108740736U, 23221740928U, 23334741376U, 23447737216U, 23560740992U, - 23673741184U, 23786740864U, 23899737728U, 24012741248U, 24125734784U, - 24238736512U, 24351741824U, 24464740736U, 24577737088U, 24690741632U, - 24803739776U, 24916740736U, 25029740416U, 25142740864U, 25255741568U, - 25368741248U, 25481740672U, 25594741376U, 25707741568U, 25820741504U, - 25933730432U, 26046739072U, 26159741824U, 26272741504U, 26385740672U, - 26498740096U, 26611741568U, 26724740992U, 26837739904U, 26950735232U, - 27063738496U, 27176741248U, 27289741184U, 27402740864U, 27515740544U, - 27628737152U, 27741740672U, 27854741632U, 27967740544U, 28080739712U, - 28193738368U, 28306741376U, 28419737728U, 28532739968U, 28645739648U, - 28758740096U, 28871741312U, 28984739456U, 29097740416U, 29210740864U, - 29323741312U, 29436740224U, 29549741696U, 29662738304U, 29775741568U, - 29888741504U, 30001740928U, 30114737024U, 30227735168U, 30340737664U, - 30453738368U, 30566737024U, 30679733632U, 30792740224U, 30905740928U, - 31018740352U, 31131740032U, 31244738944U, 31357737344U, 31470741376U, - 31583740544U, 31696740224U, 31809738112U, 31922739328U, 32035737472U, - 32148740992U, 32261741696U, 32374740352U, 32487741824U, 32600740736U, - 32713739648U, 32826740608U, 32939729792U, 33052740992U, 33165740672U, - 33278739584U, 33391741312U, 33504739712U, 33617740928U, 33730740608U, - 33843738496U, 33956739968U, 34069741696U, 34182739328U, 34295741824U, - 34408739968U, 34521740672U, 34634736512U, 34747741568U, 34860741248U, - 34973739392U, 35086738304U, 35199741056U, 35312736896U, 35425741184U, - 35538741376U, 35651740288U, 35764737152U, 35877741184U, 35990739584U, - 36103740544U, 36216740992U, 36329739392U, 36442737536U, 36555741568U, - 36668740736U, 36781741184U, 36894737024U, 37007741312U, 37120739456U, - 37233741184U, 37346736256U, 37459736192U, 37572734336U, 37685739904U, - 37798740352U, 37911737728U, 38024741504U, 38137739648U, 38250740608U, - 38363741824U, 38476740992U, 38589741184U, 38702740096U, 38815741312U, - 38928741248U, 39041738368U, 39154739584U, 39267741824U, 39380739712U, - 39493735808U, 39606741632U, 39719741312U, 39832741504U, 39945739648U, - 40058740352U, 40171740032U, 40284740992U, 40397740672U, 40510740352U, - 40623740288U, 40736738176U, 40849737856U, 40962741376U, 41075739776U, - 41188737664U, 41301735808U, 41414738048U, 41527741312U, 41640740992U, - 41753739904U, 41866739072U, 41979738496U, 42092740736U, 42205739648U, - 42318740608U, 42431741312U, 42544738688U, 42657741184U, 42770738048U, - 42883741568U, 42996741248U, 43109740928U, 43222736512U, 43335741056U, - 43448730496U, 43561740416U, 43674741632U, 43787740544U, 43900741504U, - 44013739648U, 44126740864U, 44239740544U, 44352741248U, 44465738368U, - 44578735232U, 44691739264U, 44804741504U, 44917741696U, 45030741376U, - 45143741824U, 45256740992U, 45369739136U, 45482740096U, 45595739776U, - 45708739712U, 45821740672U, 45934741376U, 46047741056U, 46160741248U, - 46273737088U, 46386740864U, 46499739008U, 46612739968U, 46725735296U, - 46838740864U, 46951741568U, 47064737152U, 47177741696U, 47290741376U, - 47403738752U, 47516741248U, 47629739648U, 47742741632U, 47855737984U, - 47968740224U, 48081738368U, 48194741632U, 48307739264U, 48420739712U, - 48533739136U, 48646738304U, 48759741824U, 48872741504U, 48985739392U, - 49098741376U, 49211741056U, 49324740992U, 49437738368U, 49550740864U, - 49663735424U, 49776737408U, 49889740672U, 50002738816U, 50115738752U, - 50228739712U, 50341741696U, 50454736768U, 50567738752U, 50680739968U, - 50793736832U, 50906734976U, 51019741568U, 51132739456U, 51245741696U, - 51358741376U, 51471741056U, 51584738944U, 51697734272U, 51810739072U, - 51923736448U, 52036740736U, 52149741184U, 52262737024U, 52375738496U, - 52488740992U, 52601739136U, 52714740352U, 52827736448U, 52940738176U, - 53053741696U, 53166740864U, 53279741824U, 53392741504U, 53505739136U, - 53618739584U, 53731741312U, 53844741248U, 53957741696U, 54070741376U, - 54183740288U, 54296741504U, 54409741696U, 54522739072U, 54635737472U, - 54748741504U, 54861736064U, 54974740096U, 55087741568U, 55200733568U, - 55313741696U, 55426734464U, 55539741056U, 55652741504U, 55765741184U, - 55878741376U, 55991730304U, 56104740992U, 56217740672U, 56330731648U, - 56443737472U, 56556724352U, 56669740672U, 56782739072U, 56895740032U, - 57008741248U, 57121741696U, 57234740096U, 57347741312U, 57460741504U +// Reap[ +// While[j < n, +// Module[{i = +// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + + +static const size_t dag_sizes[2048] = { + 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, + 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, + 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, + 1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U, + 1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U, + 1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U, + 1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U, + 1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U, + 1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U, + 1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U, + 1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U, + 1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U, + 1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U, + 1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U, + 1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U, + 1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U, + 1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U, + 1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U, + 1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U, + 1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U, + 1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U, + 1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U, + 1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U, + 2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U, + 2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U, + 2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U, + 2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U, + 2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U, + 2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U, + 2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U, + 2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U, + 2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U, + 2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U, + 2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U, + 2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U, + 2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U, + 2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U, + 2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U, + 2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U, + 2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U, + 2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U, + 2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U, + 2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U, + 2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U, + 2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U, + 2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U, + 3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U, + 3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U, + 3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U, + 3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U, + 3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U, + 3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U, + 3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U, + 3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U, + 3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U, + 3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U, + 3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U, + 3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U, + 3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U, + 3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U, + 3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U, + 3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U, + 3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U, + 3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U, + 3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U, + 3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U, + 3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U, + 3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U, + 3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U, + 3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U, + 4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U, + 4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U, + 4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U, + 4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U, + 4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U, + 4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U, + 4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U, + 4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U, + 4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U, + 4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U, + 4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U, + 4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U, + 4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U, + 4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U, + 4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U, + 4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U, + 4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U, + 4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U, + 4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U, + 4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U, + 4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U, + 4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U, + 4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U, + 4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U, + 5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U, + 5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U, + 5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U, + 5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U, + 5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U, + 5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U, + 5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U, + 5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U, + 5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U, + 5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U, + 5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U, + 5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U, + 5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U, + 5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U, + 5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U, + 5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U, + 5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U, + 5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U, + 5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U, + 5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U, + 5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U, + 5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U, + 5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U, + 5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U, + 6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U, + 6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U, + 6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U, + 6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U, + 6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U, + 6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U, + 6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U, + 6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U, + 6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U, + 6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U, + 6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U, + 6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U, + 6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U, + 6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U, + 6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U, + 6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U, + 6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U, + 6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U, + 6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U, + 6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U, + 6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U, + 6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U, + 6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U, + 6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U, + 7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U, + 7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U, + 7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U, + 7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U, + 7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U, + 7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U, + 7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U, + 7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U, + 7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U, + 7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U, + 7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U, + 7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U, + 7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U, + 7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U, + 7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U, + 7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U, + 7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U, + 7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U, + 7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U, + 7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U, + 7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U, + 7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U, + 7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U, + 7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U, + 8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U, + 8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U, + 8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U, + 8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U, + 8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U, + 8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U, + 8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U, + 8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U, + 8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U, + 8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U, + 8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U, + 8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U, + 8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U, + 8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U, + 8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U, + 8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U, + 8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U, + 8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U, + 8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U, + 8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U, + 8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U, + 8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U, + 8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U, + 9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U, + 9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U, + 9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U, + 9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U, + 9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U, + 9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U, + 9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U, + 9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U, + 9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U, + 9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U, + 9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U, + 9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U, + 9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U, + 9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U, + 9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U, + 9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U, + 9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U, + 9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U, + 9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U, + 9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U, + 9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U, + 9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U, + 9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U, + 9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U, + 10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U, + 10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U, + 10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U, + 10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U, + 10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U, + 10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U, + 10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U, + 10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U, + 10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U, + 10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U, + 10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U, + 10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U, + 10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U, + 10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U, + 10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U, + 10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U, + 10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U, + 10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U, + 10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U, + 10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U, + 10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U, + 10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U, + 10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U, + 10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U, + 11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U, + 11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U, + 11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U, + 11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U, + 11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U, + 11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U, + 11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U, + 11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U, + 11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U, + 11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U, + 11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U, + 11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U, + 11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U, + 11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U, + 11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U, + 11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U, + 11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U, + 11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U, + 11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U, + 11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U, + 11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U, + 11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U, + 11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U, + 11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U, + 12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U, + 12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U, + 12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U, + 12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U, + 12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U, + 12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U, + 12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U, + 12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U, + 12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U, + 12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U, + 12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U, + 12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U, + 12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U, + 12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U, + 12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U, + 12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U, + 12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U, + 12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U, + 12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U, + 12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U, + 12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U, + 12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U, + 12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U, + 12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U, + 13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U, + 13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U, + 13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U, + 13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U, + 13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U, + 13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U, + 13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U, + 13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U, + 13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U, + 13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U, + 13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U, + 13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U, + 13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U, + 13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U, + 13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U, + 13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U, + 13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U, + 13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U, + 13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U, + 13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U, + 13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U, + 13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U, + 13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U, + 13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U, + 14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U, + 14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U, + 14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U, + 14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U, + 14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U, + 14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U, + 14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U, + 14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U, + 14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U, + 14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U, + 14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U, + 14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U, + 14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U, + 14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U, + 14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U, + 14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U, + 14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U, + 14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U, + 14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U, + 14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U, + 14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U, + 14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U, + 14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U, + 14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U, + 15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U, + 15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U, + 15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U, + 15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U, + 15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U, + 15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U, + 15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U, + 15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U, + 15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U, + 15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U, + 15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U, + 15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U, + 15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U, + 15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U, + 15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U, + 15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U, + 15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U, + 15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U, + 15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U, + 15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U, + 15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U, + 15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U, + 15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U, + 16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U, + 16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U, + 16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U, + 16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U, + 16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U, + 16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U, + 16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U, + 16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U, + 16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U, + 16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U, + 16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U, + 16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U, + 16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U, + 16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U, + 16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U, + 16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U, + 16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U, + 16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U, + 16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U, + 16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U, + 16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U, + 16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U, + 16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U, + 16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U, + 17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U, + 17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U, + 17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U, + 17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U, + 17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U, + 17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U, + 17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U, + 17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U, + 17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U, + 17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U, + 17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U, + 17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U, + 17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U, + 17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U, + 17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U, + 17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U, + 17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U, + 17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U, + 17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U, + 17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U, + 17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U, + 17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U, + 17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U, + 17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U, + 18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U, + 18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U, + 18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U, + 18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U, + 18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U, + 18228444544U, 18236833408U, 18245220736U }; -// 500 Epochs worth of tabulated DAG sizes (~3.5 Years) // Generated with the following Mathematica Code: + // GetCacheSizes[n_] := Module[{ -// DAGSizeBytesInit = 2^30, -// MixBytes = 128, -// DAGGrowth = 113000000, -// HashBytes = 64, -// DAGParents = 1024, -// j = 0}, -// Reap[ -// While[j < n, -// Module[{i = Floor[(DAGSizeBytesInit + DAGGrowth * j) / (DAGParents * HashBytes)]}, -// While[! PrimeQ[i], i--]; -// Sow[i*HashBytes]; j++]]]][[2]][[1]] - -const size_t cache_sizes[] = { - 1048384U, 1158208U, 1268416U, 1377856U, 1489856U, 1599296U, 1710656U, - 1820608U, 1930816U, 2041024U, 2151872U, 2261696U, 2371904U, 2482624U, - 2593216U, 2703296U, 2814016U, 2924224U, 3034816U, 3144896U, 3255488U, - 3365312U, 3475904U, 3586624U, 3696064U, 3806272U, 3917504U, 4027456U, - 4138304U, 4248512U, 4359104U, 4469312U, 4579264U, 4689728U, 4797376U, - 4909888U, 5020096U, 5131328U, 5241664U, 5351744U, 5461312U, 5572544U, - 5683264U, 5793472U, 5903552U, 6014144U, 6121664U, 6235072U, 6344896U, - 6454592U, 6565952U, 6675904U, 6786112U, 6896704U, 7006784U, 7117888U, - 7228096U, 7338304U, 7448768U, 7557952U, 7669184U, 7779776U, 7889216U, - 8000192U, 8110912U, 8220736U, 8331712U, 8441536U, 8552384U, 8662592U, - 8772928U, 8883136U, 8993728U, 9103168U, 9214528U, 9323968U, 9434816U, - 9545152U, 9655616U, 9766336U, 9876544U, 9986624U, 10097344U, 10207424U, - 10316864U, 10427968U, 10538432U, 10649152U, 10758976U, 10869568U, 10979776U, - 11089472U, 11200832U, 11309632U, 11420608U, 11531584U, 11641792U, 11751104U, - 11862976U, 11973184U, 12083264U, 12193856U, 12304064U, 12414656U, 12524608U, - 12635072U, 12745792U, 12855616U, 12965824U, 13076416U, 13187008U, 13297216U, - 13407808U, 13518016U, 13627072U, 13738688U, 13848256U, 13959488U, 14069696U, - 14180288U, 14290624U, 14399552U, 14511424U, 14621504U, 14732096U, 14841664U, - 14951744U, 15062336U, 15172672U, 15283264U, 15393088U, 15504448U, 15614272U, - 15723712U, 15834944U, 15945152U, 16055744U, 16165696U, 16277056U, 16387136U, - 16494784U, 16607936U, 16718272U, 16828736U, 16938176U, 17048384U, 17159872U, - 17266624U, 17380544U, 17490496U, 17600192U, 17711296U, 17821376U, 17931968U, - 18041152U, 18152896U, 18261952U, 18373568U, 18483392U, 18594112U, 18703936U, - 18814912U, 18924992U, 19034944U, 19145408U, 19256128U, 19366208U, 19477184U, - 19587136U, 19696576U, 19808192U, 19916992U, 20028352U, 20137664U, 20249024U, - 20358848U, 20470336U, 20580544U, 20689472U, 20801344U, 20911424U, 21020096U, - 21130688U, 21242176U, 21352384U, 21462208U, 21573824U, 21683392U, 21794624U, - 21904448U, 22013632U, 22125248U, 22235968U, 22344512U, 22456768U, 22566848U, - 22677056U, 22786496U, 22897984U, 23008064U, 23118272U, 23228992U, 23338816U, - 23449408U, 23560256U, 23670464U, 23780672U, 23891264U, 24001216U, 24110656U, - 24221888U, 24332608U, 24442688U, 24552512U, 24662464U, 24773696U, 24884032U, - 24994496U, 25105216U, 25215296U, 25324864U, 25435712U, 25546432U, 25655744U, - 25767232U, 25876672U, 25986368U, 26098112U, 26207936U, 26318912U, 26428736U, - 26539712U, 26650048U, 26760256U, 26869184U, 26979776U, 27091136U, 27201728U, - 27311552U, 27422272U, 27532352U, 27642304U, 27752896U, 27863744U, 27973952U, - 28082752U, 28194752U, 28305344U, 28415168U, 28524992U, 28636352U, 28746304U, - 28857152U, 28967104U, 29077184U, 29187904U, 29298496U, 29408576U, 29518912U, - 29628992U, 29739968U, 29850176U, 29960512U, 30070336U, 30180544U, 30290752U, - 30398912U, 30512192U, 30622784U, 30732992U, 30842176U, 30953536U, 31063744U, - 31174336U, 31284544U, 31395136U, 31504448U, 31615552U, 31725632U, 31835072U, - 31946176U, 32057024U, 32167232U, 32277568U, 32387008U, 32497984U, 32608832U, - 32719168U, 32829376U, 32939584U, 33050048U, 33160768U, 33271232U, 33381184U, - 33491648U, 33601856U, 33712576U, 33822016U, 33932992U, 34042816U, 34153024U, - 34263104U, 34373824U, 34485056U, 34594624U, 34704832U, 34816064U, 34926272U, - 35036224U, 35146816U, 35255104U, 35367104U, 35478208U, 35588416U, 35698496U, - 35808832U, 35918656U, 36029888U, 36139456U, 36250688U, 36360512U, 36471104U, - 36581696U, 36691136U, 36802112U, 36912448U, 37022912U, 37132864U, 37242944U, - 37354048U, 37464512U, 37574848U, 37684928U, 37794752U, 37904704U, 38015552U, - 38125888U, 38236864U, 38345792U, 38457152U, 38567744U, 38678336U, 38787776U, - 38897216U, 39009088U, 39117632U, 39230144U, 39340352U, 39450304U, 39560384U, - 39671488U, 39781312U, 39891392U, 40002112U, 40112704U, 40223168U, 40332608U, - 40443968U, 40553792U, 40664768U, 40774208U, 40884416U, 40993984U, 41105984U, - 41215424U, 41326528U, 41436992U, 41546048U, 41655872U, 41768128U, 41878336U, - 41988928U, 42098752U, 42209344U, 42319168U, 42429248U, 42540352U, 42649792U, - 42761024U, 42871616U, 42981824U, 43092032U, 43201856U, 43312832U, 43423552U, - 43533632U, 43643584U, 43753792U, 43864384U, 43974976U, 44084032U, 44195392U, - 44306368U, 44415296U, 44526016U, 44637248U, 44746816U, 44858048U, 44967872U, - 45078848U, 45188288U, 45299264U, 45409216U, 45518272U, 45630272U, 45740224U, - 45850432U, 45960896U, 46069696U, 46182208U, 46292416U, 46402624U, 46512064U, - 46623296U, 46733888U, 46843712U, 46953664U, 47065024U, 47175104U, 47285696U, - 47395904U, 47506496U, 47615296U, 47726912U, 47837632U, 47947712U, 48055232U, - 48168128U, 48277952U, 48387392U, 48499648U, 48609472U, 48720064U, 48830272U, - 48940096U, 49050944U, 49160896U, 49271744U, 49381568U, 49492288U, 49602752U, - 49712576U, 49822016U, 49934272U, 50042816U, 50154304U, 50264128U, 50374336U, - 50484416U, 50596288U, 50706752U, 50816704U, 50927168U, 51035456U, 51146944U, - 51258176U, 51366976U, 51477824U, 51589568U, 51699776U, 51809728U, 51920576U, - 52030016U, 52140736U, 52251328U, 52361152U, 52470592U, 52582592U, 52691776U, - 52803136U, 52912576U, 53020736U, 53132224U, 53242688U, 53354816U, 53465536U, - 53575232U, 53685568U, 53796544U, 53906752U, 54016832U, 54126656U, 54236992U, - 54347456U, 54457408U, 54569024U, 54679232U, 54789184U, 54899776U, 55008832U, - 55119296U, 55231168U, 55341248U, 55451584U, 55562048U, 55672256U, 55782208U, - 55893184U, 56002112U, 56113216U +// DataSetSizeBytesInit = 2^30, +// MixBytes = 128, +// DataSetGrowth = 2^23, +// HashBytes = 64, +// CacheMultiplier = 1024, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + +const size_t cache_sizes[2048] = { + 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, + 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, + 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, + 19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U, + 20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U, + 21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U, + 22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U, + 23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U, + 24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U, + 25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U, + 25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U, + 26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U, + 27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U, + 28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U, + 29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U, + 30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U, + 31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U, + 32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U, + 33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U, + 34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U, + 35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U, + 36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U, + 36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U, + 37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U, + 38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U, + 39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U, + 40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U, + 41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U, + 42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U, + 43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U, + 44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U, + 45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U, + 46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U, + 47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U, + 47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U, + 48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U, + 49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U, + 50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U, + 51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U, + 52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U, + 53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U, + 54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U, + 55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U, + 56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U, + 57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U, + 58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U, + 58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U, + 59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U, + 60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U, + 61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U, + 62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U, + 63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U, + 64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U, + 65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U, + 66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U, + 67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U, + 68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U, + 69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U, + 69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U, + 70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U, + 71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U, + 72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U, + 73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U, + 74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U, + 75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U, + 76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U, + 77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U, + 78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U, + 79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U, + 80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U, + 81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U, + 81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U, + 82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U, + 83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U, + 84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U, + 85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U, + 86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U, + 87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U, + 88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U, + 89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U, + 90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U, + 91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U, + 92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U, + 92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U, + 93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U, + 94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U, + 95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U, + 96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U, + 97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U, + 98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U, + 99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U, + 100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U, + 100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U, + 101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U, + 102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U, + 103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U, + 104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U, + 104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U, + 105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U, + 106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U, + 107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U, + 108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U, + 108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U, + 109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U, + 110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U, + 111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U, + 111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U, + 112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U, + 113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U, + 114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U, + 115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U, + 115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U, + 116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U, + 117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U, + 118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U, + 119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U, + 119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U, + 120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U, + 121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U, + 122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U, + 122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U, + 123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U, + 124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U, + 125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U, + 126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U, + 126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U, + 127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U, + 128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U, + 129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U, + 130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U, + 130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U, + 131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U, + 132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U, + 133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U, + 133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U, + 134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U, + 135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U, + 136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U, + 137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U, + 137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U, + 138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U, + 139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U, + 140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U, + 141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U, + 141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U, + 142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U, + 143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U, + 144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U, + 144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U, + 145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U, + 146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U, + 147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U, + 148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U, + 148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U, + 149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U, + 150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U, + 151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U, + 152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U, + 152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U, + 153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U, + 154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U, + 155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U, + 155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U, + 156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U, + 157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U, + 158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U, + 159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U, + 159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U, + 160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U, + 161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U, + 162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U, + 163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U, + 163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U, + 164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U, + 165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U, + 166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U, + 166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U, + 167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U, + 168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U, + 169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U, + 170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U, + 170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U, + 171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U, + 172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U, + 173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U, + 174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U, + 174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U, + 175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U, + 176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U, + 177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U, + 177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U, + 178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U, + 179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U, + 180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U, + 181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U, + 181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U, + 182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U, + 183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U, + 184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U, + 185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U, + 185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U, + 186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U, + 187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U, + 188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U, + 189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U, + 189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U, + 190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U, + 191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U, + 192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U, + 192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U, + 193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U, + 194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U, + 195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U, + 196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U, + 196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U, + 197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U, + 198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U, + 199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U, + 200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U, + 200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U, + 201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U, + 202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U, + 203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U, + 203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U, + 204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U, + 205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U, + 206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U, + 207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U, + 207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U, + 208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U, + 209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U, + 210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U, + 211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U, + 211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U, + 212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U, + 213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U, + 214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U, + 214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U, + 215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U, + 216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U, + 217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U, + 218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U, + 218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U, + 219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U, + 220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U, + 221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U, + 222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U, + 222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U, + 223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U, + 224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U, + 225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U, + 225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U, + 226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U, + 227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U, + 228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U, + 229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U, + 229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U, + 230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U, + 231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U, + 232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U, + 233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U, + 233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U, + 234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U, + 235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U, + 236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U, + 236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U, + 237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U, + 238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U, + 239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U, + 240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U, + 240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U, + 241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U, + 242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U, + 243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U, + 244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U, + 244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U, + 245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U, + 246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U, + 247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U, + 247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U, + 248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U, + 249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U, + 250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U, + 251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U, + 251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U, + 252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U, + 253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U, + 254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U, + 255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U, + 255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U, + 256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U, + 257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U, + 258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U, + 258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U, + 259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U, + 260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U, + 261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U, + 262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U, + 262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U, + 263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U, + 264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U, + 265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U, + 266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U, + 266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U, + 267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U, + 268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U, + 269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U, + 270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U, + 270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U, + 271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U, + 272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U, + 273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U, + 273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U, + 274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U, + 275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U, + 276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U, + 277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U, + 277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U, + 278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U, + 279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U, + 280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U, + 281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U, + 281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U, + 282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U, + 283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U, + 284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U, + 284950208U, 285081536U }; #ifdef __cplusplus diff --git a/libethash/ethash.h b/libethash/ethash.h index b96e6347d..a7159de65 100644 --- a/libethash/ethash.h +++ b/libethash/ethash.h @@ -1,19 +1,20 @@ /* - This file is part of cpp-ethereum. + This file is part of ethash. - cpp-ethereum is free software: you can redistribute it and/or modify + ethash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, + ethash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . + along with ethash. If not, see . */ + /** @file ethash.h * @date 2015 */ @@ -25,26 +26,17 @@ #include #include "compiler.h" -#define ETHASH_REVISION 19 -#define ETHASH_DAGSIZE_BYTES_INIT 1073741824U // 2**30 -#define ETHASH_DAG_GROWTH 113000000U -#define ETHASH_EPOCH_LENGTH 30000U -#define ETHASH_MIX_BYTES 128 -#define ETHASH_DAG_PARENTS 256 -#define ETHASH_CACHE_ROUNDS 3 -#define ETHASH_ACCESSES 64 - -// ********************* -// TODO: Remove once other code moved over to compliant naming scheme. -#define REVISION 19 -#define DAGSIZE_BYTES_INIT 1073741824U // 2**30 -#define DAG_GROWTH 113000000U +#define REVISION 23 +#define DATASET_BYTES_INIT 1073741824U // 2**30 +#define DATASET_BYTES_GROWTH 8388608U // 2**23 +#define CACHE_BYTES_INIT 1073741824U // 2**24 +#define CACHE_BYTES_GROWTH 131072U // 2**17 #define EPOCH_LENGTH 30000U #define MIX_BYTES 128 -#define DAG_PARENTS 256 +#define HASH_BYTES 64 +#define DATASET_PARENTS 256 #define CACHE_ROUNDS 3 #define ACCESSES 64 -// ********************* #ifdef __cplusplus extern "C" { @@ -70,35 +62,54 @@ static inline void ethash_params_init(ethash_params *params, const uint32_t bloc } typedef struct ethash_cache { - void *mem; + void *mem; } ethash_cache; void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); +void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); + +static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { + ethash_cache c; + c.mem = cache; + ethash_mkcache(&c, params, seed); +} + +static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { + ethash_cache c; + c.mem = (void *) cache; + ethash_light(ret, &c, params, header_hash, nonce); +} + +static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { + ethash_cache c; + c.mem = (void *) cache; + ethash_compute_full_data(full, params, &c); +} -static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { ethash_cache c; c.mem = cache; ethash_mkcache(&c, params, seed); } -static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_cache c; c.mem = (void*)cache; ethash_light(ret, &c, params, header_hash, nonce); } -static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_cache c; c.mem = (void*)cache; ethash_compute_full_data(full, params, &c); } -static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_full(ret, full, params, header_hash, nonce); } +static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { + ethash_full(ret, full, params, header_hash, nonce); +} +// Returns if hash is less than or equal to difficulty static inline int ethash_check_difficulty( const uint8_t hash[32], const uint8_t difficulty[32]) { // Difficulty is big endian for (int i = 0; i < 32; i++) { if (hash[i] == difficulty[i]) continue; - return hash[i] < difficulty[i]; + return hash[i] < difficulty[i]; } - return 1; + return 1; } -void ethash_quick_hash( - uint8_t return_hash[32], +int ethash_quick_check_difficulty( const uint8_t header_hash[32], const uint64_t nonce, - const uint8_t mix_hash[32]); + const uint8_t mix_hash[32], + const uint8_t difficulty[32]); #ifdef __cplusplus } diff --git a/libethash/internal.c b/libethash/internal.c index a2b82d375..0a7e767e7 100644 --- a/libethash/internal.c +++ b/libethash/internal.c @@ -1,12 +1,12 @@ /* - This file is part of cpp-ethereum. + This file is part of ethash. - cpp-ethereum is free software: you can redistribute it and/or modify + ethash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, + ethash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file dash.cpp +/** @file internal.c * @author Tim Hughes * @author Matthew Wampler-Doty * @date 2015 @@ -38,12 +38,12 @@ #endif // WITH_CRYPTOPP size_t ethash_get_datasize(const uint32_t block_number) { - assert(block_number / EPOCH_LENGTH < 500); + assert(block_number / EPOCH_LENGTH < 2048); return dag_sizes[block_number / EPOCH_LENGTH]; } size_t ethash_get_cachesize(const uint32_t block_number) { - assert(block_number / EPOCH_LENGTH < 500); + assert(block_number / EPOCH_LENGTH < 2048); return cache_sizes[block_number / EPOCH_LENGTH]; } @@ -55,7 +55,7 @@ void static ethash_compute_cache_nodes( ethash_params const *params, const uint8_t seed[32]) { assert((params->cache_size % sizeof(node)) == 0); - uint32_t const num_nodes = (uint32_t)(params->cache_size / sizeof(node)); + uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node)); SHA3_512(nodes[0].bytes, seed, 32); @@ -68,10 +68,9 @@ void static ethash_compute_cache_nodes( uint32_t const idx = nodes[i].words[0] % num_nodes; node data; data = nodes[(num_nodes - 1 + i) % num_nodes]; - for (unsigned w = 0; w != NODE_WORDS; ++w) - { - data.words[w] ^= nodes[idx].words[w]; - } + for (unsigned w = 0; w != NODE_WORDS; ++w) { + data.words[w] ^= nodes[idx].words[w]; + } SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); } } @@ -86,7 +85,7 @@ void static ethash_compute_cache_nodes( } void ethash_mkcache( - ethash_cache *cache, + ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]) { node *nodes = (node *) cache->mem; @@ -99,13 +98,13 @@ void ethash_calculate_dag_item( const struct ethash_params *params, const struct ethash_cache *cache) { - uint32_t num_parent_nodes = (uint32_t)(params->cache_size / sizeof(node)); + uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); node const *cache_nodes = (node const *) cache->mem; node const *init = &cache_nodes[node_index % num_parent_nodes]; - memcpy(ret, init, sizeof(node)); - ret->words[0] ^= node_index; - SHA3_512(ret->bytes, ret->bytes, sizeof(node)); + memcpy(ret, init, sizeof(node)); + ret->words[0] ^= node_index; + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); #if defined(_M_X64) && ENABLE_SSE __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); @@ -115,12 +114,11 @@ void ethash_calculate_dag_item( __m128i xmm3 = ret->xmm[3]; #endif - for (unsigned i = 0; i != DAG_PARENTS; ++i) - { - uint32_t parent_index = ((node_index ^ i)*FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes; + for (unsigned i = 0; i != DATASET_PARENTS; ++i) { + uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes; node const *parent = &cache_nodes[parent_index]; - #if defined(_M_X64) && ENABLE_SSE +#if defined(_M_X64) && ENABLE_SSE { xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); @@ -143,10 +141,10 @@ void ethash_calculate_dag_item( ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); } } - #endif +#endif } - SHA3_512(ret->bytes, ret->bytes, sizeof(node)); + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); } void ethash_compute_full_data( @@ -164,7 +162,7 @@ void ethash_compute_full_data( } static void ethash_hash( - ethash_return_value * ret, + ethash_return_value *ret, node const *full_nodes, ethash_cache const *cache, ethash_params const *params, @@ -174,7 +172,7 @@ static void ethash_hash( assert((params->full_size % MIX_WORDS) == 0); // pack hash and nonce together into first 40 bytes of s_mix - assert(sizeof(node)*8 == 512); + assert(sizeof(node) * 8 == 512); node s_mix[MIX_NODES + 1]; memcpy(s_mix[0].bytes, header_hash, 32); @@ -193,23 +191,21 @@ static void ethash_hash( } #endif - node* const mix = s_mix + 1; + node *const mix = s_mix + 1; for (unsigned w = 0; w != MIX_WORDS; ++w) { mix->words[w] = s_mix[0].words[w % NODE_WORDS]; } unsigned const page_size = sizeof(uint32_t) * MIX_WORDS, - num_full_pages = (unsigned)(params->full_size / page_size); + num_full_pages = (unsigned) (params->full_size / page_size); - for (unsigned i = 0; i != ACCESSES; ++i) - { - uint32_t const index = ((s_mix->words[0] ^ i)*FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages; + for (unsigned i = 0; i != ACCESSES; ++i) { + uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages; - for (unsigned n = 0; n != MIX_NODES; ++n) - { - const node * dag_node = &full_nodes[MIX_NODES * index + n]; + for (unsigned n = 0; n != MIX_NODES; ++n) { + const node *dag_node = &full_nodes[MIX_NODES * index + n]; if (!full_nodes) { node tmp_node; @@ -217,7 +213,7 @@ static void ethash_hash( dag_node = &tmp_node; } - #if defined(_M_X64) && ENABLE_SSE +#if defined(_M_X64) && ENABLE_SSE { __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); @@ -235,20 +231,19 @@ static void ethash_hash( mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]); } } - #endif +#endif } } - // compress mix - for (unsigned w = 0; w != MIX_WORDS; w += 4) - { - uint32_t reduction = mix->words[w+0]; - reduction = reduction*FNV_PRIME ^ mix->words[w+1]; - reduction = reduction*FNV_PRIME ^ mix->words[w+2]; - reduction = reduction*FNV_PRIME ^ mix->words[w+3]; - mix->words[w/4] = reduction; - } + // compress mix + for (unsigned w = 0; w != MIX_WORDS; w += 4) { + uint32_t reduction = mix->words[w + 0]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 1]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 2]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 3]; + mix->words[w / 4] = reduction; + } #if BYTE_ORDER != LITTLE_ENDIAN for (unsigned w = 0; w != MIX_WORDS/4; ++w) { @@ -258,7 +253,7 @@ static void ethash_hash( memcpy(ret->mix_hash, mix->bytes, 32); // final Keccak hash - SHA3_256(ret->result, s_mix->bytes, 64+32); // Keccak-256(s + compressed_mix) + SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) } void ethash_quick_hash( @@ -267,7 +262,7 @@ void ethash_quick_hash( const uint64_t nonce, const uint8_t mix_hash[32]) { - uint8_t buf[64+32]; + uint8_t buf[64 + 32]; memcpy(buf, header_hash, 32); #if BYTE_ORDER != LITTLE_ENDIAN nonce = fix_endian64(nonce); @@ -275,7 +270,14 @@ void ethash_quick_hash( memcpy(&(buf[32]), &nonce, 8); SHA3_512(buf, buf, 40); memcpy(&(buf[64]), mix_hash, 32); - SHA3_256(return_hash, buf, 64+32); + SHA3_256(return_hash, buf, 64 + 32); +} + +void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) { + memset(seedhash, 0, 32); + const uint32_t epochs = block_number / EPOCH_LENGTH; + for (uint32_t i = 0; i < epochs; ++i) + SHA3_256(seedhash, seedhash, 32); } int ethash_quick_check_difficulty( @@ -289,10 +291,10 @@ int ethash_quick_check_difficulty( return ethash_check_difficulty(return_hash, difficulty); } -void ethash_full(ethash_return_value * ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { +void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); } -void ethash_light(ethash_return_value * ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { +void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { ethash_hash(ret, NULL, cache, params, previous_hash, nonce); -} +} \ No newline at end of file diff --git a/libethash/internal.h b/libethash/internal.h index d77991d56..bcbacdaa4 100644 --- a/libethash/internal.h +++ b/libethash/internal.h @@ -37,6 +37,12 @@ void ethash_calculate_dag_item( ethash_cache const *cache ); +void ethash_quick_hash( + uint8_t return_hash[32], + const uint8_t header_hash[32], + const uint64_t nonce, + const uint8_t mix_hash[32]); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/libethash/sha3_cryptopp.cpp b/libethash/sha3_cryptopp.cpp index 9454ce04a..6cbbcad8f 100644 --- a/libethash/sha3_cryptopp.cpp +++ b/libethash/sha3_cryptopp.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of ethash. - cpp-ethereum is free software: you can redistribute it and/or modify + ethash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, + ethash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . + along with ethash. If not, see . */ /** @file sha3.cpp diff --git a/libethash/util.h b/libethash/util.h index 2f59076f6..ba8957815 100644 --- a/libethash/util.h +++ b/libethash/util.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of ethash. - cpp-ethereum is free software: you can redistribute it and/or modify + ethash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, + ethash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . + along with ethash. If not, see . */ /** @file util.h * @author Tim Hughes diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index f04353aac..bbd78224f 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -104,6 +104,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { + if (_header.itemCount() != 15) + throw InvalidBlockHeaderItemCount(); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 76efc06a2..d26ac0260 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -22,6 +22,7 @@ #include "Common.h" #include #include +#include "Ethasher.h" #include "Exceptions.h" using namespace std; using namespace dev; @@ -32,15 +33,16 @@ namespace dev namespace eth { +const unsigned c_ethashVersion = c_ethashRevision; const unsigned c_protocolVersion = 58; const unsigned c_databaseBaseVersion = 8; #if ETH_FATDB -const unsigned c_databaseVersionModifier = 1000; +const unsigned c_databaseVersionModifier = 1; #else const unsigned c_databaseVersionModifier = 0; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + c_databaseVersionModifier; +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (c_ethashVersion << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 80a253bdd..aabb59d25 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -38,6 +38,9 @@ extern const unsigned c_protocolVersion; /// Current database version. extern const unsigned c_databaseVersion; +/// Current database version. +extern const unsigned c_ethashVersion; + /// User-friendly string representation of the amount _b in wei. std::string formatBalance(bigint const& _b); diff --git a/libethcore/Ethasher.cpp b/libethcore/Ethasher.cpp index f80277cb2..80c263673 100644 --- a/libethcore/Ethasher.cpp +++ b/libethcore/Ethasher.cpp @@ -29,9 +29,9 @@ #include #include #include +#include #include #include -#include #include "BlockInfo.h" #include "Ethasher.h" using namespace std; @@ -44,9 +44,10 @@ Ethasher* dev::eth::Ethasher::s_this = nullptr; bytes const& Ethasher::cache(BlockInfo const& _header) { RecursiveGuard l(x_this); - if (_header.number > EPOCH_LENGTH*2048) { + if (_header.number > c_ethashEpochLength * 2048) + { std::ostringstream error; - error << "block number is too high; max is " << EPOCH_LENGTH*2048 << "(was " << _header.number << ")"; + error << "block number is too high; max is " << c_ethashEpochLength * 2048 << "(was " << _header.number << ")"; throw std::invalid_argument( error.str() ); } @@ -72,7 +73,11 @@ bytesConstRef Ethasher::full(BlockInfo const& _header) try { boost::filesystem::create_directories(getDataDir() + "/ethashcache"); } catch (...) {} - std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash().ref().cropped(0, 4)) + ".full"; + + std::string memoFile = getDataDir() + "/ethashcache/full"; + auto info = rlpList(c_ethashRevision, _header.seedHash()); + if (boost::filesystem::exists(memoFile) && contents(memoFile + ".info") != info) + boost::filesystem::remove(memoFile); m_fulls[_header.seedHash()] = contentsNew(memoFile); if (!m_fulls[_header.seedHash()]) { @@ -81,6 +86,7 @@ bytesConstRef Ethasher::full(BlockInfo const& _header) auto c = cache(_header); ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c.data()); writeFile(memoFile, m_fulls[_header.seedHash()]); + writeFile(memoFile + ".info", info); } } return m_fulls[_header.seedHash()]; @@ -101,21 +107,20 @@ ethash_params Ethasher::params(unsigned _n) bool Ethasher::verify(BlockInfo const& _header) { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (_header.number >= c_ethashEpochLength * 2048) return false; + h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - uint8_t quickHashOut[32]; - ethash_quick_hash( - quickHashOut, + + // should be equivalent to: + auto r = eval(_header); + return r.mixHash == _header.mixHash && r.value <= boundary; + + return ethash_quick_check_difficulty( _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_header.nonce, - _header.mixHash.data() - ); - h256 quickHashOut256 = h256(quickHashOut, h256::ConstructFromPointer); - if (quickHashOut256 > boundary) - return false; - auto e = eval(_header, _header.nonce); - return (u256)e.value <= boundary && e.mixHash == _header.mixHash; + _header.mixHash.data(), + boundary.data()); } Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce) @@ -123,5 +128,6 @@ Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce) auto p = Ethasher::params(_header); ethash_return_value r; ethash_compute_light(&r, Ethasher::get()->cache(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); +// cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/Ethasher.h b/libethcore/Ethasher.h index cfe0d1c82..c160d38da 100644 --- a/libethcore/Ethasher.h +++ b/libethcore/Ethasher.h @@ -27,8 +27,24 @@ #include #include #include +#include #include #include // TODO: REMOVE once everything merged into this class and an opaque API can be provided. +static const unsigned c_ethashRevision = REVISION; +static const unsigned c_ethashEpochLength = EPOCH_LENGTH; +#undef REVISION +#undef DATASET_BYTES_INIT +#undef DATASET_BYTES_GROWTH +#undef CACHE_BYTES_INIT +#undef CACHE_BYTES_GROWTH +#undef DAGSIZE_BYTES_INIT +#undef DAG_GROWTH +#undef EPOCH_LENGTH +#undef MIX_BYTES +#undef HASH_BYTES +#undef DATASET_PARENTS +#undef CACHE_ROUNDS +#undef ACCESSES #include "Common.h" #include "BlockInfo.h" @@ -71,6 +87,7 @@ public: inline h256 mine(uint64_t _nonce) { ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); +// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); return h256(m_ethashReturn.result, h256::ConstructFromPointer); } diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 0059854f7..f9eab7c8d 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -67,6 +67,7 @@ struct InvalidReceiptsStateRoot: virtual dev::Exception {}; struct InvalidTimestamp: virtual dev::Exception {}; struct InvalidLogBloom: virtual dev::Exception {}; class InvalidNonce: virtual public dev::Exception {}; +class InvalidBlockHeaderItemCount: virtual public dev::Exception {}; class InvalidBlockNonce: virtual public dev::Exception {}; struct InvalidParentHash: virtual dev::Exception {}; struct InvalidNumber: virtual dev::Exception {}; diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp index 694219013..d58888ab7 100644 --- a/libethcore/Params.cpp +++ b/libethcore/Params.cpp @@ -27,10 +27,10 @@ namespace dev namespace eth { -//--- BEGIN: AUTOGENERATED FROM /feeStructure.json +//--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json u256 const c_genesisDifficulty = 131072; u256 const c_maximumExtraDataSize = 1024; -u256 const c_epochDuration = 3000; +u256 const c_epochDuration = 30000; u256 const c_genesisGasLimit = 3141592; u256 const c_minGasLimit = 125000; u256 const c_gasLimitBoundDivisor = 1024; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 3cbfb4905..a34e75d71 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,32 @@ #include #if ETH_ETHASHCL #include +#define ETHASH_REVISION REVISION +#define ETHASH_DATASET_BYTES_INIT DATASET_BYTES_INIT +#define ETHASH_DATASET_BYTES_GROWTH DATASET_BYTES_GROWTH +#define ETHASH_CACHE_BYTES_INIT CACHE_BYTES_INIT +#define ETHASH_CACHE_BYTES_GROWTH CACHE_BYTES_GROWTH +#define ETHASH_DAGSIZE_BYTES_INIT DAGSIZE_BYTES_INIT +#define ETHASH_DAG_GROWTH DAG_GROWTH +#define ETHASH_EPOCH_LENGTH EPOCH_LENGTH +#define ETHASH_MIX_BYTES MIX_BYTES +#define ETHASH_HASH_BYTES HASH_BYTES +#define ETHASH_DATASET_PARENTS DATASET_PARENTS +#define ETHASH_CACHE_ROUNDS CACHE_ROUNDS +#define ETHASH_ACCESSES ACCESSES +#undef REVISION +#undef DATASET_BYTES_INIT +#undef DATASET_BYTES_GROWTH +#undef CACHE_BYTES_INIT +#undef CACHE_BYTES_GROWTH +#undef DAGSIZE_BYTES_INIT +#undef DAG_GROWTH +#undef EPOCH_LENGTH +#undef MIX_BYTES +#undef HASH_BYTES +#undef DATASET_PARENTS +#undef CACHE_ROUNDS +#undef ACCESSES #endif #include "BlockInfo.h" #include "Ethasher.h" @@ -54,11 +81,12 @@ std::pair EthashCPU::mine(BlockInfo const& _header, Ethasher::Miner m(_header); std::pair ret; - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()))); + auto tid = std::this_thread::get_id(); + static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng)); - bigint boundary = (bigint(1) << 256) / _header.difficulty; - ret.first.requirement = log2((double)boundary); + h256 boundary = u256((bigint(1) << 256) / _header.difficulty); + ret.first.requirement = log2((double)(u256)boundary); // 2^ 0 32 64 128 256 // [--------*-------------------------] @@ -72,13 +100,17 @@ std::pair EthashCPU::mine(BlockInfo const& _header, unsigned hashCount = 0; for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) { - u256 val(m.mine(tryNonce)); - best = std::min(best, log2((double)val)); + h256 val(m.mine(tryNonce)); + best = std::min(best, log2((double)(u256)val)); if (val <= boundary) { ret.first.completed = true; + assert(Ethasher::eval(_header, (Nonce)(u64)tryNonce).value == val); result.mixHash = m.lastMixHash(); result.nonce = u64(tryNonce); + BlockInfo test = _header; + assignResult(result, test); + assert(verify(test)); break; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 54167f2ad..f80680f38 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 9d7ecb605..fb29ffb6a 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -475,7 +475,7 @@ void Client::setupState(State& _s) _s.commitToMine(m_bc); } -void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Client::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { startWorking(); @@ -491,9 +491,9 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ m_tq.attemptImport(t.rlp()); } -bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) +ExecutionResult Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) { - bytes out; + ExecutionResult ret; try { u256 n; @@ -505,18 +505,41 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat n = temp.transactionsFrom(toAddress(_secret)); } Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false); - (void)gasUsed; // TODO: do something with gasused which it returns. + ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted); } catch (...) { // TODO: Some sort of notification of failure. } - return out; + return ret; } -bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice) +ExecutionResult Client::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) { + ExecutionResult ret; + try + { + u256 n; + State temp; + // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + { + ReadGuard l(x_stateDB); + temp = asOf(_blockNumber); + n = temp.transactionsFrom(toAddress(_secret)); + } + Transaction t(_value, _gasPrice, _gas, _data, n, _secret); + ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted); + } + catch (...) + { + // TODO: Some sort of notification of failure. + } + return ret; +} + +ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice) +{ + ExecutionResult ret; try { State temp; @@ -527,19 +550,17 @@ bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u2 } Executive e(temp, LastHashes(), 0); if (!e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address())) - { e.go(); - return e.out().toBytes(); - } + ret = e.executionResult(); } catch (...) { // TODO: Some sort of notification of failure. } - return bytes(); + return ret; } -Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Client::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { startWorking(); diff --git a/libethereum/Client.h b/libethereum/Client.h index 02d8ef6f8..426c78ca7 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -212,23 +212,27 @@ public: void setGasPricer(std::shared_ptr _gp) { m_gp = _gp; } /// Submits the given message-call transaction. - virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - virtual Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. - virtual void inject(bytesConstRef _rlp); + virtual void inject(bytesConstRef _rlp) override; /// Blocks until all pending transactions have been processed. - virtual void flushTransactions(); + virtual void flushTransactions() override; /// Makes the given call. Nothing is recorded into the state. - virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0); + virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) override; + + /// Does the given creation. Nothing is recorded into the state. + /// @returns the pair of the Address of the created contract together with its code. + virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) override; /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH. - virtual bytes call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether); + ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether); // Informational stuff diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index e009b49fb..b44caf4ee 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -53,7 +53,16 @@ void Executive::accrueSubState(SubState& _parentContext) bool Executive::setup(bytesConstRef _rlp) { // Entry point for a user-executed transaction. - m_t = Transaction(_rlp, CheckSignature::Sender); + try + { + m_t = Transaction(_rlp, CheckSignature::Sender); + } + catch (...) + { + clog(StateDetail) << "Invalid Signature"; + m_excepted = TransactionException::InvalidSignature; + throw; + } return setup(); } @@ -66,6 +75,7 @@ bool Executive::setup() if (m_t.nonce() != nonceReq) { clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); + m_excepted = TransactionException::InvalidNonce; BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce())); } @@ -120,7 +130,7 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen if (_gas < g) { m_endGas = 0; - m_excepted = true; + m_excepted = TransactionException::OutOfGasBase; } else { @@ -200,9 +210,15 @@ bool Executive::go(OnOpFunc const& _onOp) if (m_isCreation) { if (m_out.size() * c_createDataGas <= m_endGas) + { + m_codeDeposit = CodeDeposit::Success; m_endGas -= m_out.size() * c_createDataGas; + } else + { + m_codeDeposit = CodeDeposit::Failed; m_out.reset(); + } m_s.m_cache[m_newAddress].setCode(m_out.toBytes()); } } @@ -214,7 +230,7 @@ bool Executive::go(OnOpFunc const& _onOp) { clog(StateSafeExceptions) << "Safe VM Exception. " << diagnostic_information(_e); m_endGas = 0; - m_excepted = true; + m_excepted = toTransactionException(_e); m_ext->revert(); } catch (Exception const& _e) diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 2e89f0623..d04a39da8 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -101,7 +101,10 @@ public: /// @returns the new address for the created contract in the CREATE operation. h160 newAddress() const { return m_newAddress; } /// @returns true iff the operation ended with a VM exception. - bool excepted() const { return m_excepted; } + bool excepted() const { return m_excepted != TransactionException::None; } + + /// Get the above in an amalgamated fashion. + ExecutionResult executionResult() const { return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit); } private: bool setup(); @@ -116,7 +119,8 @@ private: unsigned m_depth = 0; ///< The context's call-depth. bool m_isCreation = false; ///< True if the transaction creates a contract, or if create() is called. - bool m_excepted = false; ///< True if the VM execution resulted in an exception. + CodeDeposit m_codeDeposit = CodeDeposit::None; ///< True if an attempted deposit failed due to lack of gas. + TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception. u256 m_endGas; ///< The final amount of gas for the transaction. Transaction m_t; ///< The original transaction. Set by setup(). diff --git a/libethereum/Interface.h b/libethereum/Interface.h index abf7c0a2d..dfbd47704 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -60,11 +60,11 @@ public: // [TRANSACTION API] /// Submits the given message-call transaction. - virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0; + virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0; /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - virtual Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0; + virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0; /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. virtual void inject(bytesConstRef _rlp) = 0; @@ -73,7 +73,11 @@ public: virtual void flushTransactions() = 0; /// Makes the given call. Nothing is recorded into the state. - virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) = 0; + virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) = 0; + + /// Does the given creation. Nothing is recorded into the state. + /// @returns the pair of the Address of the created contract together with its code. + virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, int _blockNumber = 0) = 0; // [STATE-QUERY API] diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 9bfc0c08c..0d2b3a93e 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1048,18 +1049,18 @@ LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const return ret; } -u256 State::execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output, bool _commit) +ExecutionResult State::execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p) { - return execute(getLastHashes(_bc, _bc.number()), &_rlp, o_output, _commit); + return execute(getLastHashes(_bc, _bc.number()), &_rlp, _p); } -u256 State::execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output, bool _commit) +ExecutionResult State::execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p) { - return execute(getLastHashes(_bc, _bc.number()), _rlp, o_output, _commit); + return execute(getLastHashes(_bc, _bc.number()), _rlp, _p); } // TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations. -u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, bool _commit) +ExecutionResult State::execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p) { #ifndef ETH_RELEASE commit(); // get an updated hash @@ -1093,41 +1094,38 @@ u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, ctrace << old.diff(*this); #endif - if (o_output) - *o_output = e.out().toBytes(); - - if (!_commit) - { + if (_p == Permanence::Reverted) m_cache.clear(); - return e.gasUsed(); - } - - commit(); - -#if ETH_PARANOIA && !ETH_FATDB - ctrace << "Executed; now" << rootHash(); - ctrace << old.diff(*this); - - paranoia("after execution commit.", true); - - if (e.t().receiveAddress()) + else { - EnforceRefs r(m_db, true); - if (storageRoot(e.t().receiveAddress()) && m_db.lookup(storageRoot(e.t().receiveAddress())).empty()) + commit(); + +#if ETH_PARANOIA && !ETH_FATDB + ctrace << "Executed; now" << rootHash(); + ctrace << old.diff(*this); + + paranoia("after execution commit.", true); + + if (e.t().receiveAddress()) { - cwarn << "TRIE immediately after execution; no node for receiveAddress"; - BOOST_THROW_EXCEPTION(InvalidTrie()); + EnforceRefs r(m_db, true); + if (storageRoot(e.t().receiveAddress()) && m_db.lookup(storageRoot(e.t().receiveAddress())).empty()) + { + cwarn << "TRIE immediately after execution; no node for receiveAddress"; + BOOST_THROW_EXCEPTION(InvalidTrie()); + } } - } #endif + + // TODO: CHECK TRIE after level DB flush to make sure exactly the same. + + // Add to the user-originated transactions that we've executed. + m_transactions.push_back(e.t()); + m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs())); + m_transactionSet.insert(e.t().sha3()); + } - // TODO: CHECK TRIE after level DB flush to make sure exactly the same. - - // Add to the user-originated transactions that we've executed. - m_transactions.push_back(e.t()); - m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs())); - m_transactionSet.insert(e.t().sha3()); - return e.gasUsed(); + return e.executionResult(); } State State::fromPending(unsigned _i) const diff --git a/libethereum/State.h b/libethereum/State.h index bfa60e452..36d3e7c09 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -84,6 +84,12 @@ protected: u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return 10 * szabo; } }; +enum class Permanence +{ + Reverted, + Committed +}; + /** * @brief Model of the current state of the ledger. * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). @@ -185,10 +191,10 @@ public: /// Execute a given transaction. /// This will append @a _t to the transaction list and change the state accordingly. - u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true); - u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true); - u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); } - u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true); + ExecutionResult execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p = Permanence::Committed); + ExecutionResult execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p = Permanence::Committed); + ExecutionResult execute(LastHashes const& _lh, bytes const& _rlp, Permanence _p = Permanence::Committed) { return execute(_lh, &_rlp, _p); } + ExecutionResult execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p = Permanence::Committed); /// Get the remaining gas limit in this block. u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index a89083648..3a092bf25 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -21,8 +21,10 @@ #include #include +#include #include #include +#include #include "Transaction.h" using namespace std; using namespace dev; @@ -30,6 +32,25 @@ using namespace dev::eth; #define ETH_ADDRESS_DEBUG 0 +std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _er) +{ + _out << "{" << _er.gasUsed << ", " << _er.newAddress << ", " << toHex(_er.output) << "}"; + return _out; +} + +TransactionException dev::eth::toTransactionException(VMException const& _e) +{ + if (!!dynamic_cast(&_e)) + return TransactionException::BadInstruction; + if (!!dynamic_cast(&_e)) + return TransactionException::BadJumpDestination; + if (!!dynamic_cast(&_e)) + return TransactionException::OutOfGas; + if (!!dynamic_cast(&_e)) + return TransactionException::StackUnderflow; + return TransactionException::Unknown; +} + Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig) { int field = 0; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 7dd28f7c6..85543a3fc 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -44,6 +44,46 @@ enum class CheckSignature Sender }; +enum class TransactionException +{ + None = 0, + Unknown, + InvalidSignature, + InvalidNonce, + NotEnoughCash, + OutOfGasBase, ///< Too little gas to pay for the base transaction cost. + BlockGasLimitReached, + BadInstruction, + BadJumpDestination, + OutOfGas, ///< Ran out of gas executing code of the transaction. + StackUnderflow +}; + +enum class CodeDeposit +{ + None = 0, + Failed, + Success +}; + +class VMException; + +TransactionException toTransactionException(VMException const& _e); + +/// Description of the result of executing a transaction. +struct ExecutionResult +{ + ExecutionResult() = default; + ExecutionResult(u256 _gasUsed, TransactionException _excepted, Address _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit): gasUsed(_gasUsed), excepted(_excepted), newAddress(_newAddress), output(_output.toBytes()), codeDeposit(_codeDeposit) {} + u256 gasUsed; + TransactionException excepted = TransactionException::Unknown; + Address newAddress; + bytes output; + CodeDeposit codeDeposit = CodeDeposit::None; +}; + +std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er); + /// Encodes a transaction, ready to be exported to or freshly imported from RLP. class Transaction { diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index d1968b7fa..54b698646 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -83,7 +83,7 @@ void Ethereum::connect(std::string const& _seedHost, unsigned short _port) { } -void Ethereum::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Ethereum::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { } @@ -92,7 +92,7 @@ bytes Ethereum::call(Secret _secret, u256 _value, Address _dest, bytes const& _d return bytes(); } -Address Ethereum::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Ethereum::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { return Address(); } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 517010b93..7ff685339 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -62,11 +62,11 @@ public: ~Ethereum(); /// Submits the given message-call transaction. - void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. void inject(bytesConstRef _rlp); diff --git a/libevm/VM.h b/libevm/VM.h index f2c773e4b..3efb3b119 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -56,7 +56,7 @@ public: virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - void require(u256 _n) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); } } + void require(u256 _n) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } u256 curPC() const { return m_curPC; } diff --git a/libevm/VMFace.h b/libevm/VMFace.h index f8c20feb1..7b99b5bfd 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -31,7 +31,7 @@ struct BreakPointHit: virtual VMException {}; struct BadInstruction: virtual VMException {}; struct BadJumpDestination: virtual VMException {}; struct OutOfGas: virtual VMException {}; -struct StackTooSmall: virtual VMException {}; +struct StackUnderflow: virtual VMException {}; /// EVM Virtual Machine interface class VMFace diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index 40f8a3500..1092906e4 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -16,6 +16,7 @@ */ #include "VMFactory.h" +#include #include "VM.h" #if ETH_EVMJIT diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 0a0611292..68f326bfd 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -47,9 +47,6 @@ unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const case PushData: case PushSub: return 1 + _addressLength; - case NoOptimizeBegin: - case NoOptimizeEnd: - return 0; default: break; } @@ -61,7 +58,7 @@ int AssemblyItem::deposit() const switch (m_type) { case Operation: - return instructionInfo((Instruction)(byte)m_data).ret - instructionInfo((Instruction)(byte)m_data).args; + return instructionInfo(instruction()).ret - instructionInfo(instruction()).args; case Push: case PushString: case PushTag: @@ -91,6 +88,48 @@ string AssemblyItem::getJumpTypeAsString() const } } +ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item) +{ + switch (_item.type()) + { + case Operation: + _out << " " << instructionInfo(_item.instruction()).name; + if (_item.instruction() == eth::Instruction::JUMP || _item.instruction() == eth::Instruction::JUMPI) + _out << "\t" << _item.getJumpTypeAsString(); + break; + case Push: + _out << " PUSH " << hex << _item.data(); + break; + case PushString: + _out << " PushString" << hex << (unsigned)_item.data(); + break; + case PushTag: + _out << " PushTag " << _item.data(); + break; + case Tag: + _out << " Tag " << _item.data(); + break; + case PushData: + _out << " PushData " << hex << (unsigned)_item.data(); + break; + case PushSub: + _out << " PushSub " << hex << h256(_item.data()).abridged(); + break; + case PushSubSize: + _out << " PushSubSize " << hex << h256(_item.data()).abridged(); + break; + case PushProgramSize: + _out << " PushProgramSize"; + break; + case UndefinedItem: + _out << " ???"; + break; + default: + BOOST_THROW_EXCEPTION(InvalidOpcode()); + } + return _out; +} + unsigned Assembly::bytesRequired() const { for (unsigned br = 1;; ++br) @@ -145,47 +184,7 @@ void Assembly::append(Assembly const& _a, int _deposit) ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) { for (AssemblyItem const& i: _i) - switch (i.type()) - { - case Operation: - _out << " " << instructionInfo((Instruction)(byte)i.data()).name; - break; - case Push: - _out << " PUSH" << i.data(); - break; - case PushString: - _out << " PUSH'[" << hex << (unsigned)i.data() << "]"; - break; - case PushTag: - _out << " PUSH[tag" << i.data() << "]"; - break; - case Tag: - _out << " tag" << i.data() << ": JUMPDEST"; - break; - case PushData: - _out << " PUSH*[" << hex << (unsigned)i.data() << "]"; - break; - case PushSub: - _out << " PUSHs[" << hex << h256(i.data()).abridged() << "]"; - break; - case PushSubSize: - _out << " PUSHss[" << hex << h256(i.data()).abridged() << "]"; - break; - case PushProgramSize: - _out << " PUSHSIZE"; - break; - case NoOptimizeBegin: - _out << " DoNotOptimze{{"; - break; - case NoOptimizeEnd: - _out << " DoNotOptimze}}"; - break; - case UndefinedItem: - _out << " ???"; - break; - default: - BOOST_THROW_EXCEPTION(InvalidOpcode()); - } + _out << i; return _out; } @@ -219,7 +218,7 @@ ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& switch (i.m_type) { case Operation: - _out << " " << instructionInfo((Instruction)(byte)i.m_data).name << "\t" << i.getJumpTypeAsString(); + _out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); break; case Push: _out << " PUSH " << i.m_data; @@ -245,12 +244,6 @@ ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& case PushData: _out << " PUSH [" << hex << (unsigned)i.m_data << "]"; break; - case NoOptimizeBegin: - _out << "DoNotOptimze{{"; - break; - case NoOptimizeEnd: - _out << "DoNotOptimze}}"; - break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); } @@ -384,7 +377,7 @@ Assembly& Assembly::optimise(bool _enable) { if (m[0].type() != Operation) return m.toVector(); - Instruction instr = Instruction(byte(m[0].data())); + Instruction instr = m[0].instruction(); if (Instruction::DUP1 <= instr && instr <= Instruction::DUP16) return {}; InstructionInfo info = instructionInfo(instr); @@ -424,12 +417,6 @@ Assembly& Assembly::optimise(bool _enable) count = 0; for (unsigned i = 0; i < m_items.size(); ++i) { - if (m_items[i].type() == NoOptimizeBegin) - { - while (i < m_items.size() && m_items[i].type() != NoOptimizeEnd) - ++i; - continue; - } for (auto const& r: rules) { auto vr = AssemblyItemsConstRef(&m_items).cropped(i, r.first.size()); @@ -459,13 +446,11 @@ Assembly& Assembly::optimise(bool _enable) } } } - if (m_items[i].type() == Operation && m_items[i].data() == (byte)Instruction::JUMP) + if (m_items[i].type() == Operation && m_items[i].instruction() == Instruction::JUMP) { bool o = false; while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag) { - if (m_items[i + 1].type() == NoOptimizeBegin) - break; m_items.erase(m_items.begin() + i + 1); o = true; } @@ -490,7 +475,7 @@ Assembly& Assembly::optimise(bool _enable) { auto t = *tags.begin(); unsigned i = t.second; - if (i && m_items[i - 1].type() == Operation && m_items[i - 1].data() == (byte)Instruction::JUMP) + if (i && m_items[i - 1].type() == Operation && m_items[i - 1].instruction() == Instruction::JUMP) while (i < m_items.size() && (m_items[i].type() != Tag || tags.count(m_items[i].data()))) { if (m_items[i].type() == Tag && tags.count(m_items[i].data())) @@ -599,9 +584,6 @@ bytes Assembly::assemble() const tagPos[(unsigned)i.m_data] = ret.size(); ret.push_back((byte)Instruction::JUMPDEST); break; - case NoOptimizeBegin: - case NoOptimizeEnd: - break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); } diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 242f6f1ff..280a2e81c 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "Exceptions.h" @@ -33,7 +34,7 @@ namespace dev namespace eth { -enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, PushProgramSize, Tag, PushData, NoOptimizeBegin, NoOptimizeEnd }; +enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, PushProgramSize, Tag, PushData }; class Assembly; @@ -48,11 +49,17 @@ public: AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} - AssemblyItem tag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(Tag, m_data); } - AssemblyItem pushTag() const { if (asserts(m_type == PushTag || m_type == Tag)) BOOST_THROW_EXCEPTION(Exception()); return AssemblyItem(PushTag, m_data); } + AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(Tag, m_data); } + AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(PushTag, m_data); } AssemblyItemType type() const { return m_type; } - u256 data() const { return m_data; } + u256 const& data() const { return m_data; } + /// @returns the instruction of this item (only valid if type() == Operation) + Instruction instruction() const { return Instruction(byte(m_data)); } + + /// @returns true iff the type and data of the items are equal. + bool operator==(AssemblyItem const& _other) const { return m_type == _other.m_type && m_data == _other.m_data; } + bool operator!=(AssemblyItem const& _other) const { return !operator==(_other); } /// @returns an upper bound for the number of bytes required by this item, assuming that /// the value of a jump tag takes @a _addressLength bytes. @@ -77,6 +84,7 @@ private: using AssemblyItems = std::vector; using AssemblyItemsConstRef = vector_ref; +std::ostream& operator<<(std::ostream& _out, AssemblyItem const& _item); std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i); inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { return operator<<(_out, AssemblyItemsConstRef(&_i)); } diff --git a/libevmcore/Instruction.h b/libevmcore/Instruction.h index 9eab92713..07c7b52fd 100644 --- a/libevmcore/Instruction.h +++ b/libevmcore/Instruction.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include namespace dev @@ -194,32 +195,28 @@ inline unsigned getSwapNumber(Instruction _inst) /// @returns the PUSH<_number> instruction inline Instruction pushInstruction(unsigned _number) { - if (asserts(1 <= _number && _number <= 32)) - BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid PUSH instruction requested.")); + assertThrow(1 <= _number && _number <= 32, InvalidOpcode, "Invalid PUSH instruction requested."); return Instruction(unsigned(Instruction::PUSH1) + _number - 1); } /// @returns the DUP<_number> instruction inline Instruction dupInstruction(unsigned _number) { - if (asserts(1 <= _number && _number <= 16)) - BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid DUP instruction requested.")); + assertThrow(1 <= _number && _number <= 16, InvalidOpcode, "Invalid DUP instruction requested."); return Instruction(unsigned(Instruction::DUP1) + _number - 1); } /// @returns the SWAP<_number> instruction inline Instruction swapInstruction(unsigned _number) { - if (asserts(1 <= _number && _number <= 16)) - BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid SWAP instruction requested.")); + assertThrow(1 <= _number && _number <= 16, InvalidOpcode, "Invalid SWAP instruction requested."); return Instruction(unsigned(Instruction::SWAP1) + _number - 1); } /// @returns the LOG<_number> instruction inline Instruction logInstruction(unsigned _number) { - if (asserts(_number <= 4)) - BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid LOG instruction requested.")); + assertThrow(_number <= 4, InvalidOpcode, "Invalid LOG instruction requested."); return Instruction(unsigned(Instruction::LOG0) + _number); } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 19df5ee2e..78a8232fd 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -176,14 +177,14 @@ unsigned Host::protocolVersion() const void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io, bi::tcp::endpoint _endpoint) { - /// Get or create Peer shared_ptr p; - p = m_peers[_id]; - if (!p) + if (!m_peers.count(_id)) { - p.reset(new Peer()); // this maybe redundant + p.reset(new Peer()); p->id = _id; } + else + p = m_peers[_id]; p->m_lastDisconnect = NoDisconnect; if (p->isOffline()) p->m_lastConnected = std::chrono::system_clock::now(); @@ -276,9 +277,9 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) connect(p); } } - else if (_e == NodeEntryRemoved) + else if (_e == NodeEntryDropped) { - clog(NetNote) << "p2p.host.nodeTable.events.nodeEntryRemoved " << _n; + clog(NetNote) << "p2p.host.nodeTable.events.NodeEntryDropped " << _n; RecursiveGuard l(x_sessions); m_peers.erase(_n); diff --git a/libp2p/Host.h b/libp2p/Host.h index 219316c58..ff27807a7 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -113,6 +113,7 @@ public: CapDescs caps() const { CapDescs ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; } template std::shared_ptr cap() const { try { return std::static_pointer_cast(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } } + /// Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity. void addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort); /// Set ideal number of peers. diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index d1e97fac6..bdd1f0108 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include "Common.h" diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 08bb0624a..ccfbeaba4 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -73,21 +73,17 @@ shared_ptr NodeTable::addNode(Node const& _node) // ping address if nodeid is empty if (!_node.id) { + m_pubkDiscoverPings[m_node.endpoint.udp.address()] = std::chrono::steady_clock::now(); PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); p.sign(m_secret); m_socketPointer->send(p); - shared_ptr n; - return move(n); + return move(shared_ptr()); } - Guard l(x_nodes); - if (m_nodes.count(_node.id)) { -// // SECURITY: remove this in beta - it's only for lazy connections and presents an easy attack vector. -// if (m_server->m_peers.count(id) && isPrivateAddress(m_server->m_peers.at(id)->address.address()) && ep.port() != 0) -// // Update address if the node if we now have a public IP for it. -// m_server->m_peers[id]->address = ep; - return m_nodes[_node.id]; + Guard ln(x_nodes); + if (m_nodes.count(_node.id)) + return m_nodes[_node.id]; } shared_ptr ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp))); @@ -95,12 +91,6 @@ shared_ptr NodeTable::addNode(Node const& _node) PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); p.sign(m_secret); m_socketPointer->send(p); - - // TODO p2p: rename to p2p.nodes.pending, add p2p.nodes.add event (when pong is received) - clog(NodeTableUpdate) << "p2p.nodes.add " << _node.id.abridged(); - if (m_nodeEventHandler) - m_nodeEventHandler->appendEvent(_node.id, NodeEntryAdded); - return ret; } @@ -135,7 +125,6 @@ list NodeTable::snapshot() const Node NodeTable::node(NodeId const& _id) { - // TODO p2p: eloquent copy operator Guard l(x_nodes); if (m_nodes.count(_id)) { @@ -149,7 +138,7 @@ Node NodeTable::node(NodeId const& _id) shared_ptr NodeTable::nodeEntry(NodeId _id) { Guard l(x_nodes); - return m_nodes.count(_id) ? move(m_nodes[_id]) : move(shared_ptr()); + return m_nodes.count(_id) ? m_nodes[_id] : shared_ptr(); } void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr>> _tried) @@ -191,7 +180,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr _leastSeen, shared_ptr _n m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); if (m_evictions.size() == 1) doCheckEvictions(boost::system::error_code()); - - m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); } ping(_leastSeen.get()); } @@ -307,23 +294,26 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en { if (_pubk == m_node.address()) return; - - clog(NodeTableConnect) << "Noting active node:" << _pubk.abridged() << _endpoint.address().to_string() << ":" << _endpoint.port(); - - shared_ptr node(addNode(_pubk, _endpoint, bi::tcp::endpoint(_endpoint.address(), _endpoint.port()))); - // TODO p2p: old bug (maybe gone now) sometimes node is nullptr here - if (!!node) + shared_ptr node = nodeEntry(_pubk); + if (!!node && !node->pending) { + clog(NodeTableConnect) << "Noting active node:" << _pubk.abridged() << _endpoint.address().to_string() << ":" << _endpoint.port(); + + // update udp endpoint + node->endpoint.udp.address(_endpoint.address()); + node->endpoint.udp.port(_endpoint.port()); + shared_ptr contested; { Guard l(x_state); NodeBucket& s = bucket_UNSAFE(node.get()); - s.nodes.remove_if([&node](weak_ptr n) + bool removed = false; + s.nodes.remove_if([&node, &removed](weak_ptr const& n) { if (n.lock() == node) - return true; - return false; + removed = true; + return removed; }); if (s.nodes.size() >= s_bucketSize) @@ -335,12 +325,18 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en s.nodes.pop_front(); s.nodes.push_back(node); s.touch(); + + if (!removed) + m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); } } else { s.nodes.push_back(node); s.touch(); + + if (!removed) + m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded); } } @@ -351,19 +347,17 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en void NodeTable::dropNode(shared_ptr _n) { + // remove from nodetable { Guard l(x_state); NodeBucket& s = bucket_UNSAFE(_n.get()); s.nodes.remove_if([&_n](weak_ptr n) { return n.lock() == _n; }); } - { - Guard l(x_nodes); - m_nodes.erase(_n->id); - } + // notify host clog(NodeTableUpdate) << "p2p.nodes.drop " << _n->id.abridged(); if (m_nodeEventHandler) - m_nodeEventHandler->appendEvent(_n->id, NodeEntryRemoved); + m_nodeEventHandler->appendEvent(_n->id, NodeEntryDropped); } NodeTable::NodeBucket& NodeTable::bucket_UNSAFE(NodeEntry const* _n) @@ -401,9 +395,6 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes } unsigned packetType = signedBytes[0]; - if (packetType && packetType < 4) - noteActiveNode(nodeid, _from); - bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1)); RLP rlp(rlpBytes); try { @@ -411,37 +402,49 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { case Pong::type: { -// clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); Pong in = Pong::fromBytesConstRef(_from, rlpBytes); // whenever a pong is received, check if it's in m_evictions Guard le(x_evictions); + bool evictionEntry = false; for (auto it = m_evictions.begin(); it != m_evictions.end(); it++) if (it->first.first == nodeid && it->first.second > std::chrono::steady_clock::now()) { + evictionEntry = true; if (auto n = nodeEntry(it->second)) dropNode(n); - if (auto n = node(it->first.first)) - addNode(n); + if (auto n = nodeEntry(it->first.first)) + if (m_nodeEventHandler && n->pending) + n->pending = false; it = m_evictions.erase(it); } + + // if not, check if it's known/pending or a pubk discovery ping + if (!evictionEntry) + { + if (auto n = nodeEntry(nodeid)) + n->pending = false; + } + else if (m_pubkDiscoverPings.count(_from.address())) + m_pubkDiscoverPings.erase(_from.address()); + else + return; // unsolicited pong; don't note node as active + break; } case Neighbours::type: { Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); -// clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbours from " << _from.address().to_string() << ":" << _from.port(); for (auto n: in.nodes) - noteActiveNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port)); + addNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port), bi::tcp::endpoint(bi::address::from_string(n.ipAddress), n.port)); break; } case FindNode::type: { -// clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); vector> nearest = nearestNodeEntries(in.target); @@ -450,6 +453,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { Neighbours out(_from, nearest, offset, nlimit); out.sign(m_secret); + if (out.data.size() > 1280) + clog(NetWarn) << "Sending truncated datagram, size: " << out.data.size(); m_socketPointer->send(out); } break; @@ -457,8 +462,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case PingNode::type: { -// clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes); + addNode(nodeid, _from, bi::tcp::endpoint(bi::address::from_string(in.ipAddress), in.port)); Pong p(_from); p.echo = sha3(rlpBytes); @@ -471,6 +476,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableWarn) << "Invalid Message, " << hex << packetType << ", received from " << _from.address().to_string() << ":" << dec << _from.port(); return; } + + noteActiveNode(nodeid, _from); } catch (...) { diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 9717b77a3..a97326501 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -44,11 +44,13 @@ struct NodeEntry: public Node NodeEntry(Node _src, Public _pubk, bi::udp::endpoint _udp); unsigned const distance; ///< Node's distance (xor of _src as integer). + + bool pending = true; ///< Node will be ignored until Pong is received }; enum NodeTableEventType { NodeEntryAdded, - NodeEntryRemoved + NodeEntryDropped }; class NodeTable; class NodeTableEventHandler @@ -101,11 +103,10 @@ inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) * NodeTable accepts a port for UDP and will listen to the port on all available * interfaces. * + * * [Integration] - * @todo restore nodes: affects refreshbuckets * @todo TCP endpoints - * @todo makeRequired: don't try to evict node if node isRequired. - * @todo makeRequired: exclude bucket from refresh if we have node as peer. + * @todo GC uniform 1/32 entires at 112500ms interval * * [Optimization] * @todo serialize evictions per-bucket @@ -140,16 +141,16 @@ public: /// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable. static unsigned distance(NodeId const& _a, NodeId const& _b) { u512 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } - /// Set event handler for NodeEntryAdded and NodeEntryRemoved events. + /// Set event handler for NodeEntryAdded and NodeEntryDropped events. void setEventHandler(NodeTableEventHandler* _handler) { m_nodeEventHandler.reset(_handler); } - /// Called by implementation which provided handler to process NodeEntryAdded/NodeEntryRemoved events. Events are coalesced by type whereby old events are ignored. + /// Called by implementation which provided handler to process NodeEntryAdded/NodeEntryDropped events. Events are coalesced by type whereby old events are ignored. void processEvents(); - /// Add node. Node will be pinged if it's not already known. + /// Add node. Node will be pinged and empty shared_ptr is returned if NodeId is uknown. std::shared_ptr addNode(Public const& _pubk, bi::udp::endpoint const& _udp, bi::tcp::endpoint const& _tcp); - /// Add node. Node will be pinged if it's not already known. + /// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen. std::shared_ptr addNode(Node const& _node); /// To be called when node table is empty. Runs node discovery with m_node.id as the target in order to populate node-table. @@ -225,7 +226,7 @@ private: /// Asynchronously drops _leastSeen node if it doesn't reply and adds _new node, otherwise _new node is thrown away. void evict(std::shared_ptr _leastSeen, std::shared_ptr _new); - /// Called whenever activity is received from an unknown node in order to maintain node table. + /// Called whenever activity is received from a node in order to maintain node table. void noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint); /// Used to drop node when timeout occurs or when evict() result is to keep previous node. @@ -265,6 +266,9 @@ private: Mutex x_evictions; ///< LOCK x_nodes first if both x_nodes and x_evictions locks are required. std::deque m_evictions; ///< Eviction timeouts. + + Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required. + std::map m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk. ba::io_service& m_io; ///< Used by bucket refresh timer. std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. diff --git a/libp2p/RLPxFrameIO.cpp b/libp2p/RLPxFrameIO.cpp index cb768bfeb..ac1a27bed 100644 --- a/libp2p/RLPxFrameIO.cpp +++ b/libp2p/RLPxFrameIO.cpp @@ -19,11 +19,13 @@ * @date 2015 */ +#include "RLPxFrameIO.h" +#include #include "Host.h" #include "Session.h" #include "Peer.h" #include "RLPxHandshake.h" -#include "RLPxFrameIO.h" + using namespace std; using namespace dev; using namespace dev::p2p; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index f5f6a3f38..335b9a880 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -553,17 +553,24 @@ private: class EventDefinition: public Declaration, public VariableScope, public Documented { public: - EventDefinition(SourceLocation const& _location, - ASTPointer const& _name, - ASTPointer const& _documentation, - ASTPointer const& _parameters): - Declaration(_location, _name), Documented(_documentation), m_parameters(_parameters) {} + EventDefinition( + SourceLocation const& _location, + ASTPointer const& _name, + ASTPointer const& _documentation, + ASTPointer const& _parameters, + bool _anonymous = false + ): + Declaration(_location, _name), + Documented(_documentation), + m_parameters(_parameters), + m_anonymous(_anonymous){} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; std::vector> const& getParameters() const { return m_parameters->getParameters(); } ParameterList const& getParameterList() const { return *m_parameters; } + bool isAnonymous() const { return m_anonymous; } virtual TypePointer getType(ContractDefinition const* = nullptr) const override { @@ -574,6 +581,7 @@ public: private: ASTPointer m_parameters; + bool m_anonymous = false; }; /** diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a0a688bbd..61b17f663 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -542,8 +542,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) appendTypeConversion(*arguments[arg - 1]->getType(), *function.getParameterTypes()[arg - 1], true); } - m_context << u256(h256::Arith(dev::sha3(function.getCanonicalSignature(event.getName())))); - ++numIndexed; + if (!event.isAnonymous()) + { + m_context << u256(h256::Arith(dev::sha3(function.getCanonicalSignature(event.getName())))); + ++numIndexed; + } solAssert(numIndexed <= 4, "Too many indexed arguments."); // Copy all non-indexed arguments to memory (data) m_context << u256(0); diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 99a7db96e..406d1e24a 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -70,6 +70,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinitio Json::Value event; event["type"] = "event"; event["name"] = it->getName(); + event["anonymous"] = it->isAnonymous(); Json::Value params(Json::arrayValue); for (auto const& p: it->getParameters()) { diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 459a34bd0..393d2734e 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -394,9 +394,15 @@ ASTPointer Parser::parseEventDefinition() parameters = parseParameterList(true, true); else parameters = createEmptyParameterList(); + bool anonymous = false; + if (m_scanner->getCurrentToken() == Token::Anonymous) + { + anonymous = true; + m_scanner->next(); + } nodeFactory.markEndPosition(); expectToken(Token::Semicolon); - return nodeFactory.createNode(name, docstring, parameters); + return nodeFactory.createNode(name, docstring, parameters, anonymous); } ASTPointer Parser::parseModifierInvocation() diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 2d8a49fcd..b2951e939 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -145,6 +145,7 @@ namespace solidity K(Break, "break", 0) \ K(Case, "case", 0) \ K(Const, "constant", 0) \ + K(Anonymous, "anonymous", 0) \ K(Continue, "continue", 0) \ K(Contract, "contract", 0) \ K(Default, "default", 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 04f86b922..4b5dddacd 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -536,14 +536,8 @@ bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - if (_convertTo.getCategory() == Category::Integer) - { - IntegerType const& convertTo = dynamic_cast(_convertTo); - if (m_bytes * 8 <= convertTo.getNumBits()) - return true; - } - - return _convertTo.getCategory() == Category::Contract || + return _convertTo.getCategory() == Category::Integer || + _convertTo.getCategory() == Category::Contract || _convertTo.getCategory() == getCategory(); } diff --git a/libsolidity/Utils.h b/libsolidity/Utils.h index 1411f66b4..05c5fa6f0 100644 --- a/libsolidity/Utils.h +++ b/libsolidity/Utils.h @@ -22,34 +22,9 @@ #pragma once -#include -#include - -namespace dev -{ -namespace solidity -{ +#include /// Assertion that throws an InternalCompilerError containing the given description if it is not met. #define solAssert(CONDITION, DESCRIPTION) \ - ::dev::solidity::solAssertAux(CONDITION, DESCRIPTION, __LINE__, __FILE__, ETH_FUNC) - -inline void solAssertAux(bool _condition, std::string const& _errorDescription, unsigned _line, - char const* _file, char const* _function) -{ - if (!_condition) - ::boost::throw_exception( InternalCompilerError() - << errinfo_comment(_errorDescription) - << ::boost::throw_function(_function) - << ::boost::throw_file(_file) - << ::boost::throw_line(_line)); -} - -inline void solAssertAux(void const* _pointer, std::string const& _errorDescription, unsigned _line, - char const* _file, char const* _function) -{ - solAssertAux(_pointer != nullptr, _errorDescription, _line, _file, _function); -} + assertThrow(CONDITION, ::dev::solidity::InternalCompilerError, DESCRIPTION) -} -} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 0434d1e76..76b422a18 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -953,9 +953,9 @@ void WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool _t if (_toProxy) m_accounts->queueTransaction(_t); else if (_t.to) - client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); + client()->submitTransaction(m_accounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); else - client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice); + client()->submitTransaction(m_accounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice); } void WebThreeStubServerBase::setAccounts(const vector& _accounts) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index be269ad5b..739eb8d8c 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -439,13 +439,13 @@ void ClientModel::debugRecord(unsigned _index) Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction) { - Address newAddress = m_client->transact(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice); + Address newAddress = m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice); return newAddress; } void ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) { - m_client->transact(_tr.sender, _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); + m_client->submitTransaction(_tr.sender, _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); } RecordLogEntry* ClientModel::lastBlock() const @@ -529,7 +529,7 @@ void ClientModel::onNewTransaction() { function = funcDef->name(); ContractCallDataEncoder encoder; - QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue); + QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.result.output); returned += "("; returned += returnValues.join(", "); returned += ")"; diff --git a/mix/MachineStates.h b/mix/MachineStates.h index e949db8b2..f0346ba1e 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -29,6 +29,7 @@ along with cpp-ethereum. If not, see . #include #include #include +#include #include namespace dev @@ -74,7 +75,7 @@ namespace mix std::vector machineStates; std::vector transactionData; std::vector executionCode; - bytes returnValue; + dev::eth::ExecutionResult result; dev::Address address; dev::Address sender; dev::Address contractAddress; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 3df6d7c2e..f61269005 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -176,7 +176,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c execution.finalize(); ExecutionResult d; - d.returnValue = execution.out().toVector(); + d.result = execution.executionResult(); d.machineStates = machineStates; d.executionCode = std::move(codes); d.transactionData = std::move(data); @@ -192,7 +192,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c // execute on a state if (!_call) { - _state.execute(lastHashes, rlp, nullptr, true); + _state.execute(lastHashes, rlp); if (_t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); // collect watches @@ -254,7 +254,7 @@ State MixClient::asOf(int _block) const return State(m_stateDB, bc(), bc().numberHash(_block)); } -void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); @@ -262,7 +262,7 @@ void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const executeTransaction(t, m_state, false); } -Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); @@ -283,7 +283,7 @@ void MixClient::flushTransactions() { } -bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) +dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) { u256 n; State temp; @@ -296,7 +296,23 @@ bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _ bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state executeTransaction(t, temp, true); - return lastExecution().returnValue; + return lastExecution().result; +} + +dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) +{ + u256 n; + State temp; + { + ReadGuard lr(x_state); + temp = asOf(_blockNumber); + n = temp.transactionsFrom(toAddress(_secret)); + } + Transaction t(_value, _gasPrice, _gas, _data, n, _secret); + bytes rlp = t.rlp(); + WriteGuard lw(x_state); //TODO: lock is required only for last execution state + executeTransaction(t, temp, true); + return lastExecution().result; } u256 MixClient::balanceAt(Address _a, int _block) const diff --git a/mix/MixClient.h b/mix/MixClient.h index 4c08dd35c..37b2bb5d2 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -48,11 +48,12 @@ public: ExecutionResult execution(unsigned _index) const; //dev::eth::Interface - void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; - Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override; + void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; + Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override; void inject(bytesConstRef _rlp) override; void flushTransactions() override; - bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) override; + dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) override; + dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, int _blockNumber) override; u256 balanceAt(Address _a, int _block) const override; u256 countAt(Address _a, int _block) const override; u256 stateAt(Address _a, u256 _l, int _block) const override; diff --git a/mix/qml/html/cm/anyword-hint.js b/mix/qml/html/cm/anyword-hint.js new file mode 100644 index 000000000..c76044212 --- /dev/null +++ b/mix/qml/html/cm/anyword-hint.js @@ -0,0 +1,62 @@ +(function() { + "use strict"; + + var WORD = /[\w$]+/, RANGE = 500; + + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { + var word = options && options.word || WORD; + var range = options && options.range || RANGE; + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); + var start = cur.ch, end = start; + while (end < curLine.length && word.test(curLine.charAt(end))) ++end; + while (start && word.test(curLine.charAt(start - 1))) --start; + var curWord = start != end && curLine.slice(start, end); + + var list = [], seen = {}; + var re = new RegExp(word.source, "g"); + for (var dir = -1; dir <= 1; dir += 2) { + var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; + for (; line != endLine; line += dir) { + var text = editor.getLine(line), m; + while (m = re.exec(text)) { + if (line == cur.line && m[0] === curWord) continue; + if ((!curWord || m[0].lastIndexOf(curWord, 0) === 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { + seen[m[0]] = true; + list.push({ text: m[0] }); + } + } + } + } + + if (editor.getMode().name === "solidity") + { + list = addSolToken(curWord, list, solCurrency(), solCurrency); + list = addSolToken(curWord, list, solKeywords(), solKeywords); + list = addSolToken(curWord, list, solStdContract(), solStdContract); + list = addSolToken(curWord, list, solTime(), solTime); + list = addSolToken(curWord, list, solTypes(), solTypes); + list = addSolToken(curWord, list, solMisc(), solMisc); + } + + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; + }); +})(); + + +function addSolToken(curWord, list, tokens, type) +{ + for (var key in tokens) + { + if (curWord === false || key.indexOf(curWord, 0) === 0) + { + var token = { text: key }; + token.render = function(elt, data, cur) + { + elt.className = elt.className + " " + type.name.toLowerCase(); + elt.appendChild(document.createTextNode(cur.displayText || cur.text)); + } + list.push(token); + } + } + return list; +} diff --git a/mix/qml/html/cm/closebrackets.js b/mix/qml/html/cm/closebrackets.js new file mode 100644 index 000000000..2bbc6f2a3 --- /dev/null +++ b/mix/qml/html/cm/closebrackets.js @@ -0,0 +1,184 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var defaults = { + pairs: "()[]{}''\"\"", + triples: "", + explode: "[]{}" + }; + + var Pos = CodeMirror.Pos; + + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.removeKeyMap(keyMap); + cm.state.closeBrackets = null; + } + if (val) { + cm.state.closeBrackets = val; + cm.addKeyMap(keyMap); + } + }); + + function getOption(conf, name) { + if (name == "pairs" && typeof conf == "string") return conf; + if (typeof conf == "object" && conf[name] != null) return conf[name]; + return defaults[name]; + } + + var bind = defaults.pairs + "`"; + var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; + for (var i = 0; i < bind.length; i++) + keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i)); + + function handler(ch) { + return function(cm) { return handleChar(cm, ch); }; + } + + function getConfig(cm) { + var deflt = cm.state.closeBrackets; + if (!deflt) return null; + var mode = cm.getModeAt(cm.getCursor()); + return mode.closeBrackets || deflt; + } + + function handleBackspace(cm) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + for (var i = ranges.length - 1; i >= 0; i--) { + var cur = ranges[i].head; + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)); + } + } + + function handleEnter(cm) { + var conf = getConfig(cm); + var explode = conf && getOption(conf, "explode"); + if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; + + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + cm.operation(function() { + cm.replaceSelection("\n\n", null); + cm.execCommand("goCharLeft"); + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var line = ranges[i].head.line; + cm.indentLine(line, null, true); + cm.indentLine(line + 1, null, true); + } + }); + } + + function handleChar(cm, ch) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var pos = pairs.indexOf(ch); + if (pos == -1) return CodeMirror.Pass; + var triples = getOption(conf, "triples"); + + var identical = pairs.charAt(pos + 1) == ch; + var ranges = cm.listSelections(); + var opening = pos % 2 == 0; + + var type, next; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], cur = range.head, curType; + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); + if (opening && !range.empty()) { + curType = "surround"; + } else if ((identical || !opening) && next == ch) { + if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) + curType = "skipThree"; + else + curType = "skip"; + } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch && + (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) { + curType = "addFour"; + } else if (identical) { + if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both"; + else return CodeMirror.Pass; + } else if (opening && (cm.getLine(cur.line).length == cur.ch || + isClosingBracket(next, pairs) || + /\s/.test(next))) { + curType = "both"; + } else { + return CodeMirror.Pass; + } + if (!type) type = curType; + else if (type != curType) return CodeMirror.Pass; + } + + var left = pos % 2 ? pairs.charAt(pos - 1) : ch; + var right = pos % 2 ? ch : pairs.charAt(pos + 1); + cm.operation(function() { + if (type == "skip") { + cm.execCommand("goCharRight"); + } else if (type == "skipThree") { + for (var i = 0; i < 3; i++) + cm.execCommand("goCharRight"); + } else if (type == "surround") { + var sels = cm.getSelections(); + for (var i = 0; i < sels.length; i++) + sels[i] = left + sels[i] + right; + cm.replaceSelections(sels, "around"); + } else if (type == "both") { + cm.replaceSelection(left + right, null); + cm.execCommand("goCharLeft"); + } else if (type == "addFour") { + cm.replaceSelection(left + left + left + left, "before"); + cm.execCommand("goCharRight"); + } + }); + } + + function isClosingBracket(ch, pairs) { + var pos = pairs.lastIndexOf(ch); + return pos > -1 && pos % 2 == 1; + } + + function charsAround(cm, pos) { + var str = cm.getRange(Pos(pos.line, pos.ch - 1), + Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + + // Project the token type that will exists after the given char is + // typed, and use it to determine whether it would cause the start + // of a string token. + function enteringString(cm, pos, ch) { + var line = cm.getLine(pos.line); + var token = cm.getTokenAt(pos); + if (/\bstring2?\b/.test(token.type)) return false; + var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); + stream.pos = stream.start = token.start; + for (;;) { + var type1 = cm.getMode().token(stream, token.state); + if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1); + stream.start = stream.pos; + } + } +}); diff --git a/mix/qml/html/cm/javascript-hint.js b/mix/qml/html/cm/javascript-hint.js new file mode 100644 index 000000000..7bcbf4a05 --- /dev/null +++ b/mix/qml/html/cm/javascript-hint.js @@ -0,0 +1,146 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var Pos = CodeMirror.Pos; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, keywords, getToken, options) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = {start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null}; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + var tprop = token; + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + return {list: getCompletions(token, context, keywords, options), + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; + } + + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}, + options); + }; + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + function coffeescriptHint(editor, options) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); + + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + + "toUpperCase toLowerCase split concat match replace search").split(" "); + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + var funcProps = "prototype apply call bind".split(" "); + var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + + "if in instanceof new null return switch throw true try typeof var void while with").split(" "); + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string, global = options && options.globalScope || window; + function maybeAdd(str) { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + for (var name in obj) maybeAdd(name); + } + + if (context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof global.jQuery == 'function')) + base = global.jQuery(); + else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the global object and any local scope + // (reading into JS mode internals to get at the local and global variables) + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(global); + forEach(keywords, maybeAdd); + } + return found; + } +}); diff --git a/mix/qml/html/cm/show-hint.css b/mix/qml/html/cm/show-hint.css new file mode 100644 index 000000000..663ac1223 --- /dev/null +++ b/mix/qml/html/cm/show-hint.css @@ -0,0 +1,63 @@ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + border: 1px solid silver; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; + width: 22em; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + max-width: 30em; + overflow: hidden; + white-space: pre; + color: black; + cursor: pointer; +} + +.CodeMirror-hint-active { + background: #4a90e2; + color: white; +} + +.solcurrency { + color: red; +} + +.solkeywords { + color: brown; +} + +.solstdcontract { + color: blue; +} + +.soltime { + color: green; +} + +.soltypes { + color: orange; +} + +.solMisc { + color: grey; +} diff --git a/mix/qml/html/cm/show-hint.js b/mix/qml/html/cm/show-hint.js new file mode 100644 index 000000000..e810cde48 --- /dev/null +++ b/mix/qml/html/cm/show-hint.js @@ -0,0 +1,343 @@ +(function() { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + CodeMirror.showHint = function(cm, getHints, options) { + // We want a single cursor position. + if (cm.somethingSelected()) return; + if (getHints == null) { + if (options && options.async) return; + else getHints = CodeMirror.hint.auto; + } + + if (cm.state.completionActive) cm.state.completionActive.close(); + + var completion = cm.state.completionActive = new Completion(cm, getHints, options || {}); + CodeMirror.signal(cm, "startCompletion", cm); + if (completion.options.async) + getHints(cm, function(hints) { completion.showHints(hints); }, completion.options); + else + return completion.showHints(getHints(cm, completion.options)); + }; + + function Completion(cm, getHints, options) { + this.cm = cm; + this.getHints = getHints; + this.options = options; + this.widget = this.onClose = null; + } + + Completion.prototype = { + close: function() { + if (!this.active()) return; + this.cm.state.completionActive = null; + + if (this.widget) this.widget.close(); + if (this.onClose) this.onClose(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function() { + return this.cm.state.completionActive == this; + }, + + pick: function(data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from||data.from, completion.to||data.to); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + showHints: function(data) { + if (!data || !data.list.length || !this.active()) return this.close(); + + if (this.options.completeSingle != false && data.list.length == 1) + this.pick(data, 0); + else + this.showWidget(data); + }, + + showWidget: function(data) { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + + var debounce = 0, completion = this, finished; + var closeOn = this.options.closeCharacters || /[\s()\[\]{};:>,]/; + var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length; + + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { + return setTimeout(fn, 1000/60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + function done() { + if (finished) return; + finished = true; + completion.close(); + completion.cm.off("cursorActivity", activity); + if (data) CodeMirror.signal(data, "close"); + } + + function update() { + if (finished) return; + CodeMirror.signal(data, "update"); + if (completion.options.async) + completion.getHints(completion.cm, finishUpdate, completion.options); + else + finishUpdate(completion.getHints(completion.cm, completion.options)); + } + function finishUpdate(data_) { + data = data_; + if (finished) return; + if (!data || !data.list.length) return done(); + if (completion.widget) completion.widget.close(); + completion.widget = new Widget(completion, data); + } + + function clearDebounce() { + if (debounce) { + cancelAnimationFrame(debounce); + debounce = 0; + } + } + + function activity() { + clearDebounce(); + var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line); + if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch || + pos.ch < startPos.ch || completion.cm.somethingSelected() || + (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) { + completion.close(); + } else { + debounce = requestAnimationFrame(update); + if (completion.widget) completion.widget.close(); + } + } + this.cm.on("cursorActivity", activity); + this.onClose = done; + } + }; + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(options, handle) { + var baseMap = { + Up: function() {handle.moveFocus(-1);}, + Down: function() {handle.moveFocus(1);}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, + Home: function() {handle.setFocus(0);}, + End: function() {handle.setFocus(handle.length - 1);}, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + var ourMap = options.customKeys ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function(cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (options.customKeys) + for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) + addBinding(key, options.customKeys[key]); + if (options.extraKeys) + for (var key in options.extraKeys) if (options.extraKeys.hasOwnProperty(key)) + addBinding(key, options.extraKeys[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + var widget = this, cm = completion.cm, options = completion.options; + + var hints = this.hints = document.createElement("ul"); + hints.className = "CodeMirror-hints"; + this.selectedHint = options.getDefaultSelection ? options.getDefaultSelection(cm,options,data) : 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var pos = cm.cursorCoords(options.alignWithWord !== false ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + hints.style.left = left + "px"; + hints.style.top = top + "px"; + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + (options.container || document.body).appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = box.top - (pos.bottom - pos.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = curTop - height) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.left - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX) + "px"; + } + + cm.addKeyMap(this.keyMap = buildKeyMap(options, { + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function(n) { widget.changeActive(n); }, + menuSize: function() { return widget.screenAmount(); }, + length: completions.length, + close: function() { completion.close(); }, + pick: function() { widget.pick(); }, + data: data + })); + + if (options.closeOnUnfocus !== false) { + var closingOnBlur; + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); + } + + var startScroll = cm.getScrollInfo(); + cm.on("scroll", this.onScroll = function() { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} + }); + + CodeMirror.on(hints, "click", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function() { + setTimeout(function(){cm.focus();}, 20); + }); + + CodeMirror.signal(data, "select", completions[0], hints.firstChild); + return true; + } + + Widget.prototype = { + close: function() { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus !== false) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + pick: function() { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + screenAmount: function() { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + CodeMirror.registerHelper("hint", "auto", function(cm, options) { + var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; + if (helpers.length) { + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, options); + if (cur && cur.list.length) return cur; + } + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + if (words) return CodeMirror.hint.fromList(cm, {words: words}); + } else if (CodeMirror.hint.anyword) { + return CodeMirror.hint.anyword(cm, options); + } + }); + + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, token.string.length) == token.string) + found.push(word); + } + + if (found.length) return { + list: found, + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end) + }; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; +})(); diff --git a/mix/qml/html/cm/solidity.js b/mix/qml/html/cm/solidity.js index 6e0a726ef..e1cfeefbb 100644 --- a/mix/qml/html/cm/solidity.js +++ b/mix/qml/html/cm/solidity.js @@ -12,32 +12,10 @@ CodeMirror.defineMode("solidity", function(config) { var indentUnit = config.indentUnit; - var keywords = { "address":true, "indexed":true, "event":true, "delete":true, "break":true, "case":true, "constant":true, "continue":true, "contract":true, "default":true, - "do":true, "else":true, "is":true, "for":true, "function":true, "if":true, "import":true, "mapping":true, "new":true, - "public":true, "private":true, "return":true, "returns":true, "struct":true, "switch":true, "var":true, "while":true, - "int":true, "uint":true, "hash":true, "bool":true, "string":true, "string0":true, "text":true, "real":true, - "ureal":true, - - "owned":true, - "onlyowner":true, - "named":true, - "mortal":true, - "coin":true, - }; - - for (var i = 1; i <= 32; i++) { - keywords["int" + i * 8] = true; - keywords["uint" + i * 8] = true; - keywords["hash" + i * 8] = true; - keywords["string" + i] = true; - }; - - var atoms = { - "true":true, "false":true, "null":true, - "Config":true, - "NameReg":true, - "CoinReg":true, - }; + var types = solTypes(); + var stdContract = solStdContract(); + var keywords = solKeywords(); + var atoms = solMisc(); var isOperatorChar = /[+\-*&^%:=<>!|\/]/; @@ -84,6 +62,8 @@ CodeMirror.defineMode("solidity", function(config) { return "keyword"; } if (atoms.propertyIsEnumerable(cur)) return "atom"; + if (types.propertyIsEnumerable(cur)) return "variable-2"; + if (stdContract.propertyIsEnumerable(cur)) return "variable-3"; return "variable"; } diff --git a/mix/qml/html/cm/solidityToken.js b/mix/qml/html/cm/solidityToken.js new file mode 100644 index 000000000..68bd203c7 --- /dev/null +++ b/mix/qml/html/cm/solidityToken.js @@ -0,0 +1,29 @@ +function solCurrency() +{ + return { "wei": true, "szabo": true, "finney": true, "ether": true }; +} + +function solKeywords() +{ + return { "break": true, "case": true, "constant": true, "continue": true, "contract": true, "default": true, "do": true, "else": true, "event": true, "external": true, "is": true, "indexed": true, "for": true, "function": true, "if": true, "import": true, "mapping": true, "modifier": true, "new": true, "public": true, "private": true, "internal": true, "return": true, "returns": true, "struct": true, "switch": true, "var": true, "while": true, "enum": true }; +} + +function solStdContract() +{ + return { "Config": true, "NameReg": true, "CoinReg": true, "owned": true, "onlyowner": true, "named": true, "mortal": true, "coin": true }; +} + +function solTime() +{ + return { "seconds": true, "minutes": true, "hours": true, "days": true, "weeks": true, "years": true, "after": true }; +} + +function solTypes() +{ + return { "int": true, "int8": true, "int16": true, "int24": true, "int32": true, "int40": true, "int48": true, "int56": true, "int64": true, "int72": true, "int80": true, "int88": true, "int96": true, "int104": true, "int112": true, "int120": true, "int128": true, "int136": true, "int144": true, "int152": true, "int160": true, "int168": true, "int178": true, "int184": true, "int192": true, "int200": true, "int208": true, "int216": true, "int224": true, "int232": true, "int240": true, "int248": true, "int256": true, "uint": true, "uint8": true, "uint16": true, "uint24": true, "uint32": true, "uint40": true, "uint48": true, "uint56": true, "uint64": true, "uint72": true, "uint80": true, "uint88": true, "uint96": true, "uint104": true, "uint112": true, "uint120": true, "uint128": true, "uint136": true, "uint144": true, "uint152": true, "uint160": true, "uint168": true, "uint178": true, "uint184": true, "uint192": true, "uint200": true, "uint208": true, "uint216": true, "uint224": true, "uint232": true, "uint240": true, "uint248": true, "uint256": true, "bytes0": true, "bytes1": true, "bytes2": true, "bytes3": true, "bytes4": true, "bytes5": true, "bytes6": true, "bytes7": true, "bytes8": true, "bytes9": true, "bytes10": true, "bytes11": true, "bytes12": true, "bytes13": true, "bytes14": true, "bytes15": true, "bytes16": true, "bytes17": true, "bytes18": true, "bytes19": true, "bytes20": true, "bytes21": true, "bytes22": true, "bytes23": true, "bytes24": true, "bytes25": true, "bytes26": true, "bytes27": true, "bytes28": true, "bytes29": true, "bytes30": true, "bytes31": true, "bytes32": true, "bytes": true, "byte": true, "address": true, "bool": true, "string": true, "real": true, "ureal": true }; +} + +function solMisc() +{ + return { "true": true, "false": true, "null": true }; +} diff --git a/mix/qml/html/codeeditor.html b/mix/qml/html/codeeditor.html index 994656cb7..4545b6239 100644 --- a/mix/qml/html/codeeditor.html +++ b/mix/qml/html/codeeditor.html @@ -4,11 +4,13 @@ + + @@ -16,5 +18,10 @@ + + + + + diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 30c70867b..25c20ab2d 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -1,13 +1,13 @@ - var editor = CodeMirror(document.body, { lineNumbers: true, //styleActiveLine: true, matchBrackets: true, autofocus: true, - gutters: ["CodeMirror-linenumbers", "breakpoints"] + gutters: ["CodeMirror-linenumbers", "breakpoints"], + extraKeys: { "Ctrl-Space": "autocomplete" }, + autoCloseBrackets: true }); - editor.setOption("theme", "solarized dark"); editor.setOption("indentUnit", 4); editor.setOption("indentWithTabs", true); @@ -97,6 +97,19 @@ setText = function(text) { setMode = function(mode) { this.editor.setOption("mode", mode); + + if (mode === "javascript") + { + CodeMirror.commands.autocomplete = function(cm) { + CodeMirror.showHint(cm, CodeMirror.hint.anyword); // TODO change to a proper JavaScript language completion + } + } + else if (mode === "solidity") + { + CodeMirror.commands.autocomplete = function(cm) { + CodeMirror.showHint(cm, CodeMirror.hint.anyword); + } + } }; setClipboardBase64 = function(text) { diff --git a/mix/web.qrc b/mix/web.qrc index e71e5b7c5..118177d07 100644 --- a/mix/web.qrc +++ b/mix/web.qrc @@ -21,5 +21,11 @@ qml/html/cm/dialog.js qml/html/cm/search.js qml/html/cm/searchcursor.js + qml/html/cm/anyword-hint.js + qml/html/cm/show-hint.js + qml/html/cm/show-hint.css + qml/html/cm/closebrackets.js + qml/html/cm/solidityToken.js + qml/html/cm/javascript-hint.js diff --git a/neth/main.cpp b/neth/main.cpp index 8228f2770..2ce9872ca 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -736,7 +736,7 @@ int main(int argc, char** argv) { Secret secret = h256(fromHex(sechex, ThrowType::Throw)); Address dest = h160(fromHex(fields[0], ThrowType::Throw)); - c->transact(secret, amount, dest, data, gas, gasPrice); + c->submitTransaction(secret, amount, dest, data, gas, gasPrice); } catch (BadHexCharacter& _e) { @@ -787,7 +787,7 @@ int main(int argc, char** argv) try { Address dest = h160(fromHex(fields[0], ThrowType::Throw)); - c->transact(us.secret(), amount, dest, bytes(), minGas); + c->submitTransaction(us.secret(), amount, dest, bytes(), minGas); } catch (BadHexCharacter& _e) { @@ -880,7 +880,7 @@ int main(int argc, char** argv) cwarn << "Minimum gas amount is" << minGas; else { - c->transact(us.secret(), endowment, init, gas); + c->submitTransaction(us.secret(), endowment, init, gas); } } } diff --git a/rlp/main.cpp b/rlp/main.cpp index 44873e4e4..5f2f7f358 100644 --- a/rlp/main.cpp +++ b/rlp/main.cpp @@ -38,6 +38,7 @@ void help() << " -r,--render Render the given RLP. Options:" << endl << " --indent Use string as the level indentation (default ' ')." << endl << " --hex-ints Render integers in hex." << endl + << " --string-ints Render integers in the same way as strings." << endl << " --ascii-strings Render data as C-style strings or hex depending on content being ASCII." << endl << " --force-string Force all data to be rendered as C-style strings." << endl << " --force-escape When rendering as C-style strings, force all characters to be escaped." << endl @@ -93,12 +94,13 @@ class RLPStreamer public: struct Prefs { - string indent = " "; + string indent; bool hexInts = false; + bool stringInts = true; bool hexPrefix = true; - bool forceString = true; + bool forceString = false; bool escapeAll = false; - bool forceHex = false; + bool forceHex = true; }; RLPStreamer(ostream& _out, Prefs _p): m_out(_out), m_prefs(_p) {} @@ -107,16 +109,16 @@ public: { if (_d.isNull()) m_out << "null"; - else if (_d.isInt()) + else if (_d.isInt() && !m_prefs.stringInts) if (m_prefs.hexInts) m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(toCompactBigEndian(_d.toInt(RLP::LaisezFaire), 1), 1); else m_out << _d.toInt(RLP::LaisezFaire); - else if (_d.isData()) + else if (_d.isData() || (_d.isInt() && m_prefs.stringInts)) if (m_prefs.forceString || (!m_prefs.forceHex && isAscii(_d.toString()))) m_out << escaped(_d.toString(), m_prefs.escapeAll); else - m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(_d.data()); + m_out << "\"" << (m_prefs.hexPrefix ? "0x" : "") << toHex(_d.toBytes()) << "\""; else if (_d.isList()) { m_out << "["; @@ -162,14 +164,18 @@ int main(int argc, char** argv) prefs.indent = argv[++i]; else if (arg == "--hex-ints") prefs.hexInts = true; + else if (arg == "--string-ints") + prefs.stringInts = true; else if (arg == "--ascii-strings") prefs.forceString = prefs.forceHex = false; else if (arg == "--force-string") prefs.forceString = true; else if (arg == "--force-hex") - prefs.forceHex = true; + prefs.forceHex = true, prefs.forceString = false; else if (arg == "--force-escape") prefs.escapeAll = true; + else if (arg == "-n" || arg == "--nice") + prefs.forceString = true, prefs.stringInts = false, prefs.forceHex = false, prefs.indent = " "; else if (arg == "-l" || arg == "--list-archive") mode = Mode::ListArchive; else if (arg == "-e" || arg == "--extract-archive") diff --git a/test/SolidityABIJSON.cpp b/test/SolidityABIJSON.cpp index 195270138..f7f968ea8 100644 --- a/test/SolidityABIJSON.cpp +++ b/test/SolidityABIJSON.cpp @@ -309,6 +309,7 @@ BOOST_AUTO_TEST_CASE(events) { "name": "e1", "type": "event", + "anonymous": false, "inputs": [ { "indexed": false, @@ -325,6 +326,7 @@ BOOST_AUTO_TEST_CASE(events) { "name": "e2", "type": "event", + "anonymous": false, "inputs": [] } @@ -333,6 +335,23 @@ BOOST_AUTO_TEST_CASE(events) checkInterface(sourceCode, interface); } +BOOST_AUTO_TEST_CASE(events_anonymous) +{ + char const* sourceCode = "contract test {\n" + " event e() anonymous; \n" + "}\n"; + char const* interface = R"([ + { + "name": "e", + "type": "event", + "anonymous": true, + "inputs": [] + } + + ])"; + + checkInterface(sourceCode, interface); +} BOOST_AUTO_TEST_CASE(inherited) { @@ -380,6 +399,7 @@ BOOST_AUTO_TEST_CASE(inherited) { "name": "derivedEvent", "type": "event", + "anonymous": false, "inputs": [{ "indexed": true, @@ -390,6 +410,7 @@ BOOST_AUTO_TEST_CASE(inherited) { "name": "baseEvent", "type": "event", + "anonymous": false, "inputs": [{ "indexed": true, diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index e4b55514d..0bd27a5fc 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1127,45 +1127,43 @@ BOOST_AUTO_TEST_CASE(type_conversions_cleanup) 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22})); } - +// fixed bytes to fixed bytes conversion tests BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_fixed_bytes_smaller_size) { char const* sourceCode = R"( contract Test { - function pipeTrough(bytes3 input) returns (bytes2 ret) { + function bytesToBytes(bytes4 input) returns (bytes2 ret) { return bytes2(input); } })"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("pipeTrough(bytes3)", "abc") == encodeArgs("ab")); + BOOST_CHECK(callContractFunction("bytesToBytes(bytes4)", "abcd") == encodeArgs("ab")); } -BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_same_size) +BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_fixed_bytes_greater_size) { char const* sourceCode = R"( contract Test { - function uintToBytes(uint256 h) returns (bytes32 s) { - return bytes32(h); + function bytesToBytes(bytes2 input) returns (bytes4 ret) { + return bytes4(input); } })"; compileAndRun(sourceCode); - u256 a("0x6162630000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK(callContractFunction("uintToBytes(uint256)", a) == encodeArgs(a)); + BOOST_CHECK(callContractFunction("bytesToBytes(bytes2)", "ab") == encodeArgs("ab")); } -BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_different_size) +BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_fixed_bytes_same_size) { char const* sourceCode = R"( contract Test { - function uintToBytes(uint160 h) returns (bytes20 s) { - return bytes20(h); + function bytesToBytes(bytes4 input) returns (bytes4 ret) { + return bytes4(input); } })"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("uintToBytes(uint160)", - u160("0x6161626361626361626361616263616263616263")) == encodeArgs(string("aabcabcabcaabcabcabc"))); + BOOST_CHECK(callContractFunction("bytesToBytes(bytes4)", "abcd") == encodeArgs("abcd")); } - +// fixed bytes to uint conversion tests BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_same_size) { char const* sourceCode = R"( @@ -1179,35 +1177,59 @@ BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_same_size) encodeArgs(u256("0x6162633200000000000000000000000000000000000000000000000000000000"))); } -BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_different_size) +BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_same_min_size) { char const* sourceCode = R"( contract Test { - function bytesToUint(bytes20 s) returns (uint160 h) { - return uint160(s); + function bytesToUint(bytes1 s) returns (uint8 h) { + return uint8(s); } })"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("bytesToUint(bytes20)", string("aabcabcabcaabcabcabc")) == - encodeArgs(u160("0x6161626361626361626361616263616263616263"))); + BOOST_CHECK(callContractFunction("bytesToUint(bytes1)", string("a")) == + encodeArgs(u256("0x61"))); } - -BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_different_min_size) +BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_smaller_size) { char const* sourceCode = R"( contract Test { - function bytesToUint(bytes1 s) returns (uint8 h) { - return uint8(s); + function bytesToUint(bytes4 s) returns (uint16 h) { + return uint16(s); } })"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("bytesToUint(bytes1)", string("a")) == - encodeArgs(u256("0x61"))); + BOOST_CHECK(callContractFunction("bytesToUint(bytes4)", string("abcd")) == + encodeArgs(u256("0x6364"))); } +BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_greater_size) +{ + char const* sourceCode = R"( + contract Test { + function bytesToUint(bytes4 s) returns (uint64 h) { + return uint64(s); + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("bytesToUint(bytes4)", string("abcd")) == + encodeArgs(u256("0x61626364"))); +} +// uint fixed bytes conversion tests +BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_same_size) +{ + char const* sourceCode = R"( + contract Test { + function uintToBytes(uint256 h) returns (bytes32 s) { + return bytes32(h); + } + })"; + compileAndRun(sourceCode); + u256 a("0x6162630000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK(callContractFunction("uintToBytes(uint256)", a) == encodeArgs(a)); +} -BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_different_min_size) +BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_same_min_size) { char const* sourceCode = R"( contract Test { @@ -1220,6 +1242,32 @@ BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_different_min_size) encodeArgs(string("a"))); } +BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_smaller_size) +{ + char const* sourceCode = R"( + contract Test { + function uintToBytes(uint32 h) returns (bytes2 s) { + return bytes2(h); + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("uintToBytes(uint32)", + u160("0x61626364")) == encodeArgs(string("cd"))); +} + +BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_greater_size) +{ + char const* sourceCode = R"( + contract Test { + function UintToBytes(uint16 h) returns (bytes8 s) { + return bytes8(h); + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("UintToBytes(uint16)", u256("0x6162")) == + encodeArgs(string("\0\0\0\0\0\0ab", 8))); +} + BOOST_AUTO_TEST_CASE(send_ether) { char const* sourceCode = "contract test {\n" @@ -2202,6 +2250,43 @@ BOOST_AUTO_TEST_CASE(event_no_arguments) BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit()"))); } +BOOST_AUTO_TEST_CASE(event_anonymous) +{ + char const* sourceCode = R"( + contract ClientReceipt { + event Deposit() anonymous; + function deposit() { + Deposit(); + } + } + )"; + compileAndRun(sourceCode); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 0); +} + +BOOST_AUTO_TEST_CASE(event_anonymous_with_topics) +{ + char const* sourceCode = R"( + contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint _value) anonymous; + function deposit(bytes32 _id, bool _manually) { + Deposit(msg.sender, _id, msg.value); + } + } + )"; + compileAndRun(sourceCode); + u256 value(18); + u256 id(0x1234); + callContractFunctionWithValue("deposit(bytes32,bool)", value, id); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value))); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(m_sender)); + BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(id)); +} + BOOST_AUTO_TEST_CASE(event_lots_of_data) { char const* sourceCode = R"( diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 0341d92b8..5ad395499 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -628,6 +628,11 @@ RLPStream createFullBlockFromHeader(const BlockInfo& _bi,const bytes& _txs, cons BOOST_AUTO_TEST_SUITE(BlockChainTests) +BOOST_AUTO_TEST_CASE(bcInvalidRLPTest) +{ + dev::test::executeTests("bcInvalidRLPTest", "/BlockTests", dev::test::doBlockchainTests); +} + BOOST_AUTO_TEST_CASE(bcJS_API_Test) { dev::test::executeTests("bcJS_API_Test", "/BlockTests", dev::test::doBlockchainTests); diff --git a/test/checkRandomStateTest.cpp b/test/checkRandomStateTest.cpp index 17e785f60..a4d390b16 100644 --- a/test/checkRandomStateTest.cpp +++ b/test/checkRandomStateTest.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -87,7 +88,7 @@ bool doStateTest(mValue& _v) try { - theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output); + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output; } catch (Exception const& _e) { diff --git a/test/checkRandomVMTest.cpp b/test/checkRandomVMTest.cpp index c96357714..a40922577 100644 --- a/test/checkRandomVMTest.cpp +++ b/test/checkRandomVMTest.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include #include diff --git a/test/createRandomStateTest.cpp b/test/createRandomStateTest.cpp index 13b622bb1..f422d1717 100644 --- a/test/createRandomStateTest.cpp +++ b/test/createRandomStateTest.cpp @@ -55,20 +55,37 @@ int main(int argc, char *argv[]) auto now = chrono::steady_clock::now().time_since_epoch(); auto timeSinceEpoch = chrono::duration_cast(now).count(); gen.seed(static_cast(timeSinceEpoch)); - boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16); + // set min and max length of the random evm code + boost::random::uniform_int_distribution<> lengthOfCodeDist(8, 24); + boost::random::uniform_int_distribution<> reasonableInputValuesSize(0, 7); boost::random::uniform_int_distribution<> opcodeDist(0, 255); boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x40, 0x45); + boost::random::uniform_int_distribution<> uniformInt(0, 0x7fffffff); + boost::random::variate_generator > randGenInputValue(gen, reasonableInputValuesSize); + boost::random::variate_generator > randGenUniformInt(gen, uniformInt); boost::random::variate_generator > randGen(gen, opcodeDist); boost::random::variate_generator > randGenBlockInfoOpcode(gen, BlockInfoOpcodeDist); + std::vector reasonableInputValues; + reasonableInputValues.push_back(0); + reasonableInputValues.push_back(1); + reasonableInputValues.push_back(50000); + reasonableInputValues.push_back(u256("0x10000000000000000000000000000000000000000")); + reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffff")); + reasonableInputValues.push_back(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe")); + reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + reasonableInputValues.push_back(u256("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); + reasonableInputValues.push_back(randGenUniformInt()); + int lengthOfCode = lengthOfCodeDist(gen); string randomCode; for (int i = 0; i < lengthOfCode; ++i) { + // pre-fill stack to avoid that most of the test fail with a stackunderflow if (i < 8 && (randGen() < 192)) { - randomCode += toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())); + randomCode += randGen() < 32 ? toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())) : "7f" + toHex(reasonableInputValues[randGenInputValue()]); continue; } @@ -93,7 +110,7 @@ int main(int argc, char *argv[]) }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "1000000000000000000", + "balance" : "0", "code" : "0x6001600101600055", "nonce" : "0", "storage" : { @@ -130,7 +147,16 @@ int main(int argc, char *argv[]) read_string(s, v); // insert new random code - v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : ""); + v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : "") + (randGen() > 128 ? "60005155" : ""); + + // insert new data in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomCode; + + // insert new value in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = toString(randGenUniformInt()); + + // insert new gasLimit in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = "0x" + toHex(toCompactBigEndian((int)randGenUniformInt())); // fill test doStateTests(v); @@ -162,7 +188,7 @@ void doStateTests(json_spirit::mValue& _v) try { - theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx, &output); + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx).output; } catch (Exception const& _e) { diff --git a/test/dagger.cpp b/test/dagger.cpp index a2bd6be68..f7230f705 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(basic_test) testPath += "/PoWTests"; - cnote << "Testing Secure Trie..."; + cnote << "Testing Proof of Work..."; js::mValue v; string s = asString(contents(testPath + "/ethash_tests.json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'ethash_tests.json' is empty. Have you cloned the 'tests' repo branch develop?"); diff --git a/test/net.cpp b/test/net.cpp index 831c283e2..3a69a627b 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include diff --git a/test/stCallCreateCallCodeTestFiller.json b/test/stCallCreateCallCodeTestFiller.json index b0245ee72..659ea7ccc 100644 --- a/test/stCallCreateCallCodeTestFiller.json +++ b/test/stCallCreateCallCodeTestFiller.json @@ -211,7 +211,7 @@ "transaction" : { "data" : "", - "gasLimit" : "0xffffffffffffffffffffffffffffff", + "gasLimit" : "15720826", "gasPrice" : "1", "nonce" : "", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -260,7 +260,7 @@ "transaction" : { "data" : "", - "gasLimit" : "0xffffffffffffffffffffffffffffff", + "gasLimit" : "166262", "gasPrice" : "1", "nonce" : "", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -308,7 +308,7 @@ "transaction" : { "data" : "", - "gasLimit" : "0xffffffffffffffffffffffffffffff", + "gasLimit" : "17592186099592", "gasPrice" : "1", "nonce" : "", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -355,7 +355,7 @@ "transaction" : { "data" : "", - "gasLimit" : "0xffffffffffffffffffffffffffffff", + "gasLimit" : "15720826", "gasPrice" : "1", "nonce" : "", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", diff --git a/test/state.cpp b/test/state.cpp index 162ae5f34..4ab59f7a1 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -63,7 +63,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) try { Listener::ExecTimeGuard guard{i.first}; - theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output); + output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output; } catch (Exception const& _e) { diff --git a/test/txTest.cpp b/test/txTest.cpp index e2a16e16c..a70a68f01 100644 --- a/test/txTest.cpp +++ b/test/txTest.cpp @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(mine_local_simple_tx) auto txAmount = c1bal / 2u; auto gasPrice = 10 * szabo; auto gas = dev::eth::c_callGas; - c1.transact(kp1.secret(), txAmount, kp2.address(), bytes(), gas, gasPrice); + c1.submitTransaction(kp1.secret(), txAmount, kp2.address(), bytes(), gas, gasPrice); //mine some more to include the transaction on chain mine(c1, 1); @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(mine_and_send_to_peer) auto txAmount = c1bal / 2u; auto gasPrice = 10 * szabo; auto gas = dev::eth::c_callGas; - c1.transact(kp1.secret(), txAmount, kp2.address(), bytes(), gas, gasPrice); + c1.submitTransaction(kp1.secret(), txAmount, kp2.address(), bytes(), gas, gasPrice); //mine some more to include the transaction on chain mine(c1, 1); @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(mine_and_send_to_peer_fee_check) auto txAmount = c1StartBalance / 2u; auto gasPrice = 10 * szabo; auto gas = dev::eth::c_callGas; - c1.transact(kp1.secret(), txAmount, c2.address(), bytes(), gas, gasPrice); + c1.submitTransaction(kp1.secret(), txAmount, c2.address(), bytes(), gas, gasPrice); //mine some more, this time with second client (so he can get fees from first client's tx) mine(c2, 1);