Browse Source

Merge branch 'develop' into natspec

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
ef00bc98d3
  1. 10
      alethzero/Main.ui
  2. 67
      alethzero/MainWin.cpp
  3. 3
      libethereum/Account.h
  4. 3
      libethereum/BlockChain.cpp
  5. 2
      libethereum/Client.cpp
  6. 4
      libethereum/Executive.cpp
  7. 2
      libethereum/State.cpp
  8. 6
      libethereum/Transaction.cpp
  9. 11
      libethereum/Transaction.h
  10. 6
      libethereum/TransactionQueue.cpp
  11. 1
      liblll/CodeFragment.cpp
  12. 1
      liblll/CodeFragment.h
  13. 7
      libsolidity/AST.cpp
  14. 5
      libsolidity/AST.h
  15. 9
      libsolidity/CallGraph.cpp
  16. 8
      libsolidity/CallGraph.h
  17. 33
      libsolidity/Compiler.cpp
  18. 5
      libsolidity/Compiler.h
  19. 43
      libsolidity/CompilerStack.cpp
  20. 4
      libsolidity/CompilerStack.h
  21. 10
      libsolidity/InterfaceHandler.cpp
  22. 13
      libsolidity/Parser.cpp
  23. 2
      libsolidity/Parser.h
  24. 2
      libsolidity/Types.cpp
  25. 5
      neth/main.cpp
  26. 22
      test/SolidityEndToEndTest.cpp
  27. 28
      test/SolidityNatspecJSON.cpp
  28. 2
      test/TestHelper.cpp

10
alethzero/Main.ui

@ -95,8 +95,8 @@
<widget class="QLineEdit" name="urlEdit"/> <widget class="QLineEdit" name="urlEdit"/>
</item> </item>
<item> <item>
<widget class="QWebView" name="webView" native="true"> <widget class="QWebView" name="webView">
<property name="url" stdset="0"> <property name="url">
<url> <url>
<string>about:blank</string> <string>about:blank</string>
</url> </url>
@ -1212,8 +1212,8 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QWebView" name="jsConsole" native="true"> <widget class="QWebView" name="jsConsole">
<property name="url" stdset="0"> <property name="url">
<url> <url>
<string>about:blank</string> <string>about:blank</string>
</url> </url>
@ -2035,7 +2035,7 @@ font-size: 14pt</string>
</action> </action>
<action name="importKeyFile"> <action name="importKeyFile">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>true</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Claim Ether Presale &amp;Wallet...</string> <string>Claim Ether Presale &amp;Wallet...</string>

67
alethzero/MainWin.cpp

