Browse Source

Merge remote-tracking branch 'upstream/develop' into blockTests

cl-refactor
CJentzsch 10 years ago
parent
commit
5ea3dd5df2
  1. 12
      README.md
  2. 16
      alethzero/Main.ui
  3. 160
      alethzero/MainWin.cpp
  4. 5
      alethzero/MainWin.h
  5. 65
      alethzero/OurWebThreeStubServer.cpp
  6. 19
      alethzero/OurWebThreeStubServer.h
  7. 2
      eth/main.cpp
  8. 14
      evmjit/libevmjit/Compiler.cpp
  9. 10
      libdevcore/Common.h
  10. 22
      libdevcore/CommonJS.cpp
  11. 10
      libdevcore/CommonJS.h
  12. 3
      libdevcore/FixedHash.h
  13. 23
      libdevcrypto/Common.cpp
  14. 8
      libdevcrypto/Common.h
  15. 23
      libethcore/CommonEth.cpp
  16. 2
      libethcore/CommonEth.h
  17. 3
      libethereum/Account.h
  18. 5
      libethereum/BlockChain.cpp
  19. 12
      libethereum/CanonBlockChain.cpp
  20. 12
      libethereum/CanonBlockChain.h
  21. 11
      libethereum/Client.cpp
  22. 23
      libethereum/Client.h
  23. 12
      libethereum/Executive.cpp
  24. 18
      libethereum/LogFilter.cpp
  25. 4
      libethereum/LogFilter.h
  26. 6
      libethereum/State.cpp
  27. 5
      libethereum/State.h
  28. 10
      libethereum/Transaction.cpp
  29. 11
      libethereum/Transaction.h
  30. 6
      libethereum/TransactionQueue.cpp
  31. 966
      libjsqrc/es6-promise-2.0.0.js
  32. 15
      libjsqrc/ethereumjs/README.md
  33. 3
      libjsqrc/ethereumjs/bower.json
  34. 1898
      libjsqrc/ethereumjs/dist/ethereum.js
  35. 38
      libjsqrc/ethereumjs/dist/ethereum.js.map
  36. 2
      libjsqrc/ethereumjs/dist/ethereum.min.js
  37. 13
      libjsqrc/ethereumjs/example/balance.html
  38. 14
      libjsqrc/ethereumjs/example/contract.html
  39. 76
      libjsqrc/ethereumjs/example/contract_with_array.html
  40. 120
      libjsqrc/ethereumjs/example/event.html
  41. 66
      libjsqrc/ethereumjs/example/event_inc.html
  42. 22
      libjsqrc/ethereumjs/example/natspec_contract.html
  43. 18
      libjsqrc/ethereumjs/example/node-app.js
  44. 8
      libjsqrc/ethereumjs/index.js
  45. 306
      libjsqrc/ethereumjs/lib/abi.js
  46. 114
      libjsqrc/ethereumjs/lib/autoprovider.js
  47. 56
      libjsqrc/ethereumjs/lib/const.js
  48. 200
      libjsqrc/ethereumjs/lib/contract.js
  49. 135
      libjsqrc/ethereumjs/lib/event.js
  50. 59
      libjsqrc/ethereumjs/lib/filter.js
  51. 154
      libjsqrc/ethereumjs/lib/formatters.js
  52. 126
      libjsqrc/ethereumjs/lib/httprpc.js
  53. 46
      libjsqrc/ethereumjs/lib/httpsync.js
  54. 65
      libjsqrc/ethereumjs/lib/jsonrpc.js
  55. 18
      libjsqrc/ethereumjs/lib/local.js
  56. 90
      libjsqrc/ethereumjs/lib/providermanager.js
  57. 57
      libjsqrc/ethereumjs/lib/qt.js
  58. 33
      libjsqrc/ethereumjs/lib/qtsync.js
  59. 79
      libjsqrc/ethereumjs/lib/types.js
  60. 142
      libjsqrc/ethereumjs/lib/utils.js
  61. 242
      libjsqrc/ethereumjs/lib/web3.js
  62. 98
      libjsqrc/ethereumjs/lib/websocket.js
  63. 3
      libjsqrc/ethereumjs/package.json
  64. 410
      libjsqrc/ethereumjs/test/abi.inputParser.js
  65. 461
      libjsqrc/ethereumjs/test/abi.outputParser.js
  66. 4
      libjsqrc/ethereumjs/test/db.methods.js
  67. 201
      libjsqrc/ethereumjs/test/eth.contract.js
  68. 6
      libjsqrc/ethereumjs/test/eth.methods.js
  69. 125
      libjsqrc/ethereumjs/test/event.inputParser.js
  70. 81
      libjsqrc/ethereumjs/test/event.outputParser.js
  71. 128
      libjsqrc/ethereumjs/test/jsonrpc.isValidResponse.js
  72. 47
      libjsqrc/ethereumjs/test/jsonrpc.toBatchPayload.js
  73. 40
      libjsqrc/ethereumjs/test/jsonrpc.toPayload.js
  74. 5
      libjsqrc/ethereumjs/test/shh.methods.js
  75. 2
      libjsqrc/ethereumjs/test/test.utils.js
  76. 42
      libjsqrc/ethereumjs/test/utils.extractDisplayName.js
  77. 55
      libjsqrc/ethereumjs/test/utils.extractTypeName.js
  78. 49
      libjsqrc/ethereumjs/test/utils.filters.js
  79. 8
      libjsqrc/ethereumjs/test/web3.methods.js
  80. 2
      libjsqrc/js.qrc
  81. 83
      libjsqrc/natspec.js
  82. 21
      libjsqrc/setup.js
  83. 1
      liblll/CodeFragment.cpp
  84. 1
      liblll/CodeFragment.h
  85. 124
      libqwebthree/QWebThree.cpp
  86. 10
      libqwebthree/QWebThree.h
  87. 264
      libsolidity/AST.cpp
  88. 259
      libsolidity/AST.h
  89. 6
      libsolidity/ASTForward.h
  90. 3
      libsolidity/ASTJsonConverter.cpp
  91. 60
      libsolidity/ASTPrinter.cpp
  92. 10
      libsolidity/ASTPrinter.h
  93. 20
      libsolidity/ASTVisitor.h
  94. 72
      libsolidity/AST_accept.h
  95. 4
      libsolidity/BaseTypes.h
  96. 99
      libsolidity/CallGraph.cpp
  97. 58
      libsolidity/CallGraph.h
  98. 211
      libsolidity/Compiler.cpp
  99. 25
      libsolidity/Compiler.h
  100. 89
      libsolidity/CompilerContext.cpp

12
README.md

@ -1,14 +1,12 @@
## Ethereum C++ Client.
[![Build
Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build
Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop
By Gav Wood, 2014.
[![Build
+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build
+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop
| Linux | OSX | Windows
----------|---------|-----|--------
develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1)
master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1)
evmjit | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A
[![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum)

16
alethzero/Main.ui

@ -95,8 +95,8 @@
<widget class="QLineEdit" name="urlEdit"/>
</item>
<item>
<widget class="QWebView" name="webView" native="true">
<property name="url" stdset="0">
<widget class="QWebView" name="webView">
<property name="url">
<url>
<string>about:blank</string>
</url>
@ -148,6 +148,7 @@
<addaction name="importKey"/>
<addaction name="importKeyFile"/>
<addaction name="exportKey"/>
<addaction name="killAccount"/>
<addaction name="separator"/>
<addaction name="loadJS"/>
</widget>
@ -1212,8 +1213,8 @@
<number>0</number>
</property>
<item>
<widget class="QWebView" name="jsConsole" native="true">
<property name="url" stdset="0">
<widget class="QWebView" name="jsConsole">
<property name="url">
<url>
<string>about:blank</string>
</url>
@ -2035,7 +2036,7 @@ font-size: 14pt</string>
</action>
<action name="importKeyFile">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="text">
<string>Claim Ether Presale &amp;Wallet...</string>
@ -2067,6 +2068,11 @@ font-size: 14pt</string>
<string>Use &amp;LLVM-EVM</string>
</property>
</action>
<action name="killAccount">
<property name="text">
<string>&amp;Kill Account</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

160
alethzero/MainWin.cpp

@ -60,6 +60,11 @@ using namespace dev::p2p;
using namespace dev::eth;
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)
{
for (auto n = (unsigned)units().size(); n-- != 0; )
@ -97,7 +102,7 @@ static vector<KeyPair> keysAsVector(QList<KeyPair> const& keys)
return {begin(list), end(list)};
}
static QString contentsOfQResource(string const& res)
QString contentsOfQResource(string const& res)
{
QFile file(QString::fromStdString(res));
if (!file.open(QFile::ReadOnly))
@ -107,7 +112,7 @@ static QString contentsOfQResource(string const& res)
}
//Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
Address c_newConfig = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
Address c_newConfig = Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
//Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1");
Main::Main(QWidget *parent) :
@ -173,13 +178,13 @@ Main::Main(QWidget *parent) :
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qweb));
connect(m_qweb, SIGNAL(onNewId(QString)), this, SLOT(addNewId(QString)));
});
connect(ui->webView, &QWebView::loadFinished, [=]()
{
m_qweb->poll();
});
connect(ui->webView, &QWebView::titleChanged, [=]()
@ -306,7 +311,7 @@ void Main::installBalancesWatch()
altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys)
for (auto c: altCoins)
tf.address(c).topic(h256(i.address(), h256::AlignRight));
tf.address(c).topic(0, h256(i.address(), h256::AlignRight));
uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
@ -429,6 +434,11 @@ void Main::on_jsInput_returnPressed()
ui->jsInput->setText("");
}
QVariant Main::evalRaw(QString const& _js)
{
return ui->webView->page()->currentFrame()->evaluateJavaScript(_js);
}
void Main::eval(QString const& _js)
{
if (_js.trimmed().isEmpty())
@ -447,7 +457,7 @@ void Main::eval(QString const& _js)
else
s = "<span style=\"color: #888\">unknown type</span>";
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)
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>";
@ -716,7 +726,7 @@ void Main::readSettings(bool _skipGeometry)
ui->enableOptimizer->setChecked(m_enableOptimizer);
ui->clientName->setText(s.value("clientName", "").toString());
if (ui->clientName->text().isEmpty())
ui->clientName->setText(QInputDialog::getText(this, "Enter identity", "Enter a name that will identify you on the peer network"));
ui->clientName->setText(QInputDialog::getText(nullptr, "Enter identity", "Enter a name that will identify you on the peer network"));
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString());
@ -750,7 +760,7 @@ void Main::on_importKey_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
{
js::mValue val;
@ -778,11 +788,16 @@ void Main::on_importKeyFile_triggered()
}
}
cnote << k.address();
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();
}
ethereum()->transact(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice());
}
else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
}
@ -1088,7 +1103,7 @@ void Main::refreshBlockChain()
auto b = bc.block(h);
for (auto const& i: RLP(b)[1])
{
Transaction t(i.data());
Transaction t(i.data(), CheckSignature::Sender);
if (bm || transactionMatch(filter, t))
{
QString s = t.receiveAddress() ?
@ -1170,9 +1185,6 @@ void Main::timerEvent(QTimerEvent*)
else
interval += 100;
if (m_qweb)
m_qweb->poll();
for (auto const& i: m_handlers)
{
auto ls = ethereum()->checkWatch(i.first);
@ -1197,8 +1209,9 @@ string Main::renderDiff(StateDiff const& _d) const
if (ad.balance)
{
s << "<br/>" << indent << "Balance " << dec << formatBalance(ad.balance.to());
s << " <b>" << showpos << (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from())) << noshowpos << "</b>";
s << "<br/>" << indent << "Balance " << dec << ad.balance.to() << " [=" << formatBalance(ad.balance.to()) << "]";
auto d = (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from()));
s << " <b>" << showpos << dec << d << " [=" << formatBalance(d) << "]" << noshowpos << "</b>";
}
if (ad.nonce)
{
@ -1207,7 +1220,7 @@ string Main::renderDiff(StateDiff const& _d) const
}
if (ad.code)
{
s << "<br/>" << indent << "Code " << hex << ad.code.to().size() << " bytes";
s << "<br/>" << indent << "Code " << dec << ad.code.to().size() << " bytes";
if (ad.code.from().size())
s << " (" << ad.code.from().size() << " bytes)";
}
@ -1274,12 +1287,12 @@ void Main::on_transactionQueue_currentItemChanged()
if (tx.data().size())
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 << "<div>Log Bloom: " << receipt.bloom() << "</div>";
auto r = receipt.rlp();
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 << "Pre: " << fs.rootHash() << "<br/>";
// s << "Post: <b>" << ts.rootHash() << "</b>";
@ -1370,13 +1383,13 @@ void Main::on_blocks_currentItemChanged()
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/>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 << "<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 << "<br/>Dump: " Span(Mono) << toHex(block[0].data()) << "</span>";
s << "<div>Receipts-Hex: " Span(Mono) << toHex(ethereum()->blockChain().receipts(h).rlp()) << "</span></div>";
}
else
{
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();
h256 th = sha3(rlpList(ss, tx.nonce()));
TransactionReceipt receipt = ethereum()->blockChain().receipts(h).receipts[txi];
@ -1405,12 +1418,12 @@ void Main::on_blocks_currentItemChanged()
if (tx.data().size())
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 << "<div>Log Bloom: " << receipt.bloom() << "</div>";
auto r = receipt.rlp();
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));
ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true);
@ -1529,6 +1542,7 @@ void Main::on_contracts_currentItemChanged()
for (auto const& i: storage)
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 << Div(Mono) << toHex(ethereum()->codeAt(address)) << "</div>";
ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
}
catch (dev::InvalidTrie)
@ -1584,7 +1598,7 @@ void Main::on_destination_currentTextChanged()
// updateFee();
}
static shh::Topic topicFromText(QString _s)
static shh::FullTopic topicFromText(QString _s)
{
shh::BuildTopic ret;
while (_s.size())
@ -1638,13 +1652,18 @@ static shh::Topic topicFromText(QString _s)
return ret;
}
bool Main::sourceIsSolidity(string const& _source)
{
// TODO: Improve this heuristic
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& _contractName)
{
@ -1656,7 +1675,7 @@ string const Main::getFunctionHashes(dev::solidity::CompilerStack const &_compil
{
ret += it.first.abridged();
ret += " :";
ret += it.second->getName() + "\n";
ret += it.second->getDeclaration().getName() + "\n";
}
return ret;
}
@ -1679,9 +1698,10 @@ void Main::on_data_textChanged()
dev::solidity::CompilerStack compiler;
try
{
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, m_enableOptimizer);
solidity = "<h4>Solidity</h4>";
solidity += "<pre>" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "</pre>";
solidity += "<pre>var " + QString::fromStdString(compiler.getContractNames().front()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");</pre>";
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "</pre>";
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "</pre>";
}
@ -1696,10 +1716,7 @@ void Main::on_data_textChanged()
solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>";
}
}
else
{
m_data = compileLLL(src, m_enableOptimizer, &errors);
if (errors.size())
else if (sourceIsSerpent(src))
{
try
{
@ -1713,6 +1730,9 @@ void Main::on_data_textChanged()
}
}
else
{
m_data = compileLLL(src, m_enableOptimizer, &errors);
if (errors.empty())
{
auto asmcode = compileLLLToAsm(src, false);
lll = "<h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>";
@ -1730,7 +1750,7 @@ void Main::on_data_textChanged()
for (auto const& i: errors)
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));
if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas);
@ -1963,12 +1983,82 @@ 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()
{
m_myKeys.append(KeyPair::create());
bool ok = true;
enum { NoVanity = 0, FirstTwo, FirstTwoNextTwo, FirstThree, FirstFour, StringMatch };
QStringList items = {"No vanity (instant)", "Two pairs first (a few seconds)", "Two pairs first and second (a few minutes)", "Three pairs first (a few minutes)", "Four pairs first (several hours)", "Specific hex string"};
unsigned v = items.QList<QString>::indexOf(QInputDialog::getItem(this, "Vanity Key?", "Would you a vanity key? This could take several hours.", items, 0, false, &ok));
if (!ok)
return;
bytes bs;
if (v == StringMatch)
{
QString s = QInputDialog::getText(this, "Vanity Beginning?", "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;
bs = fromHex(s.toStdString());
}
KeyPair p;
bool keepGoing = true;
unsigned done = 0;
function<void()> f = [&]() {
KeyPair lp;
while (keepGoing)
{
done++;
if (done % 1000 == 0)
cnote << "Tried" << done << "keys";
lp = KeyPair::create();
auto a = lp.address();
if (v == NoVanity ||
(v == FirstTwo && a[0] == a[1]) ||
(v == FirstTwoNextTwo && a[0] == a[1] && a[2] == a[3]) ||
(v == FirstThree && a[0] == a[1] && a[1] == a[2]) ||
(v == FirstFour && a[0] == a[1] && a[1] == a[2] && a[2] == a[3]) ||
(v == StringMatch && beginsWith(lp.address(), bs))
)
break;
}
if (keepGoing)
p = lp;
keepGoing = false;
};
vector<std::thread*> ts;
for (unsigned t = 0; t < std::thread::hardware_concurrency() - 1; ++t)
ts.push_back(new std::thread(f));
f();
for (std::thread* t: ts)
{
t->join();
delete t;
}
m_myKeys.append(p);
keysChanged();
}
void Main::on_killAccount_triggered()
{
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size())
{
auto k = m_myKeys[ui->ourAccounts->currentRow()];
if (ethereum()->balanceAt(k.address()) != 0 && QMessageBox::critical(this, "Kill Account?!", "Account " + render(k.address()) + " has " + QString::fromStdString(formatBalance(ethereum()->balanceAt(k.address()))) + " in it. It, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\nAre you sure you want to continue?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
return;
m_myKeys.erase(m_myKeys.begin() + ui->ourAccounts->currentRow());
keysChanged();
}
}
void Main::on_debugStep_triggered()
{
if (ui->debugTimeline->value() < m_history.size()) {
@ -2325,10 +2415,10 @@ void Main::refreshWhispers()
shh::Envelope const& e = w.second;
shh::Message m;
for (pair<Public, Secret> const& i: m_server->ids())
if (!!(m = e.open(i.second)))
if (!!(m = e.open(shh::FullTopic(), i.second)))
break;
if (!m)
m = e.open();
m = e.open(shh::FullTopic());
QString msg;
if (m.from())
@ -2341,7 +2431,7 @@ void Main::refreshWhispers()
time_t ex = e.expiry();
QString t(ctime(&ex));
t.chop(1);
QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topics()).c_str()).arg(msg);
QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg);
ui->whispers->addItem(item);
}
}

5
alethzero/MainWin.h

@ -71,6 +71,8 @@ struct WorldState
using WatchHandler = std::function<void(dev::eth::LocalisedLogEntries const&)>;
QString contentsOfQResource(std::string const& res);
class Main : public QMainWindow
{
Q_OBJECT
@ -88,6 +90,8 @@ public:
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
QVariant evalRaw(QString const& _js);
public slots:
void load(QString _file);
void note(QString _entry);
@ -104,6 +108,7 @@ private slots:
void on_mine_triggered();
void on_send_clicked();
void on_create_triggered();
void on_killAccount_triggered();
void on_net_triggered();
void on_verbosity_valueChanged();
void on_ourAccounts_doubleClicked();

65
alethzero/OurWebThreeStubServer.cpp

@ -24,25 +24,26 @@
#include <QMessageBox>
#include <QAbstractButton>
#include <libwebthree/WebThree.h>
#include "MainWin.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3,
std::vector<dev::KeyPair> const& _accounts, Main* main):
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3,
vector<KeyPair> const& _accounts, Main* main):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main)
{}
std::string OurWebThreeStubServer::shh_newIdentity()
string OurWebThreeStubServer::shh_newIdentity()
{
dev::KeyPair kp = dev::KeyPair::create();
KeyPair kp = dev::KeyPair::create();
emit onNewId(QString::fromStdString(toJS(kp.sec())));
return toJS(kp.pub());
}
bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, std::string const& _text) const
bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const
{
QMessageBox userInput;
userInput.setText(QString::fromStdString(_title));
@ -54,19 +55,65 @@ bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, s
return userInput.exec() == QMessageBox::Ok;
}
bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const
void OurWebThreeStubServer::showBasicValueTransferNotice(u256 _value) const
{
QMessageBox notice;
notice.setText("Basic Value Transfer Transaction");
notice.setInformativeText(QString::fromStdString("Value is " + toString(_value)));
notice.setStandardButtons(QMessageBox::Ok);
notice.exec();
}
bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
{
h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to);
if (contractCodeHash == EmptySHA3)
// recipient has no code - nothing special about this transaction.
// TODO: show basic message for value transfer.
// contract creation
return true;
std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data);
if (false) //TODO: When is is just a value transfer?
{
// recipient has no code - nothing special about this transaction, show basic value transfer info
showBasicValueTransferNotice(_t.value);
return true;
}
string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data);
if (userNotice.empty())
return showAuthenticationPopup("Unverified Pending Transaction",
"An undocumented transaction is about to be executed.");
QNatspecExpressionEvaluator evaluator(this, m_main);
userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString();
// otherwise it's a transaction to a contract for which we have the natspec
return showAuthenticationPopup("Pending Transaction", userNotice);
}
QNatspecExpressionEvaluator::QNatspecExpressionEvaluator(OurWebThreeStubServer* _server, Main* _main)
: m_server(_server), m_main(_main)
{}
QNatspecExpressionEvaluator::~QNatspecExpressionEvaluator()
{}
QString QNatspecExpressionEvaluator::evalExpression(QString const& _expression) const
{
// load natspec.js only when we need it for natspec evaluation
m_main->evalRaw(contentsOfQResource(":/js/natspec.js"));
QVariant result = m_main->evalRaw("evaluateExpression('" + _expression + "')");
if (result.type() == QVariant::Invalid)
{
cerr << "Could not evaluate natspec expression: \"" << _expression.toStdString() << "\"" << endl;
// return the expression unevaluated
return _expression;
}
return result.toString();
}

19
alethzero/OurWebThreeStubServer.h

@ -35,14 +35,31 @@ public:
std::vector<dev::KeyPair> const& _accounts, Main* main);
virtual std::string shh_newIdentity() override;
virtual bool authenticate(dev::TransactionSkeleton const& _t) const;
virtual bool authenticate(dev::TransactionSkeleton const& _t);
signals:
void onNewId(QString _s);
private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const;
void showBasicValueTransferNotice(dev::u256 _value) const;
dev::WebThreeDirect* m_web3;
Main* m_main;
};
class QNatspecExpressionEvaluator: public QObject
{
Q_OBJECT
public:
QNatspecExpressionEvaluator(OurWebThreeStubServer* _server, Main* _main);
virtual ~QNatspecExpressionEvaluator();
QString evalExpression(QString const& _expression) const;
private:
OurWebThreeStubServer* m_server;
Main* m_main;
};

2
eth/main.cpp

@ -39,7 +39,7 @@
#endif
#if ETH_JSONRPC
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/CorsHttpServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#endif
#include "BuildInfo.h"
using namespace std;

14
evmjit/libevmjit/Compiler.cpp

@ -450,13 +450,17 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
auto word = stack.pop();
auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32");
auto k32 = m_builder.CreateZExt(k32_, Type::Word);
auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8");
auto k32 = m_builder.CreateZExt(k32_, Type::lowPrecision);
auto k32x8 = m_builder.CreateMul(k32, m_builder.getInt64(8), "kx8");
// test for word >> (k * 8 + 7)
auto bitpos = m_builder.CreateAdd(k32x8, Constant::get(7), "bitpos");
auto bitval = m_builder.CreateLShr(word, bitpos, "bitval");
auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest");
auto bitpos = m_builder.CreateAdd(k32x8, m_builder.getInt64(7), "bitpos");
auto bittester = m_builder.CreateShl(Constant::get(1), bitpos);
auto bitresult = m_builder.CreateAnd(word, bittester);
auto bittest = m_builder.CreateICmpUGT(bitresult, Constant::get(0));
// FIXME: The following does not work - LLVM bug, report!
//auto bitval = m_builder.CreateLShr(word, bitpos, "bitval");
//auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest");
auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos);
auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask");

10
libdevcore/Common.h

@ -36,6 +36,7 @@
#include <map>
#include <vector>
#include <set>
#include <functional>
#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
@ -117,6 +118,15 @@ inline unsigned int toLog2(u256 _x)
return ret;
}
/// RAII utility class whose destructor calls a given function.
class ScopeGuard {
public:
ScopeGuard(std::function<void(void)> _f): m_f(_f) {}
~ScopeGuard() { m_f(); }
private:
std::function<void(void)> m_f;
};
// Assertions...
#if defined(_MSC_VER)

22
libdevcore/CommonJS.cpp

@ -45,6 +45,12 @@ bytes padded(bytes _b, unsigned _l)
return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
}
bytes paddedRight(bytes _b, unsigned _l)
{
_b.resize(_l);
return _b;
}
bytes unpadded(bytes _b)
{
auto p = asString(_b).find_last_not_of((char)0);
@ -52,12 +58,18 @@ bytes unpadded(bytes _b)
return _b;
}
std::string unpadLeft(std::string _b)
bytes unpadLeft(bytes _b)
{
auto p = _b.find_first_not_of('0');
if (p == std::string::npos)
return "0";
return _b.substr(p, _b.length() - 1);
unsigned int i = 0;
if (_b.size() == 0)
return _b;
while (i < _b.size() && _b[i] == byte(0))
i++;
if (i != 0)
_b.erase(_b.begin(), _b.begin() + i);
return _b;
}
std::string prettyU256(u256 _n)

10
libdevcore/CommonJS.h

