diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8c517fef..e3a7d9b83 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -158,6 +158,7 @@ if (NOT LANGUAGES)
add_subdirectory(libqethereum)
add_subdirectory(alethzero)
add_subdirectory(third)
+ add_subdirectory(mix)
if(QTQML)
#add_subdirectory(iethxi)
#add_subdirectory(walleth) // resurect once we want to submit ourselves to QML.
@@ -171,3 +172,4 @@ add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testet
#unset(TARGET_PLATFORM CACHE)
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index e5506a660..4a32f66b2 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -1259,9 +1259,11 @@ 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 << "
Hash w/o nonce: " << info.headerHashWithoutNonce() << "";
+ s << "
Difficulty: " << info.difficulty << "";
+ s << "
Proof-of-Work: " << ProofOfWork::eval(info.headerHashWithoutNonce(), info.nonce) << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "";
s << "
Parent: " << info.parentHash << "";
// s << "
Bloom: " << details.bloom << "";
s << "
Log Bloom: " << info.logBloom << "";
@@ -1282,6 +1284,7 @@ void Main::on_blocks_currentItemChanged()
for (auto const& i: block[1])
s << "
" << sha3(i.data()).abridged();// << ": " << i[1].toHash() << " [" << i[2].toInt() << " used]";
s << "
Post: " << info.stateRoot << "";
+ s << "
Dump: " << toHex(block[0].data()) << "";
}
else
{
@@ -1665,7 +1668,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 +1679,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 +1688,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..9485a11bf 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -337,10 +337,10 @@ int main(int argc, char** argv)
web3.connect(remoteHost, remotePort);
#if ETH_JSONRPC
- auto_ptr jsonrpcServer;
+ shared_ptr jsonrpcServer;
if (jsonrpc > -1)
{
- jsonrpcServer = auto_ptr(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us}));
+ jsonrpcServer = shared_ptr(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us}));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
}
@@ -428,7 +428,7 @@ int main(int argc, char** argv)
{
if (jsonrpc < 0)
jsonrpc = 8080;
- jsonrpcServer = auto_ptr(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us}));
+ jsonrpcServer = make_shared(new jsonrpc::CorsHttpServer(jsonrpc), web3, vector({us}));
jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening();
}
@@ -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..55250b418 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.12";
}
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..744e85a27 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 = 46;
+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 c3a8b2a80..6a123875c 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/MessageFilter.cpp b/libethereum/MessageFilter.cpp
index b04d213f9..0519fe28b 100644
--- a/libethereum/MessageFilter.cpp
+++ b/libethereum/MessageFilter.cpp
@@ -198,7 +198,7 @@ LogEntries LogFilter::matches(TransactionReceipt const& _m) const
if (!m_addresses.empty() && !m_addresses.count(e.address))
continue;
for (auto const& t: m_topics)
- if (!e.topics.count(t))
+ if (!std::count(e.topics.begin(), e.topics.end(), t))
continue;
ret.push_back(e);
}
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 40327b108..9a0426e18 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())
@@ -501,7 +501,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/ExtVMFace.h b/libevm/ExtVMFace.h
index 65761e410..9e6601d0a 100644
--- a/libevm/ExtVMFace.h
+++ b/libevm/ExtVMFace.h
@@ -49,8 +49,8 @@ using LogBloom = h512;
struct LogEntry
{
LogEntry() {}
- LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = _r[2].toBytes(); }
- LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {}
+ LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256s)_r[1]; data = _r[2].toBytes(); }
+ LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(_ts), data(std::move(_d)) {}
void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; }
@@ -64,7 +64,7 @@ struct LogEntry
}
Address address;
- h256Set topics;
+ h256s topics;
bytes data;
};
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 425eab8c8..5fb46fc68 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -53,9 +53,6 @@ inline Address asAddress(u256 _item)
inline u256 fromAddress(Address _a)
{
return (u160)_a;
-// h256 ret;
-// memcpy(&ret, &_a, sizeof(_a));
-// return ret;
}
/**
@@ -131,6 +128,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,15 +170,15 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
// These all operate on memory and therefore potentially expand it:
case Instruction::MSTORE:
require(2);
- newTempSize = m_stack.back() + 32;
+ newTempSize = (bigint)m_stack.back() + 32;
break;
case Instruction::MSTORE8:
require(2);
- newTempSize = m_stack.back() + 1;
+ newTempSize = (bigint)m_stack.back() + 1;
break;
case Instruction::MLOAD:
require(1);
- newTempSize = m_stack.back() + 32;
+ newTempSize = (bigint)m_stack.back() + 32;
break;
case Instruction::RETURN:
require(2);
@@ -193,14 +191,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;
@@ -232,10 +233,17 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::CREATE:
{
require(3);
- auto inOff = m_stack[m_stack.size() - 2];
- auto inSize = m_stack[m_stack.size() - 3];
- newTempSize = inOff + inSize;
- runGas = c_createGas;
+ u256 inOff = m_stack[m_stack.size() - 2];
+ u256 inSize = m_stack[m_stack.size() - 3];
+ newTempSize = (bigint)inOff + inSize;
+ 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;
}
@@ -304,7 +312,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:
@@ -365,6 +372,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/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp
index 4725c8c1a..059810af8 100644
--- a/libevmcore/Assembly.cpp
+++ b/libevmcore/Assembly.cpp
@@ -27,6 +27,32 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
+unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const
+{
+ switch (m_type)
+ {
+ case Operation:
+ case Tag: // 1 byte for the JUMPDEST
+ return 1;
+ case PushString:
+ return 33;
+ case Push:
+ return 1 + max(1, dev::bytesRequired(m_data));
+ case PushSubSize:
+ return 4; // worst case: a 16MB program
+ case PushTag:
+ case PushData:
+ case PushSub:
+ return 1 + _addressLength;
+ case NoOptimizeBegin:
+ case NoOptimizeEnd:
+ return 0;
+ default:
+ break;
+ }
+ BOOST_THROW_EXCEPTION(InvalidOpcode());
+}
+
int AssemblyItem::deposit() const
{
switch (m_type)
@@ -51,32 +77,7 @@ unsigned Assembly::bytesRequired() const
ret += i.second.size();
for (AssemblyItem const& i: m_items)
- switch (i.m_type)
- {
- case Operation:
- case Tag: // 1 byte for the JUMPDEST
- ret++;
- break;
- case PushString:
- ret += 33;
- break;
- case Push:
- ret += 1 + max(1, dev::bytesRequired(i.m_data));
- break;
- case PushSubSize:
- ret += 4; // worst case: a 16MB program
- break;
- case PushTag:
- case PushData:
- case PushSub:
- ret += 1 + br;
- break;
- case NoOptimizeBegin:
- case NoOptimizeEnd:
- break;
- default:
- BOOST_THROW_EXCEPTION(InvalidOpcode());
- }
+ ret += i.bytesRequired(br);
if (dev::bytesRequired(ret) <= br)
return ret;
}
@@ -243,6 +244,18 @@ inline bool popCountIncreased(AssemblyItemsConstRef _pre, AssemblyItems const& _
return count_if(begin(_post), end(_post), isPop) > count_if(begin(_pre), end(_pre), isPop);
}
+//@todo this has to move to a special optimizer class soon
+template
+unsigned bytesRequiredBySlice(Iterator _begin, Iterator _end)
+{
+ // this is only used in the optimizer, so we can provide a guess for the address length
+ unsigned addressLength = 4;
+ unsigned size = 0;
+ for (; _begin != _end; ++_begin)
+ size += _begin->bytesRequired(addressLength);
+ return size;
+}
+
struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; };
#define copt dev::LogOutputStream()
@@ -258,7 +271,7 @@ Assembly& Assembly::optimise(bool _enable)
u256 mask = (u256(1) << testBit) - 1;
return boost::multiprecision::bit_test(b, testBit) ? b | ~mask : b & mask;
};
- map> c_simple =
+ map> const c_simple =
{
{ Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} },
{ Instruction::DIV, [](u256 a, u256 b)->u256{return a / b;} },
@@ -273,7 +286,7 @@ Assembly& Assembly::optimise(bool _enable)
{ Instruction::SGT, [](u256 a, u256 b)->u256{return u2s(a) > u2s(b) ? 1 : 0;} },
{ Instruction::EQ, [](u256 a, u256 b)->u256{return a == b ? 1 : 0;} },
};
- map> c_associative =
+ map> const c_associative =
{
{ Instruction::ADD, [](u256 a, u256 b)->u256{return a + b;} },
{ Instruction::MUL, [](u256 a, u256 b)->u256{return a * b;} },
@@ -281,6 +294,8 @@ Assembly& Assembly::optimise(bool _enable)
{ Instruction::OR, [](u256 a, u256 b)->u256{return a | b;} },
{ Instruction::XOR, [](u256 a, u256 b)->u256{return a ^ b;} },
};
+ std::vector> const c_identities =
+ { { Instruction::ADD, 0}, { Instruction::MUL, 1}, { Instruction::MOD, 0}, { Instruction::OR, 0}, { Instruction::XOR, 0} };
std::vector>> rules =
{
{ { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
@@ -299,8 +314,11 @@ Assembly& Assembly::optimise(bool _enable)
rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } });
rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } });
}
+ for (auto const& i: c_identities)
+ rules.push_back({{Push, i.first}, [&](AssemblyItemsConstRef m) -> AssemblyItems
+ { return m[0].data() == i.second ? AssemblyItems() : m.toVector(); }});
// jump to next instruction
- rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }});
+ rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }});
// pop optimization, do not compute values that are popped again anyway
rules.push_back({ { AssemblyItem(UndefinedItem), Instruction::POP }, [](AssemblyItemsConstRef m) -> AssemblyItems
@@ -315,6 +333,29 @@ Assembly& Assembly::optimise(bool _enable)
return m.toVector();
return AssemblyItems(info.args, Instruction::POP);
} });
+ // compute constants close to powers of two by expressions
+ auto computeConstants = [](AssemblyItemsConstRef m) -> AssemblyItems
+ {
+ u256 const& c = m[0].data();
+ unsigned const minBits = 4 * 8;
+ if (c < (bigint(1) << minBits))
+ return m.toVector(); // we need at least "PUSH1 PUSH1 <2> EXP"
+ if (c == u256(-1))
+ return {u256(0), Instruction::NOT};
+ for (unsigned bits = minBits; bits < 256; ++bits)
+ {
+ bigint const diff = c - (bigint(1) << bits);
+ if (abs(diff) > 0xff)
+ continue;
+ AssemblyItems powerOfTwo{u256(bits), u256(2), Instruction::EXP};
+ if (diff == 0)
+ return powerOfTwo;
+ return AssemblyItems{u256(abs(diff))} + powerOfTwo +
+ AssemblyItems{diff > 0 ? Instruction::ADD : Instruction::SUB};
+ }
+ return m.toVector();
+ };
+ rules.push_back({{Push}, computeConstants});
copt << *this;
@@ -336,15 +377,27 @@ Assembly& Assembly::optimise(bool _enable)
if (matches(vr, &r.first))
{
auto rw = r.second(vr);
- if (rw.size() < vr.size() || (rw.size() == vr.size() && popCountIncreased(vr, rw)))
+ unsigned const vrSize = bytesRequiredBySlice(vr.begin(), vr.end());
+ unsigned const rwSize = bytesRequiredBySlice(rw.begin(), rw.end());
+ //@todo check the actual size (including constant sizes)
+ if (rwSize < vrSize || (rwSize == vrSize && popCountIncreased(vr, rw)))
{
copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes...";
- for (unsigned j = 0; j < vr.size(); ++j)
+ copt << AssemblyItemsConstRef(&rw);
+ if (rw.size() > vr.size())
+ {
+ // create hole in the vector
+ unsigned sizeIncrease = rw.size() - vr.size();
+ m_items.resize(m_items.size() + sizeIncrease, AssemblyItem(UndefinedItem));
+ move_backward(m_items.begin() + i, m_items.end() - sizeIncrease, m_items.end());
+ }
+
+ for (unsigned j = 0; j < max(rw.size(), vr.size()); ++j)
if (j < rw.size())
m_items[i + j] = rw[j];
else
m_items.erase(m_items.begin() + i + rw.size());
- copt << AssemblyItemsConstRef(&rw);
+
count++;
copt << "Now:\n" << m_items;
}
diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h
index b8e59a474..b144dd8d9 100644
--- a/libevmcore/Assembly.h
+++ b/libevmcore/Assembly.h
@@ -51,6 +51,9 @@ public:
AssemblyItemType type() const { return m_type; }
u256 data() const { return m_data; }
+ /// @returns an upper bound for the number of bytes required by this item, assuming that
+ /// the value of a jump tag takes @a _addressLength bytes.
+ unsigned bytesRequired(unsigned _addressLength) const;
int deposit() const;
bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); }
diff --git a/libevmcore/Instruction.h b/libevmcore/Instruction.h
index eb85c0610..f8a0478f1 100644
--- a/libevmcore/Instruction.h
+++ b/libevmcore/Instruction.h
@@ -168,8 +168,8 @@ enum class Instruction: uint8_t
CREATE = 0xf0, ///< create a new account with associated code
CALL, ///< message-call into an account
+ CALLCODE, ///< message-call with another account's code only
RETURN, ///< halt execution returning output data
- CALLCODE,
SUICIDE = 0xff ///< halt execution and register account for later deletion
};
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 85225ab7f..546d54c00 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -79,7 +79,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();
@@ -154,9 +154,9 @@ 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;
+ UPnP* upnp = nullptr;
try
{
upnp = new UPnP;
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index 5c07ec80e..4bd0b2c0e 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -378,6 +378,9 @@ void Assignment::checkTypeRequirements()
{
m_leftHandSide->checkTypeRequirements();
m_leftHandSide->requireLValue();
+ //@todo later, assignments to structs might be possible, but not to mappings
+ if (!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue())
+ BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue."));
m_rightHandSide->expectType(*m_leftHandSide->getType());
m_type = m_leftHandSide->getType();
if (m_assigmentOperator != Token::ASSIGN)
@@ -403,7 +406,7 @@ void Expression::expectType(Type const& _expectedType)
void Expression::requireLValue()
{
- if (!isLvalue())
+ if (!isLValue())
BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
m_lvalueRequested = true;
}
@@ -495,7 +498,8 @@ void MemberAccess::checkTypeRequirements()
m_type = type.getMemberType(*m_memberName);
if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString()));
- m_isLvalue = (type.getCategory() == Type::Category::STRUCT && m_type->getCategory() != Type::Category::MAPPING);
+ //@todo later, this will not always be STORAGE
+ m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE;
}
void IndexAccess::checkTypeRequirements()
@@ -507,7 +511,7 @@ void IndexAccess::checkTypeRequirements()
MappingType const& type = dynamic_cast(*m_base->getType());
m_index->expectType(*type.getKeyType());
m_type = type.getValueType();
- m_isLvalue = m_type->getCategory() != Type::Category::MAPPING;
+ m_lvalue = LValueType::STORAGE;
}
void Identifier::checkTypeRequirements()
@@ -521,7 +525,7 @@ void Identifier::checkTypeRequirements()
if (!variable->getType())
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
m_type = variable->getType();
- m_isLvalue = true;
+ m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE;
return;
}
//@todo can we unify these with TypeName::toType()?
diff --git a/libsolidity/AST.h b/libsolidity/AST.h
index 3fb251d95..87bc3cd40 100644
--- a/libsolidity/AST.h
+++ b/libsolidity/AST.h
@@ -88,11 +88,16 @@ public:
Declaration(Location const& _location, ASTPointer const& _name):
ASTNode(_location), m_name(_name) {}
- /// Returns the declared name.
+ /// @returns the declared name.
ASTString const& getName() const { return *m_name; }
+ /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
+ /// Available only after name and type resolution step.
+ Declaration* getScope() const { return m_scope; }
+ void setScope(Declaration* const& _scope) { m_scope = _scope; }
private:
ASTPointer m_name;
+ Declaration* m_scope;
};
/**
@@ -173,14 +178,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 +202,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 +218,7 @@ private:
bool m_isDeclaredConst;
ASTPointer m_returnParameters;
ASTPointer m_body;
+ ASTPointer m_documentation;
std::vector m_localVariables;
};
@@ -226,6 +242,8 @@ public:
std::shared_ptr const& getType() const { return m_type; }
void setType(std::shared_ptr const& _type) { m_type = _type; }
+ bool isLocalVariable() const { return !!dynamic_cast(getScope()); }
+
private:
ASTPointer m_typeName; ///< can be empty ("var")
@@ -510,12 +528,16 @@ private:
*/
class Expression: public ASTNode
{
+protected:
+ enum class LValueType { NONE, LOCAL, STORAGE };
+
public:
- Expression(Location const& _location): ASTNode(_location), m_isLvalue(false), m_lvalueRequested(false) {}
+ Expression(Location const& _location): ASTNode(_location), m_lvalue(LValueType::NONE), m_lvalueRequested(false) {}
virtual void checkTypeRequirements() = 0;
std::shared_ptr const& getType() const { return m_type; }
- bool isLvalue() const { return m_isLvalue; }
+ bool isLValue() const { return m_lvalue != LValueType::NONE; }
+ bool isLocalLValue() const { return m_lvalue == LValueType::LOCAL; }
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it
/// is implicitly convertible to @a _expectedType. If not, throw exception.
@@ -530,9 +552,9 @@ public:
protected:
//! Inferred type of the expression, only filled after a call to checkTypeRequirements().
std::shared_ptr m_type;
- //! Whether or not this expression is an lvalue, i.e. something that can be assigned to.
- //! This is set during calls to @a checkTypeRequirements()
- bool m_isLvalue;
+ //! If this expression is an lvalue (i.e. something that can be assigned to) and is stored
+ //! locally or in storage. This is set during calls to @a checkTypeRequirements()
+ LValueType m_lvalue;
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
bool m_lvalueRequested;
};
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index 988390d0b..17ad4fd16 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -324,7 +324,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement)
{
Expression& expression = _expressionStatement.getExpression();
ExpressionCompiler::compileExpression(m_context, expression);
- Type::Category category = expression.getType()->getCategory();
+// Type::Category category = expression.getType()->getCategory();
for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i)
m_context << eth::Instruction::POP;
return false;
diff --git a/libsolidity/Scope.cpp b/libsolidity/DeclarationContainer.cpp
similarity index 78%
rename from libsolidity/Scope.cpp
rename to libsolidity/DeclarationContainer.cpp
index 540c41204..6ea9c28c5 100644
--- a/libsolidity/Scope.cpp
+++ b/libsolidity/DeclarationContainer.cpp
@@ -20,7 +20,7 @@
* Scope - object that holds declaration of names.
*/
-#include
+#include
#include
namespace dev
@@ -28,7 +28,7 @@ namespace dev
namespace solidity
{
-bool Scope::registerDeclaration(Declaration& _declaration)
+bool DeclarationContainer::registerDeclaration(Declaration& _declaration)
{
if (m_declarations.find(_declaration.getName()) != m_declarations.end())
return false;
@@ -36,13 +36,13 @@ bool Scope::registerDeclaration(Declaration& _declaration)
return true;
}
-Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const
+Declaration* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const
{
auto result = m_declarations.find(_name);
if (result != m_declarations.end())
return result->second;
- if (_recursive && m_enclosingScope)
- return m_enclosingScope->resolveName(_name, true);
+ if (_recursive && m_enclosingContainer)
+ return m_enclosingContainer->resolveName(_name, true);
return nullptr;
}
diff --git a/libsolidity/Scope.h b/libsolidity/DeclarationContainer.h
similarity index 77%
rename from libsolidity/Scope.h
rename to libsolidity/DeclarationContainer.h
index 637c2d5ce..db6812890 100644
--- a/libsolidity/Scope.h
+++ b/libsolidity/DeclarationContainer.h
@@ -36,18 +36,20 @@ namespace solidity
* Container that stores mappings betwee names and declarations. It also contains a link to the
* enclosing scope.
*/
-class Scope
+class DeclarationContainer
{
public:
- explicit Scope(Scope* _enclosingScope = nullptr): m_enclosingScope(_enclosingScope) {}
+ explicit DeclarationContainer(Declaration* _enclosingDeclaration = nullptr, DeclarationContainer* _enclosingContainer = nullptr):
+ m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
/// Registers the declaration in the scope unless its name is already declared. Returns true iff
/// it was not yet declared.
bool registerDeclaration(Declaration& _declaration);
Declaration* resolveName(ASTString const& _name, bool _recursive = false) const;
- Scope* getEnclosingScope() const { return m_enclosingScope; }
+ Declaration* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
private:
- Scope* m_enclosingScope;
+ Declaration* m_enclosingDeclaration;
+ DeclarationContainer* m_enclosingContainer;
std::map m_declarations;
};
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/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp
index 225f2a78a..d473348b8 100644
--- a/libsolidity/NameAndTypeResolver.cpp
+++ b/libsolidity/NameAndTypeResolver.cpp
@@ -78,9 +78,9 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name
return m_currentScope->resolveName(_name, _recursive);
}
-DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes,
+DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes,
ASTNode& _astRoot):
- m_scopes(_scopes), m_currentScope(&m_scopes[nullptr])
+ m_scopes(_scopes), m_currentScope(nullptr)
{
_astRoot.accept(*this);
}
@@ -135,31 +135,30 @@ bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration)
return true;
}
-void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node)
+void DeclarationRegistrationHelper::enterNewSubScope(Declaration& _declaration)
{
- map::iterator iter;
+ map::iterator iter;
bool newlyAdded;
- tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope));
+ tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope]));
if (asserts(newlyAdded))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope."));
- m_currentScope = &iter->second;
+ m_currentScope = &_declaration;
}
void DeclarationRegistrationHelper::closeCurrentScope()
{
if (asserts(m_currentScope))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope."));
- m_currentScope = m_currentScope->getEnclosingScope();
+ m_currentScope = m_scopes[m_currentScope].getEnclosingDeclaration();
}
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
{
- if (asserts(m_currentScope))
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration registered without scope."));
- if (!m_currentScope->registerDeclaration(_declaration))
+ if (!m_scopes[m_currentScope].registerDeclaration(_declaration))
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
<< errinfo_comment("Identifier already declared."));
//@todo the exception should also contain the location of the first declaration
+ _declaration.setScope(m_currentScope);
if (_opensScope)
enterNewSubScope(_declaration);
}
diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h
index 64f3c89db..797eca605 100644
--- a/libsolidity/NameAndTypeResolver.h
+++ b/libsolidity/NameAndTypeResolver.h
@@ -25,7 +25,7 @@
#include