@ -60,6 +60,11 @@ using namespace dev::p2p;
using namespace dev::eth; using namespace dev::eth;
namespace js = json_spirit; namespace js = json_spirit;
#define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "
#define Div(S) "<div style=\"" S "\">"
#define Span(S) "<span style=\"" S "\">"
static void initUnits(QComboBox* _b) static void initUnits(QComboBox* _b)
{ {
for (auto n = (unsigned)units().size(); n-- != 0; ) for (auto n = (unsigned)units().size(); n-- != 0; )
@ -452,7 +457,7 @@ void Main::eval(QString const& _js)
else else
s = "<span style=\"color: #888\">unknown type</span>"; s = "<span style=\"color: #888\">unknown type</span>";
m_consoleHistory.push_back(qMakePair(_js, s)); m_consoleHistory.push_back(qMakePair(_js, s));
s = "<html><body style=\"font-family: Monospace, Ubuntu Mono, Lucida Console, Courier New; margin: 0; font-size: 12pt\"><div style=\"position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%\">"; s = "<html><body style=\"margin: 0;\">" Div(Mono "position: absolute; bottom: 0; border: 0px; margin: 0px; width: 100%");
for (auto const& i: m_consoleHistory) for (auto const& i: m_consoleHistory)
s += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>" s += "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em; color: #888; font-weight: bold\">&gt;</span><span style=\"color: #35d\">" + i.first.toHtmlEscaped() + "</span></div>"
"<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>"; "<div style=\"border-bottom: 1 solid #eee; width: 100%\"><span style=\"float: left; width: 1em\">&nbsp;</span><span>" + i.second + "</span></div>";
@ -755,7 +760,7 @@ void Main::on_importKey_triggered()
void Main::on_importKeyFile_triggered() void Main::on_importKeyFile_triggered()
{ {
QString s = QFileDialog::getOpenFileName(this, "Import Account", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
try try
{ {
js::mValue val; js::mValue val;
@ -785,9 +790,13 @@ void Main::on_importKeyFile_triggered()
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end()) if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end())
{ {
m_myKeys.append(k); if (m_myKeys.empty())
{
m_myKeys.push_back(KeyPair::create());
keysChanged(); keysChanged();
} }
ethereum()->transact(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice());
}
else else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
} }
@ -1093,7 +1102,7 @@ void Main::refreshBlockChain()
auto b = bc.block(h); auto b = bc.block(h);
for (auto const& i: RLP(b)[1]) for (auto const& i: RLP(b)[1])
{ {
Transaction t(i.data()); Transaction t(i.data(), CheckSignature::Sender);
if (bm || transactionMatch(filter, t)) if (bm || transactionMatch(filter, t))
{ {
QString s = t.receiveAddress() ? QString s = t.receiveAddress() ?
@ -1276,12 +1285,12 @@ void Main::on_transactionQueue_currentItemChanged()
if (tx.data().size()) if (tx.data().size())
s << dev::memDump(tx.data(), 16, true); s << dev::memDump(tx.data(), 16, true);
} }
s << "<div>Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(tx.rlp()) << "</span></div>"; s << "<div>Hex: " Span(Mono) << toHex(tx.rlp()) << "</span></div>";
s << "<hr/>"; s << "<hr/>";
s << "<div>Log Bloom: " << receipt.bloom() << "</div>"; s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
auto r = receipt.rlp(); auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>"; s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(receipt.rlp()) << "</span></div>"; s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
s << renderDiff(ethereum()->diff(i, 0)); s << renderDiff(ethereum()->diff(i, 0));
// s << "Pre: " << fs.rootHash() << "<br/>"; // s << "Pre: " << fs.rootHash() << "<br/>";
// s << "Post: <b>" << ts.rootHash() << "</b>"; // s << "Post: <b>" << ts.rootHash() << "</b>";
@ -1372,13 +1381,13 @@ void Main::on_blocks_currentItemChanged()
for (auto const& i: block[1]) for (auto const& i: block[1])
s << "<br/>" << sha3(i.data()).abridged();// << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]"; s << "<br/>" << sha3(i.data()).abridged();// << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]";
s << "<br/>Post: <b>" << info.stateRoot << "</b>"; s << "<br/>Post: <b>" << info.stateRoot << "</b>";
s << "<br/>Dump: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[0].data()) << "</span>"; s << "<br/>Dump: " Span(Mono) << toHex(block[0].data()) << "</span>";
s << "<div>Receipts-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(ethereum()->blockChain().receipts(h).rlp()) << "</span></div>"; s << "<div>Receipts-Hex: " Span(Mono) << toHex(ethereum()->blockChain().receipts(h).rlp()) << "</span></div>";
} }
else else
{ {
unsigned txi = item->data(Qt::UserRole + 1).toInt(); unsigned txi = item->data(Qt::UserRole + 1).toInt();
Transaction tx(block[1][txi].data()); Transaction tx(block[1][txi].data(), CheckSignature::Sender);
auto ss = tx.safeSender(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce())); h256 th = sha3(rlpList(ss, tx.nonce()));
TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi]; TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi];
@ -1407,12 +1416,12 @@ void Main::on_blocks_currentItemChanged()
if (tx.data().size()) if (tx.data().size())
s << dev::memDump(tx.data(), 16, true); s << dev::memDump(tx.data(), 16, true);
} }
s << "<div>Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[1][txi].data()) << "</span></div>"; s << "<div>Hex: " Span(Mono) << toHex(block[1][txi].data()) << "</span></div>";
s << "<hr/>"; s << "<hr/>";
s << "<div>Log Bloom: " << receipt.bloom() << "</div>"; s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
auto r = receipt.rlp(); auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>"; s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(receipt.rlp()) << "</span></div>"; s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
s << renderDiff(ethereum()->diff(txi, h)); s << renderDiff(ethereum()->diff(txi, h));
ui->debugCurrent->setEnabled(true); ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true); ui->debugDumpState->setEnabled(true);
@ -1531,6 +1540,7 @@ void Main::on_contracts_currentItemChanged()
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>"; s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>";
s << "<h4>Body Code</h4>" << disassemble(ethereum()->codeAt(address)); s << "<h4>Body Code</h4>" << disassemble(ethereum()->codeAt(address));
s << Div(Mono) << toHex(ethereum()->codeAt(address)) << "</div>";
ui->contractInfo->appendHtml(QString::fromStdString(s.str())); ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
} }
catch (dev::InvalidTrie) catch (dev::InvalidTrie)
@ -1640,13 +1650,18 @@ static shh::Topic topicFromText(QString _s)
return ret; return ret;
} }
bool Main::sourceIsSolidity(string const& _source) bool Main::sourceIsSolidity(string const& _source)
{ {
// TODO: Improve this heuristic // TODO: Improve this heuristic
return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol"); return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol");
} }
static bool sourceIsSerpent(string const& _source)
{
// TODO: Improve this heuristic
return (_source.substr(0, 5) == "//ser");
}
string const Main::getFunctionHashes(dev::solidity::CompilerStack const &_compiler, string const Main::getFunctionHashes(dev::solidity::CompilerStack const &_compiler,
string const& _contractName) string const& _contractName)
{ {
@ -1681,6 +1696,7 @@ void Main::on_data_textChanged()
dev::solidity::CompilerStack compiler; dev::solidity::CompilerStack compiler;
try try
{ {
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, m_enableOptimizer); m_data = compiler.compile(src, m_enableOptimizer);
solidity = "<h4>Solidity</h4>"; solidity = "<h4>Solidity</h4>";
solidity += "<pre>" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "</pre>"; solidity += "<pre>" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "</pre>";
@ -1698,10 +1714,7 @@ void Main::on_data_textChanged()
solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>"; solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>";
} }
} }
else else if (sourceIsSerpent(src))
{
m_data = compileLLL(src, m_enableOptimizer, &errors);
if (errors.size())
{ {
try try
{ {
@ -1715,6 +1728,9 @@ void Main::on_data_textChanged()
} }
} }
else else
{
m_data = compileLLL(src, m_enableOptimizer, &errors);
if (errors.empty())
{ {
auto asmcode = compileLLLToAsm(src, false); auto asmcode = compileLLLToAsm(src, false);
lll = "<h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>"; lll = "<h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>";
@ -1732,7 +1748,7 @@ void Main::on_data_textChanged()
for (auto const& i: errors) for (auto const& i: errors)
errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>"); errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>");
} }
ui->code->setHtml(errs + lll + solidity + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); ui->code->setHtml(errs + lll + solidity + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "<h4>Hex</h4>" Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>");
ui->gas->setMinimum((qint64)Client::txGas(m_data, 0)); ui->gas->setMinimum((qint64)Client::txGas(m_data, 0));
if (!ui->gas->isEnabled()) if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas); ui->gas->setValue(m_backupGas);
@ -1965,9 +1981,24 @@ void Main::on_debug_clicked()
} }
} }
bool beginsWith(Address _a, bytes const& _b)
{
for (unsigned i = 0; i < min<unsigned>(20, _b.size()); ++i)
if (_a[i] != _b[i])
return false;
return true;
}
void Main::on_create_triggered() void Main::on_create_triggered()
{ {
m_myKeys.append(KeyPair::create()); bool ok = true;
QString s = QInputDialog::getText(this, "Special Beginning?", "If you want a special key, enter some hex digits that it should begin with.\nNOTE: The more you enter, the longer generation will take.", QLineEdit::Normal, QString(), &ok);
if (!ok)
return;
KeyPair p;
while (!beginsWith(p.address(), asBytes(s.toStdString())))
p = KeyPair::create();
m_myKeys.append(p);
keysChanged(); keysChanged();
} }