@ -48,12 +48,14 @@ inline std::string toJS(dev::bytes const& _n)
/// Convert string to byte array. Input parameters can be hex or dec. Returns empty array if invalid input e.g neither dec or hex.
bytes jsToBytes(std::string const& _s);
/// Add '0' on the head of _b until _l.
/// Add '0' on the head of @a _b until @a _l.
bytes padded(bytes _b, unsigned _l);
/// Add '0' on the queue of @a _b until @a _l.
bytes paddedRight(bytes _b, unsigned _l);
/// Removing all trailing '0'. Returns empty array if input contains only '0' char.
bytes unpadded(bytes _s);
/// Remove all '0' on the head of _s. Returns 0 if _s contains only '0'.
std::string unpadLeft(std::string _s);
/// Remove all 0 byte on the head of @a _s.
bytes unpadLeft(bytes _s);
/// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256.
std::string prettyU256(u256 _n);
/// Convert h256 into user-readable string (by directly using std::string constructor).
@ -65,7 +67,7 @@ template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return FixedHash<N>(_s.substr(2 + std::max<unsigned>(40, _s.size() - 2) - 40));
return FixedHash<N>(_s.substr(2 + std::max<unsigned>(N * 2, _s.size() - 2) - N * 2));
else if (_s.find_first_not_of("0123456789") == std::string::npos)
// Decimal
return (typename FixedHash<N>::Arith)(_s);

3
libdevcore/FixedHash.h

@ -67,6 +67,9 @@ public:
/// Explicitly construct, copying from a byte array.
explicit FixedHash(bytes const& _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); }
/// Explicitly construct, copying from a byte array.
explicit FixedHash(bytesConstRef _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); }
/// Explicitly construct, copying from a bytes in memory with given pointer.
explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }

23
libdevcrypto/Common.cpp

@ -22,6 +22,7 @@
#include <random>
#include <chrono>
#include <thread>
#include <mutex>
#include <libdevcore/Guards.h>
#include "SHA3.h"
@ -34,7 +35,7 @@ using namespace dev::crypto;
static Secp256k1 s_secp256k1;
bool dev::SignatureStruct::isValid()
bool dev::SignatureStruct::isValid() const
{
if (this->v > 1 ||
this->r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
@ -79,6 +80,18 @@ bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
return true;
}
void dev::encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher)
{
// TOOD: @alex @subtly do this properly.
encrypt(KeyPair(_k).pub(), _plain, o_cipher);
}
bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
{
// TODO: @alex @subtly do this properly.
return decrypt(_k, _cipher, o_plain);
}
Public dev::recover(Signature const& _sig, h256 const& _message)
{
return s_secp256k1.recover(_sig, _message.ref());
@ -96,12 +109,16 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
KeyPair KeyPair::create()
{
static mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
static boost::thread_specific_ptr<mt19937_64> s_eng;
static unsigned s_id = 0;
if (!s_eng.get())
s_eng.reset(new mt19937_64(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count() + ++s_id));
uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
KeyPair ret(FixedHash<32>::random(s_eng));
KeyPair ret(FixedHash<32>::random(*s_eng.get()));
if (ret.address())
return ret;
}

8
libdevcrypto/Common.h

@ -51,7 +51,7 @@ struct SignatureStruct
operator Signature() const { return *(h520 const*)this; }
/// @returns true if r,s,v values are valid, otherwise false
bool isValid();
bool isValid() const;
h256 r;
h256 s;
@ -87,6 +87,12 @@ void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Decrypts cipher using Secret key.
bool decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Symmetric encryption.
void encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Symmetric decryption.
bool decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash);

23
libethcore/CommonEth.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 51;
const unsigned c_protocolVersion = 52;
const unsigned c_databaseVersion = 5;
static const vector<pair<u256, string>> g_units =
@ -63,22 +63,31 @@ vector<pair<u256, string>> const& units()
return g_units;
}
std::string formatBalance(u256 _b)
std::string formatBalance(bigint const& _b)
{
ostringstream ret;
if (_b > g_units[0].first * 10000)
u256 b;
if (_b < 0)
{
ret << (_b / g_units[0].first) << " " << g_units[0].second;
ret << "-";
b = (u256)-_b;
}
else
b = (u256)_b;
if (b > g_units[0].first * 10000)
{
ret << (b / g_units[0].first) << " " << g_units[0].second;
return ret.str();
}
ret << setprecision(5);
for (auto const& i: g_units)
if (i.first != 1 && _b >= i.first * 100)
if (i.first != 1 && b >= i.first * 100)
{
ret << (double(_b / (i.first / 1000)) / 1000.0) << " " << i.second;
ret << (double(b / (i.first / 1000)) / 1000.0) << " " << i.second;
return ret.str();
}
ret << _b << " wei";
ret << b << " wei";
return ret.str();
}

2
libethcore/CommonEth.h

@ -39,7 +39,7 @@ extern const unsigned c_protocolVersion;
extern const unsigned c_databaseVersion;
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b);
std::string formatBalance(bigint const& _b);
/// Get information concerning the currency denominations.
std::vector<std::pair<u256, std::string>> const& units();

3
libethereum/Account.h

@ -140,7 +140,8 @@ public:
h256 codeHash() const { assert(!isFreshCode()); return m_codeHash; }
/// 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().
bool codeCacheValid() const { return m_codeHash == EmptySHA3 || m_codeHash == c_contractConceptionCodeHash || m_codeCache.size(); }

5
libethereum/BlockChain.cpp

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

12
libethereum/CanonBlockChain.cpp

@ -0,0 +1,12 @@
#include "CanonBlockChain.h"
CanonBlockChain::CanonBlockChain()
{
}
CanonBlockChain::~CanonBlockChain()
{
}

12
libethereum/CanonBlockChain.h

@ -0,0 +1,12 @@
#ifndef CANONBLOCKCHAIN_H
#define CANONBLOCKCHAIN_H
class CanonBlockChain
{
public:
CanonBlockChain();
~CanonBlockChain();
};
#endif // CANONBLOCKCHAIN_H

11
libethereum/Client.cpp

@ -226,11 +226,12 @@ void Client::uninstallWatch(unsigned _i)
void Client::noteChanged(h256Set const& _filters)
{
Guard l(m_filterLock);
// cnote << "noteChanged(" << _filters << ")";
// accrue all changes left in each filter into the watches.
for (auto& i: m_watches)
if (_filters.count(i.second.id))
{
// cwatch << "!!!" << i.first << i.second.id;
cwatch << "!!!" << i.first << i.second.id;
if (m_filters.count(i.second.id))
i.second.changes += m_filters.at(i.second.id).changes;
else
@ -642,14 +643,20 @@ Transaction Client::transaction(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return Transaction(b[1][_i].data());
if (_i < b[1].itemCount())
return Transaction(b[1][_i].data(), CheckSignature::Range);
else
return Transaction();
}
BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
else
return BlockInfo();
}
LocalisedLogEntries Client::logs(LogFilter const& _f) const

23
libethereum/Client.h

@ -277,17 +277,7 @@ public:
/// Kills the blockchain. Just for debug use.
void killChain();
private:
/// Do some work. Handles blockchain maintenance and mining.
virtual void doWork();
virtual void doneWorking();
/// Overrides for being a mining host.
virtual void setupState(State& _s);
virtual bool turbo() const { return m_turboMining; }
virtual bool force() const { return m_forceMining; }
protected:
/// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed.
void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed);
@ -300,6 +290,17 @@ private:
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Set const& _filters);
private:
/// Do some work. Handles blockchain maintenance and mining.
virtual void doWork();
virtual void doneWorking();
/// Overrides for being a mining host.
virtual void setupState(State& _s);
virtual bool turbo() const { return m_turboMining; }
virtual bool force() const { return m_forceMining; }
/// Return the actual block number of the block with the given int-number (positive is the same, INT_MIN is genesis block, < 0 is negative age, thus -1 is most recently mined, 0 is pending.
unsigned numberOf(int _b) const;

12
libethereum/Executive.cpp

@ -53,7 +53,7 @@ void Executive::accrueSubState(SubState& _parentContext)
bool Executive::setup(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.
m_t = Transaction(_rlp);
m_t = Transaction(_rlp, CheckSignature::Sender);
// Avoid invalid transactions.
auto nonceReq = m_s.transactionsFrom(m_t.sender());
@ -72,17 +72,17 @@ bool Executive::setup(bytesConstRef _rlp)
BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)gasCost, (bigint)m_t.gas()));
}
u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice();
bigint cost = m_t.value() + (bigint)m_t.gas() * m_t.gasPrice();
// Avoid unaffordable transactions.
if (m_s.balance(m_t.sender()) < cost)
{
clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_t.sender());
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((bigint)cost, (bigint)m_s.balance(m_t.sender())));
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(cost, (bigint)m_s.balance(m_t.sender())));
}
u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit)
if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit)
{
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas();
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
@ -92,7 +92,7 @@ bool Executive::setup(bytesConstRef _rlp)
m_s.noteSending(m_t.sender());
// Pay...
clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
clog(StateDetail) << "Paying" << formatBalance(u256(cost)) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
m_s.subBalance(m_t.sender(), cost);
if (m_t.isCreation())
@ -197,7 +197,7 @@ bool Executive::go(OnOpFunc const& _onOp)
m_endGas -= m_out.size() * c_createDataGas;
else
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&)

18
libethereum/LogFilter.cpp

@ -43,20 +43,21 @@ bool LogFilter::matches(LogBloom _bloom) const
{
if (m_addresses.size())
{
for (auto i: m_addresses)
for (auto const& i: m_addresses)
if (_bloom.containsBloom<3>(dev::sha3(i)))
goto OK1;
return false;
}
OK1:
if (m_topics.size())
for (auto const& t: m_topics)
if (t.size())
{
for (auto i: m_topics)
for (auto const& i: t)
if (_bloom.containsBloom<3>(dev::sha3(i)))
goto OK2;
return false;
OK2:;
}
OK2:
return true;
}
@ -72,11 +73,12 @@ LogEntries LogFilter::matches(TransactionReceipt const& _m) const
for (LogEntry const& e: _m.log())
{
if (!m_addresses.empty() && !m_addresses.count(e.address))
continue;
for (auto const& t: m_topics)
if (!std::count(e.topics.begin(), e.topics.end(), t))
continue;
goto continue2;
for (unsigned i = 0; i < 4; ++i)
if (!m_topics[i].empty() && (e.topics.size() < i || !m_topics[i].count(e.topics[i])))
goto continue2;
ret.push_back(e);
continue2:;
}
return ret;
}

4
libethereum/LogFilter.h

@ -50,7 +50,7 @@ public:
LogEntries matches(TransactionReceipt const& _r) const;
LogFilter address(Address _a) { m_addresses.insert(_a); return *this; }
LogFilter topic(h256 const& _t) { m_topics.insert(_t); return *this; }
LogFilter topic(unsigned _index, h256 const& _t) { if (_index < 4) m_topics[_index].insert(_t); return *this; }
LogFilter withMax(unsigned _m) { m_max = _m; return *this; }
LogFilter withSkip(unsigned _m) { m_skip = _m; return *this; }
LogFilter withEarliest(int _e) { m_earliest = _e; return *this; }
@ -58,7 +58,7 @@ public:
private:
AddressSet m_addresses;
h256Set m_topics;
std::array<h256Set, 4> m_topics;
int m_earliest = 0;
int m_latest = -1;
unsigned m_max;

6
libethereum/State.cpp

@ -395,7 +395,7 @@ bool State::cull(TransactionQueue& _tq) const
{
try
{
Transaction t(i.second);
Transaction t(i.second, CheckSignature::Sender);
if (t.nonce() <= transactionsFrom(t.sender()))
{
_tq.drop(i.first);
@ -682,8 +682,6 @@ LogBloom State::logBloom() const
return ret;
}
// @returns the block that represents the difference between m_previousBlock and m_currentBlock.
// (i.e. all the transactions we executed).
void State::commitToMine(BlockChain const& _bc)
{
uncommitToMine();
@ -802,7 +800,7 @@ void State::completeMine()
ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes);
m_currentBlock.hash = sha3(m_currentBytes);
m_currentBlock.hash = sha3(RLP(m_currentBytes)[0].data());
cnote << "Mined " << m_currentBlock.hash.abridged() << "(parent: " << m_currentBlock.parentHash.abridged() << ")";
// Quickly reset the transactions.

5
libethereum/State.h

@ -122,11 +122,14 @@ public:
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* while (notYetMined)
* {
* // lock
* commitToMine(blockchain);
* commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* // unlock
* MineInfo info;
* for (info.complete = false; !info.complete; info = mine()) {}
* }
* // lock
* completeMine();
* // unlock

10
libethereum/Transaction.cpp

@ -30,7 +30,7 @@ using namespace dev::eth;
#define ETH_ADDRESS_DEBUG 0
Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender)
Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig)
{
int field = 0;
RLP rlp(_rlpData);
@ -46,8 +46,14 @@ Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender)
byte v = rlp[field = 6].toInt<byte>() - 27;
h256 r = rlp[field = 7].toInt<u256>();
h256 s = rlp[field = 8].toInt<u256>();
if (rlp.itemCount() > 9)
BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("to many fields in the transaction RLP"));
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();
}
catch (Exception& _e)

11
libethereum/Transaction.h

@ -37,6 +37,13 @@ enum IncludeSignature
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.
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) {}
/// 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.
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.

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.
// 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).
Transaction t(_transactionRLP, true);
Transaction t(_transactionRLP, CheckSignature::Sender);
UpgradeGuard ul(l);
// If valid, append to blocks.
@ -69,14 +69,14 @@ void TransactionQueue::setFuture(std::pair<h256, bytes> const& _t)
if (m_current.count(_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)
{
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)
m_current.insert(it->second);
m_unknown.erase(r.first, r.second);

966
libjsqrc/es6-promise-2.0.0.js

@ -1,966 +0,0 @@
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
* @version 2.0.0
*/
(function() {
"use strict";
function $$utils$$objectOrFunction(x) {
return typeof x === 'function' || (typeof x === 'object' && x !== null);
}
function $$utils$$isFunction(x) {
return typeof x === 'function';
}
function $$utils$$isMaybeThenable(x) {
return typeof x === 'object' && x !== null;
}
var $$utils$$_isArray;
if (!Array.isArray) {
$$utils$$_isArray = function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
};
} else {
$$utils$$_isArray = Array.isArray;
}
var $$utils$$isArray = $$utils$$_isArray;
var $$utils$$now = Date.now || function() { return new Date().getTime(); };
function $$utils$$F() { }
var $$utils$$o_create = (Object.create || function (o) {
if (arguments.length > 1) {
throw new Error('Second argument not supported');
}
if (typeof o !== 'object') {
throw new TypeError('Argument must be an object');
}
$$utils$$F.prototype = o;
return new $$utils$$F();
});
var $$asap$$len = 0;
var $$asap$$default = function asap(callback, arg) {
$$asap$$queue[$$asap$$len] = callback;
$$asap$$queue[$$asap$$len + 1] = arg;
$$asap$$len += 2;
if ($$asap$$len === 2) {
// If len is 1, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
$$asap$$scheduleFlush();
}
};
var $$asap$$browserGlobal = (typeof window !== 'undefined') ? window : {};
var $$asap$$BrowserMutationObserver = $$asap$$browserGlobal.MutationObserver || $$asap$$browserGlobal.WebKitMutationObserver;
// test for web worker but not in IE10
var $$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
typeof importScripts !== 'undefined' &&
typeof MessageChannel !== 'undefined';
// node
function $$asap$$useNextTick() {
return function() {
process.nextTick($$asap$$flush);
};
}
function $$asap$$useMutationObserver() {
var iterations = 0;
var observer = new $$asap$$BrowserMutationObserver($$asap$$flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function() {
node.data = (iterations = ++iterations % 2);
};
}
// web worker
function $$asap$$useMessageChannel() {
var channel = new MessageChannel();
channel.port1.onmessage = $$asap$$flush;
return function () {
channel.port2.postMessage(0);
};
}
function $$asap$$useSetTimeout() {
return function() {
setTimeout($$asap$$flush, 1);
};
}
var $$asap$$queue = new Array(1000);
function $$asap$$flush() {
for (var i = 0; i < $$asap$$len; i+=2) {
var callback = $$asap$$queue[i];
var arg = $$asap$$queue[i+1];
callback(arg);
$$asap$$queue[i] = undefined;
$$asap$$queue[i+1] = undefined;
}
$$asap$$len = 0;
}
var $$asap$$scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
$$asap$$scheduleFlush = $$asap$$useNextTick();
} else if ($$asap$$BrowserMutationObserver) {
$$asap$$scheduleFlush = $$asap$$useMutationObserver();
} else if ($$asap$$isWorker) {
$$asap$$scheduleFlush = $$asap$$useMessageChannel();
} else {
$$asap$$scheduleFlush = $$asap$$useSetTimeout();
}
function $$$internal$$noop() {}
var $$$internal$$PENDING = void 0;
var $$$internal$$FULFILLED = 1;
var $$$internal$$REJECTED = 2;
var $$$internal$$GET_THEN_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$selfFullfillment() {
return new TypeError("You cannot resolve a promise with itself");
}
function $$$internal$$cannotReturnOwn() {
return new TypeError('A promises callback cannot return that same promise.')
}
function $$$internal$$getThen(promise) {
try {
return promise.then;
} catch(error) {
$$$internal$$GET_THEN_ERROR.error = error;
return $$$internal$$GET_THEN_ERROR;
}
}
function $$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
try {
then.call(value, fulfillmentHandler, rejectionHandler);
} catch(e) {
return e;
}
}
function $$$internal$$handleForeignThenable(promise, thenable, then) {
$$asap$$default(function(promise) {
var sealed = false;
var error = $$$internal$$tryThen(then, thenable, function(value) {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
$$$internal$$resolve(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}, function(reason) {
if (sealed) { return; }
sealed = true;
$$$internal$$reject(promise, reason);
}, 'Settle: ' + (promise._label || ' unknown promise'));
if (!sealed && error) {
sealed = true;
$$$internal$$reject(promise, error);
}
}, promise);
}
function $$$internal$$handleOwnThenable(promise, thenable) {
if (thenable._state === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, thenable._result);
} else if (promise._state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, thenable._result);
} else {
$$$internal$$subscribe(thenable, undefined, function(value) {
$$$internal$$resolve(promise, value);
}, function(reason) {
$$$internal$$reject(promise, reason);
});
}
}
function $$$internal$$handleMaybeThenable(promise, maybeThenable) {
if (maybeThenable.constructor === promise.constructor) {
$$$internal$$handleOwnThenable(promise, maybeThenable);
} else {
var then = $$$internal$$getThen(maybeThenable);
if (then === $$$internal$$GET_THEN_ERROR) {
$$$internal$$reject(promise, $$$internal$$GET_THEN_ERROR.error);
} else if (then === undefined) {
$$$internal$$fulfill(promise, maybeThenable);
} else if ($$utils$$isFunction(then)) {
$$$internal$$handleForeignThenable(promise, maybeThenable, then);
} else {
$$$internal$$fulfill(promise, maybeThenable);
}
}
}
function $$$internal$$resolve(promise, value) {
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$selfFullfillment());
} else if ($$utils$$objectOrFunction(value)) {
$$$internal$$handleMaybeThenable(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}
function $$$internal$$publishRejection(promise) {
if (promise._onerror) {
promise._onerror(promise._result);
}
$$$internal$$publish(promise);
}
function $$$internal$$fulfill(promise, value) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._result = value;
promise._state = $$$internal$$FULFILLED;
if (promise._subscribers.length === 0) {
} else {
$$asap$$default($$$internal$$publish, promise);
}
}
function $$$internal$$reject(promise, reason) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._state = $$$internal$$REJECTED;
promise._result = reason;
$$asap$$default($$$internal$$publishRejection, promise);
}
function $$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers;
var length = subscribers.length;
parent._onerror = null;
subscribers[length] = child;
subscribers[length + $$$internal$$FULFILLED] = onFulfillment;
subscribers[length + $$$internal$$REJECTED] = onRejection;
if (length === 0 && parent._state) {
$$asap$$default($$$internal$$publish, parent);
}
}
function $$$internal$$publish(promise) {
var subscribers = promise._subscribers;
var settled = promise._state;
if (subscribers.length === 0) { return; }
var child, callback, detail = promise._result;
for (var i = 0; i < subscribers.length; i += 3) {
child = subscribers[i];
callback = subscribers[i + settled];
if (child) {
$$$internal$$invokeCallback(settled, child, callback, detail);
} else {
callback(detail);
}
}
promise._subscribers.length = 0;
}
function $$$internal$$ErrorObject() {
this.error = null;
}
var $$$internal$$TRY_CATCH_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$tryCatch(callback, detail) {
try {
return callback(detail);
} catch(e) {
$$$internal$$TRY_CATCH_ERROR.error = e;
return $$$internal$$TRY_CATCH_ERROR;
}
}
function $$$internal$$invokeCallback(settled, promise, callback, detail) {
var hasCallback = $$utils$$isFunction(callback),
value, error, succeeded, failed;
if (hasCallback) {
value = $$$internal$$tryCatch(callback, detail);
if (value === $$$internal$$TRY_CATCH_ERROR) {
failed = true;
error = value.error;
value = null;
} else {
succeeded = true;
}
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$cannotReturnOwn());
return;
}
} else {
value = detail;
succeeded = true;
}
if (promise._state !== $$$internal$$PENDING) {
// noop
} else if (hasCallback && succeeded) {
$$$internal$$resolve(promise, value);
} else if (failed) {
$$$internal$$reject(promise, error);
} else if (settled === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, value);
} else if (settled === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
}
}
function $$$internal$$initializePromise(promise, resolver) {
try {
resolver(function resolvePromise(value){
$$$internal$$resolve(promise, value);
}, function rejectPromise(reason) {
$$$internal$$reject(promise, reason);
});
} catch(e) {
$$$internal$$reject(promise, e);
}
}
function $$$enumerator$$makeSettledResult(state, position, value) {
if (state === $$$internal$$FULFILLED) {
return {
state: 'fulfilled',
value: value
};
} else {
return {
state: 'rejected',
reason: value
};
}
}
function $$$enumerator$$Enumerator(Constructor, input, abortOnReject, label) {
this._instanceConstructor = Constructor;
this.promise = new Constructor($$$internal$$noop, label);
this._abortOnReject = abortOnReject;
if (this._validateInput(input)) {
this._input = input;
this.length = input.length;
this._remaining = input.length;
this._init();
if (this.length === 0) {
$$$internal$$fulfill(this.promise, this._result);
} else {
this.length = this.length || 0;
this._enumerate();
if (this._remaining === 0) {
$$$internal$$fulfill(this.promise, this._result);
}
}
} else {
$$$internal$$reject(this.promise, this._validationError());
}
}
$$$enumerator$$Enumerator.prototype._validateInput = function(input) {
return $$utils$$isArray(input);
};
$$$enumerator$$Enumerator.prototype._validationError = function() {
return new Error('Array Methods must be provided an Array');
};
$$$enumerator$$Enumerator.prototype._init = function() {
this._result = new Array(this.length);
};
var $$$enumerator$$default = $$$enumerator$$Enumerator;
$$$enumerator$$Enumerator.prototype._enumerate = function() {
var length = this.length;
var promise = this.promise;
var input = this._input;
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
this._eachEntry(input[i], i);
}
};
$$$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
var c = this._instanceConstructor;
if ($$utils$$isMaybeThenable(entry)) {
if (entry.constructor === c && entry._state !== $$$internal$$PENDING) {
entry._onerror = null;
this._settledAt(entry._state, i, entry._result);
} else {
this._willSettleAt(c.resolve(entry), i);
}
} else {
this._remaining--;
this._result[i] = this._makeResult($$$internal$$FULFILLED, i, entry);
}
};
$$$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
var promise = this.promise;
if (promise._state === $$$internal$$PENDING) {
this._remaining--;
if (this._abortOnReject && state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
} else {
this._result[i] = this._makeResult(state, i, value);
}
}
if (this._remaining === 0) {
$$$internal$$fulfill(promise, this._result);
}
};
$$$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) {
return value;
};
$$$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
var enumerator = this;
$$$internal$$subscribe(promise, undefined, function(value) {
enumerator._settledAt($$$internal$$FULFILLED, i, value);
}, function(reason) {
enumerator._settledAt($$$internal$$REJECTED, i, reason);
});
};
var $$promise$all$$default = function all(entries, label) {
return new $$$enumerator$$default(this, entries, true /* abort on reject */, label).promise;
};
var $$promise$race$$default = function race(entries, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
if (!$$utils$$isArray(entries)) {
$$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
return promise;
}
var length = entries.length;
function onFulfillment(value) {
$$$internal$$resolve(promise, value);
}
function onRejection(reason) {
$$$internal$$reject(promise, reason);
}
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
$$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
}
return promise;
};
var $$promise$resolve$$default = function resolve(object, label) {
/*jshint validthis:true */
var Constructor = this;
if (object && typeof object === 'object' && object.constructor === Constructor) {
return object;
}
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$resolve(promise, object);
return promise;
};
var $$promise$reject$$default = function reject(reason, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$reject(promise, reason);
return promise;
};
var $$es6$promise$promise$$counter = 0;
function $$es6$promise$promise$$needsResolver() {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}
function $$es6$promise$promise$$needsNew() {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}
var $$es6$promise$promise$$default = $$es6$promise$promise$$Promise;
/**
Promise objects represent the eventual result of an asynchronous operation. The
primary way of interacting with a promise is through its `then` method, which
registers callbacks to receive either a promises eventual value or the reason
why the promise cannot be fulfilled.
Terminology
-----------
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
- `thenable` is an object or function that defines a `then` method.
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
- `exception` is a value that is thrown using the throw statement.
- `reason` is a value that indicates why a promise was rejected.
- `settled` the final resting state of a promise, fulfilled or rejected.
A promise can be in one of three states: pending, fulfilled, or rejected.
Promises that are fulfilled have a fulfillment value and are in the fulfilled
state. Promises that are rejected have a rejection reason and are in the
rejected state. A fulfillment value is never a thenable.
Promises can also be said to *resolve* a value. If this value is also a
promise, then the original promise's settled state will match the value's
settled state. So a promise that *resolves* a promise that rejects will
itself reject, and a promise that *resolves* a promise that fulfills will
itself fulfill.
Basic Usage:
------------
```js
var promise = new Promise(function(resolve, reject) {
// on success
resolve(value);
// on failure
reject(reason);
});
promise.then(function(value) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Advanced Usage:
---------------
Promises shine when abstracting away asynchronous interactions such as
`XMLHttpRequest`s.
```js
function getJSON(url) {
return new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
}
}
};
});
}
getJSON('/posts.json').then(function(json) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Unlike callbacks, promises are great composable primitives.
```js
Promise.all([
getJSON('/posts'),
getJSON('/comments')
]).then(function(values){
values[0] // => postsJSON
values[1] // => commentsJSON
return values;
});
```
@class Promise
@param {function} resolver
@param {String} label optional string for labeling the promise.
Useful for tooling.
@constructor
*/
function $$es6$promise$promise$$Promise(resolver, label) {
this._id = $$es6$promise$promise$$counter++;
this._label = label;
this._state = undefined;
this._result = undefined;
this._subscribers = [];
if ($$$internal$$noop !== resolver) {
if (!$$utils$$isFunction(resolver)) {
$$es6$promise$promise$$needsResolver();
}
if (!(this instanceof $$es6$promise$promise$$Promise)) {
$$es6$promise$promise$$needsNew();
}
$$$internal$$initializePromise(this, resolver);
}
}
$$es6$promise$promise$$Promise.all = $$promise$all$$default;
$$es6$promise$promise$$Promise.race = $$promise$race$$default;
$$es6$promise$promise$$Promise.resolve = $$promise$resolve$$default;
$$es6$promise$promise$$Promise.reject = $$promise$reject$$default;
$$es6$promise$promise$$Promise.prototype = {
constructor: $$es6$promise$promise$$Promise,
/**
The primary way of interacting with a promise is through its `then` method,
which registers callbacks to receive either a promise's eventual value or the
reason why the promise cannot be fulfilled.
```js
findUser().then(function(user){
// user is available
}, function(reason){
// user is unavailable, and you are given the reason why
});
```
Chaining
--------
The return value of `then` is itself a promise. This second, 'downstream'
promise is resolved with the return value of the first promise's fulfillment
or rejection handler, or rejected if the handler throws an exception.
```js
findUser().then(function (user) {
return user.name;
}, function (reason) {
return 'default name';
}).then(function (userName) {
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
// will be `'default name'`
});
findUser().then(function (user) {
throw new Error('Found user, but still unhappy');
}, function (reason) {
throw new Error('`findUser` rejected and we're unhappy');
}).then(function (value) {
// never reached
}, function (reason) {
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
});
```
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
```js
findUser().then(function (user) {
throw new PedagogicalException('Upstream error');
}).then(function (value) {
// never reached
}).then(function (value) {
// never reached
}, function (reason) {
// The `PedgagocialException` is propagated all the way down to here
});
```
Assimilation
------------
Sometimes the value you want to propagate to a downstream promise can only be
retrieved asynchronously. This can be achieved by returning a promise in the
fulfillment or rejection handler. The downstream promise will then be pending
until the returned promise is settled. This is called *assimilation*.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// The user's comments are now available
});
```
If the assimliated promise rejects, then the downstream promise will also reject.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// If `findCommentsByAuthor` fulfills, we'll have the value here
}, function (reason) {
// If `findCommentsByAuthor` rejects, we'll have the reason here
});
```
Simple Example
--------------
Synchronous Example
```javascript
var result;
try {
result = findResult();
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
findResult(function(result, err){
if (err) {
// failure
} else {
// success
}
});
```
Promise Example;
```javascript
findResult().then(function(result){
// success
}, function(reason){
// failure
});
```
Advanced Example
--------------
Synchronous Example
```javascript
var author, books;
try {
author = findAuthor();
books = findBooksByAuthor(author);
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
function foundBooks(books) {
}
function failure(reason) {
}
findAuthor(function(author, err){
if (err) {
failure(err);
// failure
} else {
try {
findBoooksByAuthor(author, function(books, err) {
if (err) {
failure(err);
} else {
try {
foundBooks(books);
} catch(reason) {
failure(reason);
}
}
});
} catch(error) {
failure(err);
}
// success
}
});
```
Promise Example;
```javascript
findAuthor().
then(findBooksByAuthor).
then(function(books){
// found books
}).catch(function(reason){
// something went wrong
});
```
@method then
@param {Function} onFulfilled
@param {Function} onRejected
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
then: function(onFulfillment, onRejection, label) {
var parent = this;
var state = parent._state;
if (state === $$$internal$$FULFILLED && !onFulfillment || state === $$$internal$$REJECTED && !onRejection) {
return this;
}
parent._onerror = null;
var child = new this.constructor($$$internal$$noop, label);
var result = parent._result;
if (state) {
var callback = arguments[state - 1];
$$asap$$default(function(){
$$$internal$$invokeCallback(state, child, callback, result);
});
} else {
$$$internal$$subscribe(parent, child, onFulfillment, onRejection);
}
return child;
},
/**
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
as the catch block of a try/catch statement.
```js
function findAuthor(){
throw new Error('couldn't find that author');
}
// synchronous
try {
findAuthor();
} catch(reason) {
// something went wrong
}
// async with promises
findAuthor().catch(function(reason){
// something went wrong
});
```
@method catch
@param {Function} onRejection
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
'catch': function(onRejection, label) {
return this.then(null, onRejection, label);
}
};
var $$es6$promise$polyfill$$default = function polyfill() {
var local;
if (typeof global !== 'undefined') {
local = global;
} else if (typeof window !== 'undefined' && window.document) {
local = window;
} else {
local = self;
}
var es6PromiseSupport =
"Promise" in local &&
// Some of these methods are missing from
// Firefox/Chrome experimental implementations
"resolve" in local.Promise &&
"reject" in local.Promise &&
"all" in local.Promise &&
"race" in local.Promise &&
// Older version of the spec had a resolver object
// as the arg rather than a function
(function() {
var resolve;
new local.Promise(function(r) { resolve = r; });
return $$utils$$isFunction(resolve);
}());
if (!es6PromiseSupport) {
local.Promise = $$es6$promise$promise$$default;
}
};
var es6$promise$umd$$ES6Promise = {
Promise: $$es6$promise$promise$$default,
polyfill: $$es6$promise$polyfill$$default
};
/* global define:true module:true window: true */
if (typeof define === 'function' && define['amd']) {
define(function() { return es6$promise$umd$$ES6Promise; });
} else if (typeof module !== 'undefined' && module['exports']) {
module['exports'] = es6$promise$umd$$ES6Promise;
} else if (typeof this !== 'undefined') {
this['ES6Promise'] = es6$promise$umd$$ES6Promise;
}
}).call(this);

