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/Executive.cpp b/libethereum/Executive.cpp index 87e675e15..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) 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 4f0a4ae3c..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. 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 f39bc9d4f..951603ab2 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -110,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 = [&]() { @@ -172,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; @@ -217,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: @@ -283,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: @@ -344,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/libevmjit/interface.c b/libevmjit/interface.c new file mode 100644 index 000000000..47589578b --- /dev/null +++ b/libevmjit/interface.c @@ -0,0 +1,30 @@ +#include + +// JIT object opaque type +typedef struct evm_jit evm_jit; + +// Contract execution return code +typedef int evm_jit_return_code; + +// Host-endian 256-bit integer type +typedef struct i256 i256; + +// Big-endian right aligned 256-bit hash +typedef struct h256 h256; + +// Runtime data struct - must be provided by external language (Go, C++, Python) +typedef struct evm_jit_rt evm_jit_rt; + +// Runtime callback functions - implementations must be provided by external language (Go, C++, Python) +void evm_jit_rt_sload(evm_jit_rt* _rt, i256* _index, i256* _ret); +void evm_jit_rt_sstore(evm_jit_rt* _rt, i256* _index, i256* _value); +void evm_jit_rt_balance(evm_jit_rt* _rt, h256* _address, i256* _ret); +// And so on... + +evm_jit* evm_jit_create(evm_jit_rt* _runtime_data); + +evm_jit_return_code evm_jit_execute(evm_jit* _jit); + +void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); + +void evm_jit_destroy(evm_jit* _jit); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 6e151d34d..b233fe552 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -78,7 +78,7 @@ std::vector Host::getInterfaceAddresses() char *addrStr = inet_ntoa(addr); bi::address address(bi::address::from_string(addrStr)); if (!isLocalHostAddress(address)) - addresses.push_back(ad.to_v4()); + addresses.push_back(address.to_v4()); } WSACleanup(); @@ -153,7 +153,7 @@ int Host::listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort) bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) { - asserts(_listenPort); + asserts(_listenPort != 0); UPnP* upnp; try diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 3fb251d95..81a12ad1a 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -173,14 +173,21 @@ private: class FunctionDefinition: public Declaration { public: - FunctionDefinition(Location const& _location, ASTPointer const& _name, bool _isPublic, - ASTPointer const& _parameters, - bool _isDeclaredConst, - ASTPointer const& _returnParameters, - ASTPointer const& _body): - Declaration(_location, _name), m_isPublic(_isPublic), m_parameters(_parameters), - m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), - m_body(_body) {} + FunctionDefinition(Location const& _location, ASTPointer const& _name, + bool _isPublic, + ASTPointer const& _documentation, + ASTPointer const& _parameters, + bool _isDeclaredConst, + ASTPointer const& _returnParameters, + ASTPointer const& _body): + Declaration(_location, _name), m_isPublic(_isPublic), + m_parameters(_parameters), + m_isDeclaredConst(_isDeclaredConst), + m_returnParameters(_returnParameters), + m_body(_body), + m_documentation(_documentation) + {} + virtual void accept(ASTVisitor& _visitor) override; bool isPublic() const { return m_isPublic; } @@ -190,6 +197,9 @@ public: std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); } ASTPointer const& getReturnParameterList() const { return m_returnParameters; } Block& getBody() { return *m_body; } + /// @return A shared pointer of an ASTString. + /// Can contain a nullptr in which case indicates absence of documentation + ASTPointer const& getDocumentation() { return m_documentation; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } std::vector const& getLocalVariables() const { return m_localVariables; } @@ -203,6 +213,7 @@ private: bool m_isDeclaredConst; ASTPointer m_returnParameters; ASTPointer m_body; + ASTPointer m_documentation; std::vector m_localVariables; }; 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/Parser.cpp b/libsolidity/Parser.cpp index 276da0728..0506bc3e3 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -117,6 +117,10 @@ ASTPointer Parser::parseContractDefinition() ASTPointer Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); + ASTPointer docstring; + if (m_scanner->getCurrentCommentLiteral() != "") + docstring = std::make_shared(m_scanner->getCurrentCommentLiteral()); + expectToken(Token::FUNCTION); ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); @@ -142,8 +146,9 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) } ASTPointer block = parseBlock(); nodeFactory.setEndPositionFromNode(block); - return nodeFactory.createNode(name, _isPublic, parameters, - isDeclaredConst, returnParameters, block); + return nodeFactory.createNode(name, _isPublic, docstring, + parameters, + isDeclaredConst, returnParameters, block); } ASTPointer Parser::parseStructDefinition() diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index dd18a320f..4ffc2223f 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -102,18 +102,55 @@ int hexValue(char c) } } // end anonymous namespace + + +/// Scoped helper for literal recording. Automatically drops the literal +/// if aborting the scanning before it's complete. +enum LiteralType { + LITERAL_TYPE_STRING, + LITERAL_TYPE_NUMBER, // not really different from string type in behaviour + LITERAL_TYPE_COMMENT +}; + +class LiteralScope +{ +public: + explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) + , m_scanner(_self) + , m_complete(false) + { + if (_type == LITERAL_TYPE_COMMENT) + m_scanner->m_nextSkippedComment.literal.clear(); + else + m_scanner->m_nextToken.literal.clear(); + } + ~LiteralScope() + { + if (!m_complete) + { + if (m_type == LITERAL_TYPE_COMMENT) + m_scanner->m_nextSkippedComment.literal.clear(); + else + m_scanner->m_nextToken.literal.clear(); + } + } + void complete() { m_complete = true; } + +private: + enum LiteralType m_type; + Scanner* m_scanner; + bool m_complete; +}; // end of LiteralScope class + + void Scanner::reset(CharStream const& _source) { - bool foundDocComment; m_source = _source; m_char = m_source.get(); skipWhitespace(); - foundDocComment = scanToken(); + scanToken(); - // special version of Scanner:next() taking the previous scanToken() result into account - m_currentToken = m_nextToken; - if (scanToken() || foundDocComment) - m_skippedComment = m_nextSkippedComment; + next(); } @@ -142,8 +179,9 @@ BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100); Token::Value Scanner::next() { m_currentToken = m_nextToken; - if (scanToken()) - m_skippedComment = m_nextSkippedComment; + m_skippedComment = m_nextSkippedComment; + scanToken(); + return m_currentToken.token; } @@ -180,10 +218,26 @@ Token::Value Scanner::skipSingleLineComment() /// For the moment this function simply consumes a single line triple slash doc comment Token::Value Scanner::scanDocumentationComment() { - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_COMMENT); advance(); //consume the last '/' - while (!isSourcePastEndOfInput() && !isLineTerminator(m_char)) + while (!isSourcePastEndOfInput()) { + if (isLineTerminator(m_char)) + { + // check if next line is also a documentation comment + skipWhitespace(); + if (!m_source.isPastEndOfInput(3) && + m_source.get(0) == '/' && + m_source.get(1) == '/' && + m_source.get(2) == '/') + { + addCommentLiteralChar('\n'); + m_char = m_source.advanceAndGet(3); + } + else + break; // next line is not a documentation comment, we are done + + } addCommentLiteralChar(m_char); advance(); } @@ -214,10 +268,10 @@ Token::Value Scanner::skipMultiLineComment() return Token::ILLEGAL; } -bool Scanner::scanToken() +void Scanner::scanToken() { - bool foundDocComment = false; m_nextToken.literal.clear(); + m_nextSkippedComment.literal.clear(); Token::Value token; do { @@ -329,7 +383,6 @@ bool Scanner::scanToken() m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; token = Token::WHITESPACE; - foundDocComment = true; } else token = skipSingleLineComment(); @@ -425,8 +478,6 @@ bool Scanner::scanToken() while (token == Token::WHITESPACE); m_nextToken.location.end = getSourcePos(); m_nextToken.token = token; - - return foundDocComment; } bool Scanner::scanEscape() @@ -474,7 +525,7 @@ Token::Value Scanner::scanString() { char const quote = m_char; advance(); // consume quote - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_STRING); while (m_char != quote && !isSourcePastEndOfInput() && !isLineTerminator(m_char)) { char c = m_char; @@ -505,7 +556,7 @@ void Scanner::scanDecimalDigits() Token::Value Scanner::scanNumber(char _charSeen) { enum { DECIMAL, HEX, BINARY } kind = DECIMAL; - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_NUMBER); if (_charSeen == '.') { // we have already seen a decimal point of the float @@ -758,7 +809,7 @@ Token::Value Scanner::scanIdentifierOrKeyword() { if (asserts(isIdentifierStart(m_char))) BOOST_THROW_EXCEPTION(InternalCompilerError()); - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_STRING); addLiteralCharAndAdvance(); // Scan the rest of the identifier characters. while (isIdentifierPart(m_char)) @@ -767,14 +818,14 @@ Token::Value Scanner::scanIdentifierOrKeyword() return KeywordOrIdentifierToken(m_nextToken.literal); } -char CharStream::advanceAndGet() +char CharStream::advanceAndGet(size_t _chars) { if (isPastEndOfInput()) return 0; - ++m_pos; + m_pos += _chars; if (isPastEndOfInput()) return 0; - return get(); + return m_source[m_pos]; } char CharStream::rollback(size_t _amount) diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 957f02b1f..49ac3651c 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -74,9 +74,9 @@ public: CharStream(): m_pos(0) {} explicit CharStream(std::string const& _source): m_source(_source), m_pos(0) {} int getPos() const { return m_pos; } - bool isPastEndOfInput() const { return m_pos >= m_source.size(); } - char get() const { return m_source[m_pos]; } - char advanceAndGet(); + bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_pos + _charsForward) >= m_source.size(); } + char get(size_t _charsForward = 0) const { return m_source[m_pos + _charsForward]; } + char advanceAndGet(size_t _chars=1); char rollback(size_t _amount); ///@{ @@ -93,22 +93,11 @@ private: }; + class Scanner { + friend class LiteralScope; public: - /// Scoped helper for literal recording. Automatically drops the literal - /// if aborting the scanning before it's complete. - class LiteralScope - { - public: - explicit LiteralScope(Scanner* self): m_scanner(self), m_complete(false) { m_scanner->startNewLiteral(); } - ~LiteralScope() { if (!m_complete) m_scanner->dropLiteral(); } - void complete() { m_complete = true; } - - private: - Scanner* m_scanner; - bool m_complete; - }; Scanner() { reset(CharStream()); } explicit Scanner(CharStream const& _source) { reset(_source); } @@ -133,8 +122,12 @@ public: ///@{ ///@name Information about the current comment token + Location getCurrentCommentLocation() const { return m_skippedComment.location; } std::string const& getCurrentCommentLiteral() const { return m_skippedComment.literal; } + /// Called by the parser during FunctionDefinition parsing to clear the current comment + void clearCurrentCommentLiteral() { m_skippedComment.literal.clear(); } + ///@} ///@{ @@ -165,10 +158,8 @@ private: ///@{ ///@name Literal buffer support - inline void startNewLiteral() { m_nextToken.literal.clear(); } inline void addLiteralChar(char c) { m_nextToken.literal.push_back(c); } inline void addCommentLiteralChar(char c) { m_nextSkippedComment.literal.push_back(c); } - inline void dropLiteral() { m_nextToken.literal.clear(); } inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } ///@} @@ -181,9 +172,8 @@ private: bool scanHexByte(char& o_scannedByte); - /// Scans a single Solidity token. Returns true if the scanned token was - /// a skipped documentation comment. False in all other cases. - bool scanToken(); + /// Scans a single Solidity token. + void scanToken(); /// Skips all whitespace and @returns true if something was skipped. bool skipWhitespace(); 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/solidityParser.cpp b/test/solidityParser.cpp index 9319a02c5..6a97a5d99 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -37,13 +37,14 @@ namespace test namespace { -ASTPointer parseText(std::string const& _source) +ASTPointer parseText(std::string const& _source) { Parser parser; return parser.parse(std::make_shared(CharStream(_source))); } } + BOOST_AUTO_TEST_SUITE(SolidityParser) BOOST_AUTO_TEST_CASE(smoke_test) @@ -91,6 +92,164 @@ BOOST_AUTO_TEST_CASE(single_function_param) BOOST_CHECK_NO_THROW(parseText(text)); } +BOOST_AUTO_TEST_CASE(function_natspec_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " function functionName(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function"); +} + +BOOST_AUTO_TEST_CASE(function_normal_comments) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " // We won't see this comment\n" + " function functionName(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, + "Should not have gotten a Natspect comment for this function"); +} + +BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is test function 1\n" + " function functionName1(hash hashin) returns (hash hashout) {}\n" + " /// This is test function 2\n" + " function functionName2(hash hashin) returns (hash hashout) {}\n" + " // nothing to see here\n" + " function functionName3(hash hashin) returns (hash hashout) {}\n" + " /// This is test function 4\n" + " function functionName4(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 1"); + + BOOST_REQUIRE_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 2"); + + BOOST_REQUIRE_NO_THROW(function = functions.at(2)); + BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, + "Should not have gotten natspec comment for functionName3()"); + + BOOST_REQUIRE_NO_THROW(function = functions.at(3)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 4"); +} + +BOOST_AUTO_TEST_CASE(multiline_function_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " /// and it has 2 lines\n" + " function functionName1(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), + " This is a test function\n" + " and it has 2 lines"); +} + +BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " /// fun1 description\n" + " function fun1(uint256 a) {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " /// and it has 2 lines\n" + " function fun(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " fun1 description"); + + BOOST_REQUIRE_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), + " This is a test function\n" + " and it has 2 lines"); +} + +BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " function ///I am in the wrong place \n" + " fun1(uint256 a) {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(!function->getDocumentation(), + "Shouldn't get natspec docstring for this function"); +} + +BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " function fun1(uint256 a) {\n" + " /// I should have been above the function signature\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(!function->getDocumentation(), + "Shouldn't get natspec docstring for this function"); +} + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 4ae5d5bf8..66efe7dc2 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,6 +125,7 @@ + @@ -342,6 +343,7 @@ + @@ -574,4 +576,4 @@ - + \ No newline at end of file diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index fd03dd451..85f1fdedc 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -190,12 +190,6 @@ libdevcrypto - - libdevcrypto - - - libdevcrypto - libethereum @@ -205,6 +199,11 @@ libevm + + + + libethereum + @@ -444,6 +443,9 @@ libevm + + libethereum + @@ -480,4 +482,4 @@ {d838fece-fc20-42f6-bff5-97c236159b80} - + \ No newline at end of file diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index a9288a212..50824fb2d 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -131,6 +131,7 @@ + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index ae89fe550..1a0d86e56 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -48,6 +48,9 @@ libevmjit + + libevmjit +