3
libethereum/Account.h

@ -140,7 +140,8 @@ public:
h256 codeHash() const { assert(!isFreshCode()); return m_codeHash; } h256 codeHash() const { assert(!isFreshCode()); return m_codeHash; }
/// Sets the code of the account. Must only be called when isFreshCode() returns true. /// Sets the code of the account. Must only be called when isFreshCode() returns true.
void setCode(bytesConstRef _code) { assert(isFreshCode()); m_codeCache = _code.toBytes(); } void setCode(bytes&& _code) { assert(isFreshCode()); m_codeCache = _code; }
void setCode(bytes const& _code) { assert(isFreshCode()); m_codeCache = _code; }
/// @returns true if the account's code is available through code(). /// @returns true if the account's code is available through code().
bool codeCacheValid() const { return m_codeHash == EmptySHA3 || m_codeHash == c_contractConceptionCodeHash || m_codeCache.size(); } bool codeCacheValid() const { return m_codeHash == EmptySHA3 || m_codeHash == c_contractConceptionCodeHash || m_codeCache.size(); }

3
libethereum/BlockChain.cpp

@ -28,6 +28,7 @@
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <liblll/Compiler.h>
#include "State.h" #include "State.h"
#include "Defaults.h" #include "Defaults.h"
using namespace std; using namespace std;
@ -56,6 +57,7 @@ std::map<Address, Account> const& dev::eth::genesisState()
{ {
static std::map<Address, Account> s_ret; static std::map<Address, Account> s_ret;
if (s_ret.empty()) if (s_ret.empty())
{
// Initialise. // Initialise.
for (auto i: vector<string>({ for (auto i: vector<string>({
"51ba59315b3a95761d0863b05ccc7a7f54703d99", "51ba59315b3a95761d0863b05ccc7a7f54703d99",
@ -68,6 +70,7 @@ std::map<Address, Account> const& dev::eth::genesisState()
"e4157b34ea9615cfbde6b4fda419828124b70c78" "e4157b34ea9615cfbde6b4fda419828124b70c78"
})) }))
s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation); s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation);
}
return s_ret; return s_ret;
} }

2
libethereum/Client.cpp

@ -642,7 +642,7 @@ Transaction Client::transaction(h256 _blockHash, unsigned _i) const
{ {
auto bl = m_bc.block(_blockHash); auto bl = m_bc.block(_blockHash);
RLP b(bl); RLP b(bl);
return Transaction(b[1][_i].data()); return Transaction(b[1][_i].data(), CheckSignature::Range);
} }
BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const

4
libethereum/Executive.cpp

@ -53,7 +53,7 @@ void Executive::accrueSubState(SubState& _parentContext)
bool Executive::setup(bytesConstRef _rlp) bool Executive::setup(bytesConstRef _rlp)
{ {
// Entry point for a user-executed transaction. // Entry point for a user-executed transaction.
m_t = Transaction(_rlp); m_t = Transaction(_rlp, CheckSignature::Sender);
// Avoid invalid transactions. // Avoid invalid transactions.
auto nonceReq = m_s.transactionsFrom(m_t.sender()); auto nonceReq = m_s.transactionsFrom(m_t.sender());
@ -197,7 +197,7 @@ bool Executive::go(OnOpFunc const& _onOp)
m_endGas -= m_out.size() * c_createDataGas; m_endGas -= m_out.size() * c_createDataGas;
else else
m_out.reset(); m_out.reset();
m_s.m_cache[m_newAddress].setCode(m_out); m_s.m_cache[m_newAddress].setCode(m_out.toBytes());
} }
} }
catch (StepsDone const&) catch (StepsDone const&)