15
libjsqrc/ethereumjs/README.md

@ -1,6 +1,6 @@
# Ethereum JavaScript API
This is the Ethereum compatible JavaScript API using `Promise`s
This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API)
which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url]
@ -23,7 +23,7 @@ Component
component install ethereum/ethereum.js
* Include `ethereum.min.js` in your html file.
* Include [es6-promise](https://github.com/jakearchibald/es6-promise) or another ES6-Shim if your browser doesn't support ECMAScript 6.
* Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/)
## Usage
Require the library:
@ -37,14 +37,8 @@ Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider)
There you go, now you can use it:
```
web3.eth.coinbase.then(function(result){
console.log(result);
return web3.eth.balanceAt(result);
}).then(function(balance){
console.log(web3.toDecimal(balance));
}).catch(function(err){
console.log(err);
});
var coinbase = web3.eth.coinbase;
var balance = web3.eth.balanceAt(coinbase);
```
@ -99,3 +93,4 @@ ethereum -ws -loglevel=4
[dep-url]: https://david-dm.org/ethereum/ethereum.js
[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg
[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies

3
libjsqrc/ethereumjs/bower.json

@ -1,11 +1,10 @@
{
"name": "ethereum.js",
"namespace": "ethereum",
"version": "0.0.8",
"version": "0.0.13",
"description": "Ethereum Compatible JavaScript API",
"main": ["./dist/ethereum.js", "./dist/ethereum.min.js"],
"dependencies": {
"es6-promise": "#master",
"bignumber.js": ">=2.0.0"
},
"repository": {

1898
libjsqrc/ethereumjs/dist/ethereum.js

File diff suppressed because it is too large

38
libjsqrc/ethereumjs/dist/ethereum.js.map

File diff suppressed because one or more lines are too long

2
libjsqrc/ethereumjs/dist/ethereum.min.js

File diff suppressed because one or more lines are too long

13
libjsqrc/ethereumjs/example/balance.html

@ -2,30 +2,27 @@
<html>
<head>
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.AutoProvider());
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
function watchBalance() {
var coinbase = web3.eth.coinbase;
var originalBalance = 0;
web3.eth.balanceAt(coinbase).then(function (balance) {
originalBalance = web3.toDecimal(balance);
var balance = web3.eth.balanceAt(coinbase);
var originalBalance = web3.toDecimal(balance);
document.getElementById('original').innerText = 'original balance: ' + originalBalance + ' watching...';
});
web3.eth.watch({altered: coinbase}).changed(function() {
web3.eth.balanceAt(coinbase).then(function (balance) {
web3.eth.watch('pending').changed(function() {
balance = web3.eth.balanceAt(coinbase)
var currentBalance = web3.toDecimal(balance);
document.getElementById("current").innerText = 'current: ' + currentBalance;
document.getElementById("diff").innerText = 'diff: ' + (currentBalance - originalBalance);
});
});
}
</script>

14
libjsqrc/ethereumjs/example/contract.html

@ -2,13 +2,12 @@
<html>
<head>
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.AutoProvider());
web3.setProvider(new web3.providers.HttpSyncProvider());
// solidity source code
var source = "" +
@ -20,7 +19,8 @@
// contract description, this will be autogenerated somehow
var desc = [{
"name": "multiply",
"name": "multiply(uint256)",
"type": "function",
"inputs": [
{
"name": "a",
@ -43,10 +43,9 @@
document.getElementById('source').innerText = source;
// create contract
web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
var address = web3.eth.transact({code: web3.eth.solidity(source)});
contract = web3.eth.contract(address, desc);
document.getElementById('call').style.visibility = 'visible';
});
}
function callExampleContract() {
@ -54,9 +53,8 @@
var param = parseInt(document.getElementById('value').value);
// call the contract
contract.multiply(param).call().then(function(res) {
document.getElementById('result').innerText = res[0];
});
var res = contract.call().multiply(param);
document.getElementById('result').innerText = res.toString(10);
}
</script>

76
libjsqrc/ethereumjs/example/contract_with_array.html

@ -0,0 +1,76 @@
<!doctype>
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider());
// solidity source code
var source = "" +
"contract test {\n" +
" function multiply(uint[] a) returns(uint d) {\n" +
" return a[0] + a[1];\n" +
" }\n" +
"}\n";
// contract description, this will be autogenerated somehow
var desc = [{
"name": "multiply(uint256[])",
"type": "function",
"inputs": [
{
"name": "a",
"type": "uint256[]"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
var contract;
function createExampleContract() {
// hide create button
document.getElementById('create').style.visibility = 'hidden';
document.getElementById('source').innerText = source;
// create contract
var address = web3.eth.transact({code: web3.eth.solidity(source)});
contract = web3.eth.contract(address, desc);
document.getElementById('call').style.visibility = 'visible';
}
function callExampleContract() {
// this should be generated by ethereum
var param = parseInt(document.getElementById('value').value);
var param2 = parseInt(document.getElementById('value2').value);
// call the contract
var res = contract.call().multiply([param, param2]);
document.getElementById('result').innerText = res.toString(10);
}
</script>
</head>
<body>
<h1>contract</h1>
<div id="source"></div>
<div id='create'>
<button type="button" onClick="createExampleContract();">create example contract</button>
</div>
<div id='call' style='visibility: hidden;'>
<input type="number" id="value" onkeyup='callExampleContract()'></input>
<input type="number" id="value2" onkeyup='callExampleContract()'></input>
</div>
<div id="result"></div>
</body>
</html>

120
libjsqrc/ethereumjs/example/event.html

@ -0,0 +1,120 @@
<!doctype>
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
var desc = [{
"type":"event",
"inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}],
"name":"Event"
}, {
"type":"event",
"inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}],
"name":"Event2"
}, {
"type":"function",
"inputs": [{"name":"a","type":"uint256"}],
"name":"foo",
"outputs": []
}];
var address = '0x01';
var contract = web3.eth.contract(address, desc);
function test1() {
// "{"topic":["0x83c9849c","0xc4d76332"],"address":"0x01"}"
web3.eth.watch(contract).changed(function (res) {
});
};
function test2() {
// "{"topic":["0x83c9849c"],"address":"0x01"}"
web3.eth.watch(contract.Event).changed(function (res) {
});
};
function test3() {
// "{"topic":["0x83c9849c"],"address":"0x01"}"
contract.Event().changed(function (res) {
});
};
function test4() {
// "{"topic":["0x83c9849c","0000000000000000000000000000000000000000000000000000000000000045"],"address":"0x01"}"
contract.Event({a: 69}).changed(function (res) {
});
};
function test5() {
// "{"topic":["0x83c9849c",["0000000000000000000000000000000000000000000000000000000000000045","000000000000000000000000000000000000000000000000000000000000002a"]],"address":"0x01"}"
contract.Event({a: [69, 42]}).changed(function (res) {
});
};
function test6() {
// "{"topic":["0x83c9849c","000000000000000000000000000000000000000000000000000000000000001e"],"max":100,"address":"0x01"}"
contract.Event({a: 30}, {max: 100}).changed(function (res) {
});
};
function test7() {
// "{"topic":["0x83c9849c","000000000000000000000000000000000000000000000000000000000000001e"],"address":"0x01"}"
web3.eth.watch(contract.Event, {a: 30}).changed(function (res) {
});
};
function test8() {
// "{"topic":["0x83c9849c","000000000000000000000000000000000000000000000000000000000000001e"],"max":100,"address":"0x01"}"
web3.eth.watch(contract.Event, {a: 30}, {max: 100}).changed(function (res) {
});
};
// not valid
// function testX() {
// web3.eth.watch([contract.Event, contract.Event2]).changed(function (res) {
// });
// };
</script>
</head>
<body>
<div>
<button type="button" onClick="test1();">test1</button>
</div>
<div>
<button type="button" onClick="test2();">test2</button>
</div>
<div>
<button type="button" onClick="test3();">test3</button>
</div>
<div>
<button type="button" onClick="test4();">test4</button>
</div>
<div>
<button type="button" onClick="test5();">test5</button>
</div>
<div>
<button type="button" onClick="test6();">test6</button>
</div>
<div>
<button type="button" onClick="test7();">test7</button>
</div>
<div>
<button type="button" onClick="test8();">test8</button>
</div>
</body>
</html>

66
libjsqrc/ethereumjs/example/event_inc.html

@ -0,0 +1,66 @@
<!doctype>
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
var source = "" +
"contract Contract { " +
" event Incremented(bool indexed odd, uint x); " +
" function Contract() { " +
" x = 69; " +
" } " +
" function inc() { " +
" ++x; " +
" Incremented(x % 2 == 1, x); " +
" } " +
" uint x; " +
"}";
var desc = [{
"type":"event",
"name":"Incremented",
"inputs": [{"name":"odd","type":"bool","indexed":true},{"name":"x","type":"uint","indexed":false}],
}, {
"type":"function",
"name":"inc",
"inputs": [],
"outputs": []
}];
var address;
var contract;
var update = function (x) {
document.getElementById('result').innerText = JSON.stringify(x);
};
var createContract = function () {
address = web3.eth.transact({code: web3.eth.solidity(source)});
contract = web3.eth.contract(address, desc);
contract.Incremented({odd: true}).changed(update);
};
var callContract = function () {
contract.call().inc();
};
</script>
</head>
<body>
<div>
<button type="button" onClick="createContract();">create contract</button>
</div>
<div>
<button type="button" onClick="callContract();">test1</button>
</div>
<div id="result">
</div>
</body>
</html>

22
libjsqrc/ethereumjs/example/natspec_contract.html

@ -2,17 +2,17 @@
<html>
<head>
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.AutoProvider());
web3.setProvider(new web3.providers.QtSyncProvider());
// solidity source code
var source = "" +
"contract test {\n" +
" /// @notice Will multiplty `a` by 7. \n" +
" /// @notice Will multiply `a` by 7. \n" +
" function multiply(uint a) returns(uint d) {\n" +
" return a * 7;\n" +
" }\n" +
@ -20,7 +20,8 @@
// contract description, this will be autogenerated somehow
var desc = [{
"name": "multiply",
"name": "multiply(uint256)",
"type": "function",
"inputs": [
{
"name": "a",
@ -43,20 +44,19 @@
document.getElementById('source').innerText = source;
// create contract
web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
contract = web3.contract(address, desc);
var address = web3.eth.transact({code: web3.eth.solidity(source)});
contract = web3.eth.contract(address, desc);
document.getElementById('call').style.visibility = 'visible';
});
}
function callExampleContract() {
// this should be generated by ethereum
var param = parseInt(document.getElementById('value').value);
// call the contract
contract.multiply(param).transact().then(function(res) {
document.getElementById('result').innerText = res[0];
});
// transaction does not return any result, cause it's not synchronous and we don't know,
// when it will be processed
contract.transact().multiply(param);
document.getElementById('result').innerText = 'transaction made';
}
</script>

18
libjsqrc/ethereumjs/example/node-app.js

@ -1,16 +1,12 @@
#!/usr/bin/env node
require('es6-promise').polyfill();
var web3 = require("../index.js");
web3.setProvider(new web3.providers.HttpRpcProvider('http://localhost:8080'));
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
var coinbase = web3.eth.coinbase;
console.log(coinbase);
var balance = web3.eth.balanceAt(coinbase);
console.log(balance);
web3.eth.coinbase.then(function(result){
console.log(result);
return web3.eth.balanceAt(result);
}).then(function(balance){
console.log(web3.toDecimal(balance));
}).catch(function(err){
console.log(err);
});

8
libjsqrc/ethereumjs/index.js

@ -2,10 +2,10 @@ var web3 = require('./lib/web3');
var ProviderManager = require('./lib/providermanager');
web3.provider = new ProviderManager();
web3.filter = require('./lib/filter');
web3.providers.WebSocketProvider = require('./lib/websocket');
web3.providers.HttpRpcProvider = require('./lib/httprpc');
web3.providers.QtProvider = require('./lib/qt');
web3.providers.AutoProvider = require('./lib/autoprovider');
web3.providers.HttpSyncProvider = require('./lib/httpsync');
web3.providers.QtSyncProvider = require('./lib/qtsync');
web3.eth.contract = require('./lib/contract');
web3.abi = require('./lib/abi');
module.exports = web3;

306
libjsqrc/ethereumjs/lib/abi.js

@ -21,167 +21,57 @@
* @date 2014
*/
// TODO: is these line is supposed to be here?
if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line
}
var web3 = require('./web3'); // jshint ignore:line
BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN });
var web3 = require('./web3');
var utils = require('./utils');
var types = require('./types');
var c = require('./const');
var f = require('./formatters');
var ETH_PADDING = 32;
/// Finds first index of array element matching pattern
/// @param array
/// @param callback pattern
/// @returns index of element
var findIndex = function (array, callback) {
var end = false;
var i = 0;
for (; i < array.length && !end; i++) {
end = callback(array[i]);
}
return end ? i - 1 : -1;
};
/// @returns a function that is used as a pattern for 'findIndex'
var findMethodIndex = function (json, methodName) {
return findIndex(json, function (method) {
return method.name === methodName;
});
};
/// @param string string to be padded
/// @param number of characters that result string should have
/// @param sign, by default 0
/// @returns right aligned string
var padLeft = function (string, chars, sign) {
return new Array(chars - string.length + 1).join(sign ? sign : "0") + string;
};
/// @param expected type prefix (string)
/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false
var prefixedType = function (prefix) {
return function (type) {
return type.indexOf(prefix) === 0;
};
};
/// @param expected type name (string)
/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false
var namedType = function (name) {
return function (type) {
return name === type;
};
var displayTypeError = function (type) {
console.error('parser does not support type: ' + type);
};
/// This method should be called if we want to check if givent type is an array type
/// @returns true if it is, otherwise false
var arrayType = function (type) {
return type.slice(-2) === '[]';
};
/// Formats input value to byte representation of int
/// If value is negative, return it's two's complement
/// If the value is floating point, round it down
/// @returns right-aligned byte representation of int
var formatInputInt = function (value) {
var padding = ETH_PADDING * 2;
if (value instanceof BigNumber || typeof value === 'number') {
if (typeof value === 'number')
value = new BigNumber(value);
value = value.round();
if (value.lessThan(0))
value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1);
value = value.toString(16);
}
else if (value.indexOf('0x') === 0)
value = value.substr(2);
else if (typeof value === 'string')
value = formatInputInt(new BigNumber(value));
else
value = (+value).toString(16);
return padLeft(value, padding);
};
/// Formats input value to byte representation of string
/// @returns left-algined byte representation of string
var formatInputString = function (value) {
return web3.fromAscii(value, ETH_PADDING).substr(2);
};
/// Formats input value to byte representation of bool
/// @returns right-aligned byte representation bool
var formatInputBool = function (value) {
return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
};
/// Formats input value to byte representation of real
/// Values are multiplied by 2^m and encoded as integers
/// @returns byte representation of real
var formatInputReal = function (value) {
return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
};
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
if (arrayType(type) || prefixedType('string')(type))
return formatInputInt(value.length);
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return f.formatInputInt(value.length);
return "";
};
/// Setups input formatters for solidity types
/// @returns an array of input formatters
var setupInputTypes = function () {
return [
{ type: prefixedType('uint'), format: formatInputInt },
{ type: prefixedType('int'), format: formatInputInt },
{ type: prefixedType('hash'), format: formatInputInt },
{ type: prefixedType('string'), format: formatInputString },
{ type: prefixedType('real'), format: formatInputReal },
{ type: prefixedType('ureal'), format: formatInputReal },
{ type: namedType('address'), format: formatInputInt },
{ type: namedType('bool'), format: formatInputBool }
];
};
var inputTypes = setupInputTypes();
var inputTypes = types.inputTypes();
/// Formats input params to bytes
/// @param contract json abi
/// @param name of the method that we want to use
/// @param abi contract method inputs
/// @param array of params that will be formatted to bytes
/// @returns bytes representation of input params
var toAbiInput = function (json, methodName, params) {
var formatInput = function (inputs, params) {
var bytes = "";
var index = findMethodIndex(json, methodName);
if (index === -1) {
return;
}
var method = json[index];
var padding = ETH_PADDING * 2;
var padding = c.ETH_PADDING * 2;
/// first we iterate in search for dynamic
method.inputs.forEach(function (input, index) {
inputs.forEach(function (input, index) {
bytes += dynamicTypeBytes(input.type, params[index]);
});
method.inputs.forEach(function (input, i) {
inputs.forEach(function (input, i) {
var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(method.inputs[i].type, params[i]);
typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
}
if (!typeMatch) {
console.error('input parser does not support type: ' + method.inputs[i].type);
displayTypeError(inputs[i].type);
}
var formatter = inputTypes[j - 1].format;
var toAppend = "";
if (arrayType(method.inputs[i].type))
if (arrayType(inputs[i].type))
toAppend = params[i].reduce(function (acc, curr) {
return acc + formatter(curr);
}, "");
@ -193,122 +83,44 @@ var toAbiInput = function (json, methodName, params) {
return bytes;
};
/// Check if input value is negative
/// @param value is hex format
/// @returns true if it is negative, otherwise false
var signedIsNegative = function (value) {
return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';
};
/// Formats input right-aligned input bytes to int
/// @returns right-aligned input bytes formatted to int
var formatOutputInt = function (value) {
// check if it's negative number
// it it is, return two's complement
if (signedIsNegative(value)) {
return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
}
return new BigNumber(value, 16);
};
/// Formats big right-aligned input bytes to uint
/// @returns right-aligned input bytes formatted to uint
var formatOutputUInt = function (value) {
return new BigNumber(value, 16);
};
/// @returns input bytes formatted to real
var formatOutputReal = function (value) {
return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128));
};
/// @returns input bytes formatted to ureal
var formatOutputUReal = function (value) {
return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128));
};
/// @returns right-aligned input bytes formatted to hex
var formatOutputHash = function (value) {
return "0x" + value;
};
/// @returns right-aligned input bytes formatted to bool
var formatOutputBool = function (value) {
return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
};
/// @returns left-aligned input bytes formatted to ascii string
var formatOutputString = function (value) {
return web3.toAscii(value);
};
/// @returns right-aligned input bytes formatted to address
var formatOutputAddress = function (value) {
return "0x" + value.slice(value.length - 40, value.length);
};
var dynamicBytesLength = function (type) {
if (arrayType(type) || prefixedType('string')(type))
return ETH_PADDING * 2;
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return c.ETH_PADDING * 2;
return 0;
};
/// Setups output formaters for solidity types
/// @returns an array of output formatters
var setupOutputTypes = function () {
return [
{ type: prefixedType('uint'), format: formatOutputUInt },
{ type: prefixedType('int'), format: formatOutputInt },
{ type: prefixedType('hash'), format: formatOutputHash },
{ type: prefixedType('string'), format: formatOutputString },
{ type: prefixedType('real'), format: formatOutputReal },
{ type: prefixedType('ureal'), format: formatOutputUReal },
{ type: namedType('address'), format: formatOutputAddress },
{ type: namedType('bool'), format: formatOutputBool }
];
};
var outputTypes = setupOutputTypes();
var outputTypes = types.outputTypes();
/// Formats output bytes back to param list
/// @param contract json abi
/// @param name of the method that we want to use
/// @param contract abi method outputs
/// @param bytes representtion of output
/// @returns array of output params
var fromAbiOutput = function (json, methodName, output) {
var index = findMethodIndex(json, methodName);
if (index === -1) {
return;
}
var formatOutput = function (outs, output) {
output = output.slice(2);
var result = [];
var method = json[index];
var padding = ETH_PADDING * 2;
var padding = c.ETH_PADDING * 2;
var dynamicPartLength = method.outputs.reduce(function (acc, curr) {
var dynamicPartLength = outs.reduce(function (acc, curr) {
return acc + dynamicBytesLength(curr.type);
}, 0);
var dynamicPart = output.slice(0, dynamicPartLength);
output = output.slice(dynamicPartLength);
method.outputs.forEach(function (out, i) {
outs.forEach(function (out, i) {
var typeMatch = false;
for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
typeMatch = outputTypes[j].type(method.outputs[i].type);
typeMatch = outputTypes[j].type(outs[i].type);
}
if (!typeMatch) {
console.error('output parser does not support type: ' + method.outputs[i].type);
displayTypeError(outs[i].type);
}
var formatter = outputTypes[j - 1].format;
if (arrayType(method.outputs[i].type)) {
var size = formatOutputUInt(dynamicPart.slice(0, padding));
if (arrayType(outs[i].type)) {
var size = f.formatOutputUInt(dynamicPart.slice(0, padding));
dynamicPart = dynamicPart.slice(padding);
var array = [];
for (var k = 0; k < size; k++) {
@ -317,7 +129,7 @@ var fromAbiOutput = function (json, methodName, output) {
}
result.push(array);
}
else if (prefixedType('string')(method.outputs[i].type)) {
else if (types.prefixedType('string')(outs[i].type)) {
dynamicPart = dynamicPart.slice(padding);
result.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
@ -332,13 +144,23 @@ var fromAbiOutput = function (json, methodName, output) {
/// @param json abi for contract
/// @returns input parser object for given json abi
/// TODO: refactor creating the parser, do not double logic from contract
var inputParser = function (json) {
var parser = {};
json.forEach(function (method) {
parser[method.name] = function () {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
var params = Array.prototype.slice.call(arguments);
return toAbiInput(json, method.name, params);
return formatInput(method.inputs, params);
};
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
parser[displayName][typeName] = impl;
});
return parser;
@ -349,32 +171,40 @@ var inputParser = function (json) {
var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
parser[method.name] = function (output) {
return fromAbiOutput(json, method.name, output);
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function (output) {
return formatOutput(method.outputs, output);
};
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
parser[displayName][typeName] = impl;
});
return parser;
};
/// @param json abi for contract
/// @param method name for which we want to get method signature
/// @returns (promise) contract method signature for method with given name
var methodSignature = function (json, name) {
var method = json[findMethodIndex(json, name)];
var result = name + '(';
var inputTypes = method.inputs.map(function (inp) {
return inp.type;
});
result += inputTypes.join(',');
result += ')';
/// @param function/event name for which we want to get signature
/// @returns signature of function/event with given name
var signatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);
};
return web3.sha3(web3.fromAscii(result));
var eventSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name));
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
methodSignature: methodSignature
formatInput: formatInput,
formatOutput: formatOutput,
signatureFromAscii: signatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
};

114
libjsqrc/ethereumjs/lib/autoprovider.js

@ -1,114 +0,0 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file autoprovider.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
*/
/*
* @brief if qt object is available, uses QtProvider,
* if not tries to connect over websockets
* if it fails, it uses HttpRpcProvider
*/
var web3 = require('./web3'); // jshint ignore:line
if (process.env.NODE_ENV !== 'build') {
var WebSocket = require('ws'); // jshint ignore:line
}
/**
* AutoProvider object prototype is implementing 'provider protocol'
* Automatically tries to setup correct provider(Qt, WebSockets or HttpRpc)
* First it checkes if we are ethereum browser (if navigator.qt object is available)
* if yes, we are using QtProvider
* if no, we check if it is possible to establish websockets connection with ethereum (ws://localhost:40404/eth is default)
* if it's not possible, we are using httprpc provider (http://localhost:8080)
* The constructor allows you to specify uris on which we are trying to connect over http or websockets
* You can do that by passing objects with fields httrpc and websockets
*/
var AutoProvider = function (userOptions) {
if (web3.haveProvider()) {
return;
}
// before we determine what provider we are, we have to cache request
this.sendQueue = [];
this.onmessageQueue = [];
if (navigator.qt) {
this.provider = new web3.providers.QtProvider();
return;
}
userOptions = userOptions || {};
var options = {
httprpc: userOptions.httprpc || 'http://localhost:8080',
websockets: userOptions.websockets || 'ws://localhost:40404/eth'
};
var self = this;
var closeWithSuccess = function (success) {
ws.close();
if (success) {
self.provider = new web3.providers.WebSocketProvider(options.websockets);
} else {
self.provider = new web3.providers.HttpRpcProvider(options.httprpc);
self.poll = self.provider.poll.bind(self.provider);
}
self.sendQueue.forEach(function (payload) {
self.provider.send(payload);
});
self.onmessageQueue.forEach(function (handler) {
self.provider.onmessage = handler;
});
};
var ws = new WebSocket(options.websockets);
ws.onopen = function() {
closeWithSuccess(true);
};
ws.onerror = function() {
closeWithSuccess(false);
};
};
/// Sends message forward to the provider, that is being used
/// if provider is not yet set, enqueues the message
AutoProvider.prototype.send = function (payload) {
if (this.provider) {
this.provider.send(payload);
return;
}
this.sendQueue.push(payload);
};
/// On incoming message sends the message to the provider that is currently being used
Object.defineProperty(AutoProvider.prototype, 'onmessage', {
set: function (handler) {
if (this.provider) {
this.provider.onmessage = handler;
return;
}
this.onmessageQueue.push(handler);
}
});
module.exports = AutoProvider;

56
libjsqrc/ethereumjs/lib/const.js

@ -0,0 +1,56 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file const.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/// required to define ETH_BIGNUMBER_ROUNDING_MODE
if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line
}
var ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
module.exports = {
ETH_PADDING: 32,
ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }
};

200
libjsqrc/ethereumjs/lib/contract.js

@ -20,11 +20,153 @@
* @date 2014
*/
var web3 = require('./web3'); // jshint ignore:line
var web3 = require('./web3');
var abi = require('./abi');
var utils = require('./utils');
var eventImpl = require('./event');
var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js
// TODO: figure out better way to solve this
web3._currentContractAbi = vars.abi;
web3._currentContractAddress = vars.address;
web3._currentContractMethodName = vars.method;
web3._currentContractMethodParams = vars.params;
};
var addFunctionRelatedPropertiesToContract = function (contract) {
contract.call = function (options) {
contract._isTransact = false;
contract._options = options;
return contract;
};
contract.transact = function (options) {
contract._isTransact = true;
contract._options = options;
return contract;
};
contract._options = {};
['gas', 'gasPrice', 'value', 'from'].forEach(function(p) {
contract[p] = function (v) {
contract._options[p] = v;
return contract;
};
});
};
var addFunctionsToContract = function (contract, desc, address) {
var inputParser = abi.inputParser(desc);
var outputParser = abi.outputParser(desc);
// create contract functions
utils.filterFunctions(desc).forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
var params = Array.prototype.slice.call(arguments);
var signature = abi.signatureFromAscii(method.name);
var parsed = inputParser[displayName][typeName].apply(null, params);
var options = contract._options || {};
options.to = address;
options.data = signature + parsed;
var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);
var collapse = options.collapse !== false;
// reset
contract._options = {};
contract._isTransact = null;
if (isTransact) {
exportNatspecGlobals({
abi: desc,
address: address,
method: method.name,
params: params
});
// transactions do not have any output, cause we do not know, when they will be processed
web3.eth.transact(options);
return;
}
var output = web3.eth.call(options);
var ret = outputParser[displayName][typeName](output);
if (collapse)
{
if (ret.length === 1)
ret = ret[0];
else if (ret.length === 0)
ret = null;
}
return ret;
};
if (contract[displayName] === undefined) {
contract[displayName] = impl;
}
contract[displayName][typeName] = impl;
});
};
var addEventRelatedPropertiesToContract = function (contract, desc, address) {
contract.address = address;
contract._onWatchEventResult = function (data) {
var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));
var parser = eventImpl.outputParser(matchingEvent);
return parser(data);
};
Object.defineProperty(contract, 'topic', {
get: function() {
return utils.filterEvents(desc).map(function (e) {
return abi.eventSignatureFromAscii(e.name);
});
}
});
};
var addEventsToContract = function (contract, desc, address) {
// create contract events
utils.filterEvents(desc).forEach(function (e) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, signature, e);
var o = event.apply(null, params);
o._onWatchEventResult = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o);
};
// this property should be used by eth.filter to check if object is an event
impl._isEvent = true;
var displayName = utils.extractDisplayName(e.name);
var typeName = utils.extractTypeName(e.name);
if (contract[displayName] === undefined) {
contract[displayName] = impl;
}
contract[displayName][typeName] = impl;
});
};
/// method signature length in bytes
var ETH_METHOD_SIGNATURE_LENGTH = 4;
/**
* This method should be called when we want to call / transact some solidity method from javascript
@ -39,50 +181,36 @@ var ETH_METHOD_SIGNATURE_LENGTH = 4;
*
* var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object
*
* myContract.myMethod('this is test string param for call').call(); // myMethod call
* myContract.myMethod('this is test string param for transact').transact() // myMethod transact
* myContract.myMethod('this is test string param for call'); // myMethod call (implicit, default)
* myContract.call().myMethod('this is test string param for call'); // myMethod call (explicit)
* myContract.transact().myMethod('this is test string param for transact'); // myMethod transact
*
* @param address - address of the contract, which should be called
* @param desc - abi json description of the contract, which is being created
* @returns contract object
*/
var contract = function (address, desc) {
var inputParser = abi.inputParser(desc);
var outputParser = abi.outputParser(desc);
var contract = {};
var contract = function (address, desc) {
// workaround for invalid assumption that method.name is the full anonymous prototype of the method.
// it's not. it's just the name. the rest of the code assumes it's actually the anonymous
// prototype, so we make it so as a workaround.
// TODO: we may not want to modify input params, maybe use copy instead?
desc.forEach(function (method) {
contract[method.name] = function () {
var params = Array.prototype.slice.call(arguments);
var parsed = inputParser[method.name].apply(null, params);
var onSuccess = function (result) {
return outputParser[method.name](result);
};
return {
call: function (extra) {
extra = extra || {};
extra.to = address;
return abi.methodSignature(desc, method.name).then(function (signature) {
extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;
return web3.eth.call(extra).then(onSuccess);
});
},
transact: function (extra) {
extra = extra || {};
extra.to = address;
return abi.methodSignature(desc, method.name).then(function (signature) {
extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;
return web3.eth.transact(extra).then(onSuccess);
});
if (method.name.indexOf('(') === -1) {
var displayName = method.name;
var typeName = method.inputs.map(function(i){return i.type; }).join();
method.name = displayName + '(' + typeName + ')';
}
};
};
});
return contract;
var result = {};
addFunctionRelatedPropertiesToContract(result);
addFunctionsToContract(result, desc, address);
addEventRelatedPropertiesToContract(result, desc, address);
addEventsToContract(result, desc, address);
return result;
};
module.exports = contract;

135
libjsqrc/ethereumjs/lib/event.js

@ -0,0 +1,135 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file event.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
var abi = require('./abi');
var utils = require('./utils');
/// filter inputs array && returns only indexed (or not) inputs
/// @param inputs array
/// @param bool if result should be an array of indexed params on not
/// @returns array of (not?) indexed params
var filterInputs = function (inputs, indexed) {
return inputs.filter(function (current) {
return current.indexed === indexed;
});
};
var inputWithName = function (inputs, name) {
var index = utils.findIndex(inputs, function (input) {
return input.name === name;
});
if (index === -1) {
console.error('indexed param with name ' + name + ' not found');
return undefined;
}
return inputs[index];
};
var indexedParamsToTopics = function (event, indexed) {
// sort keys?
return Object.keys(indexed).map(function (key) {
var inputs = [inputWithName(filterInputs(event.inputs, true), key)];
var value = indexed[key];
if (value instanceof Array) {
return value.map(function (v) {
return abi.formatInput(inputs, [v]);
});
}
return abi.formatInput(inputs, [value]);
});
};
var inputParser = function (address, signature, event) {
// valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'
return function (indexed, options) {
var o = options || {};
o.address = address;
o.topic = [];
o.topic.push(signature);
if (indexed) {
o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));
}
return o;
};
};
var getArgumentsObject = function (inputs, indexed, notIndexed) {
var indexedCopy = indexed.slice();
var notIndexedCopy = notIndexed.slice();
return inputs.reduce(function (acc, current) {
var value;
if (current.indexed)
value = indexed.splice(0, 1)[0];
else
value = notIndexed.splice(0, 1)[0];
acc[current.name] = value;
return acc;
}, {});
};
var outputParser = function (event) {
return function (output) {
var result = {
event: utils.extractDisplayName(event.name),
number: output.number,
args: {}
};
if (!output.topic) {
return result;
}
var indexedOutputs = filterInputs(event.inputs, true);
var indexedData = "0x" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join("");
var indexedRes = abi.formatOutput(indexedOutputs, indexedData);
var notIndexedOutputs = filterInputs(event.inputs, false);
var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);
result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);
return result;
};
};
var getMatchingEvent = function (events, payload) {
for (var i = 0; i < events.length; i++) {
var signature = abi.eventSignatureFromAscii(events[i].name);
if (signature === payload.topic[0]) {
return events[i];
}
}
return undefined;
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
getMatchingEvent: getMatchingEvent
};

