diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 01dfb88dc..721ab79ba 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -54,6 +54,9 @@ endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmcore devcore web3jsonrpc jsqrc) +if (EVMJIT) + target_link_libraries(${EXECUTEABLE} evmjit) +endif() if (APPLE) # First have qt5 install plugins and frameworks diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e5506a660..fc27d6e30 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1259,7 +1259,6 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << ""; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << ""; - s << "   Minimum gas price: " << formatBalance(info.minGasPrice) << ""; s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress; s << "
Nonce: " << info.nonce << ""; s << "
Parent: " << info.parentHash << ""; @@ -1665,7 +1664,7 @@ void Main::on_data_textChanged() errs.append("
" + QString::fromStdString(i).toHtmlEscaped() + "
"); } ui->code->setHtml(errs + lll + solidity + "

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); - ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 0)); + ui->gas->setMinimum((qint64)Client::txGas(m_data, 0)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); ui->gas->setEnabled(true); @@ -1676,7 +1675,7 @@ void Main::on_data_textChanged() ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true))); if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size()) { - ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 1)); + ui->gas->setMinimum((qint64)Client::txGas(m_data, 1)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); ui->gas->setEnabled(true); @@ -1685,7 +1684,7 @@ void Main::on_data_textChanged() { if (ui->gas->isEnabled()) m_backupGas = ui->gas->value(); - ui->gas->setValue((qint64)Client::txGas(m_data.size())); + ui->gas->setValue((qint64)Client::txGas(m_data)); ui->gas->setEnabled(false); } } diff --git a/eth/main.cpp b/eth/main.cpp index 408654018..9b63e0643 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -492,14 +492,12 @@ int main(int argc, char** argv) cnote << ssbd.str(); int ssize = sechex.length(); int size = hexAddr.length(); - u256 minGas = (u256)Client::txGas(data.size(), 0); + u256 minGas = (u256)Client::txGas(data, 0); if (size < 40) { if (size > 0) cwarn << "Invalid address length:" << size; } - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else if (ssize < 40) @@ -559,9 +557,9 @@ int main(int argc, char** argv) auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); - u256 minGas = (u256)Client::txGas(0, 0); + u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(hexAddr)); - c->transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); + c->transact(us.secret(), amount, dest, bytes(), minGas); } } else @@ -598,11 +596,9 @@ int main(int argc, char** argv) cnote << "Init:"; cnote << ssc.str(); } - u256 minGas = (u256)Client::txGas(init.size(), 0); + u256 minGas = (u256)Client::txGas(init, 0); if (endowment < 0) cwarn << "Invalid endowment"; - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index ae073b9b1..280268d8b 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.10"; +char const* Version = "0.7.11"; } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 44da9603c..015f8dad6 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -58,9 +58,9 @@ h256 BlockInfo::headerHashWithoutNonce() const void BlockInfo::streamRLP(RLPStream& _s, bool _nonce) const { - _s.appendList(_nonce ? 15 : 14) + _s.appendList(_nonce ? 14 : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; + << difficulty << number << gasLimit << gasUsed << timestamp << extraData; if (_nonce) _s << nonce; } @@ -86,12 +86,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) logBloom = _header[field = 6].toHash(); difficulty = _header[field = 7].toInt(); number = _header[field = 8].toInt(); - minGasPrice = _header[field = 9].toInt(); - gasLimit = _header[field = 10].toInt(); - gasUsed = _header[field = 11].toInt(); - timestamp = _header[field = 12].toInt(); - extraData = _header[field = 13].toBytes(); - nonce = _header[field = 14].toHash(); + gasLimit = _header[field = 9].toInt(); + gasUsed = _header[field = 10].toInt(); + timestamp = _header[field = 11].toInt(); + extraData = _header[field = 12].toBytes(); + nonce = _header[field = 13].toHash(); } catch (Exception const& _e) @@ -147,9 +146,6 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const if (transactionsRoot != t.root()) BOOST_THROW_EXCEPTION(InvalidTransactionsHash(t.root(), transactionsRoot)); - if (minGasPrice > mgp) - BOOST_THROW_EXCEPTION(InvalidMinGasPrice(minGasPrice, mgp)); - if (sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index d91ff244d..aa7456f72 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -66,7 +66,6 @@ public: h512 logBloom; // TODO LogBloom - get include u256 difficulty; u256 number; - u256 minGasPrice; u256 gasLimit; u256 gasUsed; u256 timestamp; @@ -95,7 +94,6 @@ public: logBloom == _cmp.logBloom && difficulty == _cmp.difficulty && number == _cmp.number && - minGasPrice == _cmp.minGasPrice && gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && @@ -122,7 +120,7 @@ public: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " << + _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce; return _out; } diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index c12c71774..010b7e408 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -33,8 +33,8 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 44; -const unsigned c_databaseVersion = 4; +const unsigned c_protocolVersion = 45; +const unsigned c_databaseVersion = 5; static const vector> g_units = { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 765b54627..531005fb2 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -101,9 +101,8 @@ bytes BlockChain::createGenesisBlock() stateRoot = state.root(); } - block.appendList(15) - // TODO: maybe make logbloom correct? - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + block.appendList(14) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -169,8 +168,6 @@ void BlockChain::close() delete m_db; m_lastBlockHash = m_genesisHash; m_details.clear(); - m_blooms.clear(); - m_traces.clear(); m_cache.clear(); } @@ -307,14 +304,10 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) State s(bi.coinbaseAddress, _db); auto tdIncrease = s.enactOn(&_block, bi, *this); auto b = s.oldBloom(); - BlockBlooms bb; - BlockTraces bt; BlockLogBlooms blb; BlockReceipts br; for (unsigned i = 0; i < s.pending().size(); ++i) { - bb.blooms.push_back(s.changesFromPending(i).bloom()); - bt.traces.push_back(s.changesFromPending(i)); blb.blooms.push_back(s.receipt(i).bloom()); br.receipts.push_back(s.receipt(i)); } @@ -330,14 +323,6 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}, b); m_details[bi.parentHash].children.push_back(newHash); } - { - WriteGuard l(x_blooms); - m_blooms[newHash] = bb; - } - { - WriteGuard l(x_traces); - m_traces[newHash] = bt; - } { WriteGuard l(x_logBlooms); m_logBlooms[newHash] = blb; @@ -349,8 +334,6 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)dev::ref(m_details[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, 1), (ldb::Slice)dev::ref(m_blooms[newHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, 2), (ldb::Slice)dev::ref(m_traces[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(newHash, 3), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(newHash, 4), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); m_db->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 74d94e164..d03818bd3 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -101,14 +101,6 @@ public: BlockDetails details(h256 _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } BlockDetails details() const { return details(currentHash()); } - /// Get the transactions' bloom filters of a block (or the most recent mined if none given). Thread-safe. - BlockBlooms blooms(h256 _hash) const { return queryExtras(_hash, m_blooms, x_blooms, NullBlockBlooms); } - BlockBlooms blooms() const { return blooms(currentHash()); } - - /// Get the transactions' trace manifests of a block (or the most recent mined if none given). Thread-safe. - BlockTraces traces(h256 _hash) const { return queryExtras(_hash, m_traces, x_traces, NullBlockTraces); } - BlockTraces traces() const { return traces(currentHash()); } - /// Get the transactions' log blooms of a block (or the most recent mined if none given). Thread-safe. BlockLogBlooms logBlooms(h256 _hash) const { return queryExtras(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); } BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); } @@ -193,10 +185,6 @@ private: /// The caches of the disk DB and their locks. mutable boost::shared_mutex x_details; mutable BlockDetailsHash m_details; - mutable boost::shared_mutex x_blooms; - mutable BlockBloomsHash m_blooms; - mutable boost::shared_mutex x_traces; - mutable BlockTracesHash m_traces; mutable boost::shared_mutex x_logBlooms; mutable BlockLogBloomsHash m_logBlooms; mutable boost::shared_mutex x_receipts; diff --git a/libethereum/BlockDetails.h b/libethereum/BlockDetails.h index 973e93070..0c3af5b33 100644 --- a/libethereum/BlockDetails.h +++ b/libethereum/BlockDetails.h @@ -54,24 +54,6 @@ struct BlockDetails h256 bloom; }; -struct BlockBlooms -{ - BlockBlooms() {} - BlockBlooms(RLP const& _r) { blooms = _r.toVector(); } - bytes rlp() const { RLPStream s; s << blooms; return s.out(); } - - h256s blooms; -}; - -struct BlockTraces -{ - BlockTraces() {} - BlockTraces(RLP const& _r) { for (auto const& i: _r) traces.emplace_back(i.data()); } - bytes rlp() const { RLPStream s(traces.size()); for (auto const& i: traces) i.streamRLP(s); return s.out(); } - - Manifests traces; -}; - struct BlockLogBlooms { BlockLogBlooms() {} @@ -91,14 +73,10 @@ struct BlockReceipts }; typedef std::map BlockDetailsHash; -typedef std::map BlockBloomsHash; -typedef std::map BlockTracesHash; typedef std::map BlockLogBloomsHash; typedef std::map BlockReceiptsHash; static const BlockDetails NullBlockDetails; -static const BlockBlooms NullBlockBlooms; -static const BlockTraces NullBlockTraces; static const BlockLogBlooms NullBlockLogBlooms; static const BlockReceipts NullBlockReceipts; diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index cb2049886..6088525fb 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -28,6 +28,9 @@ endif() target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) target_link_libraries(${EXECUTABLE} gmp) +if (EVMJIT) + target_link_libraries(${EXECUTABLE} evmjit) +endif() if("${TARGET_PLATFORM}" STREQUAL "w64") target_link_libraries(${EXECUTABLE} boost_system-mt-s) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index f609c9c14..42c063d3f 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -22,6 +22,7 @@ #include #include #include +#include "Interface.h" #include "Executive.h" #include "State.h" #include "ExtVM.h" @@ -58,15 +59,8 @@ bool Executive::setup(bytesConstRef _rlp) BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce())); } - // Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going. - if (m_t.gasPrice() < m_s.m_currentBlock.minGasPrice) - { - clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice(); - BOOST_THROW_EXCEPTION(GasPriceTooLow()); - } - // Check gas cost is enough. - u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas; + auto gasCost = Interface::txGas(m_t.data()); if (m_t.gas() < gasCost) { @@ -106,9 +100,9 @@ bool Executive::setup(bytesConstRef _rlp) } if (m_t.isCreation()) - return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - gasCost, &m_t.data(), m_sender); + return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasCost, &m_t.data(), m_sender); else - return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - gasCost, m_sender); + return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)gasCost, m_sender); } bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) @@ -118,7 +112,7 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu if (m_s.addressHasCode(_receiveAddress)) { - m_vm = VMFace::create(VMFace::Interpreter, _gas).release(); + m_vm = VMFactory::create(VMFactory::Interpreter, _gas).release(); bytes const& c = m_s.code(_receiveAddress); m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms); } @@ -137,7 +131,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception); // Execute _init. - m_vm = VMFace::create(VMFace::Interpreter, _gas).release(); + m_vm = VMFactory::create(VMFactory::Interpreter, _gas).release(); m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms); return _init.empty(); } diff --git a/libethereum/Interface.h b/libethereum/Interface.h index add9a1bda..d598e1f9b 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -128,7 +128,7 @@ public: virtual Addresses addresses(int _block) const = 0; /// Get the fee associated for a transaction with the given data. - static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; } + template static bigint txGas(T const& _data, u256 _gas = 0) { bigint ret = c_txGas + _gas; for (auto i: _data) ret += i ? c_txDataNonZeroGas : c_txDataZeroGas; return ret; } /// Get the remaining gas limit in this block. virtual u256 gasLimitRemaining() const = 0; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 2bfa83ca8..66d24a27b 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -54,7 +54,7 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); memset(_out.data(), 0, _out.size()); - if (in.v > 28) + if ((u256)in.v > 28) return; SignatureStruct sig{in.r, in.s, (byte)((int)(u256)in.v - 27)}; if (!sig.isValid()) @@ -503,7 +503,6 @@ void State::resetCurrent() m_currentBlock.timestamp = time(0); m_currentBlock.transactionsRoot = h256(); m_currentBlock.sha3Uncles = h256(); - m_currentBlock.minGasPrice = 10 * szabo; m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. @@ -1216,7 +1215,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA } else if (addressHasCode(_codeAddress)) { - auto vmObj = VMFace::create(getVMKind(), *_gas); + auto vmObj = VMFactory::create(getVMKind(), *_gas); auto& vm = *vmObj; ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level); bool revert = false; @@ -1276,7 +1275,7 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, m_cache[newAddress] = Account(balance(newAddress) + _endowment, Account::ContractConception); // Execute init code. - auto vmObj = VMFace::create(getVMKind(), *_gas); + auto vmObj = VMFactory::create(getVMKind(), *_gas); auto& vm = *vmObj; ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; diff --git a/libethereum/State.h b/libethereum/State.h index 96d53bc9e..f7bc0d119 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include "TransactionReceipt.h" #include "Executive.h" #include "AccountDiff.h" +#include "VMFactory.h" namespace dev { @@ -261,10 +263,10 @@ public: void cleanup(bool _fullCommit); /// Sets VM kind to be used by the state - void setVMKind(VMFace::Kind _kind) { m_vmKind = _kind; } + void setVMKind(VMFactory::Kind _kind) { m_vmKind = _kind; } /// Get the kind of VM used by the state - VMFace::Kind getVMKind() const { return m_vmKind; } + VMFactory::Kind getVMKind() const { return m_vmKind; } private: /// Undo the changes to the state for committing to mine. @@ -333,7 +335,7 @@ private: u256 m_blockReward; - VMFace::Kind m_vmKind = VMFace::Interpreter; ///< The kind of VM used by the state + VMFactory::Kind m_vmKind = VMFactory::Interpreter; ///< The kind of VM used by the state static std::string c_defaultPath; diff --git a/libethereum/VMFactory.cpp b/libethereum/VMFactory.cpp new file mode 100644 index 000000000..1c8de319b --- /dev/null +++ b/libethereum/VMFactory.cpp @@ -0,0 +1,28 @@ +#include + +#if ETH_EVMJIT + #include +#endif + +#include "VMFactory.h" + +namespace dev +{ +namespace eth +{ + +std::unique_ptr VMFactory::create(VMFactory::Kind _kind, u256 _gas) +{ +#if ETH_EVMJIT + auto vm = _kind == Kind::JIT ? static_cast(new jit::VM) + : static_cast(new VM); +#else + VMFace* vm = new VM; +#endif + + vm->reset(_gas); + return std::unique_ptr(vm); +} + +} +} diff --git a/libethereum/VMFactory.h b/libethereum/VMFactory.h new file mode 100644 index 000000000..5d8edc391 --- /dev/null +++ b/libethereum/VMFactory.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace dev +{ +namespace eth +{ + +/** + */ + +class VMFactory +{ +public: + enum Kind: bool { + Interpreter, +#if ETH_EVMJIT + JIT +#endif + }; + + static std::unique_ptr create(Kind, u256 _gas = 0); +}; + + +} +} diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index 6d868cac5..3e957118e 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -34,9 +34,13 @@ u256 const dev::eth::c_sstoreResetGas = 100; u256 const dev::eth::c_sstoreRefundGas = 100; u256 const dev::eth::c_createGas = 100; u256 const dev::eth::c_callGas = 20; +u256 const dev::eth::c_expGas = 1; +u256 const dev::eth::c_expByteGas = 1; u256 const dev::eth::c_memoryGas = 1; -u256 const dev::eth::c_txDataGas = 5; +u256 const dev::eth::c_txDataZeroGas = 1; +u256 const dev::eth::c_txDataNonZeroGas = 5; u256 const dev::eth::c_txGas = 500; u256 const dev::eth::c_logGas = 32; u256 const dev::eth::c_logDataGas = 1; u256 const dev::eth::c_logTopicGas = 32; +u256 const dev::eth::c_copyGas = 1; diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index e57f7ccf8..3fb8175e6 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -37,12 +37,16 @@ extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeron extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operation if the zeroness changes to zero. extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction. extern u256 const c_callGas; ///< Once per CALL operation & message call transaction. +extern u256 const c_expGas; ///< Once per EXP instuction. +extern u256 const c_expByteGas; ///< Times ceil(log256(exponent)) for the EXP instruction. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. -extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions. +extern u256 const c_txDataZeroGas; ///< Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. +extern u256 const c_txDataNonZeroGas; ///< Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_logGas; ///< Per LOG* operation. extern u256 const c_logDataGas; ///< Per byte in a LOG* operation's data. extern u256 const c_logTopicGas; ///< Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. +extern u256 const c_copyGas; ///< Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. } } diff --git a/libevm/VM.h b/libevm/VM.h index 0a9b54106..993197924 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -36,6 +36,8 @@ namespace dev namespace eth { +class VMFactory; + /** */ class VM : public VMFace @@ -53,7 +55,7 @@ public: u256s const& stack() const { return m_stack; } private: - friend VMFace; + friend VMFactory; explicit VM(u256 _gas = 0): VMFace(_gas) {} template @@ -108,6 +110,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con // FEES... bigint runGas = c_stepGas; bigint newTempSize = m_temp.size(); + bigint copySize = 0; auto onOperation = [&]() { @@ -170,14 +173,17 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::CALLDATACOPY: require(3); + copySize = m_stack[m_stack.size() - 3]; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); break; case Instruction::CODECOPY: require(3); + copySize = m_stack[m_stack.size() - 3]; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); break; case Instruction::EXTCODECOPY: require(4); + copySize = m_stack[m_stack.size() - 4]; newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]); break; @@ -215,6 +221,13 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con runGas = c_createGas; break; } + case Instruction::EXP: + { + require(2); + auto expon = m_stack[m_stack.size() - 2]; + runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8)); + break; + } case Instruction::PC: case Instruction::MSIZE: @@ -281,7 +294,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::SDIV: case Instruction::MOD: case Instruction::SMOD: - case Instruction::EXP: case Instruction::LT: case Instruction::GT: case Instruction::SLT: @@ -342,6 +354,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size()) runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += c_copyGas * (copySize + 31) / 32; onOperation(); // if (_onOp) diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp index 3313ee926..9f8c6549c 100644 --- a/libevm/VMFace.cpp +++ b/libevm/VMFace.cpp @@ -22,15 +22,7 @@ using namespace dev; using namespace dev::eth; -std::unique_ptr VMFace::create(VMFace::Kind _kind, u256 _gas) +void VMFace::reset(u256 _gas) noexcept { - std::unique_ptr vm; -#if ETH_EVMJIT - vm.reset(_kind == Kind::JIT ? static_cast(new jit::VM) : new VM); -#else - (void) _kind; // suppress unused var warning - vm.reset(new VM); -#endif - vm->reset(_gas); - return vm; + m_gas = _gas; } diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 76dc8a219..6617db1da 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -62,16 +62,12 @@ public: VMFace(VMFace const&) = delete; void operator=(VMFace const&) = delete; - virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } + virtual void reset(u256 _gas = 0) noexcept; virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; u256 gas() const { return m_gas; } - enum Kind: bool { Interpreter, JIT }; - - static std::unique_ptr create(Kind, u256 _gas = 0); - protected: u256 m_gas = 0; }; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 94e1450cd..1cc86d8aa 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -805,6 +805,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto numBytes = stack.pop(); _memory.require(beginIdx, numBytes); + // This will commit the current cost block + _gasMeter.countLogData(numBytes); + std::array topics; auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); for (size_t i = 0; i < numTopics; ++i) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 17cbf5dc4..6eb35acda 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -167,8 +167,8 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr) void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array const& _topics) { - static llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5}; - static llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4}; + llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5}; + llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4}; args[0] = getRuntimeManager().getRuntimePtr(); m_builder.CreateStore(_memIdx, m_args[0]); @@ -320,8 +320,8 @@ extern "C" { auto&& ext = _rt->getExt(); - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); + auto memIdx = llvm2eth(*_memIdx).convert_to(); + auto numBytes = llvm2eth(*_numBytes).convert_to(); auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); ext.log({}, dataRef); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 734931c32..48499259a 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -47,6 +47,16 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure case Instruction::CREATE: return static_cast(c_createGas); + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + return static_cast(c_logGas) + numTopics * static_cast(c_logTopicGas); + } + default: // Assumes instruction code is valid return static_cast(c_stepGas); } @@ -138,6 +148,14 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu createCall(m_gasCheckFunc, cost); } +void GasMeter::countLogData(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // LOGn instruction is already counted + auto cost = m_builder.CreateMul(_dataLength, Constant::get(c_logDataGas), "logdata_cost"); + commitCostBlock(cost); +} + void GasMeter::giveBack(llvm::Value* _gas) { m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 4be6c1a02..dfb4fb548 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -24,6 +24,9 @@ public: /// Calculate & count gas cost for SSTORE instruction void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + /// Count gas cost of LOG data + void countLogData(llvm::Value* _dataLength); + /// Finalize cost-block by checking gas needed for the block before the block /// @param _additionalCost adds additional cost to cost-block before commit void commitCostBlock(llvm::Value* _additionalCost = nullptr); diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 9b60fccf1..b968008aa 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -2,6 +2,7 @@ #include "VM.h" #include +#include #include "ExecutionEngine.h" #include "Compiler.h" diff --git a/libevmjit/VM.h b/libevmjit/VM.h index 93b359cd7..1c6c71181 100644 --- a/libevmjit/VM.h +++ b/libevmjit/VM.h @@ -9,6 +9,9 @@ namespace dev { namespace eth { + +class VMFactory; + namespace jit { @@ -16,8 +19,11 @@ class VM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + enum Kind: bool { Interpreter, JIT }; + static std::unique_ptr create(Kind, u256 _gas = 0); + private: - friend VMFace; + friend VMFactory; explicit VM(u256 _gas = 0): VMFace(_gas) {} bytes m_output; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4dc377791..c3c7116e4 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -363,7 +363,7 @@ void ExpressionCompiler::endVisit(Identifier& _identifier) m_context << m_context.getFunctionEntryLabel(*functionDef).pushTag(); return; } - if (VariableDeclaration* varDef = dynamic_cast(declaration)) + if (/*VariableDeclaration* varDef = */dynamic_cast(declaration)) { m_currentLValue.fromIdentifier(_identifier, *_identifier.getReferencedDeclaration()); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index e958352fd..d8b637076 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -58,7 +58,7 @@ GlobalContext::GlobalContext(): FunctionType::Location::ECRECOVER)), make_shared("ripemd160", make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(160, IntegerType::Modifier::HASH)}), FunctionType::Location::RIPEMD160))} { } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 4ab53bf86..b81fbbe31 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -397,11 +397,11 @@ MagicType::MagicType(MagicType::Kind _kind): break; case Kind::MSG: m_members = MemberList({{"sender", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"gas", make_shared(256)}, {"value", make_shared(256)}}); break; case Kind::TX: m_members = MemberList({{"origin", make_shared(0, IntegerType::Modifier::ADDRESS)}, - {"gas", make_shared(256)}, {"gasprice", make_shared(256)}}); break; default: diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 8ee9ee722..7607b7a95 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -51,7 +51,6 @@ static Json::Value toJson(dev::eth::BlockInfo const& _bi) res["transactionsRoot"] = toJS(_bi.transactionsRoot); res["difficulty"] = toJS(_bi.difficulty); res["number"] = (int)_bi.number; - res["minGasPrice"] = toJS(_bi.minGasPrice); res["gasLimit"] = (int)_bi.gasLimit; res["timestamp"] = (int)_bi.timestamp; res["extraData"] = jsFromBinary(_bi.extraData); diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 0fb7a206c..9b26e3260 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -156,6 +156,12 @@ void WhisperHost::uninstallWatch(unsigned _i) m_filters.erase(fit); } +void WhisperHost::doWork() +{ + for (auto& i: peers()) + i->cap()->sendMessages(); +} + void WhisperHost::cleanup() { // remove old messages. diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 91934dd98..b38964f8e 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "Common.h" @@ -38,7 +39,7 @@ namespace dev namespace shh { -class WhisperHost: public HostCapability, public Interface +class WhisperHost: public HostCapability, public Interface, public Worker { friend class WhisperPeer; @@ -64,7 +65,13 @@ public: void cleanup(); +protected: + void doWork(); + private: + virtual void onStarting() { startWorking(); } + virtual void onStopping() { stopWorking(); } + void streamMessage(h256 _m, RLPStream& _s) const; void noteChanged(h256 _messageHash, h256 _filter); diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 56f4e456e..c3a28e3c3 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -72,7 +72,6 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) for (auto i: _r) if (n++) host()->inject(Envelope(i), this); - sendMessages(); break; } default: @@ -97,10 +96,15 @@ void WhisperPeer::sendMessages() } } - if (!n) - // pause for a bit if no messages to send - this is horrible and broken. - // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. - this_thread::sleep_for(chrono::milliseconds(20)); + // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. + auto diff = chrono::duration_cast(chrono::system_clock::now() - m_timer); + if (n || diff.count() > 0) + { + RLPStream s; + prep(s, MessagesPacket, n).appendRaw(amalg.out(), n); + sealAndSend(s); + m_timer = chrono::system_clock::now(); + } { RLPStream s; diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index f60de8f01..faac2d870 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -68,6 +68,8 @@ private: mutable dev::Mutex x_unseen; std::map m_unseen; ///< Rated according to what they want. + + std::chrono::system_clock::time_point m_timer = std::chrono::system_clock::now(); }; } diff --git a/neth/main.cpp b/neth/main.cpp index 6be555fbb..cb6d35593 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -603,7 +603,7 @@ int main(int argc, char** argv) vector l; l.push_back("Amount"); stringstream label; - label << "Gas price (" << info.minGasPrice << ")"; + label << "Gas price"; l.push_back(label.str()); l.push_back("Gas"); vector b; @@ -646,14 +646,12 @@ int main(int argc, char** argv) ssbd << bbd; cnote << ssbd.str(); int ssize = fields[4].length(); - u256 minGas = (u256)Client::txGas(data.size(), 0); + u256 minGas = (u256)Client::txGas(data, 0); if (size < 40) { if (size > 0) cwarn << "Invalid address length:" << size; } - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else if (ssize < 40) @@ -702,9 +700,9 @@ int main(int argc, char** argv) auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); - u256 minGas = (u256)Client::txGas(0, 0); + u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(fields[0])); - c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); + c.transact(us.secret(), amount, dest, bytes(), minGas); } } } @@ -718,7 +716,7 @@ int main(int argc, char** argv) vector l; l.push_back("Endowment"); stringstream label; - label << "Gas price (" << info.minGasPrice << ")"; + label << "Gas price"; l.push_back(label.str()); l.push_back("Gas"); vector b; @@ -763,16 +761,14 @@ int main(int argc, char** argv) cnote << "Init:"; cnote << ssc.str(); } - u256 minGas = (u256)Client::txGas(init.size(), 0); + u256 minGas = (u256)Client::txGas(init, 0); if (endowment < 0) cwarn << "Invalid endowment"; - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else { - c.transact(us.secret(), endowment, init, gas, gasPrice); + c.transact(us.secret(), endowment, init, gas); } } } diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index f22e5c0aa..87bb13846 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include "vm.h" @@ -128,7 +129,7 @@ void doMyTests(json_spirit::mValue& v) assert(o.count("exec") > 0); - auto vmObj = eth::VMFace::create(eth::VMFace::Interpreter); + auto vmObj = eth::VMFactory::create(eth::VMFactory::Interpreter); auto& vm = *vmObj; test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); diff --git a/test/vm.cpp b/test/vm.cpp index b34dc1829..ce0fe0808 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "vm.h" using namespace std; using namespace json_spirit; @@ -322,8 +323,11 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) auto useJit = false; for (auto i = 0; i < argc && !useJit; ++i) useJit |= std::string(argv[i]) == "--jit"; - auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; - +#if ETH_EVMJIT + auto vmKind = useJit ? VMFactory::JIT : VMFactory::Interpreter; +#else + auto vmKind == VMFactory::Interpreter; +#endif dev::test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); @@ -339,7 +343,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) fev.code = fev.thisTxCode; } - auto vm = VMFace::create(vmKind, fev.gas); + auto vm = VMFactory::create(vmKind, fev.gas); bytes output; auto startTime = std::chrono::high_resolution_clock::now();