2
libethereum/State.cpp

@ -395,7 +395,7 @@ bool State::cull(TransactionQueue& _tq) const
{ {
try try
{ {
Transaction t(i.second); Transaction t(i.second, CheckSignature::Sender);
if (t.nonce() <= transactionsFrom(t.sender())) if (t.nonce() <= transactionsFrom(t.sender()))
{ {
_tq.drop(i.first); _tq.drop(i.first);

6
libethereum/Transaction.cpp

@ -30,7 +30,7 @@ using namespace dev::eth;
#define ETH_ADDRESS_DEBUG 0 #define ETH_ADDRESS_DEBUG 0
Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig)
{ {
int field = 0; int field = 0;
RLP rlp(_rlpData); RLP rlp(_rlpData);
@ -47,7 +47,9 @@ Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender)
h256 r = rlp[field = 7].toInt<u256>(); h256 r = rlp[field = 7].toInt<u256>();
h256 s = rlp[field = 8].toInt<u256>(); h256 s = rlp[field = 8].toInt<u256>();
m_vrs = SignatureStruct{ r, s, v }; m_vrs = SignatureStruct{ r, s, v };
if (_checkSender) if (_checkSig >= CheckSignature::Range && !m_vrs.isValid())
BOOST_THROW_EXCEPTION(InvalidSignature());
if (_checkSig == CheckSignature::Sender)
m_sender = sender(); m_sender = sender();
} }
catch (Exception& _e) catch (Exception& _e)

11
libethereum/Transaction.h

@ -37,6 +37,13 @@ enum IncludeSignature
WithSignature = 1, ///< Do include a signature. WithSignature = 1, ///< Do include a signature.
}; };
enum class CheckSignature
{
None,
Range,
Sender
};
/// Encodes a transaction, ready to be exported to or freshly imported from RLP. /// Encodes a transaction, ready to be exported to or freshly imported from RLP.
class Transaction class Transaction
{ {
@ -57,10 +64,10 @@ public:
Transaction(u256 _value, u256 _gasPrice, u256 _gas, bytes const& _data): m_type(ContractCreation), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} Transaction(u256 _value, u256 _gasPrice, u256 _gas, bytes const& _data): m_type(ContractCreation), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {}
/// Constructs a transaction from the given RLP. /// Constructs a transaction from the given RLP.
explicit Transaction(bytesConstRef _rlp, bool _checkSender = false); explicit Transaction(bytesConstRef _rlp, CheckSignature _checkSig);
/// Constructs a transaction from the given RLP. /// Constructs a transaction from the given RLP.
explicit Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} explicit Transaction(bytes const& _rlp, CheckSignature _checkSig): Transaction(&_rlp, _checkSig) {}
/// Checks equality of transactions. /// Checks equality of transactions.

6
libethereum/TransactionQueue.cpp

@ -42,7 +42,7 @@ bool TransactionQueue::import(bytesConstRef _transactionRLP)
// Check validity of _transactionRLP as a transaction. To do this we just deserialise and attempt to determine the sender. // Check validity of _transactionRLP as a transaction. To do this we just deserialise and attempt to determine the sender.
// If it doesn't work, the signature is bad. // If it doesn't work, the signature is bad.
// The transaction's nonce may yet be invalid (or, it could be "valid" but we may be missing a marginally older transaction). // The transaction's nonce may yet be invalid (or, it could be "valid" but we may be missing a marginally older transaction).
Transaction t(_transactionRLP, true); Transaction t(_transactionRLP, CheckSignature::Sender);
UpgradeGuard ul(l); UpgradeGuard ul(l);
// If valid, append to blocks. // If valid, append to blocks.
@ -69,14 +69,14 @@ void TransactionQueue::setFuture(std::pair<h256, bytes> const& _t)
if (m_current.count(_t.first)) if (m_current.count(_t.first))
{ {
m_current.erase(_t.first); m_current.erase(_t.first);
m_unknown.insert(make_pair(Transaction(_t.second).sender(), _t)); m_unknown.insert(make_pair(Transaction(_t.second, CheckSignature::Sender).sender(), _t));
} }
} }
void TransactionQueue::noteGood(std::pair<h256, bytes> const& _t) void TransactionQueue::noteGood(std::pair<h256, bytes> const& _t)
{ {
WriteGuard l(m_lock); WriteGuard l(m_lock);
auto r = m_unknown.equal_range(Transaction(_t.second).sender()); auto r = m_unknown.equal_range(Transaction(_t.second, CheckSignature::Sender).sender());
for (auto it = r.first; it != r.second; ++it) for (auto it = r.first; it != r.second; ++it)
m_current.insert(it->second); m_current.insert(it->second);
m_unknown.erase(r.first, r.second); m_unknown.erase(r.first, r.second);

1
liblll/CodeFragment.cpp

@ -266,7 +266,6 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
} }
++ii; ++ii;
} }
} }
else if (us == "LIT") else if (us == "LIT")
{ {

1
liblll/CodeFragment.h

@ -61,3 +61,4 @@ static const CodeFragment NullCodeFragment;
} }
} }

7
libsolidity/AST.cpp