59
libjsqrc/ethereumjs/lib/filter.js

@ -27,55 +27,70 @@ var web3 = require('./web3'); // jshint ignore:line
/// should be used when we want to watch something
/// it's using inner polling mechanism and is notified about changes
/// TODO: change 'options' name cause it may be not the best matching one, since we have events
var Filter = function(options, impl) {
if (typeof options !== "string") {
// topics property is deprecated, warn about it!
if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead');
}
this._onWatchResult = options._onWatchEventResult;
// evaluate lazy properties
options = {
to: options.to,
topic: options.topic,
earliest: options.earliest,
latest: options.latest,
max: options.max,
skip: options.skip,
address: options.address
};
}
this.impl = impl;
this.callbacks = [];
var self = this;
this.promise = impl.newFilter(options);
this.promise.then(function (id) {
self.id = id;
web3.on(impl.changed, id, self.trigger.bind(self));
web3.provider.startPolling({call: impl.changed, args: [id]}, id);
});
this.id = impl.newFilter(options);
web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));
};
/// alias for changed*
Filter.prototype.arrived = function(callback) {
this.changed(callback);
};
Filter.prototype.happened = function(callback) {
this.changed(callback);
};
/// gets called when there is new eth/shh message
Filter.prototype.changed = function(callback) {
var self = this;
this.promise.then(function(id) {
self.callbacks.push(callback);
});
this.callbacks.push(callback);
};
/// trigger calling new message from people
Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].call(this, messages);
for (var j = 0; j < messages.length; j++) {
var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];
this.callbacks[i].call(this, message);
}
}
};
/// should be called to uninstall current filter
Filter.prototype.uninstall = function() {
var self = this;
this.promise.then(function (id) {
self.impl.uninstallFilter(id);
web3.provider.stopPolling(id);
web3.off(impl.changed, id);
});
this.impl.uninstallFilter(this.id);
web3.provider.stopPolling(this.id);
};
/// should be called to manually trigger getting latest messages from the client
Filter.prototype.messages = function() {
var self = this;
return this.promise.then(function (id) {
return self.impl.getMessages(id);
});
return this.impl.getMessages(this.id);
};
/// alias for messages

154
libjsqrc/ethereumjs/lib/formatters.js

@ -0,0 +1,154 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file formatters.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line
}
var utils = require('./utils');
var c = require('./const');
/// @param string string to be padded
/// @param number of characters that result string should have
/// @param sign, by default 0
/// @returns right aligned string
var padLeft = function (string, chars, sign) {
return new Array(chars - string.length + 1).join(sign ? sign : "0") + string;
};
/// Formats input value to byte representation of int
/// If value is negative, return it's two's complement
/// If the value is floating point, round it down
/// @returns right-aligned byte representation of int
var formatInputInt = function (value) {
var padding = c.ETH_PADDING * 2;
if (value instanceof BigNumber || typeof value === 'number') {
if (typeof value === 'number')
value = new BigNumber(value);
BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);
value = value.round();
if (value.lessThan(0))
value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1);
value = value.toString(16);
}
else if (value.indexOf('0x') === 0)
value = value.substr(2);
else if (typeof value === 'string')
value = formatInputInt(new BigNumber(value));
else
value = (+value).toString(16);
return padLeft(value, padding);
};
/// Formats input value to byte representation of string
/// @returns left-algined byte representation of string
var formatInputString = function (value) {
return utils.fromAscii(value, c.ETH_PADDING).substr(2);
};
/// Formats input value to byte representation of bool
/// @returns right-aligned byte representation bool
var formatInputBool = function (value) {
return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
};
/// Formats input value to byte representation of real
/// Values are multiplied by 2^m and encoded as integers
/// @returns byte representation of real
var formatInputReal = function (value) {
return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
};
/// Check if input value is negative
/// @param value is hex format
/// @returns true if it is negative, otherwise false
var signedIsNegative = function (value) {
return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';
};
/// Formats input right-aligned input bytes to int
/// @returns right-aligned input bytes formatted to int
var formatOutputInt = function (value) {
value = value || "0";
// check if it's negative number
// it it is, return two's complement
if (signedIsNegative(value)) {
return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
}
return new BigNumber(value, 16);
};
/// Formats big right-aligned input bytes to uint
/// @returns right-aligned input bytes formatted to uint
var formatOutputUInt = function (value) {
value = value || "0";
return new BigNumber(value, 16);
};
/// @returns input bytes formatted to real
var formatOutputReal = function (value) {
return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128));
};
/// @returns input bytes formatted to ureal
var formatOutputUReal = function (value) {
return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128));
};
/// @returns right-aligned input bytes formatted to hex
var formatOutputHash = function (value) {
return "0x" + value;
};
/// @returns right-aligned input bytes formatted to bool
var formatOutputBool = function (value) {
return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
};
/// @returns left-aligned input bytes formatted to ascii string
var formatOutputString = function (value) {
return utils.toAscii(value);
};
/// @returns right-aligned input bytes formatted to address
var formatOutputAddress = function (value) {
return "0x" + value.slice(value.length - 40, value.length);
};
module.exports = {
formatInputInt: formatInputInt,
formatInputString: formatInputString,
formatInputBool: formatInputBool,
formatInputReal: formatInputReal,
formatOutputInt: formatOutputInt,
formatOutputUInt: formatOutputUInt,
formatOutputReal: formatOutputReal,
formatOutputUReal: formatOutputUReal,
formatOutputHash: formatOutputHash,
formatOutputBool: formatOutputBool,
formatOutputString: formatOutputString,
formatOutputAddress: formatOutputAddress
};

126
libjsqrc/ethereumjs/lib/httprpc.js

@ -1,126 +0,0 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file httprpc.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
*/
// TODO: is these line is supposed to be here?
if (process.env.NODE_ENV !== 'build') {
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
}
/**
* HttpRpcProvider object prototype is implementing 'provider protocol'
* Should be used when we want to connect to ethereum backend over http && jsonrpc
* It's compatible with cpp client
* The contructor allows to specify host uri
* This provider is using in-browser polling mechanism
*/
var HttpRpcProvider = function (host) {
this.handlers = [];
this.host = host;
};
/// Transforms inner message to proper jsonrpc object
/// @param inner message object
/// @returns jsonrpc object
function formatJsonRpcObject(object) {
return {
jsonrpc: '2.0',
method: object.call,
params: object.args,
id: object._id
};
}
/// Transforms jsonrpc object to inner message
/// @param incoming jsonrpc message
/// @returns inner message object
function formatJsonRpcMessage(message) {
var object = JSON.parse(message);
return {
_id: object.id,
data: object.result,
error: object.error
};
}
/// Prototype object method
/// Asynchronously sends request to server
/// @param payload is inner message object
/// @param cb is callback which is being called when response is comes back
HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
var data = formatJsonRpcObject(payload);
var request = new XMLHttpRequest();
request.open("POST", this.host, true);
request.send(JSON.stringify(data));
request.onreadystatechange = function () {
if (request.readyState === 4 && cb) {
cb(request);
}
};
};
/// Prototype object method
/// Should be called when we want to send single api request to server
/// Asynchronous
/// On response it passes message to handlers
/// @param payload is inner message object
HttpRpcProvider.prototype.send = function (payload) {
var self = this;
this.sendRequest(payload, function (request) {
self.handlers.forEach(function (handler) {
handler.call(self, formatJsonRpcMessage(request.responseText));
});
});
};
/// Prototype object method
/// Should be called only for polling requests
/// Asynchronous
/// On response it passege message to handlers, but only if message's result is true or not empty array
/// Otherwise response is being silently ignored
/// @param payload is inner message object
/// @id is id of poll that we are calling
HttpRpcProvider.prototype.poll = function (payload, id) {
var self = this;
this.sendRequest(payload, function (request) {
var parsed = JSON.parse(request.responseText);
if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {
return;
}
self.handlers.forEach(function (handler) {
handler.call(self, {_event: payload.call, _id: id, data: parsed.result});
});
});
};
/// Prototype object property
/// Should be used to set message handlers for this provider
Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
set: function (handler) {
this.handlers.push(handler);
}
});
module.exports = HttpRpcProvider;

46
libjsqrc/ethereumjs/lib/httpsync.js

@ -0,0 +1,46 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file httpsync.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
*/
if (process.env.NODE_ENV !== 'build') {
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
}
var HttpSyncProvider = function (host) {
this.handlers = [];
this.host = host || 'http://localhost:8080';
};
HttpSyncProvider.prototype.send = function (payload) {
//var data = formatJsonRpcObject(payload);
var request = new XMLHttpRequest();
request.open('POST', this.host, false);
request.send(JSON.stringify(payload));
// check request.status
var result = request.responseText;
return JSON.parse(result);
};
module.exports = HttpSyncProvider;

65
libjsqrc/ethereumjs/lib/jsonrpc.js

@ -0,0 +1,65 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file jsonrpc.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var messageId = 1;
/// Should be called to valid json create payload object
/// @param method of jsonrpc call, required
/// @param params, an array of method params, optional
/// @returns valid jsonrpc payload object
var toPayload = function (method, params) {
if (!method)
console.error('jsonrpc method should be specified!');
return {
jsonrpc: '2.0',
method: method,
params: params || [],
id: messageId++
};
};
/// Should be called to check if jsonrpc response is valid
/// @returns true if response is valid, otherwise false
var isValidResponse = function (response) {
return !!response &&
!response.error &&
response.jsonrpc === '2.0' &&
typeof response.id === 'number' &&
(!!response.result || typeof response.result === 'boolean');
};
/// Should be called to create batch payload object
/// @param messages, an array of objects with method (required) and params (optional) fields
var toBatchPayload = function (messages) {
return messages.map(function (message) {
return toPayload(message.method, message.params);
});
};
module.exports = {
toPayload: toPayload,
isValidResponse: isValidResponse,
toBatchPayload: toBatchPayload
};

18
libjsqrc/ethereumjs/lib/local.js

@ -0,0 +1,18 @@
var addressName = {"0x12378912345789": "Gav", "0x57835893478594739854": "Jeff"};
var nameAddress = {};
for (var prop in addressName) {
if (addressName.hasOwnProperty(prop)) {
nameAddress[addressName[prop]] = prop;
}
}
var local = {
addressBook:{
byName: addressName,
byAddress: nameAddress
}
};
if (typeof(module) !== "undefined")
module.exports = local;

90
libjsqrc/ethereumjs/lib/providermanager.js

