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
+