@ -82,7 +82,7 @@ map<FixedHash<4>, FunctionDefinition const*> ContractDefinition::getInterfaceFun
FunctionDefinition const* ContractDefinition::getConstructor() const FunctionDefinition const* ContractDefinition::getConstructor() const
{ {
for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions) for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
if (f->getName() == getName()) if (f->isConstructor())
return f.get(); return f.get();
return nullptr; return nullptr;
} }
@ -95,7 +95,7 @@ void ContractDefinition::checkIllegalOverrides() const
for (ContractDefinition const* contract: getLinearizedBaseContracts()) for (ContractDefinition const* contract: getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
{ {
if (function->getName() == contract->getName()) if (function->isConstructor())
continue; // constructors can neither be overriden nor override anything continue; // constructors can neither be overriden nor override anything
FunctionDefinition const*& override = functions[function->getName()]; FunctionDefinition const*& override = functions[function->getName()];
if (!override) if (!override)
@ -115,8 +115,7 @@ vector<pair<FixedHash<4>, FunctionDefinition const*>> const& ContractDefinition:
m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionDefinition const*>>()); m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionDefinition const*>>());
for (ContractDefinition const* contract: getLinearizedBaseContracts()) for (ContractDefinition const* contract: getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions())
if (f->isPublic() && f->getName() != contract->getName() && if (f->isPublic() && !f->isConstructor() && functionsSeen.count(f->getName()) == 0)
functionsSeen.count(f->getName()) == 0)
{ {
functionsSeen.insert(f->getName()); functionsSeen.insert(f->getName());
FixedHash<4> hash(dev::sha3(f->getCanonicalSignature())); FixedHash<4> hash(dev::sha3(f->getCanonicalSignature()));

5
libsolidity/AST.h

@ -281,12 +281,13 @@ class FunctionDefinition: public Declaration
public: public:
FunctionDefinition(Location const& _location, ASTPointer<ASTString> const& _name, FunctionDefinition(Location const& _location, ASTPointer<ASTString> const& _name,
bool _isPublic, bool _isPublic,
bool _isConstructor,
ASTPointer<ASTString> const& _documentation, ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters, ASTPointer<ParameterList> const& _parameters,
bool _isDeclaredConst, bool _isDeclaredConst,
ASTPointer<ParameterList> const& _returnParameters, ASTPointer<ParameterList> const& _returnParameters,
ASTPointer<Block> const& _body): ASTPointer<Block> const& _body):
Declaration(_location, _name), m_isPublic(_isPublic), Declaration(_location, _name), m_isPublic(_isPublic), m_isConstructor(_isConstructor),
m_parameters(_parameters), m_parameters(_parameters),
m_isDeclaredConst(_isDeclaredConst), m_isDeclaredConst(_isDeclaredConst),
m_returnParameters(_returnParameters), m_returnParameters(_returnParameters),
@ -298,6 +299,7 @@ public:
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
bool isPublic() const { return m_isPublic; } bool isPublic() const { return m_isPublic; }
bool isConstructor() const { return m_isConstructor; }
bool isDeclaredConst() const { return m_isDeclaredConst; } bool isDeclaredConst() const { return m_isDeclaredConst; }
std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); } std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); }
ParameterList const& getParameterList() const { return *m_parameters; } ParameterList const& getParameterList() const { return *m_parameters; }
@ -321,6 +323,7 @@ public:
private: private:
bool m_isPublic; bool m_isPublic;
bool m_isConstructor;
ASTPointer<ParameterList> m_parameters; ASTPointer<ParameterList> m_parameters;
bool m_isDeclaredConst; bool m_isDeclaredConst;
ASTPointer<ParameterList> m_returnParameters; ASTPointer<ParameterList> m_returnParameters;

9
libsolidity/CallGraph.cpp

@ -38,6 +38,7 @@ void CallGraph::addNode(ASTNode const& _node)
set<FunctionDefinition const*> const& CallGraph::getCalls() set<FunctionDefinition const*> const& CallGraph::getCalls()
{ {
computeCallGraph();
return m_functionsSeen; return m_functionsSeen;
} }
@ -45,8 +46,7 @@ void CallGraph::computeCallGraph()
{ {
while (!m_workQueue.empty()) while (!m_workQueue.empty())
{ {
FunctionDefinition const* fun = m_workQueue.front(); m_workQueue.front()->accept(*this);
fun->accept(*this);
m_workQueue.pop(); m_workQueue.pop();
} }
} }
@ -55,7 +55,12 @@ bool CallGraph::visit(Identifier const& _identifier)
{ {
FunctionDefinition const* fun = dynamic_cast<FunctionDefinition const*>(_identifier.getReferencedDeclaration()); FunctionDefinition const* fun = dynamic_cast<FunctionDefinition const*>(_identifier.getReferencedDeclaration());
if (fun) if (fun)
{
if (m_overrideResolver)
fun = (*m_overrideResolver)(fun->getName());
solAssert(fun, "Error finding override for function " + fun->getName());
addFunction(*fun); addFunction(*fun);
}
return true; return true;
} }

8
libsolidity/CallGraph.h