@ -23,7 +23,9 @@
* @date 2014
*/
var web3 = require('./web3'); // jshint ignore:line
var web3 = require('./web3');
var jsonrpc = require('./jsonrpc');
/**
* Provider manager object prototype
@ -35,74 +37,72 @@ var web3 = require('./web3'); // jshint ignore:line
* and provider manager polling mechanism is not used
*/
var ProviderManager = function() {
this.queued = [];
this.polls = [];
this.ready = false;
this.provider = undefined;
this.id = 1;
var self = this;
var poll = function () {
if (self.provider && self.provider.poll) {
self.polls.forEach(function (data) {
data.data._id = self.id;
self.id++;
self.provider.poll(data.data, data.id);
if (self.provider) {
var pollsBatch = self.polls.map(function (data) {
return data.data;
});
var payload = jsonrpc.toBatchPayload(pollsBatch);
var results = self.provider.send(payload);
self.polls.forEach(function (data, index) {
var result = results[index];
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return;
}
setTimeout(poll, 12000);
};
poll();
};
/// sends outgoing requests, if provider is not available, enqueue the request
ProviderManager.prototype.send = function(data, cb) {
data._id = this.id;
if (cb) {
web3._callbacks[data._id] = cb;
result = result.result;
// dont call the callback if result is not an array, or empty one
if (!(result instanceof Array) || result.length === 0) {
return;
}
data.args = data.args || [];
this.id++;
data.callback(result);
});
if(this.provider !== undefined) {
this.provider.send(data);
} else {
console.warn("provider is not set");
this.queued.push(data);
}
setTimeout(poll, 1000);
};
poll();
};
/// setups provider, which will be used for sending messages
ProviderManager.prototype.set = function(provider) {
if(this.provider !== undefined && this.provider.unload !== undefined) {
this.provider.unload();
/// sends outgoing requests
/// @params data - an object with at least 'method' property
ProviderManager.prototype.send = function(data) {
var payload = jsonrpc.toPayload(data.method, data.params);
if (this.provider === undefined) {
console.error('provider is not set');
return null;
}
this.provider = provider;
this.ready = true;
};
var result = this.provider.send(payload);
/// resends queued messages
ProviderManager.prototype.sendQueued = function() {
for(var i = 0; this.queued.length; i++) {
// Resend
this.send(this.queued[i]);
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return null;
}
return result.result;
};
/// @returns true if the provider i properly set
ProviderManager.prototype.installed = function() {
return this.provider !== undefined;
/// setups provider, which will be used for sending messages
ProviderManager.prototype.set = function(provider) {
this.provider = provider;
};
/// this method is only used, when we do not have native qt bindings and have to do polling on our own
/// should be callled, on start watching for eth/shh changes
ProviderManager.prototype.startPolling = function (data, pollId) {
if (!this.provider || !this.provider.poll) {
return;
}
this.polls.push({data: data, id: pollId});
ProviderManager.prototype.startPolling = function (data, pollId, callback) {
this.polls.push({data: data, id: pollId, callback: callback});
};
/// should be called to stop polling for certain watch changes

57
libjsqrc/ethereumjs/lib/qt.js

@ -1,57 +0,0 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file qt.js
* @authors:
* Jeffrey Wilcke <jeff@ethdev.com>
* Marek Kotewicz <marek@ethdev.com>
* @date 2014
*/
/**
* QtProvider object prototype is implementing 'provider protocol'
* Should be used inside ethereum browser. It's compatible with cpp and go clients.
* It uses navigator.qt object to pass the messages to native bindings
*/
var QtProvider = function() {
this.handlers = [];
var self = this;
navigator.qt.onmessage = function (message) {
self.handlers.forEach(function (handler) {
handler.call(self, JSON.parse(message.data));
});
};
};
/// Prototype object method
/// Should be called when we want to send single api request to native bindings
/// Asynchronous
/// Response will be received by navigator.qt.onmessage method and passed to handlers
/// @param payload is inner message object
QtProvider.prototype.send = function(payload) {
navigator.qt.postMessage(JSON.stringify(payload));
};
/// Prototype object property
/// Should be used to set message handlers for this provider
Object.defineProperty(QtProvider.prototype, "onmessage", {
set: function(handler) {
this.handlers.push(handler);
}
});
module.exports = QtProvider;

33
libjsqrc/ethereumjs/lib/qtsync.js

@ -0,0 +1,33 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file qtsync.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
*/
var QtSyncProvider = function () {
};
QtSyncProvider.prototype.send = function (payload) {
var result = navigator.qt.callMethod(JSON.stringify(payload));
return JSON.parse(result);
};
module.exports = QtSyncProvider;

79
libjsqrc/ethereumjs/lib/types.js

@ -0,0 +1,79 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file types.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var f = require('./formatters');
/// @param expected type prefix (string)
/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false
var prefixedType = function (prefix) {
return function (type) {
return type.indexOf(prefix) === 0;
};
};
/// @param expected type name (string)
/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false
var namedType = function (name) {
return function (type) {
return name === type;
};
};
/// Setups input formatters for solidity types
/// @returns an array of input formatters
var inputTypes = function () {
return [
{ type: prefixedType('uint'), format: f.formatInputInt },
{ type: prefixedType('int'), format: f.formatInputInt },
{ type: prefixedType('hash'), format: f.formatInputInt },
{ type: prefixedType('string'), format: f.formatInputString },
{ type: prefixedType('real'), format: f.formatInputReal },
{ type: prefixedType('ureal'), format: f.formatInputReal },
{ type: namedType('address'), format: f.formatInputInt },
{ type: namedType('bool'), format: f.formatInputBool }
];
};
/// Setups output formaters for solidity types
/// @returns an array of output formatters
var outputTypes = function () {
return [
{ type: prefixedType('uint'), format: f.formatOutputUInt },
{ type: prefixedType('int'), format: f.formatOutputInt },
{ type: prefixedType('hash'), format: f.formatOutputHash },
{ type: prefixedType('string'), format: f.formatOutputString },
{ type: prefixedType('real'), format: f.formatOutputReal },
{ type: prefixedType('ureal'), format: f.formatOutputUReal },
{ type: namedType('address'), format: f.formatOutputAddress },
{ type: namedType('bool'), format: f.formatOutputBool }
];
};
module.exports = {
prefixedType: prefixedType,
namedType: namedType,
inputTypes: inputTypes,
outputTypes: outputTypes
};

142
libjsqrc/ethereumjs/lib/utils.js

@ -0,0 +1,142 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file utils.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var c = require('./const');
/// Finds first index of array element matching pattern
/// @param array
/// @param callback pattern
/// @returns index of element
var findIndex = function (array, callback) {
var end = false;
var i = 0;
for (; i < array.length && !end; i++) {
end = callback(array[i]);
}
return end ? i - 1 : -1;
};
/// @returns ascii string representation of hex value prefixed with 0x
var toAscii = function(hex) {
// Find termination
var str = "";
var i = 0, l = hex.length;
if (hex.substring(0, 2) === '0x') {
i = 2;
}
for (; i < l; i+=2) {
var code = parseInt(hex.substr(i, 2), 16);
if (code === 0) {
break;
}
str += String.fromCharCode(code);
}
return str;
};
var toHex = function(str) {
var hex = "";
for(var i = 0; i < str.length; i++) {
var n = str.charCodeAt(i).toString(16);
hex += n.length < 2 ? '0' + n : n;
}
return hex;
};
/// @returns hex representation (prefixed by 0x) of ascii string
var fromAscii = function(str, pad) {
pad = pad === undefined ? 0 : pad;
var hex = toHex(str);
while (hex.length < pad*2)
hex += "00";
return "0x" + hex;
};
/// @returns display name for function/event eg. multiply(uint256) -> multiply
var extractDisplayName = function (name) {
var length = name.indexOf('(');
return length !== -1 ? name.substr(0, length) : name;
};
/// @returns overloaded part of function/event name
var extractTypeName = function (name) {
/// TODO: make it invulnerable
var length = name.indexOf('(');
return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : "";
};
/// Filters all function from input abi
/// @returns abi array with filtered objects of type 'function'
var filterFunctions = function (json) {
return json.filter(function (current) {
return current.type === 'function';
});
};
/// Filters all events form input abi
/// @returns abi array with filtered objects of type 'event'
var filterEvents = function (json) {
return json.filter(function (current) {
return current.type === 'event';
});
};
/// used to transform value/string to eth string
/// TODO: use BigNumber.js to parse int
/// TODO: add tests for it!
var toEth = function (str) {
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = c.ETH_UNITS;
while (val > 3000 && unit < units.length - 1)
{
val /= 1000;
unit++;
}
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
var replaceFunction = function($0, $1, $2) {
return $1 + ',' + $2;
};
while (true) {
var o = s;
s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
if (o === s)
break;
}
return s + ' ' + units[unit];
};
module.exports = {
findIndex: findIndex,
toAscii: toAscii,
fromAscii: fromAscii,
extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName,
filterFunctions: filterFunctions,
filterEvents: filterEvents,
toEth: toEth
};

242
libjsqrc/ethereumjs/lib/web3.js

@ -23,47 +23,11 @@
* @date 2014
*/
/// Recursively resolves all promises in given object and replaces the resolved values with promises
/// @param any object/array/promise/anything else..
/// @returns (resolves) object with replaced promises with their result
function flattenPromise (obj) {
if (obj instanceof Promise) {
return Promise.resolve(obj);
if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js');
}
if (obj instanceof Array) {
return new Promise(function (resolve) {
var promises = obj.map(function (o) {
return flattenPromise(o);
});
return Promise.all(promises).then(function (res) {
for (var i = 0; i < obj.length; i++) {
obj[i] = res[i];
}
resolve(obj);
});
});
}
if (obj instanceof Object) {
return new Promise(function (resolve) {
var keys = Object.keys(obj);
var promises = keys.map(function (key) {
return flattenPromise(obj[key]);
});
return Promise.all(promises).then(function (res) {
for (var i = 0; i < keys.length; i++) {
obj[keys[i]] = res[i];
}
resolve(obj);
});
});
}
return Promise.resolve(obj);
}
var utils = require('./utils');
/// @returns an array of objects describing web3 api methods
var web3Methods = function () {
@ -98,6 +62,7 @@ var ethMethods = function () {
{ name: 'transaction', call: transactionCall },
{ name: 'uncle', call: uncleCall },
{ name: 'compilers', call: 'eth_compilers' },
{ name: 'flush', call: 'eth_flush' },
{ name: 'lll', call: 'eth_lll' },
{ name: 'solidity', call: 'eth_solidity' },
{ name: 'serpent', call: 'eth_serpent' },
@ -113,7 +78,6 @@ var ethProperties = function () {
{ name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },
{ name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },
{ name: 'gasPrice', getter: 'eth_gasPrice' },
{ name: 'account', getter: 'eth_account' },
{ name: 'accounts', getter: 'eth_accounts' },
{ name: 'peerCount', getter: 'eth_peerCount' },
{ name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },
@ -160,7 +124,7 @@ var shhWatchMethods = function () {
return [
{ name: 'newFilter', call: 'shh_newFilter' },
{ name: 'uninstallFilter', call: 'shh_uninstallFilter' },
{ name: 'getMessage', call: 'shh_getMessages' }
{ name: 'getMessages', call: 'shh_getMessages' }
];
};
@ -169,21 +133,11 @@ var shhWatchMethods = function () {
var setupMethods = function (obj, methods) {
methods.forEach(function (method) {
obj[method.name] = function () {
return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {
var call = typeof method.call === "function" ? method.call(args) : method.call;
return {call: call, args: args};
}).then(function (request) {
return new Promise(function (resolve, reject) {
web3.provider.send(request, function (err, result) {
if (!err) {
resolve(result);
return;
}
reject(err);
});
});
}).catch(function(err) {
console.error(err);
var args = Array.prototype.slice.call(arguments);
var call = typeof method.call === 'function' ? method.call(args) : method.call;
return web3.provider.send({
method: call,
params: args
});
};
});
@ -195,30 +149,16 @@ var setupProperties = function (obj, properties) {
properties.forEach(function (property) {
var proto = {};
proto.get = function () {
return new Promise(function(resolve, reject) {
web3.provider.send({call: property.getter}, function(err, result) {
if (!err) {
resolve(result);
return;
}
reject(err);
});
return web3.provider.send({
method: property.getter
});
};
if (property.setter) {
proto.set = function (val) {
return flattenPromise([val]).then(function (args) {
return new Promise(function (resolve) {
web3.provider.send({call: property.setter, args: args}, function (err, result) {
if (!err) {
resolve(result);
return;
}
reject(err);
});
});
}).catch(function (err) {
console.error(err);
return web3.provider.send({
method: property.setter,
params: [val]
});
};
}
@ -226,97 +166,53 @@ var setupProperties = function (obj, properties) {
});
};
// TODO: import from a dependency, don't duplicate.
var hexToDec = function (hex) {
return parseInt(hex, 16).toString();
};
var decToHex = function (dec) {
return parseInt(dec).toString(16);
};
/// setups web3 object, and it's in-browser executed methods
var web3 = {
_callbacks: {},
_events: {},
providers: {},
toHex: function(str) {
var hex = "";
for(var i = 0; i < str.length; i++) {
var n = str.charCodeAt(i).toString(16);
hex += n.length < 2 ? '0' + n : n;
}
return hex;
},
/// @returns ascii string representation of hex value prefixed with 0x
toAscii: function(hex) {
// Find termination
var str = "";
var i = 0, l = hex.length;
if (hex.substring(0, 2) === '0x')
i = 2;
for(; i < l; i+=2) {
var code = parseInt(hex.substr(i, 2), 16);
if(code === 0) {
break;
}
str += String.fromCharCode(code);
}
return str;
},
toAscii: utils.toAscii,
/// @returns hex representation (prefixed by 0x) of ascii string
fromAscii: function(str, pad) {
pad = pad === undefined ? 0 : pad;
var hex = this.toHex(str);
while(hex.length < pad*2)
hex += "00";
return "0x" + hex;
},
fromAscii: utils.fromAscii,
/// @returns decimal representaton of hex value prefixed by 0x
toDecimal: function (val) {
return hexToDec(val.substring(2));
// remove 0x and place 0, if it's required
val = val.length > 2 ? val.substring(2) : "0";
return (new BigNumber(val, 16).toString(10));
},
/// @returns hex representation (prefixed by 0x) of decimal value
fromDecimal: function (val) {
return "0x" + decToHex(val);
return "0x" + (new BigNumber(val).toString(16));
},
/// used to transform value/string to eth string
toEth: function(str) {
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];
while (val > 3000 && unit < units.length - 1)
{
val /= 1000;
unit++;
}
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
var replaceFunction = function($0, $1, $2) {
return $1 + ',' + $2;
};
while (true) {
var o = s;
s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
if (o === s)
break;
}
return s + ' ' + units[unit];
},
toEth: utils.toEth,
/// eth object prototype
eth: {
watch: function (params) {
return new web3.filter(params, ethWatch);
contractFromAbi: function (abi) {
return function(addr) {
// Default to address of Config. TODO: rremove prior to genesis.
addr = addr || '0xc6d9d2cd449a754c494264e1809c50e34d64562b';
var ret = web3.eth.contract(addr, abi);
ret.address = addr;
return ret;
};
},
/// @param filter may be a string, object or event
/// @param indexed is optional, this is an object with optional event indexed params
/// @param options is optional, this is an object with optional event options ('max'...)
watch: function (filter, indexed, options) {
if (filter._isEvent) {
return filter(indexed, options);
}
return new web3.filter(filter, ethWatch);
}
},
@ -325,44 +221,12 @@ var web3 = {
/// shh object prototype
shh: {
watch: function (params) {
return new web3.filter(params, shhWatch);
}
},
/// used by filter to register callback with given id
on: function(event, id, cb) {
if(web3._events[event] === undefined) {
web3._events[event] = {};
/// @param filter may be a string, object or event
watch: function (filter, indexed) {
return new web3.filter(filter, shhWatch);
}
web3._events[event][id] = cb;
return this;
},
/// used by filter to unregister callback with given id
off: function(event, id) {
if(web3._events[event] !== undefined) {
delete web3._events[event][id];
}
return this;
},
/// used to trigger callback registered by filter
trigger: function(event, id, data) {
var callbacks = web3._events[event];
if (!callbacks || !callbacks[id]) {
return;
}
var cb = callbacks[id];
cb(data);
},
/// @returns true if provider is installed
haveProvider: function() {
return !!web3.provider.provider;
}
};
/// setups all api methods
@ -385,26 +249,8 @@ var shhWatch = {
setupMethods(shhWatch, shhWatchMethods());
web3.setProvider = function(provider) {
provider.onmessage = messageHandler;
web3.provider.set(provider);
web3.provider.sendQueued();
};
/// callled when there is new incoming message
function messageHandler(data) {
if(data._event !== undefined) {
web3.trigger(data._event, data._id, data.data);
return;
}
if(data._id) {
var cb = web3._callbacks[data._id];
if (cb) {
cb.call(this, data.error, data.data);
delete web3._callbacks[data._id];
}
}
}
module.exports = web3;

98
libjsqrc/ethereumjs/lib/websocket.js

@ -1,98 +0,0 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file websocket.js
* @authors:
* Jeffrey Wilcke <jeff@ethdev.com>
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* @date 2014
*/
// TODO: is these line is supposed to be here?
if (process.env.NODE_ENV !== 'build') {
var WebSocket = require('ws'); // jshint ignore:line
}
/**
* WebSocketProvider object prototype is implementing 'provider protocol'
* Should be used when we want to connect to ethereum backend over websockets
* It's compatible with go client
* The constructor allows to specify host uri
*/
var WebSocketProvider = function(host) {
// onmessage handlers
this.handlers = [];
// queue will be filled with messages if send is invoked before the ws is ready
this.queued = [];
this.ready = false;
this.ws = new WebSocket(host);
var self = this;
this.ws.onmessage = function(event) {
for(var i = 0; i < self.handlers.length; i++) {
self.handlers[i].call(self, JSON.parse(event.data), event);
}
};
this.ws.onopen = function() {
self.ready = true;
for (var i = 0; i < self.queued.length; i++) {
// Resend
self.send(self.queued[i]);
}
};
};
/// Prototype object method
/// Should be called when we want to send single api request to server
/// Asynchronous, it's using websockets
/// Response for the call will be received by ws.onmessage
/// @param payload is inner message object
WebSocketProvider.prototype.send = function(payload) {
if (this.ready) {
var data = JSON.stringify(payload);
this.ws.send(data);
} else {
this.queued.push(payload);
}
};
/// Prototype object method
/// Should be called to add handlers
WebSocketProvider.prototype.onMessage = function(handler) {
this.handlers.push(handler);
};
/// Prototype object method
/// Should be called to close websockets connection
WebSocketProvider.prototype.unload = function() {
this.ws.close();
};
/// Prototype object property
/// Should be used to set message handlers for this provider
Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
set: function(provider) { this.onMessage(provider); }
});
if (typeof(module) !== "undefined")
module.exports = WebSocketProvider;

3
libjsqrc/ethereumjs/package.json

@ -1,14 +1,13 @@
{
"name": "ethereum.js",
"namespace": "ethereum",
"version": "0.0.8",
"version": "0.0.13",
"description": "Ethereum Compatible JavaScript API",
"main": "./index.js",
"directories": {
"lib": "./lib"
},
"dependencies": {
"es6-promise": "*",
"ws": "*",
"xmlhttprequest": "*",
"bignumber.js": ">=2.0.0"

410
libjsqrc/ethereumjs/test/abi.parsers.js → libjsqrc/ethereumjs/test/abi.inputParser.js

@ -5,6 +5,7 @@ var clone = function (object) { return JSON.parse(JSON.stringify(object)); };
var description = [{
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
@ -48,7 +49,6 @@ describe('abi', function() {
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input uint128', function() {
@ -321,7 +321,7 @@ describe('abi', function() {
// given
var d = clone(description);
d[0].name = 'helloworld';
d[0].name = 'helloworld(int)';
d[0].inputs = [
{ type: "int" }
];
@ -331,6 +331,7 @@ describe('abi', function() {
// then
assert.equal(parser.helloworld(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.helloworld['int'](1), "0000000000000000000000000000000000000000000000000000000000000001");
});
@ -339,10 +340,12 @@ describe('abi', function() {
// given
var d = [{
name: "test",
type: "function",
inputs: [{ type: "int" }],
outputs: [{ type: "int" }]
},{
name: "test2",
type: "function",
inputs: [{ type: "string" }],
outputs: [{ type: "string" }]
}];
@ -420,408 +423,5 @@ describe('abi', function() {
});
});
describe('outputParser', function() {
it('should parse output string', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'world'
);
});
it('should parse output uint', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output int', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output hash', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash160', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash160' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
// TODO shouldnt' the expected hash be shorter?
});
it('should parse output address', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'address' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output bool', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'bool' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], true);
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000000")[0], false);
});
it('should parse output real', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'real' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000")[0], -1);
});
it('should parse output ureal', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'ureal' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
});
it('should parse multiple output strings', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" },
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[1],
'world'
);
});
it('should use proper method name', function () {
// given
var d = clone(description);
d[0].name = 'helloworld';
d[0].outputs = [
{ type: "int" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.helloworld("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
});
it('should parse multiple methods', function () {
// given
var d = [{
name: "test",
inputs: [{ type: "int" }],
outputs: [{ type: "int" }]
},{
name: "test2",
inputs: [{ type: "string" }],
outputs: [{ type: "string" }]
}];
// when
var parser = abi.outputParser(d);
//then
assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test2("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
"hello"
);
});
it('should parse output array', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int[]' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][0],
5
);
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][1],
6
);
});
});
});

461
libjsqrc/ethereumjs/test/abi.outputParser.js

@ -0,0 +1,461 @@
var assert = require('assert');
var BigNumber = require('bignumber.js');
var abi = require('../lib/abi.js');
var clone = function (object) { return JSON.parse(JSON.stringify(object)); };
var description = [{
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
describe('abi', function() {
describe('outputParser', function() {
it('should parse output string', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'world'
);
});
it('should parse output uint', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output int', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output hash', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash160', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash160' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
// TODO shouldnt' the expected hash be shorter?
});
it('should parse output address', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'address' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output bool', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'bool' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], true);
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000000")[0], false);
});
it('should parse output real', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'real' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000")[0], -1);
});
it('should parse output ureal', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'ureal' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
});
it('should parse multiple output strings', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" },
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[1],
'world'
);
});
it('should use proper method name', function () {
// given
var d = clone(description);
d[0].name = 'helloworld(int)';
d[0].outputs = [
{ type: "int" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.helloworld("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.helloworld['int']("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
});
it('should parse multiple methods', function () {
// given
var d = [{
name: "test",
type: "function",
inputs: [{ type: "int" }],
outputs: [{ type: "int" }]
},{
name: "test2",
type: "function",
inputs: [{ type: "string" }],
outputs: [{ type: "string" }]
}];
// when
var parser = abi.outputParser(d);
//then
assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test2("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
"hello"
);
});
it('should parse output array', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int[]' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][0],
5
);
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][1],
6
);
});
it('should parse 0x value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x")[0], 0);
});
it('should parse 0x value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x")[0], 0);
});
});
});

4
libjsqrc/ethereumjs/test/db.methods.js

@ -1,9 +1,7 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
var u = require('./test.utils.js');
describe('web3', function() {
describe('db', function() {

201
libjsqrc/ethereumjs/test/eth.contract.js

@ -0,0 +1,201 @@
var assert = require('assert');
var contract = require('../lib/contract.js');
describe('contract', function() {
it('should create simple contract with one method from abi with explicit type name', function () {
// given
var description = [{
"name": "test(uint256)",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
// when
var con = contract(null, description);
// then
assert.equal('function', typeof con.test);
assert.equal('function', typeof con.test['uint256']);
});
it('should create simple contract with one method from abi with implicit type name', function () {
// given
var description = [{
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
// when
var con = contract(null, description);
// then
assert.equal('function', typeof con.test);
assert.equal('function', typeof con.test['uint256']);
});
it('should create contract with multiple methods', function () {
// given
var description = [{
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
],
}, {
"name": "test2",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
// when
var con = contract(null, description);
// then
assert.equal('function', typeof con.test);
assert.equal('function', typeof con.test['uint256']);
assert.equal('function', typeof con.test2);
assert.equal('function', typeof con.test2['uint256']);
});
it('should create contract with overloaded methods', function () {
// given
var description = [{
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
],
}, {
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "string"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
// when
var con = contract(null, description);
// then
assert.equal('function', typeof con.test);
assert.equal('function', typeof con.test['uint256']);
assert.equal('function', typeof con.test['string']);
});
it('should create contract with no methods', function () {
// given
var description = [{
"name": "test(uint256)",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
// when
var con = contract(null, description);
// then
assert.equal('undefined', typeof con.test);
});
it('should create contract with one event', function () {
// given
var description = [{
"name": "test",
"type": "event",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
// when
var con = contract(null, description);
// then
assert.equal('function', typeof con.test);
assert.equal('function', typeof con.test['uint256']);
});
});

6
libjsqrc/ethereumjs/test/eth.methods.js

@ -1,9 +1,6 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
var u = require('./test.utils.js');
describe('web3', function() {
describe('eth', function() {
@ -27,7 +24,6 @@ describe('web3', function() {
u.propertyExists(web3.eth, 'listening');
u.propertyExists(web3.eth, 'mining');
u.propertyExists(web3.eth, 'gasPrice');
u.propertyExists(web3.eth, 'account');
u.propertyExists(web3.eth, 'accounts');
u.propertyExists(web3.eth, 'peerCount');
u.propertyExists(web3.eth, 'defaultBlock');

125
libjsqrc/ethereumjs/test/event.inputParser.js

@ -0,0 +1,125 @@
var assert = require('assert');
var event = require('../lib/event.js');
var f = require('../lib/formatters.js');
describe('event', function () {
describe('inputParser', function () {
it('should create basic filter input object', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl();
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 1);
assert.equal(result.topic[0], signature);
});
it('should create filter input object with options', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl({}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 1);
assert.equal(result.topic[0], signature);
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
it('should create filter input object with indexed params', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl({a: 4}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 2);
assert.equal(result.topic[0], signature);
assert.equal(result.topic[1], f.formatInputInt(4));
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
it('should create filter input object with an array of indexed params', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl({a: [4, 69]}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 2);
assert.equal(result.topic[0], signature);
assert.equal(result.topic[1][0], f.formatInputInt(4));
assert.equal(result.topic[1][1], f.formatInputInt(69));
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
});
});

81
libjsqrc/ethereumjs/test/event.outputParser.js

@ -0,0 +1,81 @@
var assert = require('assert');
var event = require('../lib/event.js');
describe('event', function () {
describe('outputParser', function () {
it('should parse basic event output object', function () {
// given
var output = {
"address":"0x78dfc5983baecf65f73e3de3a96cee24e6b7981e",
"data":"0x000000000000000000000000000000000000000000000000000000000000004b",
"number":2,
"topic":[
"0x6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad",
"0x0000000000000000000000000000000000000000000000000000000000000001"
]
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"bool","indexed":true},{"name":"b","type":"uint256","indexed":false}]
};
// when
var impl = event.outputParser(e);
var result = impl(output);
// then
assert.equal(result.event, 'Event');
assert.equal(result.number, 2);
assert.equal(Object.keys(result.args).length, 2);
assert.equal(result.args.a, true);
assert.equal(result.args.b, 75);
});
it('should parse event output object arguments in correct order', function () {
// given
var output = {
"address":"0x78dfc5983baecf65f73e3de3a96cee24e6b7981e",
"data": "0x" +
"000000000000000000000000000000000000000000000000000000000000004b" +
"000000000000000000000000000000000000000000000000000000000000004c" +
"0000000000000000000000000000000000000000000000000000000000000001",
"number":3,
"topic":[
"0x6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad",
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000005"
]
};
var e = {
name: 'Event2',
inputs: [
{"name":"a","type":"bool","indexed":true},
{"name":"b","type":"int","indexed":false},
{"name":"c","type":"int","indexed":false},
{"name":"d","type":"int","indexed":true},
{"name":"e","type":"bool","indexed":false}
]
};
// when
var impl = event.outputParser(e);
var result = impl(output);
// then
assert.equal(result.event, 'Event2');
assert.equal(result.number, 3);
assert.equal(Object.keys(result.args).length, 5);
assert.equal(result.args.a, true);
assert.equal(result.args.b, 75);
assert.equal(result.args.c, 76);
assert.equal(result.args.d, 5);
assert.equal(result.args.e, true);
});
});
});

128
libjsqrc/ethereumjs/test/jsonrpc.isValidResponse.js

@ -0,0 +1,128 @@
var assert = require('assert');
var jsonrpc = require('../lib/jsonrpc');
describe('jsonrpc', function () {
describe('isValidResponse', function () {
it('should validate basic jsonrpc response', function () {
// given
var response = {
jsonrpc: '2.0',
id: 1,
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, true);
});
it('should validate basic undefined response', function () {
// given
var response = undefined;
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response without jsonrpc field', function () {
// given
var response = {
id: 1,
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response with wrong jsonrpc version', function () {
// given
var response = {
jsonrpc: '1.0',
id: 1,
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response without id number', function () {
// given
var response = {
jsonrpc: '2.0',
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response with wrong id field', function () {
// given
var response = {
jsonrpc: '2.0',
id: 'x',
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response without result field', function () {
// given
var response = {
jsonrpc: '2.0',
id: 1
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response with result field === false', function () {
// given
var response = {
jsonrpc: '2.0',
id: 1,
result: false
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, true);
});
});
});

47
libjsqrc/ethereumjs/test/jsonrpc.toBatchPayload.js

@ -0,0 +1,47 @@
var assert = require('assert');
var jsonrpc = require('../lib/jsonrpc');
describe('jsonrpc', function () {
describe('toBatchPayload', function () {
it('should create basic batch payload', function () {
// given
var messages = [{
method: 'helloworld'
}, {
method: 'test2',
params: [1]
}];
// when
var payload = jsonrpc.toBatchPayload(messages);
// then
assert.equal(payload instanceof Array, true);
assert.equal(payload.length, 2);
assert.equal(payload[0].jsonrpc, '2.0');
assert.equal(payload[1].jsonrpc, '2.0');
assert.equal(payload[0].method, 'helloworld');
assert.equal(payload[1].method, 'test2');
assert.equal(payload[0].params instanceof Array, true);
assert.equal(payload[1].params.length, 1);
assert.equal(payload[1].params[0], 1);
assert.equal(typeof payload[0].id, 'number');
assert.equal(typeof payload[1].id, 'number');
assert.equal(payload[0].id + 1, payload[1].id);
});
it('should create batch payload for empty input array', function () {
// given
var messages = [];
// when
var payload = jsonrpc.toBatchPayload(messages);
// then
assert.equal(payload instanceof Array, true);
assert.equal(payload.length, 0);
});
});
});

40
libjsqrc/ethereumjs/test/jsonrpc.toPayload.js

@ -0,0 +1,40 @@
var assert = require('assert');
var jsonrpc = require('../lib/jsonrpc');
describe('jsonrpc', function () {
describe('toPayload', function () {
it('should create basic payload', function () {
// given
var method = 'helloworld';
// when
var payload = jsonrpc.toPayload(method);
// then
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, method);
assert.equal(payload.params instanceof Array, true);
assert.equal(payload.params.length, 0);
assert.equal(typeof payload.id, 'number');
});
it('should create payload with params', function () {
// given
var method = 'helloworld1';
var params = [123, 'test'];
// when
var payload = jsonrpc.toPayload(method, params);
// then
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, method);
assert.equal(payload.params.length, 2);
assert.equal(payload.params[0], params[0]);
assert.equal(payload.params[1], params[1]);
assert.equal(typeof payload.id, 'number');
});
});
});

5
libjsqrc/ethereumjs/test/shh.methods.js

@ -1,9 +1,6 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
var u = require('./test.utils.js');
describe('web3', function() {
describe('shh', function() {

2
libjsqrc/ethereumjs/test/utils.js → libjsqrc/ethereumjs/test/test.utils.js

@ -8,7 +8,7 @@ var methodExists = function (object, method) {
var propertyExists = function (object, property) {
it('should have property ' + property + ' implemented', function() {
assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented');
assert.notEqual('undefined', typeof object[property], 'property ' + property + ' is not implemented');
});
};

42
libjsqrc/ethereumjs/test/utils.extractDisplayName.js

@ -0,0 +1,42 @@
var assert = require('assert');
var utils = require('../lib/utils.js');
describe('utils', function () {
describe('extractDisplayName', function () {
it('should extract display name from method with no params', function () {
// given
var test = 'helloworld()';
// when
var displayName = utils.extractDisplayName(test);
// then
assert.equal(displayName, 'helloworld');
});
it('should extract display name from method with one param' , function () {
// given
var test = 'helloworld1(int)';
// when
var displayName = utils.extractDisplayName(test);
// then
assert.equal(displayName, 'helloworld1');
});
it('should extract display name from method with two params' , function () {
// given
var test = 'helloworld2(int,string)';
// when
var displayName = utils.extractDisplayName(test);
// then
assert.equal(displayName, 'helloworld2');
});
});
});

55
libjsqrc/ethereumjs/test/utils.extractTypeName.js

@ -0,0 +1,55 @@
var assert = require('assert');
var utils = require('../lib/utils.js');
describe('utils', function () {
describe('extractTypeName', function () {
it('should extract type name from method with no params', function () {
// given
var test = 'helloworld()';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, '');
});
it('should extract type name from method with one param', function () {
// given
var test = 'helloworld1(int)';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, 'int');
});
it('should extract type name from method with two params', function () {
// given
var test = 'helloworld2(int,string)';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, 'int,string');
});
it('should extract type name from method with spaces between params', function () {
// given
var test = 'helloworld3(int, string)';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, 'int,string');
});
});
});

49
libjsqrc/ethereumjs/test/utils.filters.js

@ -0,0 +1,49 @@
var assert = require('assert');
var utils = require('../lib/utils.js');
describe('utils', function() {
it('should filter functions and events from input array properly', function () {
// given
var description = [{
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
],
}, {
"name": "test2",
"type": "event",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
// when
var events = utils.filterEvents(description);
var functions = utils.filterFunctions(description);
// then
assert.equal(events.length, 1);
assert.equal(events[0].name, 'test2');
assert.equal(functions.length, 1);
assert.equal(functions[0].name, 'test');
});
});

8
libjsqrc/ethereumjs/test/web3.methods.js

@ -1,16 +1,10 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
var u = require('./test.utils.js');
describe('web3', function() {
u.methodExists(web3, 'sha3');
u.methodExists(web3, 'toAscii');
u.methodExists(web3, 'fromAscii');
u.methodExists(web3, 'toFixed');
u.methodExists(web3, 'fromFixed');
u.methodExists(web3, 'offset');
});

2
libjsqrc/js.qrc

@ -1,8 +1,8 @@
<RCC>
<qresource prefix="/js">
<file>es6-promise-2.0.0.js</file>
<file>bignumber.min.js</file>
<file>setup.js</file>
<file alias="webthree.js">ethereumjs/dist/ethereum.js</file>
<file>natspec.js</file>
</qresource>
</RCC>

83
libjsqrc/natspec.js

@ -0,0 +1,83 @@
/**
* This plugin exposes 'evaluateExpression' method which should be used
* to evaluate natspec description
* It should be reloaded each time we want to evaluate set of expressions
* Just because of security reasons
* TODO: make use of sync api (once it's finished) and remove unnecessary
* code from 'getContractMethods'
* TODO: unify method signature creation with abi.js (and make a separate method from it)
*/
/// Should be called to copy values from object to global context
var copyToContext = function (obj, context) {
var keys = Object.keys(obj);
keys.forEach(function (key) {
context[key] = obj[key];
});
}
/// Function called to get all contract's storage values
/// @returns hashmap with contract properties which are used
var getContractProperties = function (address, abi) {
return {};
};
/// Function called to get all contract's methods
/// @returns hashmap with used contract's methods
var getContractMethods = function (address, abi) {
return web3.eth.contract(address, abi);
};
/// Function called to get all contract method input variables
/// @returns hashmap with all contract's method input variables
var getContractInputParams = function (abi, methodName, params) {
var method = web3.abi.getMethodWithName(abi, methodName);
return method.inputs.reduce(function (acc, current, index) {
acc[current.name] = params[index];
return acc;
}, {});
};
/// Should be called to evaluate single expression
/// Is internally using javascript's 'eval' method
/// Should be checked if it is safe
var evaluateExpression = function (expression) {
var self = this;
var abi = web3._currentContractAbi;
var address = web3._currentContractAddress;
var methodName = web3._currentContractMethodName;
var params = web3._currentContractMethodParams;
var storage = getContractProperties(address, abi);
var methods = getContractMethods(address, abi);
var inputParams = getContractInputParams(abi, methodName, params);
copyToContext(storage, self);
copyToContext(methods, self);
copyToContext(inputParams, self);
// TODO: test if it is safe
var evaluatedExpression = "";
// match everything in `` quotes
var pattern = /\`(?:\\.|[^`\\])*\`/gim
var match;
var lastIndex = 0;
while ((match = pattern.exec(expression)) !== null) {
var startIndex = pattern.lastIndex - match[0].length;
var toEval = match[0].slice(1, match[0].length - 1);
evaluatedExpression += expression.slice(lastIndex, startIndex);
evaluatedExpression += eval(toEval).toString();
lastIndex = pattern.lastIndex;
}
evaluatedExpression += expression.slice(lastIndex);
return evaluatedExpression;
};

21
libjsqrc/setup.js

@ -22,25 +22,6 @@
navigator.qt = _web3;
(function () {
navigator.qt.handlers = [];
Object.defineProperty(navigator.qt, 'onmessage', {
set: function (handler) {
navigator.qt.handlers.push(handler);
}
});
})();
navigator.qt.response.connect(function (res) {
navigator.qt.handlers.forEach(function (handler) {
handler({data: res});
});
});
if (window.Promise === undefined) {
window.Promise = ES6Promise.Promise;
}
var web3 = require('web3');
web3.setProvider(new web3.providers.QtProvider());
web3.setProvider(new web3.providers.QtSyncProvider());

1
liblll/CodeFragment.cpp

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

1
liblll/CodeFragment.h

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

124
libqwebthree/QWebThree.cpp

@ -36,136 +36,26 @@ QWebThree::~QWebThree()
clientDieing();
}
static QString toJsonRpcBatch(std::vector<unsigned> const& _watches, QString _method)
{
QJsonArray batch;
for (int w: _watches)
{
QJsonObject res;
res["jsonrpc"] = QString::fromStdString("2.0");
res["method"] = _method;
QJsonArray params;
params.append(w);
res["params"] = params;
res["id"] = w;
batch.append(res);
}
return QString::fromUtf8(QJsonDocument(batch).toJson());
}
void QWebThree::poll()
{
if (m_watches.size() > 0)
{
QString batch = toJsonRpcBatch(m_watches, "eth_changed");
emit processData(batch, "eth_changed");
}
if (m_shhWatches.size() > 0)
{
QString batch = toJsonRpcBatch(m_shhWatches, "shh_changed");
emit processData(batch, "shh_changed");
}
}
void QWebThree::clearWatches()
{
if (m_watches.size() > 0)
{
QString batch = toJsonRpcBatch(m_watches, "eth_uninstallFilter");
m_watches.clear();
emit processData(batch, "internal");
}
if (m_shhWatches.size() > 0)
{
QString batch = toJsonRpcBatch(m_shhWatches, "shh_uninstallFilter");
m_shhWatches.clear();
emit processData(batch, "internal");
}
}
void QWebThree::clientDieing()
{
clearWatches();
this->disconnect();
}
static QString formatInput(QJsonObject const& _object)
QString QWebThree::callMethod(QString _json)
{
QJsonObject res;
res["jsonrpc"] = QString::fromStdString("2.0");
res["method"] = _object["call"];
res["params"] = _object["args"];
res["id"] = _object["_id"];
return QString::fromUtf8(QJsonDocument(res).toJson());
emit processData(_json, ""); // it's synchronous
return m_response;
}
void QWebThree::postMessage(QString _json)
void QWebThree::onDataProcessed(QString _json, QString)
{
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
QString method = f["call"].toString();
if (!method.compare("eth_uninstallFilter") && f["args"].isArray() && f["args"].toArray().size())
{
int idToRemove = f["args"].toArray()[0].toInt();
m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end());
}
else if (!method.compare("eth_uninstallFilter") && f["args"].isArray() && f["args"].toArray().size())
{
int idToRemove = f["args"].toArray()[0].toInt();
m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end());
syncResponse(QString::fromUtf8(QJsonDocument(f).toJson()));
}
emit processData(formatInput(f), method);
}
static QString formatOutput(QJsonObject const& _object)
{
QJsonObject res;
res["_id"] = _object["id"];
res["data"] = _object["result"];
res["error"] = _object["error"];
return QString::fromUtf8(QJsonDocument(res).toJson());
}
void QWebThree::onDataProcessed(QString _json, QString _addInfo)
{
if (!_addInfo.compare("internal"))
return;
if (!_addInfo.compare("shh_changed") || !_addInfo.compare("eth_changed"))
{
QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array();
for (int i = 0; i < resultsArray.size(); i++)
void QWebThree::syncResponse(QString _json)
{
QJsonObject elem = resultsArray[i].toObject();
if (elem["result"].isArray() && elem["result"].toArray().size() > 0)
{
QJsonObject res;
res["_event"] = _addInfo;
if (!_addInfo.compare("shh_changed"))
res["_id"] = (int)m_shhWatches[i]; // we can do that couse poll is synchronous
else
res["_id"] = (int)m_watches[i];
res["data"] = elem["result"].toArray();
response(QString::fromUtf8(QJsonDocument(res).toJson()));
}
}
}
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if ((!_addInfo.compare("eth_newFilter") || !_addInfo.compare("eth_newFilterString")) && f.contains("result"))
m_watches.push_back(f["result"].toInt());
else if (!_addInfo.compare("shh_newFilter") && f.contains("result"))
m_shhWatches.push_back(f["result"].toInt());
else if (!_addInfo.compare("shh_newIdentity") && f.contains("result"))
emit onNewId(f["result"].toString());
response(formatOutput(f));
m_response = _json;
}
QWebThreeConnector::QWebThreeConnector()

10
libqwebthree/QWebThree.h

@ -34,12 +34,10 @@ class QWebThree: public QObject
public:
QWebThree(QObject* _p);
virtual ~QWebThree();
void poll();
void clearWatches();
void clientDieing();
Q_INVOKABLE void postMessage(QString _json);
Q_INVOKABLE QString callMethod(QString _json);
void syncResponse(QString _json);
public slots:
void onDataProcessed(QString _json, QString _addInfo);
@ -50,8 +48,7 @@ signals:
void onNewId(QString _id);
private:
std::vector<unsigned> m_watches;
std::vector<unsigned> m_shhWatches;
QString m_response;
};
class QWebThreeConnector: public QObject, public jsonrpc::AbstractServerConnector
@ -84,7 +81,6 @@ private:
_frame->disconnect(); \
_frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/bignumber.min.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/webthree.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \

264
libsolidity/AST.cpp

@ -41,10 +41,15 @@ TypeError ASTNode::createTypeError(string const& _description) const
return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
}
TypePointer ContractDefinition::getType(ContractDefinition const* _currentContract) const
{
return make_shared<TypeType>(make_shared<ContractType>(*this), _currentContract);
}
void ContractDefinition::checkTypeRequirements()
{
for (ASTPointer<InheritanceSpecifier> const& base: getBaseContracts())
base->checkTypeRequirements();
for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: getBaseContracts())
baseSpecifier->checkTypeRequirements();
checkIllegalOverrides();
@ -53,26 +58,38 @@ void ContractDefinition::checkTypeRequirements()
BOOST_THROW_EXCEPTION(constructor->getReturnParameterList()->createTypeError(
"Non-empty \"returns\" directive for constructor."));
FunctionDefinition const* fallbackFunction = getFallbackFunction();
if (fallbackFunction && fallbackFunction->getScope() == this && !fallbackFunction->getParameters().empty())
BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError(
"Fallback function cannot take parameters."));
for (ASTPointer<ModifierDefinition> const& modifier: getFunctionModifiers())
modifier->checkTypeRequirements();
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
function->checkTypeRequirements();
// check for hash collisions in function signatures
set<FixedHash<4>> hashes;
for (auto const& hashAndFunction: getInterfaceFunctionList())
for (auto const& it: getInterfaceFunctionList())
{
FixedHash<4> const& hash = hashAndFunction.first;
FixedHash<4> const& hash = it.first;
if (hashes.count(hash))
BOOST_THROW_EXCEPTION(createTypeError("Function signature hash collision for " +
hashAndFunction.second->getCanonicalSignature()));
BOOST_THROW_EXCEPTION(createTypeError(
std::string("Function signature hash collision for ") +
it.second->getCanonicalSignature()));
hashes.insert(hash);
}
}
map<FixedHash<4>, FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::getInterfaceFunctions() const
{
vector<pair<FixedHash<4>, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList();
map<FixedHash<4>, FunctionDefinition const*> exportedFunctions(exportedFunctionList.begin(),
exportedFunctionList.end());
auto exportedFunctionList = getInterfaceFunctionList();
map<FixedHash<4>, FunctionTypePointer> exportedFunctions;
for (auto const& it: exportedFunctionList)
exportedFunctions.insert(it);
solAssert(exportedFunctionList.size() == exportedFunctions.size(),
"Hash collision at Function Definition Hash calculation");
@ -82,45 +99,100 @@ map<FixedHash<4>, FunctionDefinition const*> ContractDefinition::getInterfaceFun
FunctionDefinition const* ContractDefinition::getConstructor() const
{
for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
if (f->getName() == getName())
if (f->isConstructor())
return f.get();
return nullptr;
}
FunctionDefinition const* ContractDefinition::getFallbackFunction() const
{
for (ContractDefinition const* contract: getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions())
if (f->getName().empty())
return f.get();
return nullptr;
}
void ContractDefinition::checkIllegalOverrides() const
{
// TODO unify this at a later point. for this we need to put the constness and the access specifier
// into the types
map<string, FunctionDefinition const*> functions;
map<string, ModifierDefinition const*> modifiers;
// We search from derived to base, so the stored item causes the error.
for (ContractDefinition const* contract: getLinearizedBaseContracts())
{
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
{
if (function->getName() == contract->getName())
continue; // constructors can neither be overriden nor override anything
FunctionDefinition const*& override = functions[function->getName()];
if (function->isConstructor())
continue; // constructors can neither be overridden nor override anything
string const& name = function->getName();
if (modifiers.count(name))
BOOST_THROW_EXCEPTION(modifiers[name]->createTypeError("Override changes function to modifier."));
FunctionDefinition const*& override = functions[name];
if (!override)
override = function.get();
else if (override->isPublic() != function->isPublic() ||
else if (override->getVisibility() != function->getVisibility() ||
override->isDeclaredConst() != function->isDeclaredConst() ||
FunctionType(*override) != FunctionType(*function))
BOOST_THROW_EXCEPTION(override->createTypeError("Override changes extended function signature."));
}
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
{
string const& name = modifier->getName();
if (functions.count(name))
BOOST_THROW_EXCEPTION(functions[name]->createTypeError("Override changes modifier to function."));
ModifierDefinition const*& override = modifiers[name];
if (!override)
override = modifier.get();
else if (ModifierType(*override) != ModifierType(*modifier))
BOOST_THROW_EXCEPTION(override->createTypeError("Override changes modifier signature."));
}
}
}
std::vector<ASTPointer<EventDefinition>> const& ContractDefinition::getInterfaceEvents() const
{
if (!m_interfaceEvents)
{
set<string> eventsSeen;
m_interfaceEvents.reset(new std::vector<ASTPointer<EventDefinition>>());
for (ContractDefinition const* contract: getLinearizedBaseContracts())
for (ASTPointer<EventDefinition> const& e: contract->getEvents())
if (eventsSeen.count(e->getName()) == 0)
{
eventsSeen.insert(e->getName());
m_interfaceEvents->push_back(e);
}
}
return *m_interfaceEvents;
}
vector<pair<FixedHash<4>, FunctionDefinition const*>> const& ContractDefinition::getInterfaceFunctionList() const
vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getInterfaceFunctionList() const
{
if (!m_interfaceFunctionList)
{
set<string> functionsSeen;
m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionDefinition const*>>());
m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>());
for (ContractDefinition const* contract: getLinearizedBaseContracts())
{
for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions())
if (f->isPublic() && f->getName() != contract->getName() &&
functionsSeen.count(f->getName()) == 0)
if (f->isPublic() && !f->isConstructor() && !f->getName().empty() && functionsSeen.count(f->getName()) == 0)
{
functionsSeen.insert(f->getName());
FixedHash<4> hash(dev::sha3(f->getCanonicalSignature()));
m_interfaceFunctionList->push_back(make_pair(hash, f.get()));
m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*f, false)));
}
for (ASTPointer<VariableDeclaration> const& v: contract->getStateVariables())
if (v->isPublic() && functionsSeen.count(v->getName()) == 0)
{
FunctionType ftype(*v);
functionsSeen.insert(v->getName());
FixedHash<4> hash(dev::sha3(ftype.getCanonicalSignature(v->getName())));
m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*v)));
}
}
}
return *m_interfaceFunctionList;
@ -142,6 +214,11 @@ void InheritanceSpecifier::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in constructer call."));
}
TypePointer StructDefinition::getType(ContractDefinition const*) const
{
return make_shared<TypeType>(make_shared<StructType>(*this));
}
void StructDefinition::checkMemberTypes() const
{
for (ASTPointer<VariableDeclaration> const& member: getMembers())
@ -170,18 +247,73 @@ void StructDefinition::checkRecursion() const
}
}
TypePointer FunctionDefinition::getType(ContractDefinition const*) const
{
return make_shared<FunctionType>(*this);
}
void FunctionDefinition::checkTypeRequirements()
{
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
modifier->checkTypeRequirements();
m_body->checkTypeRequirements();
}
string FunctionDefinition::getCanonicalSignature() const
{
return getName() + FunctionType(*this).getCanonicalSignature();
return FunctionType(*this).getCanonicalSignature(getName());
}
Declaration::LValueType VariableDeclaration::getLValueType() const
{
if (dynamic_cast<FunctionDefinition const*>(getScope()) || dynamic_cast<ModifierDefinition const*>(getScope()))
return Declaration::LValueType::LOCAL;
else
return Declaration::LValueType::STORAGE;
}
TypePointer ModifierDefinition::getType(ContractDefinition const*) const
{
return make_shared<ModifierType>(*this);
}
void ModifierDefinition::checkTypeRequirements()
{
m_body->checkTypeRequirements();
}
void ModifierInvocation::checkTypeRequirements()
{
m_modifierName->checkTypeRequirements();
for (ASTPointer<Expression> const& argument: m_arguments)
argument->checkTypeRequirements();
ModifierDefinition const* modifier = dynamic_cast<ModifierDefinition const*>(m_modifierName->getReferencedDeclaration());
solAssert(modifier, "Function modifier not found.");
vector<ASTPointer<VariableDeclaration>> const& parameters = modifier->getParameters();
if (parameters.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation."));
for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType()))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation."));
}
void EventDefinition::checkTypeRequirements()
{
int numIndexed = 0;
for (ASTPointer<VariableDeclaration> const& var: getParameters())
{
if (var->isIndexed())
numIndexed++;
if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
}
if (numIndexed > 3)
BOOST_THROW_EXCEPTION(createTypeError("More than 3 indexed arguments for event."));
}
void Block::checkTypeRequirements()
@ -219,7 +351,8 @@ void Return::checkTypeRequirements()
{
if (!m_expression)
return;
solAssert(m_returnParameters, "Return parameters not assigned.");
if (!m_returnParameters)
BOOST_THROW_EXCEPTION(createTypeError("Return arguments not allowed."));
if (m_returnParameters->getParameters().size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
"than in returns declaration."));
@ -341,8 +474,9 @@ void FunctionCall::checkTypeRequirements()
//@todo for structs, we have to check the number of arguments to be equal to the
// number of non-mapping members
if (m_arguments.size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("More than one argument for "
"explicit type conersion."));
BOOST_THROW_EXCEPTION(createTypeError("More than one argument for explicit type conversion."));
if (!m_names.empty())
BOOST_THROW_EXCEPTION(createTypeError("Type conversion can't allow named arguments."));
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType()))
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
m_type = type.getActualType();
@ -355,9 +489,44 @@ void FunctionCall::checkTypeRequirements()
TypePointers const& parameterTypes = functionType->getParameterTypes();
if (parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
if (m_names.empty())
{
for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
}
else
{
auto const& parameterNames = functionType->getParameterNames();
if (parameterNames.size() != m_names.size())
BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing."));
// check duplicate names
for (size_t i = 0; i < m_names.size(); i++) {
for (size_t j = i + 1; j < m_names.size(); j++) {
if (m_names[i] == m_names[j])
BOOST_THROW_EXCEPTION(createTypeError("Duplicate named argument."));
}
}
for (size_t i = 0; i < m_names.size(); i++) {
bool found = false;
for (size_t j = 0; j < parameterNames.size(); j++) {
if (parameterNames[j] == *m_names[i]) {
// check type convertible
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[j]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
found = true;
break;
}
}
if (!found)
BOOST_THROW_EXCEPTION(createTypeError("Named argument doesn't match function declaration."));
}
}
// @todo actually the return type should be an anonymous struct,
// but we change it to the type of the first return value until we have structs
if (functionType->getReturnParameterTypes().empty())
@ -395,7 +564,7 @@ void MemberAccess::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
"visible in " + type.toString()));
//@todo later, this will not always be STORAGE
m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE;
m_lvalue = type.getCategory() == Type::Category::STRUCT ? Declaration::LValueType::STORAGE : Declaration::LValueType::NONE;
}
void IndexAccess::checkTypeRequirements()
@ -407,52 +576,17 @@ void IndexAccess::checkTypeRequirements()
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
m_index->expectType(*type.getKeyType());
m_type = type.getValueType();
m_lvalue = LValueType::STORAGE;
m_lvalue = Declaration::LValueType::STORAGE;
}
void Identifier::checkTypeRequirements()
{
solAssert(m_referencedDeclaration, "Identifier not resolved.");
VariableDeclaration const* variable = dynamic_cast<VariableDeclaration const*>(m_referencedDeclaration);
if (variable)
{
if (!variable->getType())
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
m_type = variable->getType();
m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE;
return;
}
//@todo can we unify these with TypeName::toType()?
StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(m_referencedDeclaration);
if (structDef)
{
// note that we do not have a struct type here
m_type = make_shared<TypeType>(make_shared<StructType>(*structDef));
return;
}
FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(m_referencedDeclaration);
if (functionDef)
{
// a function reference is not a TypeType, because calling a TypeType converts to the type.
// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
// conversion.
m_type = make_shared<FunctionType>(*functionDef);
return;
}
ContractDefinition const* contractDef = dynamic_cast<ContractDefinition const*>(m_referencedDeclaration);
if (contractDef)
{
m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef), m_currentContract);
return;
}
MagicVariableDeclaration const* magicVariable = dynamic_cast<MagicVariableDeclaration const*>(m_referencedDeclaration);
if (magicVariable)
{
m_type = magicVariable->getType();
return;
}
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type."));
m_lvalue = m_referencedDeclaration->getLValueType();
m_type = m_referencedDeclaration->getType(m_currentContract);
if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined."));
}
void ElementaryTypeNameExpression::checkTypeRequirements()

259
libsolidity/AST.h

@ -132,27 +132,76 @@ private:
class Declaration: public ASTNode
{
public:
Declaration(Location const& _location, ASTPointer<ASTString> const& _name):
ASTNode(_location), m_name(_name), m_scope(nullptr) {}
enum class LValueType { NONE, LOCAL, STORAGE };
enum class Visibility { DEFAULT, PUBLIC, PROTECTED, PRIVATE };
Declaration(Location const& _location, ASTPointer<ASTString> const& _name,
Visibility _visibility = Visibility::DEFAULT):
ASTNode(_location), m_name(_name), m_visibility(_visibility), m_scope(nullptr) {}
/// @returns the declared name.
ASTString const& getName() const { return *m_name; }
Visibility getVisibility() const { return m_visibility == Visibility::DEFAULT ? getDefaultVisibility() : m_visibility; }
bool isPublic() const { return getVisibility() == Visibility::PUBLIC; }
/// @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 const* getScope() const { return m_scope; }
void setScope(Declaration const* _scope) { m_scope = _scope; }
/// @returns the type of expressions referencing this declaration.
/// The current contract has to be given since this context can change the type, especially of
/// contract types.
virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0;
/// @returns the lvalue type of expressions referencing this declaration
virtual LValueType getLValueType() const { return LValueType::NONE; }
protected:
virtual Visibility getDefaultVisibility() const { return Visibility::PUBLIC; }
private:
ASTPointer<ASTString> m_name;
Visibility m_visibility;
Declaration const* m_scope;
};
/**
* Abstract class that is added to each AST node that can store local variables.
*/
class VariableScope
{
public:
void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); }
std::vector<VariableDeclaration const*> const& getLocalVariables() const { return m_localVariables; }
private:
std::vector<VariableDeclaration const*> m_localVariables;
};
/**
* Abstract class that is added to each AST node that can receive documentation.
*/
class Documented
{
public:
explicit Documented(ASTPointer<ASTString> const& _documentation): m_documentation(_documentation) {}
/// @return A shared pointer of an ASTString.
/// Can contain a nullptr in which case indicates absence of documentation
ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
protected:
ASTPointer<ASTString> m_documentation;
};
/// @}
/**
* Definition of a contract. This is the only AST nodes where child nodes are not visited in
* document order. It first visits all struct declarations, then all variable declarations and
* finally all function declarations.
*/
class ContractDefinition: public Declaration
class ContractDefinition: public Declaration, public Documented
{
public:
ContractDefinition(Location const& _location,
@ -161,13 +210,16 @@ public:
std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts,
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions):
Declaration(_location, _name),
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
std::vector<ASTPointer<EventDefinition>> const& _events):
Declaration(_location, _name), Documented(_documentation),
m_baseContracts(_baseContracts),
m_definedStructs(_definedStructs),
m_stateVariables(_stateVariables),
m_definedFunctions(_definedFunctions),
m_documentation(_documentation)
m_functionModifiers(_functionModifiers),
m_events(_events)
{}
virtual void accept(ASTVisitor& _visitor) override;
@ -176,41 +228,46 @@ public:
std::vector<ASTPointer<InheritanceSpecifier>> const& getBaseContracts() const { return m_baseContracts; }
std::vector<ASTPointer<StructDefinition>> const& getDefinedStructs() const { return m_definedStructs; }
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<ModifierDefinition>> const& getFunctionModifiers() const { return m_functionModifiers; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
std::vector<ASTPointer<EventDefinition>> const& getEvents() const { return m_events; }
std::vector<ASTPointer<EventDefinition>> const& getInterfaceEvents() const;
virtual TypePointer getType(ContractDefinition const* m_currentContract) const override;
/// Checks that there are no illegal overrides, that the constructor does not have a "returns"
/// and calls checkTypeRequirements on all its functions.
void checkTypeRequirements();
/// @return A shared pointer of an ASTString.
/// Can contain a nullptr in which case indicates absence of documentation
ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
/// @returns a map of canonical function signatures to FunctionDefinitions
/// as intended for use by the ABI.
std::map<FixedHash<4>, FunctionDefinition const*> getInterfaceFunctions() const;
std::map<FixedHash<4>, FunctionTypePointer> getInterfaceFunctions() const;
/// List of all (direct and indirect) base contracts in order from derived to base, including
/// the contract itself. Available after name resolution
std::vector<ContractDefinition const*> const& getLinearizedBaseContracts() const { return m_linearizedBaseContracts; }
void setLinearizedBaseContracts(std::vector<ContractDefinition const*> const& _bases) { m_linearizedBaseContracts = _bases; }
/// Returns the constructor or nullptr if no constructor was specified
/// Returns the constructor or nullptr if no constructor was specified.
FunctionDefinition const* getConstructor() const;
/// Returns the fallback function or nullptr if no constructor was specified.
FunctionDefinition const* getFallbackFunction() const;
private:
void checkIllegalOverrides() const;
std::vector<std::pair<FixedHash<4>, FunctionDefinition const*>> const& getInterfaceFunctionList() const;
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& getInterfaceFunctionList() const;
std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
ASTPointer<ASTString> m_documentation;
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
std::vector<ASTPointer<EventDefinition>> m_events;
std::vector<ContractDefinition const*> m_linearizedBaseContracts;
mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionDefinition const*>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents;
};
class InheritanceSpecifier: public ASTNode
@ -245,6 +302,8 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& getMembers() const { return m_members; }
virtual TypePointer getType(ContractDefinition const*) const override;
/// Checks that the members do not include any recursive structs and have valid types
/// (e.g. no functions).
void checkValidityOfMembers() const;
@ -276,40 +335,39 @@ private:
std::vector<ASTPointer<VariableDeclaration>> m_parameters;
};
class FunctionDefinition: public Declaration
class FunctionDefinition: public Declaration, public VariableScope, public Documented
{
public:
FunctionDefinition(Location const& _location, ASTPointer<ASTString> const& _name,
bool _isPublic,
Declaration::Visibility _visibility, bool _isConstructor,
ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters,
bool _isDeclaredConst,
std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
ASTPointer<ParameterList> const& _returnParameters,
ASTPointer<Block> const& _body):
Declaration(_location, _name), m_isPublic(_isPublic),
Declaration(_location, _name, _visibility), Documented(_documentation),
m_isConstructor(_isConstructor),
m_parameters(_parameters),
m_isDeclaredConst(_isDeclaredConst),
m_functionModifiers(_modifiers),
m_returnParameters(_returnParameters),
m_body(_body),
m_documentation(_documentation)
m_body(_body)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
bool isPublic() const { return m_isPublic; }
bool isConstructor() const { return m_isConstructor; }
bool isDeclaredConst() const { return m_isDeclaredConst; }
std::vector<ASTPointer<ModifierInvocation>> const& getModifiers() const { return m_functionModifiers; }
std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); }
ParameterList const& getParameterList() const { return *m_parameters; }
std::vector<ASTPointer<VariableDeclaration>> const& getReturnParameters() const { return m_returnParameters->getParameters(); }
ASTPointer<ParameterList> const& getReturnParameterList() const { return m_returnParameters; }
Block const& getBody() const { return *m_body; }
/// @return A shared pointer of an ASTString.
/// Can contain a nullptr in which case indicates absence of documentation
ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); }
std::vector<VariableDeclaration const*> const& getLocalVariables() const { return m_localVariables; }
virtual TypePointer getType(ContractDefinition const*) const override;
/// Checks that all parameters have allowed types and calls checkTypeRequirements on the body.
void checkTypeRequirements();
@ -320,14 +378,12 @@ public:
std::string getCanonicalSignature() const;
private:
bool m_isPublic;
bool m_isConstructor;
ASTPointer<ParameterList> m_parameters;
bool m_isDeclaredConst;
std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
ASTPointer<ParameterList> m_returnParameters;
ASTPointer<Block> m_body;
ASTPointer<ASTString> m_documentation;
std::vector<VariableDeclaration const*> m_localVariables;
};
/**
@ -338,8 +394,10 @@ class VariableDeclaration: public Declaration
{
public:
VariableDeclaration(Location const& _location, ASTPointer<TypeName> const& _type,
ASTPointer<ASTString> const& _name):
Declaration(_location, _name), m_typeName(_type) {}
ASTPointer<ASTString> const& _name, Visibility _visibility,
bool _isStateVar = false, bool _isIndexed = false):
Declaration(_location, _name, _visibility), m_typeName(_type),
m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
@ -347,17 +405,107 @@ public:
/// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
/// declared and there is no assignment to the variable that fixes the type.
std::shared_ptr<Type const> const& getType() const { return m_type; }
TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; }
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
virtual LValueType getLValueType() const override;
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; }
protected:
Visibility getDefaultVisibility() const override { return Visibility::PROTECTED; }
private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
bool m_isStateVariable; ///< Whether or not this is a contract state variable
bool m_isIndexed; ///< Whether this is an indexed variable (used by events).
std::shared_ptr<Type const> m_type; ///< derived type, initially empty
};
/**
* Definition of a function modifier.
*/
class ModifierDefinition: public Declaration, public VariableScope, public Documented
{
public:
ModifierDefinition(Location const& _location,
ASTPointer<ASTString> const& _name,
ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters,
ASTPointer<Block> const& _body):
Declaration(_location, _name), Documented(_documentation),
m_parameters(_parameters), m_body(_body) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); }
ParameterList const& getParameterList() const { return *m_parameters; }
Block const& getBody() const { return *m_body; }
virtual TypePointer getType(ContractDefinition const* = nullptr) const override;
void checkTypeRequirements();
private:
ASTPointer<ParameterList> m_parameters;
ASTPointer<Block> m_body;
};
/**
* Invocation/usage of a modifier in a function header.
*/
class ModifierInvocation: public ASTNode
{
public:
ModifierInvocation(Location const& _location, ASTPointer<Identifier> const& _name,
std::vector<ASTPointer<Expression>> _arguments):
ASTNode(_location), m_modifierName(_name), m_arguments(_arguments) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
ASTPointer<Identifier> const& getName() const { return m_modifierName; }
std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; }
void checkTypeRequirements();
private:
ASTPointer<Identifier> m_modifierName;
std::vector<ASTPointer<Expression>> m_arguments;
};
/**
* Definition of a (loggable) event.
*/
class EventDefinition: public Declaration, public VariableScope, public Documented
{
public:
EventDefinition(Location const& _location,
ASTPointer<ASTString> const& _name,
ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters):
Declaration(_location, _name), Documented(_documentation), m_parameters(_parameters) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); }
ParameterList const& getParameterList() const { return *m_parameters; }
virtual TypePointer getType(ContractDefinition const* = nullptr) const override
{
return std::make_shared<FunctionType>(*this);
}
void checkTypeRequirements();
private:
ASTPointer<ParameterList> m_parameters;
};
/**
* Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global
* functions when such an identifier is encountered. Will never have a valid location in the source code.
@ -372,7 +520,7 @@ public:
virtual void accept(ASTConstVisitor&) const override { BOOST_THROW_EXCEPTION(InternalCompilerError()
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
std::shared_ptr<Type const> const& getType() const { return m_type; }
virtual TypePointer getType(ContractDefinition const* = nullptr) const override { return m_type; }
private:
std::shared_ptr<Type const> m_type;
@ -499,6 +647,21 @@ private:
std::vector<ASTPointer<Statement>> m_statements;
};
/**
* Special placeholder statement denoted by "_" used in function modifiers. This is replaced by
* the original function when the modifier is applied.
*/
class PlaceholderStatement: public Statement
{
public:
PlaceholderStatement(Location const& _location): Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override { }
};
/**
* If-statement with an optional "else" part. Note that "else if" is modeled by having a new
* if-statement as the false (else) body.
@ -615,12 +778,8 @@ public:
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
void setFunctionReturnParameters(ParameterList const& _parameters) { m_returnParameters = &_parameters; }
ParameterList const& getFunctionReturnParameters() const
{
solAssert(m_returnParameters, "");
return *m_returnParameters;
}
void setFunctionReturnParameters(ParameterList const* _parameters) { m_returnParameters = _parameters; }
ParameterList const* getFunctionReturnParameters() const { return m_returnParameters; }
Expression const* getExpression() const { return m_expression.get(); }
private:
@ -683,16 +842,13 @@ private:
*/
class Expression: public ASTNode
{
protected:
enum class LValueType { NONE, LOCAL, STORAGE };
public:
Expression(Location const& _location): ASTNode(_location), m_lvalue(LValueType::NONE), m_lvalueRequested(false) {}
Expression(Location const& _location): ASTNode(_location) {}
virtual void checkTypeRequirements() = 0;
std::shared_ptr<Type const> const& getType() const { return m_type; }
bool isLValue() const { return m_lvalue != LValueType::NONE; }
bool isLocalLValue() const { return m_lvalue == LValueType::LOCAL; }
bool isLValue() const { return m_lvalue != Declaration::LValueType::NONE; }
bool isLocalLValue() const { return m_lvalue == Declaration::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.
@ -709,9 +865,9 @@ protected:
std::shared_ptr<Type const> m_type;
//! 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;
Declaration::LValueType m_lvalue = Declaration::LValueType::NONE;
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
bool m_lvalueRequested;
bool m_lvalueRequested = false;
};
/// Assignment, can also be a compound assignment.
@ -807,14 +963,15 @@ class FunctionCall: public Expression
{
public:
FunctionCall(Location const& _location, ASTPointer<Expression> const& _expression,
std::vector<ASTPointer<Expression>> const& _arguments):
Expression(_location), m_expression(_expression), m_arguments(_arguments) {}
std::vector<ASTPointer<Expression>> const& _arguments, std::vector<ASTPointer<ASTString>> const& _names):
Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
Expression const& getExpression() const { return *m_expression; }
std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
std::vector<ASTPointer<ASTString>> const& getNames() const { return m_names; }
/// Returns true if this is not an actual function call, but an explicit type conversion
/// or constructor call.
@ -823,6 +980,7 @@ public:
private:
ASTPointer<Expression> m_expression;
std::vector<ASTPointer<Expression>> m_arguments;
std::vector<ASTPointer<ASTString>> m_names;
};
/**
@ -976,5 +1134,6 @@ private:
/// @}
}
}

6
libsolidity/ASTForward.h

@ -43,6 +43,9 @@ class StructDefinition;
class ParameterList;
class FunctionDefinition;
class VariableDeclaration;
class ModifierDefinition;
class ModifierInvocation;
class EventDefinition;
class MagicVariableDeclaration;
class TypeName;
class ElementaryTypeName;
@ -50,6 +53,7 @@ class UserDefinedTypeName;
class Mapping;
class Statement;
class Block;
class PlaceholderStatement;
class IfStatement;
class BreakableStatement;
class WhileStatement;
@ -72,6 +76,8 @@ class Identifier;
class ElementaryTypeNameExpression;
class Literal;
class VariableScope;
// Used as pointers to AST nodes, to be replaced by more clever pointers, e.g. pointers which do
// not do reference counting but point to a special memory area that is completely released
// explicitly.

3
libsolidity/ASTJsonConverter.cpp

@ -118,9 +118,10 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
bool ASTJsonConverter::visit(VariableDeclaration const& _node)
{
bool isLocalVariable = (_node.getLValueType() == VariableDeclaration::LValueType::LOCAL);
addJsonNode("VariableDeclaration",
{ make_pair("name", _node.getName()),
make_pair("local", boost::lexical_cast<std::string>(_node.isLocalVariable()))},
make_pair("local", boost::lexical_cast<std::string>(isLocalVariable))},
true);
return true;
}

60
libsolidity/ASTPrinter.cpp

@ -57,6 +57,13 @@ bool ASTPrinter::visit(ContractDefinition const& _node)
return goDeeper();
}
bool ASTPrinter::visit(InheritanceSpecifier const& _node)
{
writeLine("InheritanceSpecifier \"" + _node.getName()->getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(StructDefinition const& _node)
{
writeLine("StructDefinition \"" + _node.getName() + "\"");
@ -87,6 +94,27 @@ bool ASTPrinter::visit(VariableDeclaration const& _node)
return goDeeper();
}
bool ASTPrinter::visit(ModifierDefinition const& _node)
{
writeLine("ModifierDefinition \"" + _node.getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(ModifierInvocation const& _node)
{
writeLine("ModifierInvocation \"" + _node.getName()->getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(EventDefinition const& _node)
{
writeLine("EventDefinition \"" + _node.getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(TypeName const& _node)
{
writeLine("TypeName");
@ -129,6 +157,13 @@ bool ASTPrinter::visit(Block const& _node)
return goDeeper();
}
bool ASTPrinter::visit(PlaceholderStatement const& _node)
{
writeLine("PlaceholderStatement");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(IfStatement const& _node)
{
writeLine("IfStatement");
@ -302,6 +337,11 @@ void ASTPrinter::endVisit(ContractDefinition const&)
m_indentation--;
}
void ASTPrinter::endVisit(InheritanceSpecifier const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(StructDefinition const&)
{
m_indentation--;
@ -322,6 +362,21 @@ void ASTPrinter::endVisit(VariableDeclaration const&)
m_indentation--;
}
void ASTPrinter::endVisit(ModifierDefinition const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(ModifierInvocation const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(EventDefinition const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(TypeName const&)
{
m_indentation--;
@ -352,6 +407,11 @@ void ASTPrinter::endVisit(Block const&)
m_indentation--;
}
void ASTPrinter::endVisit(PlaceholderStatement const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(IfStatement const&)
{
m_indentation--;

10
libsolidity/ASTPrinter.h

@ -44,16 +44,21 @@ public:
bool visit(ImportDirective const& _node) override;
bool visit(ContractDefinition const& _node) override;
bool visit(InheritanceSpecifier const& _node) override;
bool visit(StructDefinition const& _node) override;
bool visit(ParameterList const& _node) override;
bool visit(FunctionDefinition const& _node) override;
bool visit(VariableDeclaration const& _node) override;
bool visit(ModifierDefinition const& _node) override;
bool visit(ModifierInvocation const& _node) override;
bool visit(EventDefinition const& _node) override;
bool visit(TypeName const& _node) override;
bool visit(ElementaryTypeName const& _node) override;
bool visit(UserDefinedTypeName const& _node) override;
bool visit(Mapping const& _node) override;
bool visit(Statement const& _node) override;
bool visit(Block const& _node) override;
bool visit(PlaceholderStatement const& _node) override;
bool visit(IfStatement const& _node) override;
bool visit(BreakableStatement const& _node) override;
bool visit(WhileStatement const& _node) override;
@ -78,16 +83,21 @@ public:
void endVisit(ImportDirective const&) override;
void endVisit(ContractDefinition const&) override;
void endVisit(InheritanceSpecifier const&) override;
void endVisit(StructDefinition const&) override;
void endVisit(ParameterList const&) override;
void endVisit(FunctionDefinition const&) override;
void endVisit(VariableDeclaration const&) override;
void endVisit(ModifierDefinition const&) override;
void endVisit(ModifierInvocation const&) override;
void endVisit(EventDefinition const&) override;
void endVisit(TypeName const&) override;
void endVisit(ElementaryTypeName const&) override;
void endVisit(UserDefinedTypeName const&) override;
void endVisit(Mapping const&) override;
void endVisit(Statement const&) override;
void endVisit(Block const&) override;
void endVisit(PlaceholderStatement const&) override;
void endVisit(IfStatement const&) override;
void endVisit(BreakableStatement const&) override;
void endVisit(WhileStatement const&) override;

20
libsolidity/ASTVisitor.h

@ -45,16 +45,21 @@ public:
virtual bool visit(SourceUnit&) { return true; }
virtual bool visit(ImportDirective&) { return true; }
virtual bool visit(ContractDefinition&) { return true; }
virtual bool visit(InheritanceSpecifier&) { return true; }
virtual bool visit(StructDefinition&) { return true; }
virtual bool visit(ParameterList&) { return true; }
virtual bool visit(FunctionDefinition&) { return true; }
virtual bool visit(VariableDeclaration&) { return true; }
virtual bool visit(ModifierDefinition&) { return true; }
virtual bool visit(ModifierInvocation&) { return true; }
virtual bool visit(EventDefinition&) { return true; }
virtual bool visit(TypeName&) { return true; }
virtual bool visit(ElementaryTypeName&) { return true; }
virtual bool visit(UserDefinedTypeName&) { return true; }
virtual bool visit(Mapping&) { return true; }
virtual bool visit(Statement&) { return true; }
virtual bool visit(Block&) { return true; }
virtual bool visit(PlaceholderStatement&) { return true; }
virtual bool visit(IfStatement&) { return true; }
virtual bool visit(BreakableStatement&) { return true; }
virtual bool visit(WhileStatement&) { return true; }
@ -81,16 +86,21 @@ public:
virtual void endVisit(SourceUnit&) { }
virtual void endVisit(ImportDirective&) { }
virtual void endVisit(ContractDefinition&) { }
virtual void endVisit(InheritanceSpecifier&) { }
virtual void endVisit(StructDefinition&) { }
virtual void endVisit(ParameterList&) { }
virtual void endVisit(FunctionDefinition&) { }
virtual void endVisit(VariableDeclaration&) { }
virtual void endVisit(ModifierDefinition&) { }
virtual void endVisit(ModifierInvocation&) { }
virtual void endVisit(EventDefinition&) { }
virtual void endVisit(TypeName&) { }
virtual void endVisit(ElementaryTypeName&) { }
virtual void endVisit(UserDefinedTypeName&) { }
virtual void endVisit(Mapping&) { }
virtual void endVisit(Statement&) { }
virtual void endVisit(Block&) { }
virtual void endVisit(PlaceholderStatement&) { }
virtual void endVisit(IfStatement&) { }
virtual void endVisit(BreakableStatement&) { }
virtual void endVisit(WhileStatement&) { }
@ -121,16 +131,21 @@ public:
virtual bool visit(SourceUnit const&) { return true; }
virtual bool visit(ImportDirective const&) { return true; }
virtual bool visit(ContractDefinition const&) { return true; }
virtual bool visit(InheritanceSpecifier const&) { return true; }
virtual bool visit(StructDefinition const&) { return true; }
virtual bool visit(ParameterList const&) { return true; }
virtual bool visit(FunctionDefinition const&) { return true; }
virtual bool visit(VariableDeclaration const&) { return true; }
virtual bool visit(ModifierDefinition const&) { return true; }
virtual bool visit(ModifierInvocation const&) { return true; }
virtual bool visit(EventDefinition const&) { return true; }
virtual bool visit(TypeName const&) { return true; }
virtual bool visit(ElementaryTypeName const&) { return true; }
virtual bool visit(UserDefinedTypeName const&) { return true; }
virtual bool visit(Mapping const&) { return true; }
virtual bool visit(Statement const&) { return true; }
virtual bool visit(Block const&) { return true; }
virtual bool visit(PlaceholderStatement const&) { return true; }
virtual bool visit(IfStatement const&) { return true; }
virtual bool visit(BreakableStatement const&) { return true; }
virtual bool visit(WhileStatement const&) { return true; }
@ -157,16 +172,21 @@ public:
virtual void endVisit(SourceUnit const&) { }
virtual void endVisit(ImportDirective const&) { }
virtual void endVisit(ContractDefinition const&) { }
virtual void endVisit(InheritanceSpecifier const&) { }
virtual void endVisit(StructDefinition const&) { }
virtual void endVisit(ParameterList const&) { }
virtual void endVisit(FunctionDefinition const&) { }
virtual void endVisit(VariableDeclaration const&) { }
virtual void endVisit(ModifierDefinition const&) { }
virtual void endVisit(ModifierInvocation const&) { }
virtual void endVisit(EventDefinition const&) { }
virtual void endVisit(TypeName const&) { }
virtual void endVisit(ElementaryTypeName const&) { }
virtual void endVisit(UserDefinedTypeName const&) { }
virtual void endVisit(Mapping const&) { }
virtual void endVisit(Statement const&) { }
virtual void endVisit(Block const&) { }
virtual void endVisit(PlaceholderStatement const&) { }
virtual void endVisit(IfStatement const&) { }
virtual void endVisit(BreakableStatement const&) { }
virtual void endVisit(WhileStatement const&) { }

72
libsolidity/AST_accept.h

@ -64,6 +64,8 @@ void ContractDefinition::accept(ASTVisitor& _visitor)
listAccept(m_baseContracts, _visitor);
listAccept(m_definedStructs, _visitor);
listAccept(m_stateVariables, _visitor);
listAccept(m_events, _visitor);
listAccept(m_functionModifiers, _visitor);
listAccept(m_definedFunctions, _visitor);
}
_visitor.endVisit(*this);
@ -76,6 +78,8 @@ void ContractDefinition::accept(ASTConstVisitor& _visitor) const
listAccept(m_baseContracts, _visitor);
listAccept(m_definedStructs, _visitor);
listAccept(m_stateVariables, _visitor);
listAccept(m_events, _visitor);
listAccept(m_functionModifiers, _visitor);
listAccept(m_definedFunctions, _visitor);
}
_visitor.endVisit(*this);
@ -142,6 +146,7 @@ void FunctionDefinition::accept(ASTVisitor& _visitor)
m_parameters->accept(_visitor);
if (m_returnParameters)
m_returnParameters->accept(_visitor);
listAccept(m_functionModifiers, _visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
@ -154,6 +159,7 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const
m_parameters->accept(_visitor);
if (m_returnParameters)
m_returnParameters->accept(_visitor);
listAccept(m_functionModifiers, _visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
@ -175,6 +181,60 @@ void VariableDeclaration::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
void ModifierDefinition::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
{
m_parameters->accept(_visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
}
void ModifierDefinition::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
{
m_parameters->accept(_visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
}
void ModifierInvocation::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
{
m_modifierName->accept(_visitor);
listAccept(m_arguments, _visitor);
}
_visitor.endVisit(*this);
}
void ModifierInvocation::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
{
m_modifierName->accept(_visitor);
listAccept(m_arguments, _visitor);
}
_visitor.endVisit(*this);
}
void EventDefinition::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
m_parameters->accept(_visitor);
_visitor.endVisit(*this);
}
void EventDefinition::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
m_parameters->accept(_visitor);
_visitor.endVisit(*this);
}
void TypeName::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
@ -245,6 +305,18 @@ void Block::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
void PlaceholderStatement::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void PlaceholderStatement::accept(ASTConstVisitor& _visitor) const
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void IfStatement::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))

4
libsolidity/BaseTypes.h

@ -41,6 +41,8 @@ struct Location
start(_start), end(_end), sourceName(_sourceName) { }
Location(): start(-1), end(-1) { }
bool isEmpty() const { return start == -1 && end == -1; }
int start;
int end;
std::shared_ptr<std::string const> sourceName;
@ -49,6 +51,8 @@ struct Location
/// Stream output for Location (used e.g. in boost exceptions).
inline std::ostream& operator<<(std::ostream& _out, Location const& _location)
{
if (_location.isEmpty())
return _out << "NO_LOCATION_SPECIFIED";
return _out << *_location.sourceName << "[" << _location.start << "," << _location.end << ")";
}

99
libsolidity/CallGraph.cpp

@ -1,99 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Callgraph of functions inside a contract.
*/
#include <libsolidity/AST.h>
#include <libsolidity/CallGraph.h>
using namespace std;
namespace dev
{
namespace solidity
{
void CallGraph::addNode(ASTNode const& _node)
{
_node.accept(*this);
}
set<FunctionDefinition const*> const& CallGraph::getCalls()
{
return m_functionsSeen;
}
void CallGraph::computeCallGraph()
{
while (!m_workQueue.empty())
{
FunctionDefinition const* fun = m_workQueue.front();
fun->accept(*this);
m_workQueue.pop();
}
}
bool CallGraph::visit(Identifier const& _identifier)
{
FunctionDefinition const* fun = dynamic_cast<FunctionDefinition const*>(_identifier.getReferencedDeclaration());
if (fun)
addFunction(*fun);
return true;
}
bool CallGraph::visit(FunctionDefinition const& _function)
{
addFunction(_function);
return true;
}
bool CallGraph::visit(MemberAccess const& _memberAccess)
{
// used for "BaseContract.baseContractFunction"
if (_memberAccess.getExpression().getType()->getCategory() == Type::Category::TYPE)
{
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.getExpression().getType());
if (type.getMembers().getMemberType(_memberAccess.getMemberName()))
{
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*type.getActualType())
.getContractDefinition();
for (ASTPointer<FunctionDefinition> const& function: contract.getDefinedFunctions())
if (function->getName() == _memberAccess.getMemberName())
{
addFunction(*function);
return true;
}
}
}
return true;
}
void CallGraph::addFunction(FunctionDefinition const& _function)
{
if (!m_functionsSeen.count(&_function))
{
m_functionsSeen.insert(&_function);
m_workQueue.push(&_function);
}
}
}
}

58
libsolidity/CallGraph.h

@ -1,58 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Callgraph of functions inside a contract.
*/
#include <set>
#include <queue>
#include <boost/range/iterator_range.hpp>
#include <libsolidity/ASTVisitor.h>
namespace dev
{
namespace solidity
{
/**
* Can be used to compute the graph of calls (or rather references) between functions of the same
* contract. Current functionality is limited to computing all functions that are directly
* or indirectly called by some functions.
*/
class CallGraph: private ASTConstVisitor
{
public:
void addNode(ASTNode const& _node);
void computeCallGraph();
std::set<FunctionDefinition const*> const& getCalls();
private:
virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(Identifier const& _identifier) override;
virtual bool visit(MemberAccess const& _memberAccess) override;
void addFunction(FunctionDefinition const& _function);
std::set<FunctionDefinition const*> m_functionsSeen;
std::queue<FunctionDefinition const*> m_workQueue;
};
}
}

211
libsolidity/Compiler.cpp

@ -28,7 +28,6 @@
#include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/CompilerUtils.h>
#include <libsolidity/CallGraph.h>
using namespace std;
@ -40,17 +39,14 @@ void Compiler::compileContract(ContractDefinition const& _contract,
{
m_context = CompilerContext(); // clear it just in case
initializeContext(_contract, _contracts);
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (function->getName() != contract->getName()) // don't add the constructor here
m_context.addFunction(*function);
appendFunctionSelector(_contract);
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (function->getName() != contract->getName()) // don't add the constructor here
set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
while (!functions.empty())
{
for (Declaration const* function: functions)
function->accept(*this);
functions = m_context.getFunctionsWithoutCode();
}
// Swap the runtime context with the creation-time context
swap(m_context, m_runtimeContext);
@ -62,6 +58,7 @@ void Compiler::initializeContext(ContractDefinition const& _contract,
map<ContractDefinition const*, bytes const*> const& _contracts)
{
m_context.setCompiledContracts(_contracts);
m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts());
registerStateVariables(_contract);
}
@ -69,35 +66,18 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
{
// arguments for base constructors, filled in derived-to-base order
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments;
set<FunctionDefinition const*> neededFunctions;
set<ASTNode const*> nodesUsedInConstructors;
// Determine the arguments that are used for the base constructors and also which functions
// are needed at compile time.
// Determine the arguments that are used for the base constructors.
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->getConstructor())
nodesUsedInConstructors.insert(constructor);
for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
{
ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
base->getName()->getReferencedDeclaration());
solAssert(baseContract, "");
if (baseArguments.count(baseContract) == 0)
{
baseArguments[baseContract] = &base->getArguments();
for (ASTPointer<Expression> const& arg: base->getArguments())
nodesUsedInConstructors.insert(arg.get());
}
}
}
//@TODO add virtual functions
neededFunctions = getFunctionsCalled(nodesUsedInConstructors);
for (FunctionDefinition const* fun: neededFunctions)
m_context.addFunction(*fun);
// Call constructors in base-to-derived order.
// The Constructor for the most derived contract is called later.
@ -119,10 +99,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
m_context << u256(0) << eth::Instruction::RETURN;
// note that we have to explicitly include all used functions because of absolute jump
// labels
for (FunctionDefinition const* fun: neededFunctions)
fun->accept(*this);
// note that we have to include the functions again because of absolute jump labels
set<Declaration const*> functions = m_context.getFunctionsWithoutCode();
while (!functions.empty())
{
for (Declaration const* function: functions)
function->accept(*this);
functions = m_context.getFunctionsWithoutCode();
}
}
void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor,
@ -131,11 +115,7 @@ void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor,
FunctionType constructorType(_constructor);
eth::AssemblyItem returnLabel = m_context.pushNewTag();
for (unsigned i = 0; i < _arguments.size(); ++i)
{
compileExpression(*_arguments[i]);
ExpressionCompiler::appendTypeConversion(m_context, *_arguments[i]->getType(),
*constructorType.getParameterTypes()[i]);
}
compileExpression(*_arguments[i], constructorType.getParameterTypes()[i]);
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor));
m_context << returnLabel;
}
@ -147,71 +127,69 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
unsigned argumentSize = 0;
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters())
argumentSize += CompilerUtils::getPaddedSize(var->getType()->getCalldataEncodedSize());
if (argumentSize > 0)
{
m_context << u256(argumentSize);
m_context.appendProgramSize();
m_context << u256(CompilerUtils::dataStartOffset); // copy it to byte four as expected for ABI calls
m_context << eth::Instruction::CODECOPY;
appendCalldataUnpacker(_constructor, true);
appendCalldataUnpacker(FunctionType(_constructor).getParameterTypes(), true);
}
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor));
m_context << returnTag;
}
set<FunctionDefinition const*> Compiler::getFunctionsCalled(set<ASTNode const*> const& _nodes)
{
// TODO this does not add virtual functions
CallGraph callgraph;
for (ASTNode const* node: _nodes)
callgraph.addNode(*node);
return callgraph.getCalls();
}
void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
{
map<FixedHash<4>, FunctionDefinition const*> interfaceFunctions = _contract.getInterfaceFunctions();
map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.getInterfaceFunctions();
map<FixedHash<4>, const eth::AssemblyItem> callDataUnpackerEntryPoints;
// retrieve the function signature hash from the calldata
m_context << u256(1) << u256(0);
if (!interfaceFunctions.empty())
CompilerUtils(m_context).loadFromMemory(0, 4, false, true);
// stack now is: 1 0 <funhash>
// for (auto it = interfaceFunctions.cbegin(); it != interfaceFunctions.cend(); ++it)
for (auto const& it: interfaceFunctions)
{
callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag()));
m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ;
m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first));
}
if (FunctionDefinition const* fallback = _contract.getFallbackFunction())
{
eth::AssemblyItem returnTag = m_context.pushNewTag();
fallback->accept(*this);
m_context << returnTag;
appendReturnValuePacker(FunctionType(*fallback).getReturnParameterTypes());
}
else
m_context << eth::Instruction::STOP; // function not found
for (auto const& it: interfaceFunctions)
{
FunctionDefinition const& function = *it.second;
FunctionTypePointer const& functionType = it.second;
m_context << callDataUnpackerEntryPoints.at(it.first);
eth::AssemblyItem returnTag = m_context.pushNewTag();
appendCalldataUnpacker(function);
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
appendCalldataUnpacker(functionType->getParameterTypes());
m_context.appendJumpTo(m_context.getFunctionEntryLabel(it.second->getDeclaration()));
m_context << returnTag;
appendReturnValuePacker(function);
appendReturnValuePacker(functionType->getReturnParameterTypes());
}
}
unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, bool _fromMemory)
unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory)
{
// We do not check the calldata size, everything is zero-padded.
unsigned dataOffset = CompilerUtils::dataStartOffset; // the 4 bytes of the function hash signature
//@todo this can be done more efficiently, saving some CALLDATALOAD calls
for (ASTPointer<VariableDeclaration> const& var: _function.getParameters())
for (TypePointer const& type: _typeParameters)
{
unsigned const c_numBytes = var->getType()->getCalldataEncodedSize();
unsigned const c_numBytes = type->getCalldataEncodedSize();
if (c_numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
bool const c_leftAligned = var->getType()->getCategory() == Type::Category::STRING;
<< errinfo_comment("Type " + type->toString() + " not yet supported."));
bool const c_leftAligned = type->getCategory() == Type::Category::STRING;
bool const c_padToWords = true;
dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned,
!_fromMemory, c_padToWords);
@ -219,26 +197,26 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b
return dataOffset;
}
void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
{
//@todo this can be also done more efficiently
unsigned dataOffset = 0;
vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters();
unsigned stackDepth = CompilerUtils(m_context).getSizeOnStack(parameters);
for (unsigned i = 0; i < parameters.size(); ++i)
unsigned stackDepth = 0;
for (TypePointer const& type: _typeParameters)
stackDepth += type->getSizeOnStack();
for (TypePointer const& type: _typeParameters)
{
Type const& paramType = *parameters[i]->getType();
unsigned numBytes = paramType.getCalldataEncodedSize();
unsigned numBytes = type->getCalldataEncodedSize();
if (numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(parameters[i]->getLocation())
<< errinfo_comment("Type " + paramType.toString() + " not yet supported."));
CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
ExpressionCompiler::appendTypeConversion(m_context, paramType, paramType, true);
bool const c_leftAligned = paramType.getCategory() == Type::Category::STRING;
<< errinfo_comment("Type " + type->toString() + " not yet supported."));
CompilerUtils(m_context).copyToStackTop(stackDepth, *type);
ExpressionCompiler::appendTypeConversion(m_context, *type, *type, true);
bool const c_leftAligned = type->getCategory() == Type::Category::STRING;
bool const c_padToWords = true;
dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, c_leftAligned, c_padToWords);
stackDepth -= paramType.getSizeOnStack();
stackDepth -= type->getSizeOnStack();
}
// note that the stack is not cleaned up here
m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN;
@ -251,30 +229,50 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract)
m_context.addStateVariable(*variable);
}
bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
{
solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
m_context.startFunction(_variableDeclaration);
m_breakTags.clear();
m_continueTags.clear();
m_context << m_context.getFunctionEntryLabel(_variableDeclaration);
ExpressionCompiler::appendStateVariableAccessor(m_context, _variableDeclaration);
return false;
}
bool Compiler::visit(FunctionDefinition const& _function)
{
//@todo to simplify this, the calling convention could by changed such that
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
// although note that this reduces the size of the visible stack
m_context.startNewFunction();
m_context.startFunction(_function);
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
m_context << m_context.getFunctionEntryLabel(_function);
m_stackCleanupForReturn = 0;
m_currentFunction = &_function;
m_modifierDepth = 0;
// stack upon entry: [return address] [arg0] [arg1] ... [argn]
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]
unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters());
m_context.adjustStackOffset(parametersSize);
for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters())
m_context.addVariable(*variable);
{
m_context.addVariable(*variable, parametersSize);
parametersSize -= variable->getType()->getSizeOnStack();
}
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
m_context.addAndInitializeVariable(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
m_context.addAndInitializeVariable(*localVariable);
_function.getBody().accept(*this);
appendModifierOrFunctionCode();
m_context << m_returnTag;
@ -401,13 +399,15 @@ bool Compiler::visit(Return const& _return)
//@todo modifications are needed to make this work with functions returning multiple values
if (Expression const* expression = _return.getExpression())
{
compileExpression(*expression);
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType());
solAssert(_return.getFunctionReturnParameters(), "Invalid return parameters pointer.");
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters()->getParameters().front();
compileExpression(*expression, firstVariable.getType());
CompilerUtils(m_context).moveToStackVariable(firstVariable);
}
for (unsigned i = 0; i < m_stackCleanupForReturn; ++i)
m_context << eth::Instruction::POP;
m_context.appendJumpTo(m_returnTag);
m_context.adjustStackOffset(m_stackCleanupForReturn);
return false;
}
@ -415,10 +415,7 @@ bool Compiler::visit(VariableDefinition const& _variableDefinition)
{
if (Expression const* expression = _variableDefinition.getExpression())
{
compileExpression(*expression);
ExpressionCompiler::appendTypeConversion(m_context,
*expression->getType(),
*_variableDefinition.getDeclaration().getType());
compileExpression(*expression, _variableDefinition.getDeclaration().getType());
CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration());
}
return false;
@ -432,9 +429,51 @@ bool Compiler::visit(ExpressionStatement const& _expressionStatement)
return false;
}
void Compiler::compileExpression(Expression const& _expression)
bool Compiler::visit(PlaceholderStatement const&)
{
++m_modifierDepth;
appendModifierOrFunctionCode();
--m_modifierDepth;
return true;
}
void Compiler::appendModifierOrFunctionCode()
{
solAssert(m_currentFunction, "");
if (m_modifierDepth >= m_currentFunction->getModifiers().size())
m_currentFunction->getBody().accept(*this);
else
{
ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth];
ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName());
solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), "");
for (unsigned i = 0; i < modifier.getParameters().size(); ++i)
{
m_context.addVariable(*modifier.getParameters()[i]);
compileExpression(*modifierInvocation->getArguments()[i],
modifier.getParameters()[i]->getType());
}
for (VariableDeclaration const* localVariable: modifier.getLocalVariables())
m_context.addAndInitializeVariable(*localVariable);
unsigned const c_stackSurplus = CompilerUtils::getSizeOnStack(modifier.getParameters()) +
CompilerUtils::getSizeOnStack(modifier.getLocalVariables());
m_stackCleanupForReturn += c_stackSurplus;
modifier.getBody().accept(*this);
for (unsigned i = 0; i < c_stackSurplus; ++i)
m_context << eth::Instruction::POP;
m_stackCleanupForReturn -= c_stackSurplus;
}
}
void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
{
ExpressionCompiler::compileExpression(m_context, _expression, m_optimize);
if (_targetType)
ExpressionCompiler::appendTypeConversion(m_context, *_expression.getType(), *_targetType);
}
}

25
libsolidity/Compiler.h

@ -21,6 +21,7 @@
*/
#include <ostream>
#include <functional>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/CompilerContext.h>
@ -30,7 +31,8 @@ namespace solidity {
class Compiler: private ASTConstVisitor
{
public:
explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_context(), m_returnTag(m_context.newTag()) {}
explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_context(),
m_returnTag(m_context.newTag()) {}
void compileContract(ContractDefinition const& _contract,
std::map<ContractDefinition const*, bytes const*> const& _contracts);
@ -48,16 +50,15 @@ private:
void appendBaseConstructorCall(FunctionDefinition const& _constructor,
std::vector<ASTPointer<Expression>> const& _arguments);
void appendConstructorCall(FunctionDefinition const& _constructor);
/// Recursively searches the call graph and returns all functions referenced inside _nodes.
std::set<FunctionDefinition const*> getFunctionsCalled(std::set<ASTNode const*> const& _nodes);
void appendFunctionSelector(ContractDefinition const& _contract);
/// 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.
unsigned appendCalldataUnpacker(FunctionDefinition const& _function, bool _fromMemory = false);
void appendReturnValuePacker(FunctionDefinition const& _function);
/// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers.
/// From memory if @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
unsigned appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
void appendReturnValuePacker(TypePointers const& _typeParameters);
void registerStateVariables(ContractDefinition const& _contract);
virtual bool visit(VariableDeclaration const& _variableDeclaration) override;
virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(IfStatement const& _ifStatement) override;
virtual bool visit(WhileStatement const& _whileStatement) override;
@ -67,8 +68,13 @@ private:
virtual bool visit(Return const& _return) override;
virtual bool visit(VariableDefinition const& _variableDefinition) override;
virtual bool visit(ExpressionStatement const& _expressionStatement) override;
virtual bool visit(PlaceholderStatement const&) override;
void compileExpression(Expression const& _expression);
/// Appends one layer of function modifier code of the current function, or the function
/// body itself if the last modifier was reached.
void appendModifierOrFunctionCode();
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
bool const m_optimize;
CompilerContext m_context;
@ -76,6 +82,9 @@ private:
std::vector<eth::AssemblyItem> m_breakTags; ///< tag to jump to for a "break" statement
std::vector<eth::AssemblyItem> m_continueTags; ///< tag to jump to for a "continue" statement
eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement
unsigned m_modifierDepth = 0;
FunctionDefinition const* m_currentFunction;
unsigned m_stackCleanupForReturn; ///< this number of stack elements need to be removed before jump to m_returnTag
};
}

89
libsolidity/CompilerContext.cpp

@ -43,10 +43,19 @@ void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
m_stateVariablesSize += _declaration.getType()->getStorageSize();
}
void CompilerContext::addVariable(VariableDeclaration const& _declaration)
void CompilerContext::startFunction(Declaration const& _function)
{
m_localVariables[&_declaration] = m_localVariablesSize;
m_localVariablesSize += _declaration.getType()->getSizeOnStack();
m_functionsWithCode.insert(&_function);
m_localVariables.clear();
m_asm.setDeposit(0);
*this << getFunctionEntryLabel(_function);
}
void CompilerContext::addVariable(VariableDeclaration const& _declaration,
unsigned _offsetToCurrent)
{
solAssert(m_asm.deposit() >= 0 && unsigned(m_asm.deposit()) >= _offsetToCurrent, "");
m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent;
}
void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
@ -56,14 +65,6 @@ void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _decla
int const size = _declaration.getType()->getSizeOnStack();
for (int i = 0; i < size; ++i)
*this << u256(0);
m_asm.adjustDeposit(-size);
}
void CompilerContext::addFunction(FunctionDefinition const& _function)
{
eth::AssemblyItem tag(m_asm.newTag());
m_functionEntryLabels.insert(make_pair(&_function, tag));
m_virtualFunctionEntryLabels.insert(make_pair(_function.getName(), tag));
}
bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
@ -75,38 +76,82 @@ bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _con
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
{
return m_localVariables.count(_declaration) > 0;
return m_localVariables.count(_declaration);
}
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(Declaration const& _declaration)
{
auto res = m_functionEntryLabels.find(&_declaration);
if (res == m_functionEntryLabels.end())
{
auto res = m_functionEntryLabels.find(&_function);
solAssert(res != m_functionEntryLabels.end(), "Function entry label not found.");
eth::AssemblyItem tag(m_asm.newTag());
m_functionEntryLabels.insert(make_pair(&_declaration, tag));
return tag.tag();
}
else
return res->second.tag();
}
eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefinition const& _function) const
eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefinition const& _function)
{
auto res = m_virtualFunctionEntryLabels.find(_function.getName());
solAssert(res != m_virtualFunctionEntryLabels.end(), "Function entry label not found.");
return res->second.tag();
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
for (ContractDefinition const* contract: m_inheritanceHierarchy)
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _function.getName())
return getFunctionEntryLabel(*function);
solAssert(false, "Virtual function " + _function.getName() + " not found.");
return m_asm.newTag(); // not reached
}
eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base)
{
// search for first contract after _base
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_base);
solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
for (++it; it != m_inheritanceHierarchy.end(); ++it)
for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _name)
return getFunctionEntryLabel(*function);
solAssert(false, "Super function " + _name + " not found.");
return m_asm.newTag(); // not reached
}
set<Declaration const*> CompilerContext::getFunctionsWithoutCode()
{
set<Declaration const*> functions;
for (auto const& it: m_functionEntryLabels)
if (m_functionsWithCode.count(it.first) == 0)
functions.insert(it.first);
return move(functions);
}
ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const
{
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
for (ContractDefinition const* contract: m_inheritanceHierarchy)
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
if (modifier->getName() == _name)
return *modifier.get();
BOOST_THROW_EXCEPTION(InternalCompilerError()
<< errinfo_comment("Function modifier " + _name + " not found."));
}
unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const
{
auto res = m_localVariables.find(&_declaration);
solAssert(res != m_localVariables.end(), "Variable not found on stack.");
return m_localVariablesSize - res->second - 1;
return res->second;
}
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
{
return _baseOffset + m_asm.deposit();
return m_asm.deposit() - _baseOffset - 1;
}
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
{
return -baseToCurrentStackOffset(-_offset);
return m_asm.deposit() - _offset - 1;
}
u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save