@ -22,6 +22,7 @@
#include <set> #include <set>
#include <queue> #include <queue>
#include <functional>
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
@ -38,8 +39,11 @@ namespace solidity
class CallGraph: private ASTConstVisitor class CallGraph: private ASTConstVisitor
{ {
public: public:
using OverrideResolver = std::function<FunctionDefinition const*(std::string const&)>;
CallGraph(OverrideResolver const& _overrideResolver): m_overrideResolver(&_overrideResolver) {}
void addNode(ASTNode const& _node); void addNode(ASTNode const& _node);
void computeCallGraph();
std::set<FunctionDefinition const*> const& getCalls(); std::set<FunctionDefinition const*> const& getCalls();
@ -48,8 +52,10 @@ private:
virtual bool visit(Identifier const& _identifier) override; virtual bool visit(Identifier const& _identifier) override;
virtual bool visit(MemberAccess const& _memberAccess) override; virtual bool visit(MemberAccess const& _memberAccess) override;
void computeCallGraph();
void addFunction(FunctionDefinition const& _function); void addFunction(FunctionDefinition const& _function);
OverrideResolver const* m_overrideResolver;
std::set<FunctionDefinition const*> m_functionsSeen; std::set<FunctionDefinition const*> m_functionsSeen;
std::queue<FunctionDefinition const*> m_workQueue; std::queue<FunctionDefinition const*> m_workQueue;
}; };

33
libsolidity/Compiler.cpp

@ -43,13 +43,13 @@ void Compiler::compileContract(ContractDefinition const& _contract,
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts()) for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (function->getName() != contract->getName()) // don't add the constructor here if (!function->isConstructor())
m_context.addFunction(*function); m_context.addFunction(*function);
appendFunctionSelector(_contract); appendFunctionSelector(_contract);
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts()) for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (function->getName() != contract->getName()) // don't add the constructor here if (!function->isConstructor())
function->accept(*this); function->accept(*this);
// Swap the runtime context with the creation-time context // Swap the runtime context with the creation-time context
@ -93,10 +93,29 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
} }
} }
//@TODO add virtual functions auto overrideResolver = [&](string const& _name) -> FunctionDefinition const*
neededFunctions = getFunctionsCalled(nodesUsedInConstructors); {
for (ContractDefinition const* contract: bases)
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _name)
return function.get();
return nullptr;
};
neededFunctions = getFunctionsCalled(nodesUsedInConstructors, overrideResolver);
// First add all overrides (or the functions themselves if there is no override)
for (FunctionDefinition const* fun: neededFunctions)
{
FunctionDefinition const* override = nullptr;
if (!fun->isConstructor())
override = overrideResolver(fun->getName());
if (!!override && neededFunctions.count(override))
m_context.addFunction(*override);
}
// now add the rest
for (FunctionDefinition const* fun: neededFunctions) for (FunctionDefinition const* fun: neededFunctions)
if (fun->isConstructor() || overrideResolver(fun->getName()) != fun)
m_context.addFunction(*fun); m_context.addFunction(*fun);
// Call constructors in base-to-derived order. // Call constructors in base-to-derived order.
@ -159,10 +178,10 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
m_context << returnTag; m_context << returnTag;
} }
set<FunctionDefinition const*> Compiler::getFunctionsCalled(set<ASTNode const*> const& _nodes) set<FunctionDefinition const*> Compiler::getFunctionsCalled(set<ASTNode const*> const& _nodes,
function<FunctionDefinition const*(string const&)> const& _resolveOverrides)
{ {
// TODO this does not add virtual functions CallGraph callgraph(_resolveOverrides);
CallGraph callgraph;
for (ASTNode const* node: _nodes) for (ASTNode const* node: _nodes)
callgraph.addNode(*node); callgraph.addNode(*node);
return callgraph.getCalls(); return callgraph.getCalls();

5
libsolidity/Compiler.h

@ -21,6 +21,7 @@
*/ */
#include <ostream> #include <ostream>
#include <functional>
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
#include <libsolidity/CompilerContext.h> #include <libsolidity/CompilerContext.h>
@ -49,7 +50,9 @@ private:
std::vector<ASTPointer<Expression>> const& _arguments); std::vector<ASTPointer<Expression>> const& _arguments);
void appendConstructorCall(FunctionDefinition const& _constructor); void appendConstructorCall(FunctionDefinition const& _constructor);
/// Recursively searches the call graph and returns all functions referenced inside _nodes. /// Recursively searches the call graph and returns all functions referenced inside _nodes.
std::set<FunctionDefinition const*> getFunctionsCalled(std::set<ASTNode const*> const& _nodes); /// _resolveOverride is called to resolve virtual function overrides.
std::set<FunctionDefinition const*> getFunctionsCalled(std::set<ASTNode const*> const& _nodes,
std::function<FunctionDefinition const*(std::string const&)> const& _resolveOverride);
void appendFunctionSelector(ContractDefinition const& _contract); void appendFunctionSelector(ContractDefinition const& _contract);
/// Creates code that unpacks the arguments for the given function, from memory if /// Creates code that unpacks the arguments for the given function, from memory if
/// @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes. /// @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.

43
libsolidity/CompilerStack.cpp

@ -21,6 +21,7 @@
* Full-stack compiler that converts a source code string to bytecode. * Full-stack compiler that converts a source code string to bytecode.
*/ */
#include <boost/algorithm/string.hpp>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h> #include <libsolidity/Parser.h>
@ -123,9 +124,49 @@ void CompilerStack::compile(bool _optimize)
} }
} }
string CompilerStack::expanded(string const& _sourceCode)
{
// TODO: populate some nicer way.
static const map<string, string> c_requires = {
{ "Config", "contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}" },
{ "owned", "contract owned{function owned(){owner = msg.sender;}address owner;}" },
{ "mortal", "#require owned\ncontract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}" },
{ "NameReg", "contract NameReg{function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}}" },
{ "named", "#require Config NameReg\ncontract named is mortal, owned {function named(string32 name) {NameReg(Config().lookup(1)).register(name);}" },
{ "std", "#require owned mortal Config NameReg named" },
};
string sub;
set<string> got;
function<string(string const&)> localExpanded;
localExpanded = [&](string const& s) -> string
{
string ret = s;
for (size_t p = 0; p != string::npos;)
if ((p = ret.find("#require ")) != string::npos)
{
string n = ret.substr(p + 9, ret.find_first_of('\n', p + 9) - p - 9);
ret.replace(p, n.size() + 9, "");
vector<string> rs;
boost::split(rs, n, boost::is_any_of(" \t,"), boost::token_compress_on);
for (auto const& r: rs)
if (!got.count(r))
{
if (c_requires.count(r))
sub.append("\n" + localExpanded(c_requires.at(r)) + "\n");
got.insert(r);
}
}
// TODO: remove once we have genesis contracts.
else if ((p = ret.find("Config()")) != string::npos)
ret.replace(p, 8, "Config(0x661005d2720d855f1d9976f88bb10c1a3398c77f)");
return ret;
};
return sub + localExpanded(_sourceCode);
}
bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize) bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
{ {
parse(_sourceCode); parse(expanded(_sourceCode));
compile(_optimize); compile(_optimize);
return getBytecode(); return getBytecode();
} }

4
libsolidity/CompilerStack.h

@ -138,6 +138,10 @@ private:
Contract(); Contract();
}; };
/// Expand source code with preprocessor-like includes.
/// @todo Replace with better framework.
std::string expanded(std::string const& _sourceCode);
void reset(bool _keepSources = false); void reset(bool _keepSources = false);
void resolveImports(); void resolveImports();

10
libsolidity/InterfaceHandler.cpp

@ -351,9 +351,15 @@ void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _
currPos = appendDocTag(currPos, end, _owner); currPos = appendDocTag(currPos, end, _owner);
else if (currPos != end) else if (currPos != end)
{ {
if (nlPos == end) //end of text // if it begins without a tag then consider it as @notice
if (currPos == _string.begin())
{
currPos = parseDocTag(currPos, end, "notice", CommentOwner::FUNCTION);
continue;
}
else if (nlPos == end) //end of text
return; return;
// else skip the line if a newline was found // else skip the line if a newline was found and we get here
currPos = nlPos + 1; currPos = nlPos + 1;
} }
} }

13
libsolidity/Parser.cpp

@ -112,9 +112,9 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
ASTPointer<ContractDefinition> Parser::parseContractDefinition() ASTPointer<ContractDefinition> Parser::parseContractDefinition()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docstring; ASTPointer<ASTString> docString;
if (m_scanner->getCurrentCommentLiteral() != "") if (m_scanner->getCurrentCommentLiteral() != "")
docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); docString = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
expectToken(Token::CONTRACT); expectToken(Token::CONTRACT);
ASTPointer<ASTString> name = expectIdentifierToken(); ASTPointer<ASTString> name = expectIdentifierToken();
vector<ASTPointer<InheritanceSpecifier>> baseContracts; vector<ASTPointer<InheritanceSpecifier>> baseContracts;
@ -142,7 +142,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
expectToken(Token::COLON); expectToken(Token::COLON);
} }
else if (currentToken == Token::FUNCTION) else if (currentToken == Token::FUNCTION)
functions.push_back(parseFunctionDefinition(visibilityIsPublic)); functions.push_back(parseFunctionDefinition(visibilityIsPublic, name.get()));
else if (currentToken == Token::STRUCT) else if (currentToken == Token::STRUCT)
structs.push_back(parseStructDefinition()); structs.push_back(parseStructDefinition());
else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING ||
@ -157,7 +157,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
} }
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RBRACE); expectToken(Token::RBRACE);
return nodeFactory.createNode<ContractDefinition>(name, docstring, baseContracts, structs, return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs,
stateVariables, functions); stateVariables, functions);
} }
@ -178,7 +178,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
return nodeFactory.createNode<InheritanceSpecifier>(name, arguments); return nodeFactory.createNode<InheritanceSpecifier>(name, arguments);
} }
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic) ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, ASTString const* _contractName)
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docstring; ASTPointer<ASTString> docstring;
@ -210,7 +210,8 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
} }
ASTPointer<Block> block = parseBlock(); ASTPointer<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block); nodeFactory.setEndPositionFromNode(block);
return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, docstring, bool const c_isConstructor = (_contractName && *name == *_contractName);
return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, c_isConstructor, docstring,
parameters, parameters,
isDeclaredConst, returnParameters, block); isDeclaredConst, returnParameters, block);
} }

2
libsolidity/Parser.h

@ -50,7 +50,7 @@ private:
ASTPointer<ImportDirective> parseImportDirective(); ASTPointer<ImportDirective> parseImportDirective();
ASTPointer<ContractDefinition> parseContractDefinition(); ASTPointer<ContractDefinition> parseContractDefinition();
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic); ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic, ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition(); ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<VariableDeclaration> parseVariableDeclaration(bool _allowVar); ASTPointer<VariableDeclaration> parseVariableDeclaration(bool _allowVar);
ASTPointer<TypeName> parseTypeName(bool _allowVar); ASTPointer<TypeName> parseTypeName(bool _allowVar);

2
libsolidity/Types.cpp

@ -716,7 +716,7 @@ MemberList const& TypeType::getMembers() const
// We are accessing the type of a base contract, so add all public and private // We are accessing the type of a base contract, so add all public and private
// functions. Note that this does not add inherited functions on purpose. // functions. Note that this does not add inherited functions on purpose.
for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions())
if (f->getName() != contract.getName()) if (!f->isConstructor())
members[f->getName()] = make_shared<FunctionType>(*f); members[f->getName()] = make_shared<FunctionType>(*f);
} }
m_members.reset(new MemberList(members)); m_members.reset(new MemberList(members));

5
neth/main.cpp

@ -305,7 +305,6 @@ int main(int argc, char** argv)
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
string dbPath; string dbPath;
unsigned mining = ~(unsigned)0; unsigned mining = ~(unsigned)0;
(void)mining;
NodeMode mode = NodeMode::Full; NodeMode mode = NodeMode::Full;
unsigned peers = 5; unsigned peers = 5;
#if ETH_JSONRPC #if ETH_JSONRPC
@ -441,6 +440,8 @@ int main(int argc, char** argv)
web3.connect(Host::pocHost()); web3.connect(Host::pocHost());
if (remoteHost.size()) if (remoteHost.size())
web3.connect(remoteHost, remotePort); web3.connect(remoteHost, remotePort);
if (mining)
c->startMining();
#if ETH_JSONRPC #if ETH_JSONRPC
shared_ptr<WebThreeStubServer> jsonrpcServer; shared_ptr<WebThreeStubServer> jsonrpcServer;
@ -885,7 +886,7 @@ int main(int argc, char** argv)
auto b = bc.block(h); auto b = bc.block(h);
for (auto const& i: RLP(b)[1]) for (auto const& i: RLP(b)[1])
{ {
Transaction t(i.data()); Transaction t(i.data(), CheckSignature::Sender);
auto s = t.receiveAddress() ? auto s = t.receiveAddress() ?
boost::format(" %1% %2%> %3%: %4% [%5%]") % boost::format(" %1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) % toString(t.safeSender()) %

22
test/SolidityEndToEndTest.cpp

@ -1610,6 +1610,28 @@ BOOST_AUTO_TEST_CASE(function_usage_in_constructor_arguments)
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(2)); BOOST_CHECK(callContractFunction("getA()") == encodeArgs(2));
} }
BOOST_AUTO_TEST_CASE(virtual_function_usage_in_constructor_arguments)
{
char const* sourceCode = R"(
contract BaseBase {
uint m_a;
function BaseBase(uint a) {
m_a = a;
}
function overridden() returns (uint r) { return 1; }
function g() returns (uint r) { return overridden(); }
}
contract Base is BaseBase(BaseBase.g()) {
}
contract Derived is Base() {
function getA() returns (uint r) { return m_a; }
function overridden() returns (uint r) { return 2; }
}
)";
compileAndRun(sourceCode, 0, "Derived");
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(2));
}
BOOST_AUTO_TEST_CASE(constructor_argument_overriding) BOOST_AUTO_TEST_CASE(constructor_argument_overriding)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

28
test/SolidityNatspecJSON.cpp

@ -506,17 +506,35 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error)
BOOST_CHECK_THROW(checkNatspec(sourceCode, natspec, false), DocstringParsingError); BOOST_CHECK_THROW(checkNatspec(sourceCode, natspec, false), DocstringParsingError);
} }
// test for bug where having no tags in docstring would cause infinite loop BOOST_AUTO_TEST_CASE(natspec_notice_without_tag)
BOOST_AUTO_TEST_CASE(natspec_no_tags)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" /// I do something awesome\n" " /// I do something awesome\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" " function mul(uint a) returns(uint d) { return a * 7; }\n"
"}\n"; "}\n";
char const* natspec = "{\"methods\": {}}"; char const* natspec = "{"
"\"methods\":{"
" \"mul(uint256)\":{ \"notice\": \"I do something awesome\"}"
"}}";
checkNatspec(sourceCode, natspec, false); checkNatspec(sourceCode, natspec, true);
}
BOOST_AUTO_TEST_CASE(natspec_multiline_notice_without_tag)
{
char const* sourceCode = "contract test {\n"
" /// I do something awesome\n"
" /// which requires two lines to explain\n"
" function mul(uint a) returns(uint d) { return a * 7; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul(uint256)\":{ \"notice\": \"I do something awesome which requires two lines to explain\"}"
"}}";
checkNatspec(sourceCode, natspec, true);
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

2
test/TestHelper.cpp

@ -115,7 +115,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
if (code.size()) if (code.size())
{ {
_state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); _state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception);
_state.m_cache[address].setCode(bytesConstRef(&code)); _state.m_cache[address].setCode(code);
} }
else else
_state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation); _state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation);

Loading…
Cancel
Save