Browse Source

Merge branch 'develop' into pr/cmake_runtime_output_directory

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
b6dbf27c65
  1. 18
      CMakeLists.txt
  2. 5
      alethzero/Context.h
  3. 7
      alethzero/Main.ui
  4. 208
      alethzero/MainWin.cpp
  5. 17
      alethzero/MainWin.h
  6. 69
      alethzero/OurWebThreeStubServer.cpp
  7. 43
      alethzero/OurWebThreeStubServer.h
  8. 55
      alethzero/Transact.cpp
  9. 5
      alethzero/Transact.h
  10. 261
      alethzero/Transact.ui
  11. 13
      appdmg.json.in
  12. BIN
      bg.png
  13. 5
      cmake/EthDependencies.cmake
  14. 17
      cmake/scripts/appdmg.cmake
  15. 190
      eth/main.cpp
  16. 2
      exp/main.cpp
  17. 4
      libdevcore/Common.cpp
  18. 2
      libdevcore/Common.h
  19. 14
      libdevcore/CommonIO.cpp
  20. 2
      libdevcore/CommonIO.h
  21. 1
      libdevcore/FixedHash.h
  22. 13
      libdevcore/StructuredLogger.cpp
  23. 14
      libdevcore/StructuredLogger.h
  24. 1
      libdevcrypto/SecretStore.cpp
  25. 5
      libdevcrypto/SecretStore.h
  26. 13
      libethash-cl/ethash_cl_miner.cpp
  27. 8
      libethcore/BlockInfo.cpp
  28. 11
      libethcore/Common.h
  29. 2
      libethcore/CommonJS.cpp
  30. 14
      libethcore/CommonJS.h
  31. 39
      libethereum/BlockChain.cpp
  32. 1
      libethereum/ClientBase.h
  33. 4
      libethereum/Interface.h
  34. 14
      libethereum/KeyManager.cpp
  35. 17
      libethereum/KeyManager.h
  36. 1
      libethereum/State.cpp
  37. 2
      libethereum/State.h
  38. 2
      libjsqrc/ethereumjs/bower.json
  39. 448
      libjsqrc/ethereumjs/dist/web3-light.js
  40. 22
      libjsqrc/ethereumjs/dist/web3-light.js.map
  41. 4
      libjsqrc/ethereumjs/dist/web3-light.min.js
  42. 448
      libjsqrc/ethereumjs/dist/web3.js
  43. 22
      libjsqrc/ethereumjs/dist/web3.js.map
  44. 4
      libjsqrc/ethereumjs/dist/web3.min.js
  45. 2
      libjsqrc/ethereumjs/example/event_inc.html
  46. 103
      libjsqrc/ethereumjs/lib/solidity/abi.js
  47. 85
      libjsqrc/ethereumjs/lib/solidity/coder.js
  48. 14
      libjsqrc/ethereumjs/lib/solidity/formatters.js
  49. 191
      libjsqrc/ethereumjs/lib/solidity/param.js
  50. 5
      libjsqrc/ethereumjs/lib/solidity/utils.js
  51. 2
      libjsqrc/ethereumjs/lib/version.json
  52. 17
      libjsqrc/ethereumjs/lib/web3/eth.js
  53. 2
      libjsqrc/ethereumjs/lib/web3/event.js
  54. 2
      libjsqrc/ethereumjs/lib/web3/formatters.js
  55. 23
      libjsqrc/ethereumjs/lib/web3/httpprovider.js
  56. 2
      libjsqrc/ethereumjs/package.js
  57. 2
      libjsqrc/ethereumjs/package.json
  58. 515
      libjsqrc/ethereumjs/test/abi.inputParser.js
  59. 419
      libjsqrc/ethereumjs/test/abi.outputParser.js
  60. 45
      libjsqrc/ethereumjs/test/coder.decodeParam.js
  61. 82
      libjsqrc/ethereumjs/test/coder.encodeParam.js
  62. 1
      libjsqrc/ethereumjs/test/contract.js
  63. 26
      libjsqrc/ethereumjs/test/event.encode.js
  64. 70
      libjsqrc/ethereumjs/test/formatters.inputTransactionFormatter.js
  65. 15
      libjsqrc/ethereumjs/test/web3.eth.filter.js
  66. 38
      libjsqrc/ethereumjs/test/web3.eth.hashRate.js
  67. 10
      libp2p/Host.cpp
  68. 2
      libp2p/Host.h
  69. 78
      libp2p/NodeTable.cpp
  70. 4
      libp2p/NodeTable.h
  71. 46
      libsolidity/Compiler.cpp
  72. 14
      libsolidity/InterfaceHandler.cpp
  73. 5
      libtestutils/FixedWebThreeServer.cpp
  74. 6
      libtestutils/FixedWebThreeServer.h
  75. 51
      libweb3jsonrpc/AccountHolder.cpp
  76. 85
      libweb3jsonrpc/AccountHolder.h
  77. 4
      libweb3jsonrpc/WebThreeStubServer.cpp
  78. 2
      libweb3jsonrpc/WebThreeStubServer.h
  79. 43
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  80. 10
      libweb3jsonrpc/WebThreeStubServerBase.h
  81. 5
      mix/ClientModel.cpp
  82. 3
      mix/ClientModel.h
  83. 18
      mix/ContractCallDataEncoder.cpp
  84. 1
      mix/ContractCallDataEncoder.h
  85. 33
      mix/MixClient.cpp
  86. 4
      mix/MixClient.h
  87. 5
      mix/Web3Server.cpp
  88. 3
      mix/Web3Server.h
  89. 9
      neth/main.cpp
  90. 10
      test/libevm/vm.cpp
  91. 43
      test/libsolidity/SolidityABIJSON.cpp
  92. 10
      test/libsolidity/SolidityCompiler.cpp
  93. 17
      test/libsolidity/SolidityEndToEndTest.cpp
  94. 22
      test/libsolidity/SolidityNameAndTypeResolution.cpp
  95. 28
      test/libweb3jsonrpc/AccountHolder.cpp

18
CMakeLists.txt

@ -155,7 +155,7 @@ set (ETH_HAVE_WEBENGINE 1)
# Backwards compatibility # Backwards compatibility
if (HEADLESS) if (HEADLESS)
message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0") message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0")
set(BUNDLE "minimal") set(GUI OFF)
endif () endif ()
# TODO: Abstract into something sensible and move into a function. # TODO: Abstract into something sensible and move into a function.
@ -397,8 +397,22 @@ if (GUI)
endif() endif()
if (APPLE AND GUI)
add_custom_target(appdmg
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND}
-DAPP_DMG_EXE=${ETH_APP_DMG}
-DAPP_DMG_FILE=appdmg.json.in
-DAPP_DMG_ICON="alethzero/alethzero.icns"
-DAPP_DMG_BACKGROUND="bg.png"
-DETH_BUILD_DIR="${CMAKE_BINARY_DIR}"
-DETH_MIX_APP="$<TARGET_FILE_DIR:mix>"
-DETH_ALETHZERO_APP="$<TARGET_FILE_DIR:AlethZero>"
-P "${ETH_SCRIPTS_DIR}/appdmg.cmake"
)
#unset(TARGET_PLATFORM CACHE) endif ()
if (WIN32) if (WIN32)
# packaging stuff # packaging stuff

5
alethzero/Context.h

@ -29,7 +29,7 @@
class QComboBox; class QComboBox;
namespace dev { namespace eth { struct StateDiff; } } namespace dev { namespace eth { struct StateDiff; class KeyManager; } }
#define Small "font-size: small; " #define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; " #define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "
@ -64,5 +64,8 @@ public:
virtual std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const = 0; virtual std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const = 0;
virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0; virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0;
virtual std::string render(dev::Address const& _a) const = 0; virtual std::string render(dev::Address const& _a) const = 0;
virtual dev::Secret retrieveSecret(dev::Address const& _a) const = 0;
virtual dev::eth::KeyManager& keyManager() = 0;
}; };

7
alethzero/Main.ui

@ -548,12 +548,15 @@
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="dragDropMode"> <property name="showDropIndicator" stdset="0">
<enum>QAbstractItemView::InternalMove</enum> <bool>false</bool>
</property> </property>
<property name="alternatingRowColors"> <property name="alternatingRowColors">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

208
alethzero/MainWin.cpp

@ -31,6 +31,7 @@
#include <QtWidgets/QDialog> #include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog> #include <QtWidgets/QInputDialog>
#include <QtWidgets/QListWidgetItem>
#include <QtWebEngine/QtWebEngine> #include <QtWebEngine/QtWebEngine>
#include <QtWebEngineWidgets/QWebEngineView> #include <QtWebEngineWidgets/QWebEngineView>
#include <QtWebEngineWidgets/QWebEngineCallback> #include <QtWebEngineWidgets/QWebEngineCallback>
@ -143,6 +144,38 @@ Main::Main(QWidget *parent) :
// ui->log->addItem(QString::fromStdString(s)); // ui->log->addItem(QString::fromStdString(s));
}; };
// Open Key Store
bool opened = false;
if (m_keyManager.exists())
while (!opened)
{
QString s = QInputDialog::getText(nullptr, "Master password", "Enter your MASTER account password.", QLineEdit::Password, QString());
if (m_keyManager.load(s.toStdString()))
opened = true;
else if (QMessageBox::question(
nullptr,
"Invalid password entered",
"The password you entered is incorrect. If you have forgotten your password, and you wish to start afresh, manually remove the file: " + QString::fromStdString(getDataDir("ethereum")) + "/keys.info",
QMessageBox::Retry,
QMessageBox::Abort)
== QMessageBox::Abort)
exit(0);
}
if (!opened)
{
QString password;
while (true)
{
password = QInputDialog::getText(nullptr, "Master password", "Enter a MASTER password for your key store. Make it strong. You probably want to write it down somewhere and keep it safe and secure; your identity will rely on this - you never want to lose it.", QLineEdit::Password, QString());
QString confirm = QInputDialog::getText(nullptr, "Master password", "Confirm this password by typing it again", QLineEdit::Password, QString());
if (password == confirm)
break;
QMessageBox::warning(nullptr, "Try again", "You entered two different passwords - please enter the same password twice.", QMessageBox::Ok);
}
m_keyManager.create(password.toStdString());
m_keyManager.import(Secret::random(), "Default identity");
}
#if ETH_DEBUG #if ETH_DEBUG
m_servers.append("127.0.0.1:30300"); m_servers.append("127.0.0.1:30300");
#endif #endif
@ -168,15 +201,13 @@ Main::Main(QWidget *parent) :
ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray(); m_networkConfig = s.value("peers").toByteArray();
bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size());
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth", "shh"}, p2p::NetworkPreferences(), network)); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth", "shh"}, p2p::NetworkPreferences(), network));
m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads));
m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), keysAsVector(m_myKeys), this)); m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), this));
connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString)));
m_server->setIdentities(keysAsVector(owned())); m_server->setIdentities(keysAsVector(owned()));
m_server->StartListening(); m_server->StartListening();
@ -198,6 +229,7 @@ Main::Main(QWidget *parent) :
// ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true);
// QWebEngineInspector* inspector = new QWebEngineInspector(); // QWebEngineInspector* inspector = new QWebEngineInspector();
// inspector->setPage(page); // inspector->setPage(page);
setBeneficiary(*m_keyManager.accounts().begin());
readSettings(); readSettings();
#if !ETH_FATDB #if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts); removeDockWidget(ui->dockWidget_accounts);
@ -358,9 +390,9 @@ void Main::installBalancesWatch()
// TODO: Update for new currencies reg. // TODO: Update for new currencies reg.
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i) for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i)
altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1))); altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1)));
for (auto i: m_myKeys) for (auto const& i: m_keyManager.accounts())
for (auto c: altCoins) for (auto c: altCoins)
tf.address(c).topic(0, h256(i.address(), h256::AlignRight)); tf.address(c).topic(0, h256(i, h256::AlignRight));
uninstallWatch(m_balancesFilter); uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
@ -429,7 +461,7 @@ void Main::load(QString _s)
void Main::on_newTransaction_triggered() void Main::on_newTransaction_triggered()
{ {
m_transact.setEnvironment(m_myKeys, ethereum(), &m_natSpecDB); m_transact.setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB);
m_transact.exec(); m_transact.exec();
} }
@ -616,17 +648,7 @@ void Main::on_paranoia_triggered()
void Main::writeSettings() void Main::writeSettings()
{ {
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
{ s.remove("address");
QByteArray b;
b.resize(sizeof(Secret) * m_myKeys.size());
auto p = b.data();
for (auto i: m_myKeys)
{
memcpy(p, &(i.secret()), sizeof(Secret));
p += sizeof(Secret);
}
s.setValue("address", b);
}
{ {
QByteArray b; QByteArray b;
b.resize(sizeof(Secret) * m_myIdentities.size()); b.resize(sizeof(Secret) * m_myIdentities.size());
@ -666,6 +688,20 @@ void Main::writeSettings()
s.setValue("windowState", saveState()); s.setValue("windowState", saveState());
} }
Secret Main::retrieveSecret(Address const& _a) const
{
auto info = m_keyManager.accountDetails()[_a];
while (true)
{
if (Secret s = m_keyManager.secret(_a, [&](){
return QInputDialog::getText(const_cast<Main*>(this), "Import Account Key", QString("Enter the password for the account %2 (%1). The hint is:\n%3").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first)).arg(QString::fromStdString(info.second)), QLineEdit::Password).toStdString();
}))
return s;
else if (QMessageBox::warning(const_cast<Main*>(this), "Incorrect Password", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel)
return Secret();
}
}
void Main::readSettings(bool _skipGeometry) void Main::readSettings(bool _skipGeometry)
{ {
QSettings s("ethereum", "alethzero"); QSettings s("ethereum", "alethzero");
@ -675,22 +711,17 @@ void Main::readSettings(bool _skipGeometry)
restoreState(s.value("windowState").toByteArray()); restoreState(s.value("windowState").toByteArray());
{ {
m_myKeys.clear();
QByteArray b = s.value("address").toByteArray(); QByteArray b = s.value("address").toByteArray();
if (b.isEmpty()) if (!b.isEmpty())
m_myKeys.append(KeyPair::create());
else
{ {
h256 k; h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{ {
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) if (!m_keyManager.accounts().count(KeyPair(k).address()))
m_myKeys.append(KeyPair(k)); m_keyManager.import(k, "Imported (UNSAFE) key.");
} }
} }
ethereum()->setAddress(m_myKeys.back().address());
m_server->setAccounts(keysAsVector(m_myKeys));
} }
{ {
@ -735,16 +766,38 @@ void Main::readSettings(bool _skipGeometry)
on_urlEdit_returnPressed(); on_urlEdit_returnPressed();
} }
std::string Main::getPassword(std::string const& _title, std::string const& _for)
{
QString password;
while (true)
{
password = QInputDialog::getText(nullptr, QString::fromStdString(_title), QString::fromStdString(_for), QLineEdit::Password, QString());
QString confirm = QInputDialog::getText(nullptr, QString::fromStdString(_title), "Confirm this password by typing it again", QLineEdit::Password, QString());
if (password == confirm)
break;
QMessageBox::warning(nullptr, QString::fromStdString(_title), "You entered two different passwords - please enter the same password twice.", QMessageBox::Ok);
}
return password.toStdString();
}
void Main::on_importKey_triggered() void Main::on_importKey_triggered()
{ {
QString s = QInputDialog::getText(this, "Import Account Key", "Enter account's secret key"); QString s = QInputDialog::getText(this, "Import Account Key", "Enter account's secret key", QLineEdit::Password);
bytes b = fromHex(s.toStdString()); bytes b = fromHex(s.toStdString());
if (b.size() == 32) if (b.size() == 32)
{ {
auto k = KeyPair(h256(b)); auto k = KeyPair(h256(b));
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end()) if (!m_keyManager.accounts().count(k.address()))
{ {
m_myKeys.append(k); QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name");
if (QMessageBox::question(this, "Additional Security?", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
std::string password = getPassword("Import Account Key", "Enter the password you would like to use for this key. Don't forget it!");
std::string hint = QInputDialog::getText(this, "Import Account Key", "Enter a hint to help you remember this password.").toStdString();
m_keyManager.import(k.secret(), s.toStdString(), password, hint);
}
else
m_keyManager.import(k.secret(), s.toStdString());
keysChanged(); keysChanged();
} }
else else
@ -785,15 +838,8 @@ void Main::on_importKeyFile_triggered()
} }
cnote << k.address(); cnote << k.address();
if (std::find(m_myKeys.begin(), m_myKeys.end(), k) == m_myKeys.end()) if (!m_keyManager.accounts().count(k.address()))
{ ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice());
if (m_myKeys.empty())
{
m_myKeys.push_back(KeyPair::create());
keysChanged();
}
ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_myKeys.back().address(), {}, c_txGas, gasPrice());
}
else else
QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account.");
} }
@ -812,10 +858,12 @@ void Main::on_importKeyFile_triggered()
void Main::on_exportKey_triggered() void Main::on_exportKey_triggered()
{ {
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0)
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(k.address()) + " is:\n" + toHex(k.sec().ref()))); Address h((byte const*)hba.data(), Address::ConstructFromPointer);
Secret s = retrieveSecret(h);
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex()));
} }
} }
@ -913,6 +961,24 @@ void Main::refreshMining()
*/ */
} }
void Main::setBeneficiary(Address const& _b)
{
for (int i = 0; i < ui->ourAccounts->count(); ++i)
{
auto hba = ui->ourAccounts->item(i)->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
ui->ourAccounts->item(i)->setCheckState(h == _b ? Qt::Checked : Qt::Unchecked);
}
m_beneficiary = _b;
ethereum()->setAddress(_b);
}
void Main::on_ourAccounts_itemClicked(QListWidgetItem* _i)
{
auto hba = _i->data(Qt::UserRole).toByteArray();
setBeneficiary(Address((byte const*)hba.data(), Address::ConstructFromPointer));
}
void Main::refreshBalances() void Main::refreshBalances()
{ {
cwatch << "refreshBalances()"; cwatch << "refreshBalances()";
@ -931,11 +997,13 @@ void Main::refreshBalances()
// cdebug << n << addr << denom << sha3(h256(n).asBytes()); // cdebug << n << addr << denom << sha3(h256(n).asBytes());
altCoins[addr] = make_tuple(fromRaw(n), 0, denom); altCoins[addr] = make_tuple(fromRaw(n), 0, denom);
}*/ }*/
for (auto i: m_myKeys) for (pair<Address, std::pair<std::string, std::string>> const& i: m_keyManager.accountDetails())
{ {
u256 b = ethereum()->balanceAt(i.address()); u256 b = ethereum()->balanceAt(i.first);
(new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.address()))).arg((unsigned)ethereum()->countAt(i.address())), ui->ourAccounts)) QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.first))).arg((unsigned)ethereum()->countAt(i.first)).arg(QString::fromStdString(i.second.first)), ui->ourAccounts);
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size)); li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size));
li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
li->setCheckState(m_beneficiary == i.first ? Qt::Checked : Qt::Unchecked);
totalBalance += b; totalBalance += b;
// for (auto& c: altCoins) // for (auto& c: altCoins)
@ -1385,23 +1453,6 @@ void Main::on_transactionQueue_currentItemChanged()
ui->pendingInfo->moveCursor(QTextCursor::Start); ui->pendingInfo->moveCursor(QTextCursor::Start);
} }
void Main::ourAccountsRowsMoved()
{
QList<KeyPair> myKeys;
for (int i = 0; i < ui->ourAccounts->count(); ++i)
{
auto hba = ui->ourAccounts->item(i)->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
for (auto i: m_myKeys)
if (i.address() == h)
myKeys.push_back(i);
}
m_myKeys = myKeys;
if (m_server.get())
m_server->setAccounts(keysAsVector(m_myKeys));
}
void Main::on_inject_triggered() void Main::on_inject_triggered()
{ {
QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex"); QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex");
@ -1827,7 +1878,7 @@ void Main::on_mine_triggered()
{ {
if (ui->mine->isChecked()) if (ui->mine->isChecked())
{ {
ethereum()->setAddress(m_myKeys.last().address()); ethereum()->setAddress(m_beneficiary);
ethereum()->startMining(); ethereum()->startMining();
} }
else else
@ -1837,7 +1888,6 @@ void Main::on_mine_triggered()
void Main::keysChanged() void Main::keysChanged()
{ {
onBalancesChange(); onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
} }
bool beginsWith(Address _a, bytes const& _b) bool beginsWith(Address _a, bytes const& _b)
@ -1901,24 +1951,39 @@ void Main::on_newAccount_triggered()
t->join(); t->join();
delete t; delete t;
} }
m_myKeys.append(p);
QString s = QInputDialog::getText(this, "Create Account", "Enter this account's name");
if (QMessageBox::question(this, "Create Account", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!");
std::string hint = QInputDialog::getText(this, "Create Account", "Enter a hint to help you remember this password.").toStdString();
m_keyManager.import(p.secret(), s.toStdString(), password, hint);
}
else
m_keyManager.import(p.secret(), s.toStdString());
keysChanged(); keysChanged();
} }
void Main::on_killAccount_triggered() void Main::on_killAccount_triggered()
{ {
if (ui->ourAccounts->currentRow() >= 0 && ui->ourAccounts->currentRow() < m_myKeys.size()) if (ui->ourAccounts->currentRow() >= 0)
{ {
auto k = m_myKeys[ui->ourAccounts->currentRow()]; auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer);
auto k = m_keyManager.accountDetails()[h];
if ( if (
ethereum()->balanceAt(k.address()) != 0 && ethereum()->balanceAt(h) != 0 &&
QMessageBox::critical(this, "Kill Account?!", QMessageBox::critical(this, QString::fromStdString("Kill Account " + k.first + "?!"),
QString::fromStdString("Account " + render(k.address()) + " has " + 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.\n" QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " 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.\n"
"Are you sure you want to continue?"), "Are you sure you want to continue?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
return; return;
m_myKeys.erase(m_myKeys.begin() + ui->ourAccounts->currentRow()); m_keyManager.kill(h);
if (m_keyManager.accounts().empty())
m_keyManager.import(Secret::random(), "Default account");
keysChanged(); keysChanged();
if (m_beneficiary == h)
setBeneficiary(*m_keyManager.accounts().begin());
} }
} }
@ -1929,7 +1994,8 @@ void Main::on_go_triggered()
ui->net->setChecked(true); ui->net->setChecked(true);
on_net_triggered(); on_net_triggered();
} }
web3()->addNode(p2p::NodeId(), Host::pocHost()); for (auto const& i: Host::pocHosts())
web3()->requirePeer(i.first, i.second);
} }
std::string Main::prettyU256(dev::u256 const& _n) const std::string Main::prettyU256(dev::u256 const& _n) const

17
alethzero/MainWin.h

@ -35,6 +35,7 @@
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
#include <libethereum/KeyManager.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include "Context.h" #include "Context.h"
@ -42,6 +43,8 @@
#include "NatspecHandler.h" #include "NatspecHandler.h"
#include "Connect.h" #include "Connect.h"
class QListWidgetItem;
namespace Ui { namespace Ui {
class Main; class Main;
} }
@ -86,10 +89,14 @@ public:
std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const override; std::pair<dev::Address, dev::bytes> fromString(std::string const& _a) const override;
std::string renderDiff(dev::eth::StateDiff const& _d) const override; std::string renderDiff(dev::eth::StateDiff const& _d) const override;
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; } QList<dev::KeyPair> owned() const { return m_myIdentities; }
dev::u256 gasPrice() const { return 10 * dev::eth::szabo; } dev::u256 gasPrice() const { return 10 * dev::eth::szabo; }
dev::eth::KeyManager& keyManager() override { return m_keyManager; }
dev::Secret retrieveSecret(dev::Address const& _a) const override;
public slots: public slots:
void load(QString _file); void load(QString _file);
void note(QString _entry); void note(QString _entry);
@ -144,7 +151,7 @@ private slots:
void on_exportState_triggered(); void on_exportState_triggered();
// Stuff concerning the blocks/transactions/accounts panels // Stuff concerning the blocks/transactions/accounts panels
void ourAccountsRowsMoved(); void on_ourAccounts_itemClicked(QListWidgetItem* _i);
void on_ourAccounts_doubleClicked(); void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked(); void on_accounts_doubleClicked();
void on_accounts_currentItemChanged(); void on_accounts_currentItemChanged();
@ -236,6 +243,9 @@ private:
void refreshBlockCount(); void refreshBlockCount();
void refreshBalances(); void refreshBalances();
void setBeneficiary(dev::Address const& _b);
std::string getPassword(std::string const& _title, std::string const& _for);
std::unique_ptr<Ui::Main> ui; std::unique_ptr<Ui::Main> ui;
std::unique_ptr<dev::WebThreeDirect> m_webThree; std::unique_ptr<dev::WebThreeDirect> m_webThree;
@ -247,10 +257,11 @@ private:
QByteArray m_networkConfig; QByteArray m_networkConfig;
QStringList m_servers; QStringList m_servers;
QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities; QList<dev::KeyPair> m_myIdentities;
dev::eth::KeyManager m_keyManager;
QString m_privateChain; QString m_privateChain;
dev::Address m_nameReg; dev::Address m_nameReg;
dev::Address m_beneficiary;
QList<QPair<QString, QString>> m_consoleHistory; QList<QPair<QString, QString>> m_consoleHistory;
QMutex m_logLock; QMutex m_logLock;

69
alethzero/OurWebThreeStubServer.cpp

@ -20,23 +20,23 @@
*/ */
#include "OurWebThreeStubServer.h" #include "OurWebThreeStubServer.h"
#include <QMessageBox> #include <QMessageBox>
#include <QAbstractButton> #include <QAbstractButton>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include "MainWin.h" #include "MainWin.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, OurWebThreeStubServer::OurWebThreeStubServer(
vector<KeyPair> const& _accounts, Main* _main): jsonrpc::AbstractServerConnector& _conn,
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main) WebThreeDirect& _web3,
Main* _main
):
WebThreeStubServer(_conn, _web3, make_shared<OurAccountHolder>(_web3, _main), _main->owned().toVector().toStdVector()),
m_main(_main)
{ {
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
} }
string OurWebThreeStubServer::shh_newIdentity() string OurWebThreeStubServer::shh_newIdentity()
@ -46,7 +46,18 @@ string OurWebThreeStubServer::shh_newIdentity()
return toJS(kp.pub()); return toJS(kp.pub());
} }
bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) OurAccountHolder::OurAccountHolder(
WebThreeDirect& _web3,
Main* _main
):
AccountHolder([=](){ return m_web3->ethereum(); }),
m_web3(&_web3),
m_main(_main)
{
connect(_main, SIGNAL(poll()), this, SLOT(doValidations()));
}
bool OurAccountHolder::showAuthenticationPopup(string const& _title, string const& _text)
{ {
if (!m_main->confirm()) if (!m_main->confirm())
{ {
@ -66,18 +77,18 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string
//return button == QMessageBox::Ok; //return button == QMessageBox::Ok;
} }
bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showSendNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") +
", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + ".");
} }
bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) bool OurAccountHolder::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy)
{ {
return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!",
"ÐApp is attempting to call into an unknown contract at address " + "ÐApp is attempting to call into an unknown contract at address " +
@ -93,25 +104,47 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t,
"REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!");
} }
void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) void OurAccountHolder::authenticate(TransactionSkeleton const& _t)
{ {
Guard l(x_queued); Guard l(x_queued);
m_queued.push(make_pair(_t, _toProxy)); m_queued.push(_t);
} }
void OurWebThreeStubServer::doValidations() void OurAccountHolder::doValidations()
{ {
Guard l(x_queued); Guard l(x_queued);
while (!m_queued.empty()) while (!m_queued.empty())
{ {
auto q = m_queued.front(); auto t = m_queued.front();
m_queued.pop(); m_queued.pop();
if (validateTransaction(q.first, q.second))
WebThreeStubServerBase::authenticate(q.first, q.second); bool proxy = isProxyAccount(t.from);
if (!proxy && !isRealAccount(t.from))
{
cwarn << "Trying to send from non-existant account" << t.from;
return;
}
// TODO: determine gas price.
if (!validateTransaction(t, proxy))
return;
if (proxy)
queueTransaction(t);
else
// sign and submit.
if (Secret s = m_main->retrieveSecret(t.from))
m_web3->ethereum()->submitTransaction(s, t);
} }
} }
bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) AddressHash OurAccountHolder::realAccounts() const
{
return m_main->keyManager().accounts();
}
bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _toProxy)
{ {
if (_t.creation) if (_t.creation)
{ {

43
alethzero/OurWebThreeStubServer.h

@ -25,26 +25,29 @@
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/AccountHolder.h>
class Main; class Main;
class OurWebThreeStubServer: public QObject, public WebThreeStubServer class OurAccountHolder: public QObject, public dev::eth::AccountHolder
{ {
Q_OBJECT Q_OBJECT
public: public:
OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, OurAccountHolder(
std::vector<dev::KeyPair> const& _accounts, Main* main); dev::WebThreeDirect& _web3,
Main* _main
virtual std::string shh_newIdentity() override; );
virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
signals:
void onNewId(QString _s);
public slots: public slots:
void doValidations(); void doValidations();
protected:
// easiest to return keyManager.addresses();
virtual dev::AddressHash realAccounts() const override;
// use web3 to submit a signed transaction to accept
virtual void authenticate(dev::eth::TransactionSkeleton const& _t) override;
private: private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text); bool showAuthenticationPopup(std::string const& _title, std::string const& _text);
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
@ -53,9 +56,29 @@ private:
bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy); bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
std::queue<std::pair<dev::eth::TransactionSkeleton, bool>> m_queued; std::queue<dev::eth::TransactionSkeleton> m_queued;
dev::Mutex x_queued; dev::Mutex x_queued;
dev::WebThreeDirect* m_web3; dev::WebThreeDirect* m_web3;
Main* m_main; Main* m_main;
}; };
class OurWebThreeStubServer: public QObject, public WebThreeStubServer
{
Q_OBJECT
public:
OurWebThreeStubServer(
jsonrpc::AbstractServerConnector& _conn,
dev::WebThreeDirect& _web3,
Main* main
);
virtual std::string shh_newIdentity() override;
signals:
void onNewId(QString _s);
private:
Main* m_main;
};

55
alethzero/Transact.cpp

@ -39,6 +39,7 @@
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Utility.h> #include <libethereum/Utility.h>
#include <libethereum/KeyManager.h>
#if ETH_SERPENT #if ETH_SERPENT
#include <libserpent/funcs.h> #include <libserpent/funcs.h>
#include <libserpent/util.h> #include <libserpent/util.h>
@ -69,11 +70,20 @@ Transact::~Transact()
delete ui; delete ui;
} }
void Transact::setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB) void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB)
{ {
m_myKeys = _myKeys; m_accounts = _accounts;
m_ethereum = _eth; m_ethereum = _eth;
m_natSpecDB = _natSpecDB; m_natSpecDB = _natSpecDB;
ui->from->clear();
for (auto const& i: m_accounts)
{
auto d = m_context->keyManager().accountDetails()[i];
u256 b = ethereum()->balanceAt(i, PendingBlock);
QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(i))).arg(QString::fromStdString(d.first));
ui->from->addItem(s);
}
} }
bool Transact::isCreation() const bool Transact::isCreation() const
@ -126,8 +136,8 @@ void Transact::updateFee()
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false; bool ok = false;
for (auto i: m_myKeys) for (auto const& i: m_accounts)
if (ethereum()->balanceAt(i.address()) >= totalReq) if (ethereum()->balanceAt(i) >= totalReq)
{ {
ok = true; ok = true;
break; break;
@ -388,22 +398,33 @@ Secret Transact::findSecret(u256 _totalReq) const
if (!ethereum()) if (!ethereum())
return Secret(); return Secret();
Secret best; Address best;
u256 bestBalance = 0; u256 bestBalance = 0;
for (auto const& i: m_myKeys) for (auto const& i: m_accounts)
{ {
auto b = ethereum()->balanceAt(i.address(), PendingBlock); auto b = ethereum()->balanceAt(i, PendingBlock);
if (b >= _totalReq) if (b >= _totalReq)
return i.secret(); {
best = i;
break;
}
if (b > bestBalance) if (b > bestBalance)
bestBalance = b, best = i.secret(); bestBalance = b, best = i;
} }
return best; return m_context->retrieveSecret(best);
}
Address Transact::fromAccount()
{
auto it = m_accounts.begin();
std::advance(it, ui->from->currentIndex());
return *it;
} }
void Transact::on_send_clicked() void Transact::on_send_clicked()
{ {
Secret s = findSecret(value() + fee()); // Secret s = findSecret(value() + fee());
Secret s = m_context->retrieveSecret(fromAccount());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock);
if (!s || b < value() + fee()) if (!s || b < value() + fee())
{ {
@ -440,9 +461,10 @@ void Transact::on_send_clicked()
void Transact::on_debug_clicked() void Transact::on_debug_clicked()
{ {
Secret s = findSecret(value() + fee()); // Secret s = findSecret(value() + fee());
auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); Address from = fromAccount();
if (!s || b < value() + fee()) auto b = ethereum()->balanceAt(from, PendingBlock);
if (!from || b < value() + fee())
{ {
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount.");
return; return;
@ -452,8 +474,9 @@ void Transact::on_debug_clicked()
{ {
State st(ethereum()->postState()); State st(ethereum()->postState());
Transaction t = isCreation() ? Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) : Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(from)) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(dev::toAddress(s)), s); Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(from));
t.forceSender(from);
Debugger dw(m_context, this); Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0); Executive e(st, ethereum()->blockChain(), 0);
dw.populate(e, t); dw.populate(e, t);

5
alethzero/Transact.h

@ -41,7 +41,7 @@ public:
explicit Transact(Context* _context, QWidget* _parent = 0); explicit Transact(Context* _context, QWidget* _parent = 0);
~Transact(); ~Transact();
void setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB);
private slots: private slots:
void on_destination_currentTextChanged(QString); void on_destination_currentTextChanged(QString);
@ -60,6 +60,7 @@ private:
dev::eth::Client* ethereum() const { return m_ethereum; } dev::eth::Client* ethereum() const { return m_ethereum; }
void rejigData(); void rejigData();
dev::Address fromAccount();
void updateDestination(); void updateDestination();
void updateFee(); void updateFee();
bool isCreation() const; bool isCreation() const;
@ -76,7 +77,7 @@ private:
unsigned m_backupGas = 0; unsigned m_backupGas = 0;
dev::bytes m_data; dev::bytes m_data;
QList<dev::KeyPair> m_myKeys; dev::AddressHash m_accounts;
dev::eth::Client* m_ethereum = nullptr; dev::eth::Client* m_ethereum = nullptr;
Context* m_context = nullptr; Context* m_context = nullptr;
NatSpecFace* m_natSpecDB = nullptr; NatSpecFace* m_natSpecDB = nullptr;

261
alethzero/Transact.ui

@ -14,91 +14,69 @@
<string>Transact</string> <string>Transact</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="1" colspan="2"> <item row="5" column="0">
<widget class="QSpinBox" name="value"> <widget class="QLabel" name="label_2">
<property name="suffix"> <property name="sizePolicy">
<string/> <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="maximum"> <property name="text">
<number>430000000</number> <string>D&amp;ata</string>
</property> </property>
<property name="value"> <property name="alignment">
<number>0</number> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>data</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="5" column="3">
<widget class="QLabel" name="label5_2"> <widget class="QCheckBox" name="optimize">
<property name="text"> <property name="text">
<string>&amp;Amount</string> <string>&amp;Optimise</string>
</property> </property>
<property name="buddy"> <property name="checked">
<cstring>value</cstring> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1" colspan="3"> <item row="4" column="1">
<widget class="QLineEdit" name="calculatedName"> <widget class="QSpinBox" name="gas">
<property name="enabled"> <property name="suffix">
<bool>false</bool> <string> gas</string>
</property> </property>
<property name="readOnly"> <property name="minimum">
<bool>true</bool> <number>1</number>
</property> </property>
<property name="placeholderText"> <property name="maximum">
<string/> <number>430000000</number>
</property>
<property name="value">
<number>10000</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="4"> <item row="8" column="0">
<widget class="QSplitter" name="splitter_5"> <widget class="QPushButton" name="cancel">
<property name="orientation"> <property name="text">
<enum>Qt::Vertical</enum> <string>&amp;Cancel</string>
</property>
<property name="shortcut">
<string>Esc</string>
</property> </property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget> </widget>
</item> </item>
<item row="3" column="3"> <item row="8" column="2">
<widget class="QComboBox" name="gasPriceUnits"/> <widget class="QPushButton" name="debug">
</item>
<item row="4" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string/> <string>&amp;Debug</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label5"> <widget class="QLabel" name="label5">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -114,53 +92,68 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="3"> <item row="7" column="0" colspan="4">
<widget class="QComboBox" name="valueUnits"/> <widget class="QLabel" name="total">
</item> <property name="sizePolicy">
<item row="7" column="2"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<widget class="QPushButton" name="debug"> <horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>&amp;Debug</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="3"> <item row="3" column="1" colspan="2">
<widget class="QPushButton" name="send"> <widget class="QSpinBox" name="value">
<property name="text"> <property name="suffix">
<string>&amp;Execute</string> <string/>
</property> </property>
<property name="default"> <property name="maximum">
<bool>false</bool> <number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label5_2">
<property name="text"> <property name="text">
<string>&amp;Gas</string> <string>&amp;Amount</string>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>gas</cstring> <cstring>value</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="8" column="3">
<widget class="QSpinBox" name="gas"> <widget class="QPushButton" name="send">
<property name="suffix"> <property name="text">
<string> gas</string> <string>&amp;Execute</string>
</property>
<property name="minimum">
<number>1</number>
</property> </property>
<property name="maximum"> <property name="default">
<number>430000000</number> <bool>false</bool>
</property> </property>
<property name="value"> </widget>
<number>10000</number> </item>
<item row="1" column="1" colspan="3">
<widget class="QComboBox" name="destination">
<property name="editable">
<bool>true</bool>
</property> </property>
<item>
<property name="text">
<string>(Create Contract)</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="3" column="2"> <item row="4" column="2">
<widget class="QSpinBox" name="gasPrice"> <widget class="QSpinBox" name="gasPrice">
<property name="prefix"> <property name="prefix">
<string>@ </string> <string>@ </string>
@ -173,49 +166,63 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3"> <item row="6" column="0" colspan="4">
<widget class="QCheckBox" name="optimize"> <widget class="QSplitter" name="splitter_5">
<property name="text"> <property name="orientation">
<string>&amp;Optimise</string> <enum>Qt::Vertical</enum>
</property>
<property name="checked">
<bool>true</bool>
</property> </property>
<widget class="QPlainTextEdit" name="data">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>D&amp;ata</string> <string>&amp;Gas</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<property name="buddy"> <property name="buddy">
<cstring>data</cstring> <cstring>gas</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="3"> <item row="2" column="1" colspan="3">
<widget class="QComboBox" name="destination"> <widget class="QLineEdit" name="calculatedName">
<property name="editable"> <property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
<item> <property name="placeholderText">
<property name="text"> <string/>
<string>(Create Contract)</string> </property>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="6" column="0" colspan="4"> <item row="3" column="3">
<widget class="QLabel" name="total"> <widget class="QComboBox" name="valueUnits"/>
</item>
<item row="5" column="1" colspan="2">
<widget class="QLabel" name="fee">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -225,18 +232,24 @@
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="0" column="0">
<widget class="QPushButton" name="cancel"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>&amp;Cancel</string> <string>&amp;From</string>
</property> </property>
<property name="shortcut"> <property name="buddy">
<string>Esc</string> <cstring>from</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="from"/>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>

13
appdmg.json.in

@ -0,0 +1,13 @@
{
"title": "Ethereum",
"icon": "appdmg_icon.icns",
"background": "appdmg_background.png",
"icon-size": 80,
"contents": [
{ "x": 600, "y": 170, "type": "link", "path": "/Applications" },
{ "x": 150, "y": 90, "type": "file", "path": "${ETH_ALETHZERO_APP}" },
{ "x": 150, "y": 260, "type": "file", "path": "${ETH_MIX_APP}" }
]
}

BIN
bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

5
cmake/EthDependencies.cmake

@ -159,6 +159,11 @@ if (GUI)
message(" - windeployqt path: ${WINDEPLOYQT_APP}") message(" - windeployqt path: ${WINDEPLOYQT_APP}")
endif() endif()
if (APPLE)
find_program(ETH_APP_DMG appdmg)
message(" - appdmg location : ${ETH_APP_DMG}")
endif()
if (USENPM) if (USENPM)
# TODO check node && npm version # TODO check node && npm version

17
cmake/scripts/appdmg.cmake

@ -0,0 +1,17 @@
if (NOT APP_DMG_EXE)
message(FATAL_ERROR "Please install appdmg! https://github.com/LinusU/node-appdmg")
endif()
string(REPLACE "/Contents/MacOS" "" ETH_MIX_APP "${ETH_MIX_APP}")
string(REPLACE "/Contents/MacOS" "" ETH_ALETHZERO_APP "${ETH_ALETHZERO_APP}")
set(OUTFILE "${ETH_BUILD_DIR}/appdmg.json")
configure_file(${APP_DMG_FILE} ${OUTFILE})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${APP_DMG_ICON}" "${ETH_BUILD_DIR}/appdmg_icon.icns")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${APP_DMG_BACKGROUND}" "${ETH_BUILD_DIR}/appdmg_background.png")
execute_process(COMMAND ${CMAKE_COMMAND} -E remove "${ETH_BUILD_DIR}/Ethereum.dmg")
execute_process(COMMAND ${APP_DMG_EXE} ${OUTFILE} "${ETH_BUILD_DIR}/Ethereum.dmg")

190
eth/main.cpp

@ -37,6 +37,7 @@
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libethereum/KeyManager.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#if ETH_JSCONSOLE || !ETH_TRUE #if ETH_JSCONSOLE || !ETH_TRUE
#include <libjsconsole/JSConsole.h> #include <libjsconsole/JSConsole.h>
@ -46,6 +47,7 @@
#include <readline/history.h> #include <readline/history.h>
#endif #endif
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/AccountHolder.h>
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h> #include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h> #include <jsonrpccpp/client/connectors/httpclient.h>
@ -89,10 +91,8 @@ void interactiveHelp()
<< " minestart Starts mining." << endl << " minestart Starts mining." << endl
<< " minestop Stops mining." << endl << " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl << " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " address Gives the current address." << endl
<< " secret Gives the current secret" << endl
<< " block Gives the current block height." << endl << " block Gives the current block height." << endl
<< " balance Gives the current balance." << endl << " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl
<< " transact Execute a given transaction." << endl << " transact Execute a given transaction." << endl
<< " send Execute a given transaction with current secret." << endl << " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl << " contract Create a new contract with current secret." << endl
@ -101,7 +101,7 @@ void interactiveHelp()
<< " listaccounts List the accounts on the network." << endl << " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl << " listcontracts List the contracts on the network." << endl
#endif #endif
<< " setsecret <secret> Set the secret to the hex secret key." << endl << " setsigningkey <addr> Set the address with which to sign transactions." << endl
<< " setaddress <addr> Set the coinbase (mining payout) address." << endl << " setaddress <addr> Set the coinbase (mining payout) address." << endl
<< " exportconfig <path> Export the config (.RLP) to the path provided." << endl << " exportconfig <path> Export the config (.RLP) to the path provided." << endl
<< " importconfig <path> Import the config (.RLP) from the path provided." << endl << " importconfig <path> Import the config (.RLP) from the path provided." << endl
@ -125,13 +125,18 @@ void help()
#endif #endif
<< " -K,--kill First kill the blockchain." << endl << " -K,--kill First kill the blockchain." << endl
<< " -R,--rebuild Rebuild the blockchain from the existing database." << endl << " -R,--rebuild Rebuild the blockchain from the existing database." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--session-secret <secretkeyhex> Set the secret key for use with send command, for this session only." << endl << " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
<< " --sign-key <address> Sign all transactions with the key of the given address." << endl
<< " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl
<< " --master <password> Give the master password for the key store." << endl << " --master <password> Give the master password for the key store." << endl
<< " --password <password> Give a password for a private key." << endl
<< endl
<< "Client transacting:" << endl << "Client transacting:" << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl << " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl << " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (default: 30.679)." << endl
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< endl
<< "Client mining:" << endl << "Client mining:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl << " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl
@ -141,6 +146,7 @@ void help()
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
<< " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl << " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
<< endl
<< "Client networking:" << endl << "Client networking:" << endl
<< " --client-name <name> Add a name to your client's version string (default: blank)." << endl << " --client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
@ -153,12 +159,15 @@ void help()
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl << " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl << " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
<< endl
<< "Work farming mode:" << endl << "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL. Use with -G/--opencl." << endl << " -F,--farm <url> Put into mining farm mode with the work server at URL. Use with -G/--opencl." << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl << " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif #endif
<< endl
<< "Ethash verify mode:" << endl << "Ethash verify mode:" << endl
<< " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl << " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< endl
<< "Benchmarking mode:" << endl << "Benchmarking mode:" << endl
<< " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
<< " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl << " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
@ -167,14 +176,17 @@ void help()
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl << " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif #endif
<< endl
<< "DAG creation mode:" << endl << "DAG creation mode:" << endl
<< " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl << " -D,--create-dag <this/next/number> Create the DAG in preparation for mining on given block and exit." << endl
<< endl
<< "Import/export modes:" << endl << "Import/export modes:" << endl
<< " -I,--import <file> Import file as a concatenated series of blocks and exit." << endl << " -I,--import <file> Import file as a concatenated series of blocks and exit." << endl
<< " -E,--export <file> Export file as a concatenated series of blocks and exit." << endl << " -E,--export <file> Export file as a concatenated series of blocks and exit." << endl
<< " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --from <n> Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --to <n> Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl
<< " --only <n> Equivalent to --export-from n --export-to n." << endl << " --only <n> Equivalent to --export-from n --export-to n." << endl
<< endl
<< "General Options:" << endl << "General Options:" << endl
<< " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl << " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl
#if ETH_EVMJIT || !ETH_TRUE #if ETH_EVMJIT || !ETH_TRUE
@ -537,13 +549,14 @@ int main(int argc, char** argv)
/// Mining params /// Mining params
unsigned mining = 0; unsigned mining = 0;
bool forceMining = false; bool forceMining = false;
KeyPair sigKey = KeyPair::create(); Address signingKey;
Secret sessionSecret; Address sessionKey;
Address coinbase = sigKey.address(); Address beneficiary = signingKey;
/// Structured logging params /// Structured logging params
bool structuredLogging = false; bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S"; string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string structuredLoggingURL;
/// Transaction params /// Transaction params
TransactionPriority priority = TransactionPriority::Medium; TransactionPriority priority = TransactionPriority::Medium;
@ -568,11 +581,20 @@ int main(int argc, char** argv)
string configFile = getDataDir() + "/config.rlp"; string configFile = getDataDir() + "/config.rlp";
bytes b = contents(configFile); bytes b = contents(configFile);
strings passwordsToNote;
Secrets toImport;
if (b.size()) if (b.size())
{ {
RLP config(b); RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>()); if (config[0].size() == 32) // secret key - import and forget.
coinbase = config[1].toHash<Address>(); {
Secret s = config[0].toHash<Secret>();
toImport.push_back(s);
}
else // new format - just use it as an address.
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>();
} }
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
@ -600,6 +622,8 @@ int main(int argc, char** argv)
cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl; cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl;
remotePort = (short)atoi(argv[++i]); remotePort = (short)atoi(argv[++i]);
} }
else if (arg == "--password" && i + 1 < argc)
passwordsToNote.push_back(argv[++i]);
else if (arg == "--master" && i + 1 < argc) else if (arg == "--master" && i + 1 < argc)
masterPassword = argv[++i]; masterPassword = argv[++i];
else if ((arg == "-I" || arg == "--import") && i + 1 < argc) else if ((arg == "-I" || arg == "--import") && i + 1 < argc)
@ -742,7 +766,7 @@ int main(int argc, char** argv)
} }
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
try { try {
coinbase = h160(fromHex(argv[++i], WhenError::Throw)); beneficiary = h160(fromHex(argv[++i], WhenError::Throw));
} }
catch (BadHexCharacter&) catch (BadHexCharacter&)
{ {
@ -758,14 +782,32 @@ int main(int argc, char** argv)
minerType = MinerType::CPU; minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl") else if (arg == "-G" || arg == "--opencl")
minerType = MinerType::GPU; minerType = MinerType::GPU;
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) /*<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
sigKey = KeyPair(h256(fromHex(argv[++i]))); << " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc) << " --sign-key <address> Sign all transactions with the key of the given address." << endl
sessionSecret = h256(fromHex(argv[++i])); << " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl*/
else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc)
{
Secret s(fromHex(argv[++i]));
toImport.push_back(s);
signingKey = toAddress(s);
}
else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc)
{
Secret s(fromHex(argv[++i]));
toImport.push_back(s);
sessionKey = toAddress(s);
}
else if ((arg == "--sign-key") && i + 1 < argc)
sessionKey = Address(fromHex(argv[++i]));
else if ((arg == "--session-sign-key") && i + 1 < argc)
sessionKey = Address(fromHex(argv[++i]));
else if (arg == "--structured-logging-format" && i + 1 < argc) else if (arg == "--structured-logging-format" && i + 1 < argc)
structuredLoggingFormat = string(argv[++i]); structuredLoggingFormat = string(argv[++i]);
else if (arg == "--structured-logging") else if (arg == "--structured-logging")
structuredLogging = true; structuredLogging = true;
else if (arg == "--structured-logging-destination" && i + 1 < argc)
structuredLoggingURL = argv[++i];
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i]; dbPath = argv[++i];
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc) else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
@ -949,16 +991,24 @@ int main(int argc, char** argv)
} }
} }
KeyManager keyManager;
for (auto const& s: passwordsToNote)
keyManager.notePassword(s);
for (auto const& s: toImport)
{
keyManager.import(s, "Imported key");
if (!signingKey)
signingKey = toAddress(s);
}
{ {
RLPStream config(2); RLPStream config(2);
config << sigKey.secret() << coinbase; config << signingKey << beneficiary;
writeFile(configFile, config.out()); writeFile(configFile, config.out());
} }
if (sessionSecret) if (sessionKey)
sigKey = KeyPair(sessionSecret); signingKey = sessionKey;
if (minerType == MinerType::CPU) if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads); ProofOfWork::CPUMiner::setNumInstances(miningThreads);
@ -983,7 +1033,7 @@ int main(int argc, char** argv)
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
@ -1072,27 +1122,68 @@ int main(int argc, char** argv)
c->setGasPricer(gasPricer); c->setGasPricer(gasPricer);
c->setForceMining(forceMining); c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU); c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(coinbase); c->setAddress(beneficiary);
c->setNetworkId(networkId); c->setNetworkId(networkId);
} }
cout << "Transaction Signer: " << sigKey.address() << endl; cout << "Transaction Signer: " << signingKey << endl;
cout << "Mining Benefactor: " << coinbase << endl; cout << "Mining Benefactor: " << beneficiary << endl;
web3.startNetwork(); web3.startNetwork();
cout << "Node ID: " << web3.enode() << endl; cout << "Node ID: " << web3.enode() << endl;
if (bootstrap) if (bootstrap)
web3.addNode(p2p::NodeId(), Host::pocHost()); for (auto const& i: Host::pocHosts())
web3.requirePeer(i.first, i.second);
if (remoteHost.size()) if (remoteHost.size())
web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC if (keyManager.exists())
while (masterPassword.empty())
{
masterPassword = getPassword("Please enter your MASTER password: ");
if (!keyManager.load(masterPassword))
{
cout << "Password invalid. Try again." << endl;
masterPassword.clear();
}
}
else
{
while (masterPassword.empty())
{
masterPassword = getPassword("Please enter a MASTER password to protect your key store (make it strong!): ");
string confirm = getPassword("Please confirm the password by entering it again: ");
if (masterPassword != confirm)
{
cout << "Passwords were different. Try again." << endl;
masterPassword.clear();
}
}
keyManager.create(masterPassword);
}
string logbuf;
bool silence = false;
std::string additional;
g_logPost = [&](std::string const& a, char const*) { if (silence) logbuf += a + "\n"; else cout << "\r \r" << a << endl << additional << flush; };
// TODO: give hints &c.
auto getPassword = [&](Address const& a){
auto s = silence;
silence = true;
cout << endl;
string ret = dev::getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): ");
silence = s;
return ret;
};
#if ETH_JSONRPC || !ETH_TRUE
shared_ptr<WebThreeStubServer> jsonrpcServer; shared_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector; unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({sigKey}))); jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
#endif #endif
@ -1103,15 +1194,15 @@ int main(int argc, char** argv)
if (interactive) if (interactive)
{ {
string logbuf; additional = "Press Enter";
string l; string l;
while (!g_exit) while (!g_exit)
{ {
g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << "Press Enter" << flush; }; silence = false;
cout << logbuf << "Press Enter" << flush; cout << logbuf << "Press Enter" << flush;
std::getline(cin, l); std::getline(cin, l);
logbuf.clear(); logbuf.clear();
g_logPost = [&](std::string const& a, char const*) { logbuf += a + "\n"; }; silence = true;
#if ETH_READLINE #if ETH_READLINE
if (l.size()) if (l.size())
@ -1224,7 +1315,7 @@ int main(int argc, char** argv)
iss >> g_logVerbosity; iss >> g_logVerbosity;
cout << "Verbosity: " << g_logVerbosity << endl; cout << "Verbosity: " << g_logVerbosity << endl;
} }
#if ETH_JSONRPC #if ETH_JSONRPC || !ETH_TRUE
else if (cmd == "jsonport") else if (cmd == "jsonport")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
@ -1236,7 +1327,7 @@ int main(int argc, char** argv)
if (jsonrpc < 0) if (jsonrpc < 0)
jsonrpc = SensibleHttpPort; jsonrpc = SensibleHttpPort;
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({sigKey}))); jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<SimpleAccountHolder>([&](){return web3.ethereum();}, getPassword, keyManager), vector<KeyPair>()));
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
else if (cmd == "jsonstop") else if (cmd == "jsonstop")
@ -1248,11 +1339,8 @@ int main(int argc, char** argv)
#endif #endif
else if (cmd == "address") else if (cmd == "address")
{ {
cout << "Current address:" << endl << sigKey.address() << endl; cout << "Current mining beneficiary:" << endl << beneficiary << endl;
} cout << "Current signing account:" << endl << signingKey << endl;
else if (cmd == "secret")
{
cout << "Secret Key: " << sigKey.secret() << endl;
} }
else if (c && cmd == "block") else if (c && cmd == "block")
{ {
@ -1267,7 +1355,15 @@ int main(int argc, char** argv)
} }
else if (c && cmd == "balance") else if (c && cmd == "balance")
{ {
cout << "Current balance: " << formatBalance( c->balanceAt(sigKey.address())) << " = " <<c->balanceAt(sigKey.address()) << " wei" << endl; cout << "Current balance:" << endl;
u256 total = 0;
for (auto const& i: keyManager.accountDetails())
{
auto b = c->balanceAt(i.first);
cout << ((i.first == signingKey) ? "SIGNING " : " ") << ((i.first == beneficiary) ? "COINBASE " : " ") << i.second.first << " (" << i.first << "): " << formatBalance(b) << " = " << b << " wei" << endl;
total += b;
}
cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl;
} }
else if (c && cmd == "transact") else if (c && cmd == "transact")
{ {
@ -1383,7 +1479,7 @@ int main(int argc, char** argv)
try try
{ {
Address dest = h160(fromHex(hexAddr, WhenError::Throw)); Address dest = h160(fromHex(hexAddr, WhenError::Throw));
c->submitTransaction(sigKey.secret(), amount, dest, bytes(), minGas); c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), amount, dest, bytes(), minGas);
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {
@ -1452,7 +1548,7 @@ int main(int argc, char** argv)
else if (gas < minGas) else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas; cwarn << "Minimum gas amount is" << minGas;
else else
c->submitTransaction(sigKey.secret(), endowment, init, gas, gasPrice); c->submitTransaction(keyManager.secret(signingKey, [&](){ return getPassword(signingKey); }), endowment, init, gas, gasPrice);
} }
else else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX"; cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
@ -1563,13 +1659,13 @@ int main(int argc, char** argv)
} }
} }
} }
else if (cmd == "setsecret") else if (cmd == "setsigningkey")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
{ {
string hexSec; string hexSec;
iss >> hexSec; iss >> hexSec;
sigKey = KeyPair(h256(fromHex(hexSec))); signingKey = Address(fromHex(hexSec));
} }
else else
cwarn << "Require parameter: setSecret HEXSECRETKEY"; cwarn << "Require parameter: setSecret HEXSECRETKEY";
@ -1586,7 +1682,7 @@ int main(int argc, char** argv)
{ {
try try
{ {
coinbase = h160(fromHex(hexAddr, WhenError::Throw)); beneficiary = h160(fromHex(hexAddr, WhenError::Throw));
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {
@ -1609,7 +1705,7 @@ int main(int argc, char** argv)
string path; string path;
iss >> path; iss >> path;
RLPStream config(2); RLPStream config(2);
config << sigKey.secret() << coinbase; config << signingKey << beneficiary;
writeFile(path, config.out()); writeFile(path, config.out());
} }
else else
@ -1625,8 +1721,8 @@ int main(int argc, char** argv)
if (b.size()) if (b.size())
{ {
RLP config(b); RLP config(b);
sigKey = KeyPair(config[0].toHash<Secret>()); signingKey = config[0].toHash<Address>();
coinbase = config[1].toHash<Address>(); beneficiary = config[1].toHash<Address>();
} }
else else
cwarn << path << "has no content!"; cwarn << path << "has no content!";

2
exp/main.cpp

@ -81,7 +81,7 @@ int main()
// cdebug << toString(a2); // cdebug << toString(a2);
Address a2("19c486071651b2650449ba3c6a807f316a73e8fe"); Address a2("19c486071651b2650449ba3c6a807f316a73e8fe");
cdebug << keyman.keys(); cdebug << keyman.accountDetails();
cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; }); cdebug << "Secret key for " << a << "is" << keyman.secret(a, [](){ return "bar"; });
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);

4
libdevcore/Common.cpp

@ -28,7 +28,9 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.9.17"; char const* Version = "0.9.18";
const u256 UndefinedU256 = ~(u256)0;
void HasInvariants::checkInvariants() const void HasInvariants::checkInvariants() const
{ {

2
libdevcore/Common.h

@ -82,6 +82,8 @@ using u160s = std::vector<u160>;
using u256Set = std::set<u256>; using u256Set = std::set<u256>;
using u160Set = std::set<u160>; using u160Set = std::set<u160>;
extern const u256 UndefinedU256;
// Map types. // Map types.
using StringMap = std::map<std::string, std::string>; using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>; using u256Map = std::map<u256, u256>;

14
libdevcore/CommonIO.cpp

@ -20,7 +20,8 @@
*/ */
#include "CommonIO.h" #include "CommonIO.h"
#include <iostream>
#include <cstdlib>
#include <fstream> #include <fstream>
#include "Exceptions.h" #include "Exceptions.h"
using namespace std; using namespace std;
@ -117,3 +118,14 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data)
ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size()); ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size());
} }
std::string dev::getPassword(std::string const& _prompt)
{
#if WIN32
cout << _prompt << flush;
std::string ret;
std::getline(cin, ret);
return ret;
#else
return getpass(_prompt.c_str());
#endif
}

2
libdevcore/CommonIO.h

@ -42,6 +42,8 @@
namespace dev namespace dev
{ {
std::string getPassword(std::string const& _prompt);
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes. /// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file); bytes contents(std::string const& _file);
std::string contentsString(std::string const& _file); std::string contentsString(std::string const& _file);

1
libdevcore/FixedHash.h

@ -282,6 +282,7 @@ namespace std
{ {
/// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash. /// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash.
template<> struct hash<dev::h64>: dev::h64::hash {}; template<> struct hash<dev::h64>: dev::h64::hash {};
template<> struct hash<dev::h128>: dev::h128::hash {};
template<> struct hash<dev::h160>: dev::h160::hash {}; template<> struct hash<dev::h160>: dev::h160::hash {};
template<> struct hash<dev::h256>: dev::h256::hash {}; template<> struct hash<dev::h256>: dev::h256::hash {};
template<> struct hash<dev::h512>: dev::h512::hash {}; template<> struct hash<dev::h512>: dev::h512::hash {};

13
libdevcore/StructuredLogger.cpp

@ -34,6 +34,15 @@ using namespace std;
namespace dev namespace dev
{ {
void StructuredLogger::initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL)
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
if (_destinationURL.size() > 7 && _destinationURL.substr(0, 7) == "file://")
m_out.open(_destinationURL.substr(7));
// TODO: support tcp://
}
void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const void StructuredLogger::outputJson(Json::Value const& _value, std::string const& _name) const
{ {
Json::Value event; Json::Value event;
@ -41,7 +50,7 @@ void StructuredLogger::outputJson(Json::Value const& _value, std::string const&
Json::FastWriter fastWriter; Json::FastWriter fastWriter;
Guard l(s_lock); Guard l(s_lock);
event[_name] = _value; event[_name] = _value;
cout << fastWriter.write(event) << endl; (m_out.is_open() ? m_out : cout) << fastWriter.write(event) << endl;
} }
void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion) void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersion)
@ -51,6 +60,7 @@ void StructuredLogger::starting(string const& _clientImpl, const char* _ethVersi
Json::Value event; Json::Value event;
event["client_impl"] = _clientImpl; event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion); event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str()); event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "starting"); get().outputJson(event, "starting");
@ -64,6 +74,7 @@ void StructuredLogger::stopping(string const& _clientImpl, const char* _ethVersi
Json::Value event; Json::Value event;
event["client_impl"] = _clientImpl; event["client_impl"] = _clientImpl;
event["eth_version"] = std::string(_ethVersion); event["eth_version"] = std::string(_ethVersion);
// TODO net_version
event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str()); event["ts"] = dev::toString(chrono::system_clock::now(), get().m_timeFormat.c_str());
get().outputJson(event, "stopping"); get().outputJson(event, "stopping");

14
libdevcore/StructuredLogger.h

@ -25,6 +25,7 @@
#pragma once #pragma once
#include <fstream>
#include <string> #include <string>
#include <chrono> #include <chrono>
@ -46,11 +47,7 @@ public:
* http://en.cppreference.com/w/cpp/chrono/c/strftime * http://en.cppreference.com/w/cpp/chrono/c/strftime
* with which to display timestamps * with which to display timestamps
*/ */
void initialize(bool _enabled, std::string const& _timeFormat) void initialize(bool _enabled, std::string const& _timeFormat, std::string const& _destinationURL = "");
{
m_enabled = _enabled;
m_timeFormat = _timeFormat;
}
static StructuredLogger& get() static StructuredLogger& get()
{ {
@ -92,6 +89,11 @@ public:
std::string const& _prevHash std::string const& _prevHash
); );
static void transactionReceived(std::string const& _hash, std::string const& _remoteId); static void transactionReceived(std::string const& _hash, std::string const& _remoteId);
// TODO: static void pendingQueueChanged(std::vector<h256> const& _hashes);
// TODO: static void miningStarted();
// TODO: static void stillMining(unsigned _hashrate);
// TODO: static void miningStopped();
private: private:
// Singleton class. Private default ctor and no copying // Singleton class. Private default ctor and no copying
StructuredLogger() = default; StructuredLogger() = default;
@ -102,6 +104,8 @@ private:
bool m_enabled = false; bool m_enabled = false;
std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S"; std::string m_timeFormat = "%Y-%m-%dT%H:%M:%S";
mutable std::ofstream m_out;
}; };
} }

1
libdevcrypto/SecretStore.cpp

@ -104,6 +104,7 @@ void SecretStore::save(std::string const& _keysPath)
void SecretStore::load(std::string const& _keysPath) void SecretStore::load(std::string const& _keysPath)
{ {
fs::path p(_keysPath); fs::path p(_keysPath);
boost::filesystem::create_directories(p);
js::mValue v; js::mValue v;
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (is_regular_file(it->path())) if (is_regular_file(it->path()))

5
libdevcrypto/SecretStore.h

@ -23,6 +23,7 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <libdevcore/FixedHash.h>
#include "Common.h" #include "Common.h"
#include "FileSystem.h" #include "FileSystem.h"
@ -48,8 +49,8 @@ private:
static std::string encrypt(bytes const& _v, std::string const& _pass); static std::string encrypt(bytes const& _v, std::string const& _pass);
static bytes decrypt(std::string const& _v, std::string const& _pass); static bytes decrypt(std::string const& _v, std::string const& _pass);
mutable std::map<h128, bytes> m_cached; mutable std::unordered_map<h128, bytes> m_cached;
std::map<h128, std::pair<std::string, std::string>> m_keys; std::unordered_map<h128, std::pair<std::string, std::string>> m_keys;
}; };
} }

13
libethash-cl/ethash_cl_miner.cpp

@ -27,6 +27,7 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include <queue> #include <queue>
#include <random>
#include <vector> #include <vector>
#include <libethash/util.h> #include <libethash/util.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
@ -306,21 +307,15 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
// update header constant buffer // update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
for (unsigned i = 0; i != c_num_buffers; ++i) for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
#if CL_VERSION_1_2 && 0 #if CL_VERSION_1_2 && 0
cl::Event pre_return_event; cl::Event pre_return_event;
if (!m_opencl_1_1) if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else else
#endif #endif
{
m_queue.finish(); m_queue.finish();
}
/* /*
__kernel void ethash_combined_search( __kernel void ethash_combined_search(
@ -341,7 +336,9 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
unsigned buf = 0; unsigned buf = 0;
for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size) std::random_device engine;
uint64_t start_nonce = std::uniform_int_distribution<uint64_t>()(engine);
for (; ; start_nonce += c_search_batch_size)
{ {
// supply output buffer to kernel // supply output buffer to kernel
m_search_kernel.setArg(0, m_search_buf[buf]); m_search_kernel.setArg(0, m_search_buf[buf]);
@ -386,9 +383,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
// not safe to return until this is ready // not safe to return until this is ready
#if CL_VERSION_1_2 && 0 #if CL_VERSION_1_2 && 0
if (!m_opencl_1_1) if (!m_opencl_1_1)
{
pre_return_event.wait(); pre_return_event.wait();
}
#endif #endif
} }

8
libethcore/BlockInfo.cpp

@ -228,7 +228,7 @@ u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
return c_genesisGasLimit; return c_genesisGasLimit;
else else
// target minimum of 3141592 // target minimum of 3141592
return max<u256>(max<u256>(c_minGasLimit, 3141592), (_parent.gasLimit * (c_gasLimitBoundDivisor - 1) + (_parent.gasUsed * 6 / 5)) / c_gasLimitBoundDivisor); return max<u256>(max<u256>(c_minGasLimit, 3141592), _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor);
} }
u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
@ -246,9 +246,9 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty));
if (gasLimit < c_minGasLimit || if (gasLimit < c_minGasLimit ||
gasLimit < _parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor || gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor ||
gasLimit > _parent.gasLimit * (c_gasLimitBoundDivisor + 1) / c_gasLimitBoundDivisor) gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit * (c_gasLimitBoundDivisor + 1) / c_gasLimitBoundDivisor)); BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor));
// Check timestamp is after previous timestamp. // Check timestamp is after previous timestamp.
if (parentHash) if (parentHash)

11
libethcore/Common.h

@ -136,5 +136,16 @@ private:
using Handler = std::shared_ptr<Signal::HandlerAux>; using Handler = std::shared_ptr<Signal::HandlerAux>;
struct TransactionSkeleton
{
bool creation = false;
Address from;
Address to;
u256 value;
bytes data;
u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256;
};
} }
} }

2
libethcore/CommonJS.cpp

@ -26,8 +26,6 @@
namespace dev namespace dev
{ {
const u256 UndefinedU256 = ~(u256)0;
Address toAddress(std::string const& _sn) Address toAddress(std::string const& _sn)
{ {
if (_sn.size() == 40) if (_sn.size() == 40)

14
libethcore/CommonJS.h

@ -48,8 +48,6 @@ inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev:
/// 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. /// 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, bool _abridged = true); std::string prettyU256(u256 _n, bool _abridged = true);
extern const u256 UndefinedU256;
} }
@ -59,18 +57,6 @@ namespace dev
namespace eth namespace eth
{ {
struct TransactionSkeleton
{
bool creation = false;
Address from;
Address to;
u256 value;
bytes data;
u256 gas = UndefinedU256;
u256 gasPrice = UndefinedU256;
};
/// Convert to a block number, a bit like jsToInt, except that it correctly recognises "pending" and "latest". /// Convert to a block number, a bit like jsToInt, except that it correctly recognises "pending" and "latest".
BlockNumber jsToBlockNumber(std::string const& _js); BlockNumber jsToBlockNumber(std::string const& _js);

39
libethereum/BlockChain.cpp

@ -456,7 +456,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
{ {
// Check transactions are valid and that they result in a state equivalent to our state_root. // Check transactions are valid and that they result in a state equivalent to our state_root.
// Get total difficulty increase and update state, checking it. // Get total difficulty increase and update state, checking it.
State s(_db); //, bi.coinbaseAddress State s(_db);
auto tdIncrease = s.enactOn(&_block, bi, *this, _ir); auto tdIncrease = s.enactOn(&_block, bi, *this, _ir);
BlockLogBlooms blb; BlockLogBlooms blb;
@ -467,6 +467,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
br.receipts.push_back(s.receipt(i)); br.receipts.push_back(s.receipt(i));
} }
s.cleanup(true); s.cleanup(true);
td = pd.totalDifficulty + tdIncrease; td = pd.totalDifficulty + tdIncrease;
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
@ -603,7 +604,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
{ {
newLastBlockHash = bi.hash(); newLastBlockHash = bi.hash();
newLastBlockNumber = (unsigned)bi.number; newLastBlockNumber = (unsigned)bi.number;
extrasBatch.Put(ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32));
} }
clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route; clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route;
@ -623,12 +623,33 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
m_blocksDB->Write(m_writeOptions, &blocksBatch); m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch); m_extrasDB->Write(m_writeOptions, &extrasBatch);
DEV_WRITE_GUARDED(x_lastBlockHash) if (isKnown(bi.hash()) && !details(bi.hash()))
{ {
m_lastBlockHash = newLastBlockHash; clog(BlockChainDebug) << "Known block just inserted has no details.";
m_lastBlockNumber = newLastBlockNumber; clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
} }
try {
State canary(_db, *this, bi.hash());
}
catch (...)
{
clog(BlockChainDebug) << "Failed to initialise State object form imported block.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
if (m_lastBlockHash != newLastBlockHash)
DEV_WRITE_GUARDED(x_lastBlockHash)
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&m_lastBlockHash, 32));
}
#if ETH_PARANOIA || !ETH_TRUE #if ETH_PARANOIA || !ETH_TRUE
checkConsistency(); checkConsistency();
#endif #endif
@ -646,14 +667,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
if (!route.empty()) if (!route.empty())
noteCanonChanged(); noteCanonChanged();
if (isKnown(bi.hash()) && !details(bi.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
clog(BlockChainDebug) << "Block:" << bi;
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
}
h256s fresh; h256s fresh;
h256s dead; h256s dead;
bool isOld = true; bool isOld = true;

1
libethereum/ClientBase.h

@ -81,6 +81,7 @@ public:
/// Submits a new contract-creation transaction. /// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through). /// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override;
using Interface::submitTransaction;
/// Makes the given call. Nothing is recorded into the state. /// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override; virtual ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock, FudgeFactor _ff = FudgeFactor::Strict) override;

4
libethereum/Interface.h

@ -72,6 +72,10 @@ public:
/// @returns the new contract's address (assuming it all goes through). /// @returns the new contract's address (assuming it all goes through).
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0; virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0;
/// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through).
Address submitTransaction(Secret const& _secret, TransactionSkeleton const& _t) { if (_t.creation) return submitTransaction(_secret, _t.value, _t.data, _t.gas, _t.gasPrice); submitTransaction(_secret, _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); return Address(); }
/// Blocks until all pending transactions have been processed. /// Blocks until all pending transactions have been processed.
virtual void flushTransactions() = 0; virtual void flushTransactions() = 0;

14
libethereum/KeyManager.cpp

@ -28,6 +28,7 @@
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace eth;
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
KeyManager::KeyManager(std::string const& _keysFile): KeyManager::KeyManager(std::string const& _keysFile):
@ -151,9 +152,18 @@ void KeyManager::kill(Address const& _a)
m_store.kill(id); m_store.kill(id);
} }
std::map<Address, std::pair<std::string, std::string>> KeyManager::keys() const AddressHash KeyManager::accounts() const
{ {
std::map<Address, std::pair<std::string, std::string>> ret; AddressHash ret;
for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second) > 0)
ret.insert(i.first);
return ret;
}
std::unordered_map<Address, std::pair<std::string, std::string>> KeyManager::accountDetails() const
{
std::unordered_map<Address, std::pair<std::string, std::string>> ret;
for (auto const& i: m_addrLookup) for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second) > 0) if (m_keyInfo.count(i.second) > 0)
ret[i.first] = make_pair(m_keyInfo.at(i.second).info, m_passwordInfo.at(m_keyInfo.at(i.second).passHash)); ret[i.first] = make_pair(m_keyInfo.at(i.second).info, m_passwordInfo.at(m_keyInfo.at(i.second).passHash));

17
libethereum/KeyManager.h

@ -28,7 +28,8 @@
namespace dev namespace dev
{ {
namespace eth
{
class UnknownPassword: public Exception {}; class UnknownPassword: public Exception {};
struct KeyInfo struct KeyInfo
@ -65,7 +66,10 @@ public:
bool load(std::string const& _pass); bool load(std::string const& _pass);
void save(std::string const& _pass) const { write(_pass, m_keysFile); } void save(std::string const& _pass) const { write(_pass, m_keysFile); }
std::map<Address, std::pair<std::string, std::string>> keys() const; void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; }
AddressHash accounts() const;
std::unordered_map<Address, std::pair<std::string, std::string>> accountDetails() const;
h128 uuid(Address const& _a) const; h128 uuid(Address const& _a) const;
Address address(h128 const& _uuid) const; Address address(h128 const& _uuid) const;
@ -92,12 +96,12 @@ private:
void write(h128 const& _key, std::string const& _keysFile) const; void write(h128 const& _key, std::string const& _keysFile) const;
// Ethereum keys. // Ethereum keys.
std::map<Address, h128> m_addrLookup; std::unordered_map<Address, h128> m_addrLookup;
std::map<h128, KeyInfo> m_keyInfo; std::unordered_map<h128, KeyInfo> m_keyInfo;
std::map<h256, std::string> m_passwordInfo; std::unordered_map<h256, std::string> m_passwordInfo;
// Passwords that we're storing. // Passwords that we're storing.
mutable std::map<h256, std::string> m_cachedPasswords; mutable std::unordered_map<h256, std::string> m_cachedPasswords;
// The default password for keys in the keystore - protected by the master password. // The default password for keys in the keystore - protected by the master password.
std::string m_password; std::string m_password;
@ -108,3 +112,4 @@ private:
}; };
} }
}

1
libethereum/State.cpp

@ -707,6 +707,7 @@ void State::cleanup(bool _fullCommit)
{ {
if (_fullCommit) if (_fullCommit)
{ {
paranoia("immediately before database commit", true); paranoia("immediately before database commit", true);
// Commit the new trie to disk. // Commit the new trie to disk.

2
libethereum/State.h

@ -49,7 +49,7 @@ class BlockChain;
class State; class State;
struct StateChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct StateChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct StateTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; struct StateTrace: public LogChannel { static const char* name(); static const int verbosity = 5; };
struct StateDetail: public LogChannel { static const char* name(); static const int verbosity = 14; }; struct StateDetail: public LogChannel { static const char* name(); static const int verbosity = 14; };
struct StateSafeExceptions: public LogChannel { static const char* name(); static const int verbosity = 21; }; struct StateSafeExceptions: public LogChannel { static const char* name(); static const int verbosity = 21; };

2
libjsqrc/ethereumjs/bower.json

@ -1,7 +1,7 @@
{ {
"name": "web3", "name": "web3",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.3.3", "version": "0.3.6",
"description": "Ethereum Compatible JavaScript API", "description": "Ethereum Compatible JavaScript API",
"main": [ "main": [
"./dist/web3.js", "./dist/web3.js",

448
libjsqrc/ethereumjs/dist/web3-light.js

@ -22,118 +22,29 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ
* @date 2014 * @date 2014
*/ */
var utils = require('../utils/utils');
var coder = require('./coder'); var coder = require('./coder');
var solUtils = require('./utils'); var utils = require('./utils');
/**
* Formats input params to bytes
*
* @method formatInput
* @param {Array} abi inputs of method
* @param {Array} params that will be formatted to bytes
* @returns bytes representation of input params
*/
var formatInput = function (inputs, params) {
var i = inputs.map(function (input) {
return input.type;
});
return coder.encodeParams(i, params);
};
/**
* Formats output bytes back to param list
*
* @method formatOutput
* @param {Array} abi outputs of method
* @param {String} bytes represention of output
* @returns {Array} output params
*/
var formatOutput = function (outs, bytes) {
var o = outs.map(function (out) {
return out.type;
});
return coder.decodeParams(o, bytes);
};
/**
* Should be called to create input parser for contract with given abi
*
* @method inputParser
* @param {Array} contract abi
* @returns {Object} 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) {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
var params = Array.prototype.slice.call(arguments);
return formatInput(method.inputs, params);
};
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
parser[displayName][typeName] = impl;
});
return parser;
};
/**
* Should be called to create output parser for contract with given abi
*
* @method outputParser
* @param {Array} contract abi
* @returns {Object} output parser for given json abi
*/
var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
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;
};
var formatConstructorParams = function (abi, params) { var formatConstructorParams = function (abi, params) {
var constructor = solUtils.getConstructor(abi, params.length); var constructor = utils.getConstructor(abi, params.length);
if (!constructor) { if (!constructor) {
if (params.length > 0) { if (params.length > 0) {
console.warn("didn't found matching constructor, using default one"); console.warn("didn't found matching constructor, using default one");
} }
return ''; return '';
} }
return formatInput(constructor.inputs, params);
return coder.encodeParams(constructor.inputs.map(function (input) {
return input.type;
}), params);
}; };
module.exports = { module.exports = {
inputParser: inputParser,
outputParser: outputParser,
formatInput: formatInput,
formatOutput: formatOutput,
formatConstructorParams: formatConstructorParams formatConstructorParams: formatConstructorParams
}; };
},{"../utils/utils":8,"./coder":2,"./utils":5}],2:[function(require,module,exports){
},{"./coder":2,"./utils":5}],2:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -213,9 +124,8 @@ SolidityType.prototype.formatInput = function (param, arrayType) {
return param.map(function (p) { return param.map(function (p) {
return self._inputFormatter(p); return self._inputFormatter(p);
}).reduce(function (acc, current) { }).reduce(function (acc, current) {
acc.appendArrayElement(current); return acc.combine(current);
return acc; }, f.formatInputInt(param.length)).withOffset(32);
}, new SolidityParam('', f.formatInputInt(param.length).value));
} }
return this._inputFormatter(param); return this._inputFormatter(param);
}; };
@ -232,9 +142,9 @@ SolidityType.prototype.formatOutput = function (param, arrayType) {
if (arrayType) { if (arrayType) {
// let's assume, that we solidity will never return long arrays :P // let's assume, that we solidity will never return long arrays :P
var result = []; var result = [];
var length = new BigNumber(param.prefix, 16); var length = new BigNumber(param.dynamicPart().slice(0, 64), 16);
for (var i = 0; i < length * 64; i += 64) { for (var i = 0; i < length * 64; i += 64) {
result.push(this._outputFormatter(new SolidityParam(param.suffix.slice(i, i + 64)))); result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64))));
} }
return result; return result;
} }
@ -242,31 +152,21 @@ SolidityType.prototype.formatOutput = function (param, arrayType) {
}; };
/** /**
* Should be used to check if a type is variadic * Should be used to slice single param from bytes
* *
* @method isVariadicType * @method sliceParam
* @param {String} type * @param {String} bytes
* @returns {Bool} true if the type is variadic * @param {Number} index of param to slice
*/
SolidityType.prototype.isVariadicType = function (type) {
return isArrayType(type) || this._mode === 'bytes';
};
/**
* Should be used to shift param from params group
*
* @method shiftParam
* @param {String} type * @param {String} type
* @returns {SolidityParam} shifted param * @returns {SolidityParam} param
*/ */
SolidityType.prototype.shiftParam = function (type, param) { SolidityType.prototype.sliceParam = function (bytes, index, type) {
if (this._mode === 'bytes') { if (this._mode === 'bytes') {
return param.shiftBytes(); return SolidityParam.decodeBytes(bytes, index);
} else if (isArrayType(type)) { } else if (isArrayType(type)) {
var length = new BigNumber(param.prefix.slice(0, 64), 16); return SolidityParam.decodeArray(bytes, index);
return param.shiftArray(length);
} }
return param.shiftValue(); return SolidityParam.decodeParam(bytes, index);
}; };
/** /**
@ -296,28 +196,6 @@ SolidityCoder.prototype._requireType = function (type) {
return solidityType; return solidityType;
}; };
/**
* Should be used to transform plain bytes to SolidityParam object
*
* @method _bytesToParam
* @param {Array} types of params
* @param {String} bytes to be transformed to SolidityParam
* @return {SolidityParam} SolidityParam for this group of params
*/
SolidityCoder.prototype._bytesToParam = function (types, bytes) {
var self = this;
var prefixTypes = types.reduce(function (acc, type) {
return self._requireType(type).isVariadicType(type) ? acc + 1 : acc;
}, 0);
var valueTypes = types.length - prefixTypes;
var prefix = bytes.slice(0, prefixTypes * 64);
bytes = bytes.slice(prefixTypes * 64);
var value = bytes.slice(0, valueTypes * 64);
var suffix = bytes.slice(valueTypes * 64);
return new SolidityParam(value, prefix, suffix);
};
/** /**
* Should be used to transform plain param of given type to SolidityParam * Should be used to transform plain param of given type to SolidityParam
* *
@ -352,24 +230,11 @@ SolidityCoder.prototype.encodeParam = function (type, param) {
*/ */
SolidityCoder.prototype.encodeParams = function (types, params) { SolidityCoder.prototype.encodeParams = function (types, params) {
var self = this; var self = this;
return types.map(function (type, index) { var solidityParams = types.map(function (type, index) {
return self._formatInput(type, params[index]); return self._formatInput(type, params[index]);
}).reduce(function (acc, solidityParam) { });
acc.append(solidityParam);
return acc;
}, new SolidityParam()).encode();
};
/** return SolidityParam.encodeList(solidityParams);
* Should be used to transform SolidityParam to plain param
*
* @method _formatOutput
* @param {String} type
* @param {SolidityParam} param
* @return {Object} plain param
*/
SolidityCoder.prototype._formatOutput = function (type, param) {
return this._requireType(type).formatOutput(param, isArrayType(type));
}; };
/** /**
@ -381,7 +246,7 @@ SolidityCoder.prototype._formatOutput = function (type, param) {
* @return {Object} plain param * @return {Object} plain param
*/ */
SolidityCoder.prototype.decodeParam = function (type, bytes) { SolidityCoder.prototype.decodeParam = function (type, bytes) {
return this._formatOutput(type, this._bytesToParam([type], bytes)); return this.decodeParams([type], bytes)[0];
}; };
/** /**
@ -394,10 +259,9 @@ SolidityCoder.prototype.decodeParam = function (type, bytes) {
*/ */
SolidityCoder.prototype.decodeParams = function (types, bytes) { SolidityCoder.prototype.decodeParams = function (types, bytes) {
var self = this; var self = this;
var param = this._bytesToParam(types, bytes); return types.map(function (type, index) {
return types.map(function (type) {
var solidityType = self._requireType(type); var solidityType = self._requireType(type);
var p = solidityType.shiftParam(type, param); var p = solidityType.sliceParam(bytes, index, type);
return solidityType.formatOutput(p, isArrayType(type)); return solidityType.formatOutput(p, isArrayType(type));
}); });
}; };
@ -530,7 +394,7 @@ var formatInputBytes = function (value) {
*/ */
var formatInputDynamicBytes = function (value) { var formatInputDynamicBytes = function (value) {
var result = utils.fromAscii(value, c.ETH_PADDING).substr(2); var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);
return new SolidityParam('', formatInputInt(value.length).value, result); return new SolidityParam(formatInputInt(value.length).value + result, 32);
}; };
/** /**
@ -576,7 +440,7 @@ var signedIsNegative = function (value) {
* @returns {BigNumber} right-aligned output bytes formatted to big number * @returns {BigNumber} right-aligned output bytes formatted to big number
*/ */
var formatOutputInt = function (param) { var formatOutputInt = function (param) {
var value = param.value || "0"; var value = param.staticPart() || "0";
// check if it's negative number // check if it's negative number
// it it is, return two's complement // it it is, return two's complement
@ -594,7 +458,7 @@ var formatOutputInt = function (param) {
* @returns {BigNumeber} right-aligned output bytes formatted to uint * @returns {BigNumeber} right-aligned output bytes formatted to uint
*/ */
var formatOutputUInt = function (param) { var formatOutputUInt = function (param) {
var value = param.value || "0"; var value = param.staticPart() || "0";
return new BigNumber(value, 16); return new BigNumber(value, 16);
}; };
@ -628,7 +492,7 @@ var formatOutputUReal = function (param) {
* @returns {Boolean} right-aligned input bytes formatted to bool * @returns {Boolean} right-aligned input bytes formatted to bool
*/ */
var formatOutputBool = function (param) { var formatOutputBool = function (param) {
return param.value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
}; };
/** /**
@ -640,7 +504,7 @@ var formatOutputBool = function (param) {
*/ */
var formatOutputBytes = function (param) { var formatOutputBytes = function (param) {
// length might also be important! // length might also be important!
return utils.toAscii(param.value); return utils.toAscii(param.staticPart());
}; };
/** /**
@ -652,7 +516,7 @@ var formatOutputBytes = function (param) {
*/ */
var formatOutputDynamicBytes = function (param) { var formatOutputDynamicBytes = function (param) {
// length might also be important! // length might also be important!
return utils.toAscii(param.suffix); return utils.toAscii(param.dynamicPart().slice(64));
}; };
/** /**
@ -663,7 +527,7 @@ var formatOutputDynamicBytes = function (param) {
* @returns {String} address * @returns {String} address
*/ */
var formatOutputAddress = function (param) { var formatOutputAddress = function (param) {
var value = param.value; var value = param.staticPart();
return "0x" + value.slice(value.length - 40, value.length); return "0x" + value.slice(value.length - 40, value.length);
}; };
@ -707,91 +571,196 @@ module.exports = {
* @date 2015 * @date 2015
*/ */
var utils = require('../utils/utils');
/** /**
* SolidityParam object prototype. * SolidityParam object prototype.
* Should be used when encoding, decoding solidity bytes * Should be used when encoding, decoding solidity bytes
*/ */
var SolidityParam = function (value, prefix, suffix) { var SolidityParam = function (value, offset) {
this.prefix = prefix || '';
this.value = value || ''; this.value = value || '';
this.suffix = suffix || ''; this.offset = offset; // offset in bytes
};
/**
* This method should be used to get length of params's dynamic part
*
* @method dynamicPartLength
* @returns {Number} length of dynamic part (in bytes)
*/
SolidityParam.prototype.dynamicPartLength = function () {
return this.dynamicPart().length / 2;
};
/**
* This method should be used to create copy of solidity param with different offset
*
* @method withOffset
* @param {Number} offset length in bytes
* @returns {SolidityParam} new solidity param with applied offset
*/
SolidityParam.prototype.withOffset = function (offset) {
return new SolidityParam(this.value, offset);
}; };
/** /**
* This method should be used to encode two params one after another * This method should be used to combine solidity params together
* eg. when appending an array
* *
* @method append * @method combine
* @param {SolidityParam} param that it appended after this * @param {SolidityParam} param with which we should combine
* @param {SolidityParam} result of combination
*/ */
SolidityParam.prototype.append = function (param) { SolidityParam.prototype.combine = function (param) {
this.prefix += param.prefix; return new SolidityParam(this.value + param.value);
this.value += param.value;
this.suffix += param.suffix;
}; };
/** /**
* This method should be used to encode next param in an array * This method should be called to check if param has dynamic size.
* If it has, it returns true, otherwise false
* *
* @method appendArrayElement * @method isDynamic
* @param {SolidityParam} param that is appended to an array * @returns {Boolean}
*/ */
SolidityParam.prototype.appendArrayElement = function (param) { SolidityParam.prototype.isDynamic = function () {
this.suffix += param.value; return this.value.length > 64;
this.prefix += param.prefix;
// TODO: suffix not supported = it's required for nested arrays;
}; };
/** /**
* This method should be used to create bytearrays from param * This method should be called to transform offset to bytes
*
* @method offsetAsBytes
* @returns {String} bytes representation of offset
*/
SolidityParam.prototype.offsetAsBytes = function () {
return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset).toString(16), 64);
};
/**
* This method should be called to get static part of param
*
* @method staticPart
* @returns {String} offset if it is a dynamic param, otherwise value
*/
SolidityParam.prototype.staticPart = function () {
if (!this.isDynamic()) {
return this.value;
}
return this.offsetAsBytes();
};
/**
* This method should be called to get dynamic part of param
*
* @method dynamicPart
* @returns {String} returns a value if it is a dynamic param, otherwise empty string
*/
SolidityParam.prototype.dynamicPart = function () {
return this.isDynamic() ? this.value : '';
};
/**
* This method should be called to encode param
* *
* @method encode * @method encode
* @return {String} encoded param(s) * @returns {String}
*/ */
SolidityParam.prototype.encode = function () { SolidityParam.prototype.encode = function () {
return this.prefix + this.value + this.suffix; return this.staticPart() + this.dynamicPart();
}; };
/** /**
* This method should be used to shift first param from group of params * This method should be called to encode array of params
* *
* @method shiftValue * @method encodeList
* @return {SolidityParam} first value param * @param {Array[SolidityParam]} params
* @returns {String}
*/ */
SolidityParam.prototype.shiftValue = function () { SolidityParam.encodeList = function (params) {
var value = this.value.slice(0, 64);
this.value = this.value.slice(64); // updating offsets
return new SolidityParam(value); var totalOffset = params.length * 32;
var offsetParams = params.map(function (param) {
if (!param.isDynamic()) {
return param;
}
var offset = totalOffset;
totalOffset += param.dynamicPartLength();
return param.withOffset(offset);
});
// encode everything!
return offsetParams.reduce(function (result, param) {
return result + param.dynamicPart();
}, offsetParams.reduce(function (result, param) {
return result + param.staticPart();
}, ''));
}; };
/** /**
* This method should be used to first bytes param from group of params * This method should be used to decode plain (static) solidity param at given index
* *
* @method shiftBytes * @method decodeParam
* @return {SolidityParam} first bytes param * @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/ */
SolidityParam.prototype.shiftBytes = function () { SolidityParam.decodeParam = function (bytes, index) {
return this.shiftArray(1); index = index || 0;
return new SolidityParam(bytes.substr(index * 64, 64));
}; };
/** /**
* This method should be used to shift an array from group of params * This method should be called to get offset value from bytes at given index
* *
* @method shiftArray * @method getOffset
* @param {Number} size of an array to shift * @param {String} bytes
* @return {SolidityParam} first array param * @param {Number} index
* @returns {Number} offset as number
*/
var getOffset = function (bytes, index) {
// we can do this cause offset is rather small
return parseInt('0x' + bytes.substr(index * 64, 64));
};
/**
* This method should be called to decode solidity bytes param at given index
*
* @method decodeBytes
* @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/
SolidityParam.decodeBytes = function (bytes, index) {
index = index || 0;
//TODO add support for strings longer than 32 bytes
//var length = parseInt('0x' + bytes.substr(offset * 64, 64));
var offset = getOffset(bytes, index);
// 2 * , cause we also parse length
return new SolidityParam(bytes.substr(offset * 2, 2 * 64));
};
/**
* This method should be used to decode solidity array at given index
*
* @method decodeArray
* @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/ */
SolidityParam.prototype.shiftArray = function (length) { SolidityParam.decodeArray = function (bytes, index) {
var prefix = this.prefix.slice(0, 64); index = index || 0;
this.prefix = this.value.slice(64); var offset = getOffset(bytes, index);
var suffix = this.suffix.slice(0, 64 * length); var length = parseInt('0x' + bytes.substr(offset * 2, 64));
this.suffix = this.suffix.slice(64 * length); return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64));
return new SolidityParam('', prefix, suffix);
}; };
module.exports = SolidityParam; module.exports = SolidityParam;
},{}],5:[function(require,module,exports){ },{"../utils/utils":8}],5:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -828,6 +797,11 @@ var getConstructor = function (abi, numberOfArgs) {
})[0]; })[0];
}; };
//var getSupremeType = function (type) {
//return type.substr(0, type.indexOf('[')) + ']';
//};
module.exports = { module.exports = {
getConstructor: getConstructor getConstructor: getConstructor
}; };
@ -1394,7 +1368,7 @@ module.exports = {
},{"bignumber.js":"bignumber.js"}],9:[function(require,module,exports){ },{"bignumber.js":"bignumber.js"}],9:[function(require,module,exports){
module.exports={ module.exports={
"version": "0.3.3" "version": "0.3.6"
} }
},{}],10:[function(require,module,exports){ },{}],10:[function(require,module,exports){
@ -1796,7 +1770,7 @@ module.exports = {
/** /**
* Web3 * Web3
* *
* @module web3 * @module web3
*/ */
@ -1850,16 +1824,16 @@ var uncleCountCall = function (args) {
/// @returns an array of objects describing web3.eth api methods /// @returns an array of objects describing web3.eth api methods
var getBalance = new Method({ var getBalance = new Method({
name: 'getBalance', name: 'getBalance',
call: 'eth_getBalance', call: 'eth_getBalance',
params: 2, params: 2,
inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],
outputFormatter: formatters.outputBigNumberFormatter outputFormatter: formatters.outputBigNumberFormatter
}); });
var getStorageAt = new Method({ var getStorageAt = new Method({
name: 'getStorageAt', name: 'getStorageAt',
call: 'eth_getStorageAt', call: 'eth_getStorageAt',
params: 3, params: 3,
inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]
}); });
@ -1872,7 +1846,7 @@ var getCode = new Method({
}); });
var getBlock = new Method({ var getBlock = new Method({
name: 'getBlock', name: 'getBlock',
call: blockCall, call: blockCall,
params: 2, params: 2,
inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }], inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],
@ -1997,6 +1971,11 @@ var properties = [
name: 'mining', name: 'mining',
getter: 'eth_mining' getter: 'eth_mining'
}), }),
new Property({
name: 'hashrate',
getter: 'eth_hashrate',
outputFormatter: utils.toDecimal
}),
new Property({ new Property({
name: 'gasPrice', name: 'gasPrice',
getter: 'eth_gasPrice', getter: 'eth_gasPrice',
@ -2118,7 +2097,7 @@ SolidityEvent.prototype.encode = function (indexed, options) {
['fromBlock', 'toBlock'].filter(function (f) { ['fromBlock', 'toBlock'].filter(function (f) {
return options[f] !== undefined; return options[f] !== undefined;
}).forEach(function (f) { }).forEach(function (f) {
result[f] = utils.toHex(options[f]); result[f] = formatters.inputBlockNumberFormatter(options[f]);
}); });
result.topics = []; result.topics = [];
@ -2447,7 +2426,7 @@ var inputTransactionFormatter = function (options){
delete options.code; delete options.code;
} }
['gasPrice', 'gas', 'value'].filter(function (key) { ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
return options[key] !== undefined; return options[key] !== undefined;
}).forEach(function(key){ }).forEach(function(key){
options[key] = utils.fromDecimal(options[key]); options[key] = utils.fromDecimal(options[key]);
@ -2796,15 +2775,32 @@ HttpProvider.prototype.send = function (payload) {
//if (request.status !== 200) { //if (request.status !== 200) {
//return; //return;
//} //}
return JSON.parse(request.responseText);
var result = request.responseText;
try {
result = JSON.parse(result);
} catch(e) {
throw errors.InvalidResponse(result);
}
return result;
}; };
HttpProvider.prototype.sendAsync = function (payload, callback) { HttpProvider.prototype.sendAsync = function (payload, callback) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.onreadystatechange = function() { request.onreadystatechange = function() {
if (request.readyState === 4) { if (request.readyState === 4) {
// TODO: handle the error properly here!!! var result = request.responseText;
callback(null, JSON.parse(request.responseText)); var error = null;
try {
result = JSON.parse(result);
} catch(e) {
error = errors.InvalidResponse(result);
}
callback(error, result);
} }
}; };

22
libjsqrc/ethereumjs/dist/web3-light.js.map

File diff suppressed because one or more lines are too long

4
libjsqrc/ethereumjs/dist/web3-light.min.js

File diff suppressed because one or more lines are too long

448
libjsqrc/ethereumjs/dist/web3.js

@ -22,118 +22,29 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ
* @date 2014 * @date 2014
*/ */
var utils = require('../utils/utils');
var coder = require('./coder'); var coder = require('./coder');
var solUtils = require('./utils'); var utils = require('./utils');
/**
* Formats input params to bytes
*
* @method formatInput
* @param {Array} abi inputs of method
* @param {Array} params that will be formatted to bytes
* @returns bytes representation of input params
*/
var formatInput = function (inputs, params) {
var i = inputs.map(function (input) {
return input.type;
});
return coder.encodeParams(i, params);
};
/**
* Formats output bytes back to param list
*
* @method formatOutput
* @param {Array} abi outputs of method
* @param {String} bytes represention of output
* @returns {Array} output params
*/
var formatOutput = function (outs, bytes) {
var o = outs.map(function (out) {
return out.type;
});
return coder.decodeParams(o, bytes);
};
/**
* Should be called to create input parser for contract with given abi
*
* @method inputParser
* @param {Array} contract abi
* @returns {Object} 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) {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
var params = Array.prototype.slice.call(arguments);
return formatInput(method.inputs, params);
};
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
parser[displayName][typeName] = impl;
});
return parser;
};
/**
* Should be called to create output parser for contract with given abi
*
* @method outputParser
* @param {Array} contract abi
* @returns {Object} output parser for given json abi
*/
var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
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;
};
var formatConstructorParams = function (abi, params) { var formatConstructorParams = function (abi, params) {
var constructor = solUtils.getConstructor(abi, params.length); var constructor = utils.getConstructor(abi, params.length);
if (!constructor) { if (!constructor) {
if (params.length > 0) { if (params.length > 0) {
console.warn("didn't found matching constructor, using default one"); console.warn("didn't found matching constructor, using default one");
} }
return ''; return '';
} }
return formatInput(constructor.inputs, params);
return coder.encodeParams(constructor.inputs.map(function (input) {
return input.type;
}), params);
}; };
module.exports = { module.exports = {
inputParser: inputParser,
outputParser: outputParser,
formatInput: formatInput,
formatOutput: formatOutput,
formatConstructorParams: formatConstructorParams formatConstructorParams: formatConstructorParams
}; };
},{"../utils/utils":8,"./coder":2,"./utils":5}],2:[function(require,module,exports){
},{"./coder":2,"./utils":5}],2:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -213,9 +124,8 @@ SolidityType.prototype.formatInput = function (param, arrayType) {
return param.map(function (p) { return param.map(function (p) {
return self._inputFormatter(p); return self._inputFormatter(p);
}).reduce(function (acc, current) { }).reduce(function (acc, current) {
acc.appendArrayElement(current); return acc.combine(current);
return acc; }, f.formatInputInt(param.length)).withOffset(32);
}, new SolidityParam('', f.formatInputInt(param.length).value));
} }
return this._inputFormatter(param); return this._inputFormatter(param);
}; };
@ -232,9 +142,9 @@ SolidityType.prototype.formatOutput = function (param, arrayType) {
if (arrayType) { if (arrayType) {
// let's assume, that we solidity will never return long arrays :P // let's assume, that we solidity will never return long arrays :P
var result = []; var result = [];
var length = new BigNumber(param.prefix, 16); var length = new BigNumber(param.dynamicPart().slice(0, 64), 16);
for (var i = 0; i < length * 64; i += 64) { for (var i = 0; i < length * 64; i += 64) {
result.push(this._outputFormatter(new SolidityParam(param.suffix.slice(i, i + 64)))); result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64))));
} }
return result; return result;
} }
@ -242,31 +152,21 @@ SolidityType.prototype.formatOutput = function (param, arrayType) {
}; };
/** /**
* Should be used to check if a type is variadic * Should be used to slice single param from bytes
* *
* @method isVariadicType * @method sliceParam
* @param {String} type * @param {String} bytes
* @returns {Bool} true if the type is variadic * @param {Number} index of param to slice
*/
SolidityType.prototype.isVariadicType = function (type) {
return isArrayType(type) || this._mode === 'bytes';
};
/**
* Should be used to shift param from params group
*
* @method shiftParam
* @param {String} type * @param {String} type
* @returns {SolidityParam} shifted param * @returns {SolidityParam} param
*/ */
SolidityType.prototype.shiftParam = function (type, param) { SolidityType.prototype.sliceParam = function (bytes, index, type) {
if (this._mode === 'bytes') { if (this._mode === 'bytes') {
return param.shiftBytes(); return SolidityParam.decodeBytes(bytes, index);
} else if (isArrayType(type)) { } else if (isArrayType(type)) {
var length = new BigNumber(param.prefix.slice(0, 64), 16); return SolidityParam.decodeArray(bytes, index);
return param.shiftArray(length);
} }
return param.shiftValue(); return SolidityParam.decodeParam(bytes, index);
}; };
/** /**
@ -296,28 +196,6 @@ SolidityCoder.prototype._requireType = function (type) {
return solidityType; return solidityType;
}; };
/**
* Should be used to transform plain bytes to SolidityParam object
*
* @method _bytesToParam
* @param {Array} types of params
* @param {String} bytes to be transformed to SolidityParam
* @return {SolidityParam} SolidityParam for this group of params
*/
SolidityCoder.prototype._bytesToParam = function (types, bytes) {
var self = this;
var prefixTypes = types.reduce(function (acc, type) {
return self._requireType(type).isVariadicType(type) ? acc + 1 : acc;
}, 0);
var valueTypes = types.length - prefixTypes;
var prefix = bytes.slice(0, prefixTypes * 64);
bytes = bytes.slice(prefixTypes * 64);
var value = bytes.slice(0, valueTypes * 64);
var suffix = bytes.slice(valueTypes * 64);
return new SolidityParam(value, prefix, suffix);
};
/** /**
* Should be used to transform plain param of given type to SolidityParam * Should be used to transform plain param of given type to SolidityParam
* *
@ -352,24 +230,11 @@ SolidityCoder.prototype.encodeParam = function (type, param) {
*/ */
SolidityCoder.prototype.encodeParams = function (types, params) { SolidityCoder.prototype.encodeParams = function (types, params) {
var self = this; var self = this;
return types.map(function (type, index) { var solidityParams = types.map(function (type, index) {
return self._formatInput(type, params[index]); return self._formatInput(type, params[index]);
}).reduce(function (acc, solidityParam) { });
acc.append(solidityParam);
return acc;
}, new SolidityParam()).encode();
};
/** return SolidityParam.encodeList(solidityParams);
* Should be used to transform SolidityParam to plain param
*
* @method _formatOutput
* @param {String} type
* @param {SolidityParam} param
* @return {Object} plain param
*/
SolidityCoder.prototype._formatOutput = function (type, param) {
return this._requireType(type).formatOutput(param, isArrayType(type));
}; };
/** /**
@ -381,7 +246,7 @@ SolidityCoder.prototype._formatOutput = function (type, param) {
* @return {Object} plain param * @return {Object} plain param
*/ */
SolidityCoder.prototype.decodeParam = function (type, bytes) { SolidityCoder.prototype.decodeParam = function (type, bytes) {
return this._formatOutput(type, this._bytesToParam([type], bytes)); return this.decodeParams([type], bytes)[0];
}; };
/** /**
@ -394,10 +259,9 @@ SolidityCoder.prototype.decodeParam = function (type, bytes) {
*/ */
SolidityCoder.prototype.decodeParams = function (types, bytes) { SolidityCoder.prototype.decodeParams = function (types, bytes) {
var self = this; var self = this;
var param = this._bytesToParam(types, bytes); return types.map(function (type, index) {
return types.map(function (type) {
var solidityType = self._requireType(type); var solidityType = self._requireType(type);
var p = solidityType.shiftParam(type, param); var p = solidityType.sliceParam(bytes, index, type);
return solidityType.formatOutput(p, isArrayType(type)); return solidityType.formatOutput(p, isArrayType(type));
}); });
}; };
@ -530,7 +394,7 @@ var formatInputBytes = function (value) {
*/ */
var formatInputDynamicBytes = function (value) { var formatInputDynamicBytes = function (value) {
var result = utils.fromAscii(value, c.ETH_PADDING).substr(2); var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);
return new SolidityParam('', formatInputInt(value.length).value, result); return new SolidityParam(formatInputInt(value.length).value + result, 32);
}; };
/** /**
@ -576,7 +440,7 @@ var signedIsNegative = function (value) {
* @returns {BigNumber} right-aligned output bytes formatted to big number * @returns {BigNumber} right-aligned output bytes formatted to big number
*/ */
var formatOutputInt = function (param) { var formatOutputInt = function (param) {
var value = param.value || "0"; var value = param.staticPart() || "0";
// check if it's negative number // check if it's negative number
// it it is, return two's complement // it it is, return two's complement
@ -594,7 +458,7 @@ var formatOutputInt = function (param) {
* @returns {BigNumeber} right-aligned output bytes formatted to uint * @returns {BigNumeber} right-aligned output bytes formatted to uint
*/ */
var formatOutputUInt = function (param) { var formatOutputUInt = function (param) {
var value = param.value || "0"; var value = param.staticPart() || "0";
return new BigNumber(value, 16); return new BigNumber(value, 16);
}; };
@ -628,7 +492,7 @@ var formatOutputUReal = function (param) {
* @returns {Boolean} right-aligned input bytes formatted to bool * @returns {Boolean} right-aligned input bytes formatted to bool
*/ */
var formatOutputBool = function (param) { var formatOutputBool = function (param) {
return param.value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
}; };
/** /**
@ -640,7 +504,7 @@ var formatOutputBool = function (param) {
*/ */
var formatOutputBytes = function (param) { var formatOutputBytes = function (param) {
// length might also be important! // length might also be important!
return utils.toAscii(param.value); return utils.toAscii(param.staticPart());
}; };
/** /**
@ -652,7 +516,7 @@ var formatOutputBytes = function (param) {
*/ */
var formatOutputDynamicBytes = function (param) { var formatOutputDynamicBytes = function (param) {
// length might also be important! // length might also be important!
return utils.toAscii(param.suffix); return utils.toAscii(param.dynamicPart().slice(64));
}; };
/** /**
@ -663,7 +527,7 @@ var formatOutputDynamicBytes = function (param) {
* @returns {String} address * @returns {String} address
*/ */
var formatOutputAddress = function (param) { var formatOutputAddress = function (param) {
var value = param.value; var value = param.staticPart();
return "0x" + value.slice(value.length - 40, value.length); return "0x" + value.slice(value.length - 40, value.length);
}; };
@ -707,91 +571,196 @@ module.exports = {
* @date 2015 * @date 2015
*/ */
var utils = require('../utils/utils');
/** /**
* SolidityParam object prototype. * SolidityParam object prototype.
* Should be used when encoding, decoding solidity bytes * Should be used when encoding, decoding solidity bytes
*/ */
var SolidityParam = function (value, prefix, suffix) { var SolidityParam = function (value, offset) {
this.prefix = prefix || '';
this.value = value || ''; this.value = value || '';
this.suffix = suffix || ''; this.offset = offset; // offset in bytes
};
/**
* This method should be used to get length of params's dynamic part
*
* @method dynamicPartLength
* @returns {Number} length of dynamic part (in bytes)
*/
SolidityParam.prototype.dynamicPartLength = function () {
return this.dynamicPart().length / 2;
};
/**
* This method should be used to create copy of solidity param with different offset
*
* @method withOffset
* @param {Number} offset length in bytes
* @returns {SolidityParam} new solidity param with applied offset
*/
SolidityParam.prototype.withOffset = function (offset) {
return new SolidityParam(this.value, offset);
}; };
/** /**
* This method should be used to encode two params one after another * This method should be used to combine solidity params together
* eg. when appending an array
* *
* @method append * @method combine
* @param {SolidityParam} param that it appended after this * @param {SolidityParam} param with which we should combine
* @param {SolidityParam} result of combination
*/ */
SolidityParam.prototype.append = function (param) { SolidityParam.prototype.combine = function (param) {
this.prefix += param.prefix; return new SolidityParam(this.value + param.value);
this.value += param.value;
this.suffix += param.suffix;
}; };
/** /**
* This method should be used to encode next param in an array * This method should be called to check if param has dynamic size.
* If it has, it returns true, otherwise false
* *
* @method appendArrayElement * @method isDynamic
* @param {SolidityParam} param that is appended to an array * @returns {Boolean}
*/ */
SolidityParam.prototype.appendArrayElement = function (param) { SolidityParam.prototype.isDynamic = function () {
this.suffix += param.value; return this.value.length > 64;
this.prefix += param.prefix;
// TODO: suffix not supported = it's required for nested arrays;
}; };
/** /**
* This method should be used to create bytearrays from param * This method should be called to transform offset to bytes
*
* @method offsetAsBytes
* @returns {String} bytes representation of offset
*/
SolidityParam.prototype.offsetAsBytes = function () {
return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset).toString(16), 64);
};
/**
* This method should be called to get static part of param
*
* @method staticPart
* @returns {String} offset if it is a dynamic param, otherwise value
*/
SolidityParam.prototype.staticPart = function () {
if (!this.isDynamic()) {
return this.value;
}
return this.offsetAsBytes();
};
/**
* This method should be called to get dynamic part of param
*
* @method dynamicPart
* @returns {String} returns a value if it is a dynamic param, otherwise empty string
*/
SolidityParam.prototype.dynamicPart = function () {
return this.isDynamic() ? this.value : '';
};
/**
* This method should be called to encode param
* *
* @method encode * @method encode
* @return {String} encoded param(s) * @returns {String}
*/ */
SolidityParam.prototype.encode = function () { SolidityParam.prototype.encode = function () {
return this.prefix + this.value + this.suffix; return this.staticPart() + this.dynamicPart();
}; };
/** /**
* This method should be used to shift first param from group of params * This method should be called to encode array of params
* *
* @method shiftValue * @method encodeList
* @return {SolidityParam} first value param * @param {Array[SolidityParam]} params
* @returns {String}
*/ */
SolidityParam.prototype.shiftValue = function () { SolidityParam.encodeList = function (params) {
var value = this.value.slice(0, 64);
this.value = this.value.slice(64); // updating offsets
return new SolidityParam(value); var totalOffset = params.length * 32;
var offsetParams = params.map(function (param) {
if (!param.isDynamic()) {
return param;
}
var offset = totalOffset;
totalOffset += param.dynamicPartLength();
return param.withOffset(offset);
});
// encode everything!
return offsetParams.reduce(function (result, param) {
return result + param.dynamicPart();
}, offsetParams.reduce(function (result, param) {
return result + param.staticPart();
}, ''));
}; };
/** /**
* This method should be used to first bytes param from group of params * This method should be used to decode plain (static) solidity param at given index
* *
* @method shiftBytes * @method decodeParam
* @return {SolidityParam} first bytes param * @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/ */
SolidityParam.prototype.shiftBytes = function () { SolidityParam.decodeParam = function (bytes, index) {
return this.shiftArray(1); index = index || 0;
return new SolidityParam(bytes.substr(index * 64, 64));
}; };
/** /**
* This method should be used to shift an array from group of params * This method should be called to get offset value from bytes at given index
* *
* @method shiftArray * @method getOffset
* @param {Number} size of an array to shift * @param {String} bytes
* @return {SolidityParam} first array param * @param {Number} index
* @returns {Number} offset as number
*/
var getOffset = function (bytes, index) {
// we can do this cause offset is rather small
return parseInt('0x' + bytes.substr(index * 64, 64));
};
/**
* This method should be called to decode solidity bytes param at given index
*
* @method decodeBytes
* @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/
SolidityParam.decodeBytes = function (bytes, index) {
index = index || 0;
//TODO add support for strings longer than 32 bytes
//var length = parseInt('0x' + bytes.substr(offset * 64, 64));
var offset = getOffset(bytes, index);
// 2 * , cause we also parse length
return new SolidityParam(bytes.substr(offset * 2, 2 * 64));
};
/**
* This method should be used to decode solidity array at given index
*
* @method decodeArray
* @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/ */
SolidityParam.prototype.shiftArray = function (length) { SolidityParam.decodeArray = function (bytes, index) {
var prefix = this.prefix.slice(0, 64); index = index || 0;
this.prefix = this.value.slice(64); var offset = getOffset(bytes, index);
var suffix = this.suffix.slice(0, 64 * length); var length = parseInt('0x' + bytes.substr(offset * 2, 64));
this.suffix = this.suffix.slice(64 * length); return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64));
return new SolidityParam('', prefix, suffix);
}; };
module.exports = SolidityParam; module.exports = SolidityParam;
},{}],5:[function(require,module,exports){ },{"../utils/utils":8}],5:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -828,6 +797,11 @@ var getConstructor = function (abi, numberOfArgs) {
})[0]; })[0];
}; };
//var getSupremeType = function (type) {
//return type.substr(0, type.indexOf('[')) + ']';
//};
module.exports = { module.exports = {
getConstructor: getConstructor getConstructor: getConstructor
}; };
@ -1394,7 +1368,7 @@ module.exports = {
},{"bignumber.js":"bignumber.js"}],9:[function(require,module,exports){ },{"bignumber.js":"bignumber.js"}],9:[function(require,module,exports){
module.exports={ module.exports={
"version": "0.3.3" "version": "0.3.6"
} }
},{}],10:[function(require,module,exports){ },{}],10:[function(require,module,exports){
@ -1796,7 +1770,7 @@ module.exports = {
/** /**
* Web3 * Web3
* *
* @module web3 * @module web3
*/ */
@ -1850,16 +1824,16 @@ var uncleCountCall = function (args) {
/// @returns an array of objects describing web3.eth api methods /// @returns an array of objects describing web3.eth api methods
var getBalance = new Method({ var getBalance = new Method({
name: 'getBalance', name: 'getBalance',
call: 'eth_getBalance', call: 'eth_getBalance',
params: 2, params: 2,
inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],
outputFormatter: formatters.outputBigNumberFormatter outputFormatter: formatters.outputBigNumberFormatter
}); });
var getStorageAt = new Method({ var getStorageAt = new Method({
name: 'getStorageAt', name: 'getStorageAt',
call: 'eth_getStorageAt', call: 'eth_getStorageAt',
params: 3, params: 3,
inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]
}); });
@ -1872,7 +1846,7 @@ var getCode = new Method({
}); });
var getBlock = new Method({ var getBlock = new Method({
name: 'getBlock', name: 'getBlock',
call: blockCall, call: blockCall,
params: 2, params: 2,
inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }], inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],
@ -1997,6 +1971,11 @@ var properties = [
name: 'mining', name: 'mining',
getter: 'eth_mining' getter: 'eth_mining'
}), }),
new Property({
name: 'hashrate',
getter: 'eth_hashrate',
outputFormatter: utils.toDecimal
}),
new Property({ new Property({
name: 'gasPrice', name: 'gasPrice',
getter: 'eth_gasPrice', getter: 'eth_gasPrice',
@ -2118,7 +2097,7 @@ SolidityEvent.prototype.encode = function (indexed, options) {
['fromBlock', 'toBlock'].filter(function (f) { ['fromBlock', 'toBlock'].filter(function (f) {
return options[f] !== undefined; return options[f] !== undefined;
}).forEach(function (f) { }).forEach(function (f) {
result[f] = utils.toHex(options[f]); result[f] = formatters.inputBlockNumberFormatter(options[f]);
}); });
result.topics = []; result.topics = [];
@ -2447,7 +2426,7 @@ var inputTransactionFormatter = function (options){
delete options.code; delete options.code;
} }
['gasPrice', 'gas', 'value'].filter(function (key) { ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
return options[key] !== undefined; return options[key] !== undefined;
}).forEach(function(key){ }).forEach(function(key){
options[key] = utils.fromDecimal(options[key]); options[key] = utils.fromDecimal(options[key]);
@ -2796,15 +2775,32 @@ HttpProvider.prototype.send = function (payload) {
//if (request.status !== 200) { //if (request.status !== 200) {
//return; //return;
//} //}
return JSON.parse(request.responseText);
var result = request.responseText;
try {
result = JSON.parse(result);
} catch(e) {
throw errors.InvalidResponse(result);
}
return result;
}; };
HttpProvider.prototype.sendAsync = function (payload, callback) { HttpProvider.prototype.sendAsync = function (payload, callback) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.onreadystatechange = function() { request.onreadystatechange = function() {
if (request.readyState === 4) { if (request.readyState === 4) {
// TODO: handle the error properly here!!! var result = request.responseText;
callback(null, JSON.parse(request.responseText)); var error = null;
try {
result = JSON.parse(result);
} catch(e) {
error = errors.InvalidResponse(result);
}
callback(error, result);
} }
}; };

22
libjsqrc/ethereumjs/dist/web3.js.map

File diff suppressed because one or more lines are too long

4
libjsqrc/ethereumjs/dist/web3.min.js

File diff suppressed because one or more lines are too long

2
libjsqrc/ethereumjs/example/event_inc.html

@ -45,7 +45,7 @@
var contract; var contract;
var update = function (err, x) { var update = function (err, x) {
document.getElementById('result').innerText = JSON.stringify(x, null, 2); document.getElementById('result').textContent = JSON.stringify(x, null, 2);
}; };
var createContract = function () { var createContract = function () {

103
libjsqrc/ethereumjs/lib/solidity/abi.js

@ -21,113 +21,24 @@
* @date 2014 * @date 2014
*/ */
var utils = require('../utils/utils');
var coder = require('./coder'); var coder = require('./coder');
var solUtils = require('./utils'); var utils = require('./utils');
/**
* Formats input params to bytes
*
* @method formatInput
* @param {Array} abi inputs of method
* @param {Array} params that will be formatted to bytes
* @returns bytes representation of input params
*/
var formatInput = function (inputs, params) {
var i = inputs.map(function (input) {
return input.type;
});
return coder.encodeParams(i, params);
};
/**
* Formats output bytes back to param list
*
* @method formatOutput
* @param {Array} abi outputs of method
* @param {String} bytes represention of output
* @returns {Array} output params
*/
var formatOutput = function (outs, bytes) {
var o = outs.map(function (out) {
return out.type;
});
return coder.decodeParams(o, bytes);
};
/**
* Should be called to create input parser for contract with given abi
*
* @method inputParser
* @param {Array} contract abi
* @returns {Object} 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) {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
var params = Array.prototype.slice.call(arguments);
return formatInput(method.inputs, params);
};
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
parser[displayName][typeName] = impl;
});
return parser;
};
/**
* Should be called to create output parser for contract with given abi
*
* @method outputParser
* @param {Array} contract abi
* @returns {Object} output parser for given json abi
*/
var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
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;
};
var formatConstructorParams = function (abi, params) { var formatConstructorParams = function (abi, params) {
var constructor = solUtils.getConstructor(abi, params.length); var constructor = utils.getConstructor(abi, params.length);
if (!constructor) { if (!constructor) {
if (params.length > 0) { if (params.length > 0) {
console.warn("didn't found matching constructor, using default one"); console.warn("didn't found matching constructor, using default one");
} }
return ''; return '';
} }
return formatInput(constructor.inputs, params);
return coder.encodeParams(constructor.inputs.map(function (input) {
return input.type;
}), params);
}; };
module.exports = { module.exports = {
inputParser: inputParser,
outputParser: outputParser,
formatInput: formatInput,
formatOutput: formatOutput,
formatConstructorParams: formatConstructorParams formatConstructorParams: formatConstructorParams
}; };

85
libjsqrc/ethereumjs/lib/solidity/coder.js

@ -77,9 +77,8 @@ SolidityType.prototype.formatInput = function (param, arrayType) {
return param.map(function (p) { return param.map(function (p) {
return self._inputFormatter(p); return self._inputFormatter(p);
}).reduce(function (acc, current) { }).reduce(function (acc, current) {
acc.appendArrayElement(current); return acc.combine(current);
return acc; }, f.formatInputInt(param.length)).withOffset(32);
}, new SolidityParam('', f.formatInputInt(param.length).value));
} }
return this._inputFormatter(param); return this._inputFormatter(param);
}; };
@ -96,9 +95,9 @@ SolidityType.prototype.formatOutput = function (param, arrayType) {
if (arrayType) { if (arrayType) {
// let's assume, that we solidity will never return long arrays :P // let's assume, that we solidity will never return long arrays :P
var result = []; var result = [];
var length = new BigNumber(param.prefix, 16); var length = new BigNumber(param.dynamicPart().slice(0, 64), 16);
for (var i = 0; i < length * 64; i += 64) { for (var i = 0; i < length * 64; i += 64) {
result.push(this._outputFormatter(new SolidityParam(param.suffix.slice(i, i + 64)))); result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64))));
} }
return result; return result;
} }
@ -106,31 +105,21 @@ SolidityType.prototype.formatOutput = function (param, arrayType) {
}; };
/** /**
* Should be used to check if a type is variadic * Should be used to slice single param from bytes
* *
* @method isVariadicType * @method sliceParam
* @param {String} type * @param {String} bytes
* @returns {Bool} true if the type is variadic * @param {Number} index of param to slice
*/
SolidityType.prototype.isVariadicType = function (type) {
return isArrayType(type) || this._mode === 'bytes';
};
/**
* Should be used to shift param from params group
*
* @method shiftParam
* @param {String} type * @param {String} type
* @returns {SolidityParam} shifted param * @returns {SolidityParam} param
*/ */
SolidityType.prototype.shiftParam = function (type, param) { SolidityType.prototype.sliceParam = function (bytes, index, type) {
if (this._mode === 'bytes') { if (this._mode === 'bytes') {
return param.shiftBytes(); return SolidityParam.decodeBytes(bytes, index);
} else if (isArrayType(type)) { } else if (isArrayType(type)) {
var length = new BigNumber(param.prefix.slice(0, 64), 16); return SolidityParam.decodeArray(bytes, index);
return param.shiftArray(length);
} }
return param.shiftValue(); return SolidityParam.decodeParam(bytes, index);
}; };
/** /**
@ -160,28 +149,6 @@ SolidityCoder.prototype._requireType = function (type) {
return solidityType; return solidityType;
}; };
/**
* Should be used to transform plain bytes to SolidityParam object
*
* @method _bytesToParam
* @param {Array} types of params
* @param {String} bytes to be transformed to SolidityParam
* @return {SolidityParam} SolidityParam for this group of params
*/
SolidityCoder.prototype._bytesToParam = function (types, bytes) {
var self = this;
var prefixTypes = types.reduce(function (acc, type) {
return self._requireType(type).isVariadicType(type) ? acc + 1 : acc;
}, 0);
var valueTypes = types.length - prefixTypes;
var prefix = bytes.slice(0, prefixTypes * 64);
bytes = bytes.slice(prefixTypes * 64);
var value = bytes.slice(0, valueTypes * 64);
var suffix = bytes.slice(valueTypes * 64);
return new SolidityParam(value, prefix, suffix);
};
/** /**
* Should be used to transform plain param of given type to SolidityParam * Should be used to transform plain param of given type to SolidityParam
* *
@ -216,24 +183,11 @@ SolidityCoder.prototype.encodeParam = function (type, param) {
*/ */
SolidityCoder.prototype.encodeParams = function (types, params) { SolidityCoder.prototype.encodeParams = function (types, params) {
var self = this; var self = this;
return types.map(function (type, index) { var solidityParams = types.map(function (type, index) {
return self._formatInput(type, params[index]); return self._formatInput(type, params[index]);
}).reduce(function (acc, solidityParam) { });
acc.append(solidityParam);
return acc;
}, new SolidityParam()).encode();
};
/** return SolidityParam.encodeList(solidityParams);
* Should be used to transform SolidityParam to plain param
*
* @method _formatOutput
* @param {String} type
* @param {SolidityParam} param
* @return {Object} plain param
*/
SolidityCoder.prototype._formatOutput = function (type, param) {
return this._requireType(type).formatOutput(param, isArrayType(type));
}; };
/** /**
@ -245,7 +199,7 @@ SolidityCoder.prototype._formatOutput = function (type, param) {
* @return {Object} plain param * @return {Object} plain param
*/ */
SolidityCoder.prototype.decodeParam = function (type, bytes) { SolidityCoder.prototype.decodeParam = function (type, bytes) {
return this._formatOutput(type, this._bytesToParam([type], bytes)); return this.decodeParams([type], bytes)[0];
}; };
/** /**
@ -258,10 +212,9 @@ SolidityCoder.prototype.decodeParam = function (type, bytes) {
*/ */
SolidityCoder.prototype.decodeParams = function (types, bytes) { SolidityCoder.prototype.decodeParams = function (types, bytes) {
var self = this; var self = this;
var param = this._bytesToParam(types, bytes); return types.map(function (type, index) {
return types.map(function (type) {
var solidityType = self._requireType(type); var solidityType = self._requireType(type);
var p = solidityType.shiftParam(type, param); var p = solidityType.sliceParam(bytes, index, type);
return solidityType.formatOutput(p, isArrayType(type)); return solidityType.formatOutput(p, isArrayType(type));
}); });
}; };

14
libjsqrc/ethereumjs/lib/solidity/formatters.js

@ -63,7 +63,7 @@ var formatInputBytes = function (value) {
*/ */
var formatInputDynamicBytes = function (value) { var formatInputDynamicBytes = function (value) {
var result = utils.fromAscii(value, c.ETH_PADDING).substr(2); var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);
return new SolidityParam('', formatInputInt(value.length).value, result); return new SolidityParam(formatInputInt(value.length).value + result, 32);
}; };
/** /**
@ -109,7 +109,7 @@ var signedIsNegative = function (value) {
* @returns {BigNumber} right-aligned output bytes formatted to big number * @returns {BigNumber} right-aligned output bytes formatted to big number
*/ */
var formatOutputInt = function (param) { var formatOutputInt = function (param) {
var value = param.value || "0"; var value = param.staticPart() || "0";
// check if it's negative number // check if it's negative number
// it it is, return two's complement // it it is, return two's complement
@ -127,7 +127,7 @@ var formatOutputInt = function (param) {
* @returns {BigNumeber} right-aligned output bytes formatted to uint * @returns {BigNumeber} right-aligned output bytes formatted to uint
*/ */
var formatOutputUInt = function (param) { var formatOutputUInt = function (param) {
var value = param.value || "0"; var value = param.staticPart() || "0";
return new BigNumber(value, 16); return new BigNumber(value, 16);
}; };
@ -161,7 +161,7 @@ var formatOutputUReal = function (param) {
* @returns {Boolean} right-aligned input bytes formatted to bool * @returns {Boolean} right-aligned input bytes formatted to bool
*/ */
var formatOutputBool = function (param) { var formatOutputBool = function (param) {
return param.value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
}; };
/** /**
@ -173,7 +173,7 @@ var formatOutputBool = function (param) {
*/ */
var formatOutputBytes = function (param) { var formatOutputBytes = function (param) {
// length might also be important! // length might also be important!
return utils.toAscii(param.value); return utils.toAscii(param.staticPart());
}; };
/** /**
@ -185,7 +185,7 @@ var formatOutputBytes = function (param) {
*/ */
var formatOutputDynamicBytes = function (param) { var formatOutputDynamicBytes = function (param) {
// length might also be important! // length might also be important!
return utils.toAscii(param.suffix); return utils.toAscii(param.dynamicPart().slice(64));
}; };
/** /**
@ -196,7 +196,7 @@ var formatOutputDynamicBytes = function (param) {
* @returns {String} address * @returns {String} address
*/ */
var formatOutputAddress = function (param) { var formatOutputAddress = function (param) {
var value = param.value; var value = param.staticPart();
return "0x" + value.slice(value.length - 40, value.length); return "0x" + value.slice(value.length - 40, value.length);
}; };

191
libjsqrc/ethereumjs/lib/solidity/param.js

@ -20,85 +20,190 @@
* @date 2015 * @date 2015
*/ */
var utils = require('../utils/utils');
/** /**
* SolidityParam object prototype. * SolidityParam object prototype.
* Should be used when encoding, decoding solidity bytes * Should be used when encoding, decoding solidity bytes
*/ */
var SolidityParam = function (value, prefix, suffix) { var SolidityParam = function (value, offset) {
this.prefix = prefix || '';
this.value = value || ''; this.value = value || '';
this.suffix = suffix || ''; this.offset = offset; // offset in bytes
};
/**
* This method should be used to get length of params's dynamic part
*
* @method dynamicPartLength
* @returns {Number} length of dynamic part (in bytes)
*/
SolidityParam.prototype.dynamicPartLength = function () {
return this.dynamicPart().length / 2;
};
/**
* This method should be used to create copy of solidity param with different offset
*
* @method withOffset
* @param {Number} offset length in bytes
* @returns {SolidityParam} new solidity param with applied offset
*/
SolidityParam.prototype.withOffset = function (offset) {
return new SolidityParam(this.value, offset);
};
/**
* This method should be used to combine solidity params together
* eg. when appending an array
*
* @method combine
* @param {SolidityParam} param with which we should combine
* @param {SolidityParam} result of combination
*/
SolidityParam.prototype.combine = function (param) {
return new SolidityParam(this.value + param.value);
};
/**
* This method should be called to check if param has dynamic size.
* If it has, it returns true, otherwise false
*
* @method isDynamic
* @returns {Boolean}
*/
SolidityParam.prototype.isDynamic = function () {
return this.value.length > 64;
}; };
/** /**
* This method should be used to encode two params one after another * This method should be called to transform offset to bytes
* *
* @method append * @method offsetAsBytes
* @param {SolidityParam} param that it appended after this * @returns {String} bytes representation of offset
*/ */
SolidityParam.prototype.append = function (param) { SolidityParam.prototype.offsetAsBytes = function () {
this.prefix += param.prefix; return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset).toString(16), 64);
this.value += param.value;
this.suffix += param.suffix;
}; };
/** /**
* This method should be used to encode next param in an array * This method should be called to get static part of param
* *
* @method appendArrayElement * @method staticPart
* @param {SolidityParam} param that is appended to an array * @returns {String} offset if it is a dynamic param, otherwise value
*/ */
SolidityParam.prototype.appendArrayElement = function (param) { SolidityParam.prototype.staticPart = function () {
this.suffix += param.value; if (!this.isDynamic()) {
this.prefix += param.prefix; return this.value;
// TODO: suffix not supported = it's required for nested arrays; }
return this.offsetAsBytes();
}; };
/** /**
* This method should be used to create bytearrays from param * This method should be called to get dynamic part of param
*
* @method dynamicPart
* @returns {String} returns a value if it is a dynamic param, otherwise empty string
*/
SolidityParam.prototype.dynamicPart = function () {
return this.isDynamic() ? this.value : '';
};
/**
* This method should be called to encode param
* *
* @method encode * @method encode
* @return {String} encoded param(s) * @returns {String}
*/ */
SolidityParam.prototype.encode = function () { SolidityParam.prototype.encode = function () {
return this.prefix + this.value + this.suffix; return this.staticPart() + this.dynamicPart();
}; };
/** /**
* This method should be used to shift first param from group of params * This method should be called to encode array of params
* *
* @method shiftValue * @method encodeList
* @return {SolidityParam} first value param * @param {Array[SolidityParam]} params
* @returns {String}
*/ */
SolidityParam.prototype.shiftValue = function () { SolidityParam.encodeList = function (params) {
var value = this.value.slice(0, 64);
this.value = this.value.slice(64); // updating offsets
return new SolidityParam(value); var totalOffset = params.length * 32;
var offsetParams = params.map(function (param) {
if (!param.isDynamic()) {
return param;
}
var offset = totalOffset;
totalOffset += param.dynamicPartLength();
return param.withOffset(offset);
});
// encode everything!
return offsetParams.reduce(function (result, param) {
return result + param.dynamicPart();
}, offsetParams.reduce(function (result, param) {
return result + param.staticPart();
}, ''));
}; };
/** /**
* This method should be used to first bytes param from group of params * This method should be used to decode plain (static) solidity param at given index
* *
* @method shiftBytes * @method decodeParam
* @return {SolidityParam} first bytes param * @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/ */
SolidityParam.prototype.shiftBytes = function () { SolidityParam.decodeParam = function (bytes, index) {
return this.shiftArray(1); index = index || 0;
return new SolidityParam(bytes.substr(index * 64, 64));
}; };
/** /**
* This method should be used to shift an array from group of params * This method should be called to get offset value from bytes at given index
* *
* @method shiftArray * @method getOffset
* @param {Number} size of an array to shift * @param {String} bytes
* @return {SolidityParam} first array param * @param {Number} index
* @returns {Number} offset as number
*/
var getOffset = function (bytes, index) {
// we can do this cause offset is rather small
return parseInt('0x' + bytes.substr(index * 64, 64));
};
/**
* This method should be called to decode solidity bytes param at given index
*
* @method decodeBytes
* @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/
SolidityParam.decodeBytes = function (bytes, index) {
index = index || 0;
//TODO add support for strings longer than 32 bytes
//var length = parseInt('0x' + bytes.substr(offset * 64, 64));
var offset = getOffset(bytes, index);
// 2 * , cause we also parse length
return new SolidityParam(bytes.substr(offset * 2, 2 * 64));
};
/**
* This method should be used to decode solidity array at given index
*
* @method decodeArray
* @param {String} bytes
* @param {Number} index
* @returns {SolidityParam}
*/ */
SolidityParam.prototype.shiftArray = function (length) { SolidityParam.decodeArray = function (bytes, index) {
var prefix = this.prefix.slice(0, 64); index = index || 0;
this.prefix = this.value.slice(64); var offset = getOffset(bytes, index);
var suffix = this.suffix.slice(0, 64 * length); var length = parseInt('0x' + bytes.substr(offset * 2, 64));
this.suffix = this.suffix.slice(64 * length); return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64));
return new SolidityParam('', prefix, suffix);
}; };
module.exports = SolidityParam; module.exports = SolidityParam;

5
libjsqrc/ethereumjs/lib/solidity/utils.js

@ -34,6 +34,11 @@ var getConstructor = function (abi, numberOfArgs) {
})[0]; })[0];
}; };
//var getSupremeType = function (type) {
//return type.substr(0, type.indexOf('[')) + ']';
//};
module.exports = { module.exports = {
getConstructor: getConstructor getConstructor: getConstructor
}; };

2
libjsqrc/ethereumjs/lib/version.json

@ -1,3 +1,3 @@
{ {
"version": "0.3.3" "version": "0.3.6"
} }

17
libjsqrc/ethereumjs/lib/web3/eth.js

@ -23,7 +23,7 @@
/** /**
* Web3 * Web3
* *
* @module web3 * @module web3
*/ */
@ -77,16 +77,16 @@ var uncleCountCall = function (args) {
/// @returns an array of objects describing web3.eth api methods /// @returns an array of objects describing web3.eth api methods
var getBalance = new Method({ var getBalance = new Method({
name: 'getBalance', name: 'getBalance',
call: 'eth_getBalance', call: 'eth_getBalance',
params: 2, params: 2,
inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],
outputFormatter: formatters.outputBigNumberFormatter outputFormatter: formatters.outputBigNumberFormatter
}); });
var getStorageAt = new Method({ var getStorageAt = new Method({
name: 'getStorageAt', name: 'getStorageAt',
call: 'eth_getStorageAt', call: 'eth_getStorageAt',
params: 3, params: 3,
inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]
}); });
@ -99,7 +99,7 @@ var getCode = new Method({
}); });
var getBlock = new Method({ var getBlock = new Method({
name: 'getBlock', name: 'getBlock',
call: blockCall, call: blockCall,
params: 2, params: 2,
inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }], inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],
@ -224,6 +224,11 @@ var properties = [
name: 'mining', name: 'mining',
getter: 'eth_mining' getter: 'eth_mining'
}), }),
new Property({
name: 'hashrate',
getter: 'eth_hashrate',
outputFormatter: utils.toDecimal
}),
new Property({ new Property({
name: 'gasPrice', name: 'gasPrice',
getter: 'eth_gasPrice', getter: 'eth_gasPrice',

2
libjsqrc/ethereumjs/lib/web3/event.js

@ -96,7 +96,7 @@ SolidityEvent.prototype.encode = function (indexed, options) {
['fromBlock', 'toBlock'].filter(function (f) { ['fromBlock', 'toBlock'].filter(function (f) {
return options[f] !== undefined; return options[f] !== undefined;
}).forEach(function (f) { }).forEach(function (f) {
result[f] = utils.toHex(options[f]); result[f] = formatters.inputBlockNumberFormatter(options[f]);
}); });
result.topics = []; result.topics = [];

2
libjsqrc/ethereumjs/lib/web3/formatters.js

@ -72,7 +72,7 @@ var inputTransactionFormatter = function (options){
delete options.code; delete options.code;
} }
['gasPrice', 'gas', 'value'].filter(function (key) { ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
return options[key] !== undefined; return options[key] !== undefined;
}).forEach(function(key){ }).forEach(function(key){
options[key] = utils.fromDecimal(options[key]); options[key] = utils.fromDecimal(options[key]);

23
libjsqrc/ethereumjs/lib/web3/httpprovider.js

@ -48,15 +48,32 @@ HttpProvider.prototype.send = function (payload) {
//if (request.status !== 200) { //if (request.status !== 200) {
//return; //return;
//} //}
return JSON.parse(request.responseText);
var result = request.responseText;
try {
result = JSON.parse(result);
} catch(e) {
throw errors.InvalidResponse(result);
}
return result;
}; };
HttpProvider.prototype.sendAsync = function (payload, callback) { HttpProvider.prototype.sendAsync = function (payload, callback) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.onreadystatechange = function() { request.onreadystatechange = function() {
if (request.readyState === 4) { if (request.readyState === 4) {
// TODO: handle the error properly here!!! var result = request.responseText;
callback(null, JSON.parse(request.responseText)); var error = null;
try {
result = JSON.parse(result);
} catch(e) {
error = errors.InvalidResponse(result);
}
callback(error, result);
} }
}; };

2
libjsqrc/ethereumjs/package.js

@ -1,7 +1,7 @@
/* jshint ignore:start */ /* jshint ignore:start */
Package.describe({ Package.describe({
name: 'ethereum:web3', name: 'ethereum:web3',
version: '0.3.3', version: '0.3.6',
summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC', summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC',
git: 'https://github.com/ethereum/ethereum.js', git: 'https://github.com/ethereum/ethereum.js',
// By default, Meteor will default to using README.md for documentation. // By default, Meteor will default to using README.md for documentation.

2
libjsqrc/ethereumjs/package.json

@ -1,7 +1,7 @@
{ {
"name": "web3", "name": "web3",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.3.3", "version": "0.3.6",
"description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC", "description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC",
"main": "./index.js", "main": "./index.js",
"directories": { "directories": {

515
libjsqrc/ethereumjs/test/abi.inputParser.js

@ -1,515 +0,0 @@
var chai = require('chai');
var assert = chai.assert;
var BigNumber = require('bignumber.js');
var abi = require('../lib/solidity/abi');
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('lib/solidity/abi', function () {
describe('inputParser', function () {
it('should parse input uint', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "uint" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
parser.test(new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(parser.test(0.1), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input uint128', function() {
// given
var d = clone(description);
d[0].inputs = [
{ type: "uint128" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
parser.test(new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(parser.test(0.1), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input uint256', function() {
// given
var d = clone(description);
d[0].inputs = [
{ type: "uint256" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
parser.test(new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(parser.test(0.1), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input int', function() {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
parser.test(new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(parser.test(0.1), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input int128', function() {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int128" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
parser.test(new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(parser.test(0.1), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input int256', function() {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int256" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(
parser.test(new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
assert.equal(parser.test(0.1), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003");
assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003");
});
it('should parse input bool', function() {
// given
var d = clone(description);
d[0].inputs = [
{ type: 'bool' }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(true), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.test(false), "0000000000000000000000000000000000000000000000000000000000000000");
});
it('should parse input address', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "address" }
];
// when
var parser = abi.inputParser(d)
// then
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
});
it('should parse input fixed bytes type', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "bytes" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test('hello'),
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000"
);
assert.equal(
parser.test('world'),
"0000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000"
);
});
it('should parse input int followed by a fixed bytes type', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int" },
{ type: "bytes" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test(9, 'hello'),
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000009" +
"68656c6c6f000000000000000000000000000000000000000000000000000000"
);
});
it('should parse input fixed bytes type followed by an int', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "bytes" },
{ type: "int" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test('hello', 9),
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000009" +
"68656c6c6f000000000000000000000000000000000000000000000000000000"
);
});
it('should use proper method name', function () {
// given
var d = clone(description);
d[0].name = 'helloworld(int)';
d[0].inputs = [
{ type: "int" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.helloworld(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(parser.helloworld['int'](1), "0000000000000000000000000000000000000000000000000000000000000001");
});
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: "bytes" }],
outputs: [{ type: "bytes" }]
}];
// when
var parser = abi.inputParser(d);
//then
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
assert.equal(
parser.test2('hello'),
"000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"
);
});
it('should parse input array of ints', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int[]" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test([5, 6]),
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006"
);
});
it('should parse an array followed by an int', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int[]" },
{ type: "int" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test([5, 6], 3),
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000003" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006"
);
});
it('should parse an int followed by an array', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int" },
{ type: "int[]" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test(3, [5, 6]),
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000003" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006"
);
});
it('should parse mixture of arrays and ints', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: "int" },
{ type: "int[]" },
{ type: "int" },
{ type: "int[]" }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(
parser.test(3, [5, 6, 1, 2], 7, [8, 9]),
"0000000000000000000000000000000000000000000000000000000000000004" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000003" +
"0000000000000000000000000000000000000000000000000000000000000007" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006" +
"0000000000000000000000000000000000000000000000000000000000000001" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000008" +
"0000000000000000000000000000000000000000000000000000000000000009"
);
});
it('should parse input real', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: 'real' }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test(2.125), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test(8.5), "0000000000000000000000000000000880000000000000000000000000000000");
assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000");
});
it('should parse input ureal', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: 'ureal' }
];
// when
var parser = abi.inputParser(d);
// then
assert.equal(parser.test(1), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test(2.125), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test(8.5), "0000000000000000000000000000000880000000000000000000000000000000");
});
it('should throw an incorrect type error', function () {
// given
var d = clone(description);
d[0].inputs = [
{ type: 'uin' }
]
// when
var parser = abi.inputParser(d);
// then
assert.throws(function () {parser.test('0x')}, Error);
});
});
});

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

@ -1,419 +0,0 @@
var assert = require('assert');
var BigNumber = require('bignumber.js');
var abi = require('../lib/solidity/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('lib/solidity/abi', function() {
describe('outputParser', function() {
it('should parse output fixed bytes type', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "bytes" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test(
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test(
"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("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[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("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[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("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[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("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[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("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[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("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
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("000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[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("0000000000000000000000000000000000000000000000000000000000000001")[0], true);
assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000000")[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("0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
assert.equal(parser.test("ffffffffffffffffffffffffffffffff00000000000000000000000000000000")[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("0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
});
it('should parse multiple output fixed bytes type', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "bytes" },
{ type: "bytes" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test(
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test(
"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("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.helloworld['int']("0000000000000000000000000000000000000000000000000000000000000001")[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: "bytes" }],
outputs: [{ type: "bytes" }]
}];
// when
var parser = abi.outputParser(d);
//then
assert.equal(parser.test("00000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test2(
"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(
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][0],
5
);
assert.equal(parser.test(
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][1],
6
);
});
it('should parse 0x0 value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0")[0], 0);
});
it('should parse 0x0 value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0")[0], 0);
});
it('should throw an incorrect type error', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uin' }
]
// when
var parser = abi.outputParser(d);
// then
assert.throws(function () {parser.test('0x')}, Error);
});
});
});

45
libjsqrc/ethereumjs/test/coder.decodeParam.js

@ -21,17 +21,32 @@ describe('lib/solidity/coder', function () {
test({ type: 'int256', expected: new bn(16), value: '0000000000000000000000000000000000000000000000000000000000000010'}); test({ type: 'int256', expected: new bn(16), value: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ type: 'int256', expected: new bn(-1), value: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'}); test({ type: 'int256', expected: new bn(-1), value: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ type: 'bytes32', expected: 'gavofyork', value: '6761766f66796f726b0000000000000000000000000000000000000000000000'}); test({ type: 'bytes32', expected: 'gavofyork', value: '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'bytes', expected: 'gavofyork', value: '0000000000000000000000000000000000000000000000000000000000000009' + test({ type: 'bytes', expected: 'gavofyork', value: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'}); '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'int[]', expected: [new bn(3)], value: '0000000000000000000000000000000000000000000000000000000000000001' + test({ type: 'int[]', expected: [new bn(3)], value: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int256[]', expected: [new bn(3)], value: '0000000000000000000000000000000000000000000000000000000000000001' + test({ type: 'int256[]', expected: [new bn(3)], value: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int[]', expected: [new bn(1), new bn(2), new bn(3)], test({ type: 'int[]', expected: [new bn(1), new bn(2), new bn(3)],
value: '0000000000000000000000000000000000000000000000000000000000000003' + value: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' + '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' + '0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'bool', expected: true, value: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'bool', expected: false, value: '0000000000000000000000000000000000000000000000000000000000000000'});
test({ type: 'real', expected: new bn(1), value: '0000000000000000000000000000000100000000000000000000000000000000'});
test({ type: 'real', expected: new bn(2.125), value: '0000000000000000000000000000000220000000000000000000000000000000'});
test({ type: 'real', expected: new bn(8.5), value: '0000000000000000000000000000000880000000000000000000000000000000'});
test({ type: 'real', expected: new bn(-1), value: 'ffffffffffffffffffffffffffffffff00000000000000000000000000000000'});
test({ type: 'ureal', expected: new bn(1), value: '0000000000000000000000000000000100000000000000000000000000000000'});
test({ type: 'ureal', expected: new bn(2.125), value: '0000000000000000000000000000000220000000000000000000000000000000'});
test({ type: 'ureal', expected: new bn(8.5), value: '0000000000000000000000000000000880000000000000000000000000000000'});
test({ type: 'address', expected: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
value: '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1'});
}); });
}); });
@ -53,16 +68,18 @@ describe('lib/solidity/coder', function () {
'6761766f66796f726b0000000000000000000000000000000000000000000000'}); '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['int', 'bytes', 'int', 'int', 'int', 'int[]'], expected: [new bn(1), 'gavofyork', new bn(2), new bn(3), new bn(4), test({ types: ['int', 'bytes', 'int', 'int', 'int', 'int[]'], expected: [new bn(1), 'gavofyork', new bn(2), new bn(3), new bn(4),
[new bn(5), new bn(6), new bn(7)]], [new bn(5), new bn(6), new bn(7)]],
values: '0000000000000000000000000000000000000000000000000000000000000009' + values: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003' + '00000000000000000000000000000000000000000000000000000000000000c0' +
'0000000000000000000000000000000000000000000000000000000000000001' + '0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000002' + '0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000003' + '0000000000000000000000000000000000000000000000000000000000000004' +
'0000000000000000000000000000000000000000000000000000000000000004' + '0000000000000000000000000000000000000000000000000000000000000100' +
'6761766f66796f726b0000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000009' +
'0000000000000000000000000000000000000000000000000000000000000005' + '6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000006' + '0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000007'}); '0000000000000000000000000000000000000000000000000000000000000005' +
'0000000000000000000000000000000000000000000000000000000000000006' +
'0000000000000000000000000000000000000000000000000000000000000007'});
}); });
}); });

82
libjsqrc/ethereumjs/test/coder.encodeParam.js

@ -15,20 +15,37 @@ describe('lib/solidity/coder', function () {
test({ type: 'int', value: 1, expected: '0000000000000000000000000000000000000000000000000000000000000001'}); test({ type: 'int', value: 1, expected: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'int', value: 16, expected: '0000000000000000000000000000000000000000000000000000000000000010'}); test({ type: 'int', value: 16, expected: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ type: 'int', value: -1, expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'}); test({ type: 'int', value: -1, expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ type: 'int', value: 0.1, expected: '0000000000000000000000000000000000000000000000000000000000000000'});
test({ type: 'int', value: 3.9, expected: '0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int256', value: 1, expected: '0000000000000000000000000000000000000000000000000000000000000001'}); test({ type: 'int256', value: 1, expected: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'int256', value: 16, expected: '0000000000000000000000000000000000000000000000000000000000000010'}); test({ type: 'int256', value: 16, expected: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ type: 'int256', value: -1, expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'}); test({ type: 'int256', value: -1, expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ type: 'bytes32', value: 'gavofyork', expected: '6761766f66796f726b0000000000000000000000000000000000000000000000'}); test({ type: 'bytes32', value: 'gavofyork', expected: '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'bytes', value: 'gavofyork', expected: '0000000000000000000000000000000000000000000000000000000000000009' + test({ type: 'bytes', value: 'gavofyork', expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'}); '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'int[]', value: [3], expected: '0000000000000000000000000000000000000000000000000000000000000001' + test({ type: 'int[]', value: [3], expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int256[]', value: [3], expected: '0000000000000000000000000000000000000000000000000000000000000001' + test({ type: 'int256[]', value: [3], expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int[]', value: [1,2,3], expected: '0000000000000000000000000000000000000000000000000000000000000003' + test({ type: 'int[]', value: [1,2,3], expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' + '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' + '0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'bool', value: true, expected: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'bool', value: false, expected: '0000000000000000000000000000000000000000000000000000000000000000'});
test({ type: 'address', value: '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
expected: '000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1'});
test({ type: 'real', value: 1, expected: '0000000000000000000000000000000100000000000000000000000000000000'});
test({ type: 'real', value: 2.125, expected: '0000000000000000000000000000000220000000000000000000000000000000'});
test({ type: 'real', value: 8.5, expected: '0000000000000000000000000000000880000000000000000000000000000000'});
test({ type: 'real', value: -1, expected: 'ffffffffffffffffffffffffffffffff00000000000000000000000000000000'});
test({ type: 'ureal', value: 1, expected: '0000000000000000000000000000000100000000000000000000000000000000'});
test({ type: 'ureal', value: 2.125, expected: '0000000000000000000000000000000220000000000000000000000000000000'});
test({ type: 'ureal', value: 8.5, expected: '0000000000000000000000000000000880000000000000000000000000000000'});
}); });
}); });
@ -49,16 +66,29 @@ describe('lib/solidity/coder', function () {
test({ types: ['int256'], values: [16], expected: '0000000000000000000000000000000000000000000000000000000000000010'}); test({ types: ['int256'], values: [16], expected: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ types: ['int256'], values: [-1], expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'}); test({ types: ['int256'], values: [-1], expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ types: ['bytes32'], values: ['gavofyork'], expected: '6761766f66796f726b0000000000000000000000000000000000000000000000'}); test({ types: ['bytes32'], values: ['gavofyork'], expected: '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['bytes'], values: ['gavofyork'], expected: '0000000000000000000000000000000000000000000000000000000000000009' + test({ types: ['bytes'], values: ['gavofyork'], expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'}); '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['int[]'], values: [[3]], expected: '0000000000000000000000000000000000000000000000000000000000000001' + test({ types: ['int[]'], values: [[3]], expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['int256[]'], values: [[3]], expected: '0000000000000000000000000000000000000000000000000000000000000001' + test({ types: ['int256[]'], values: [[3]], expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['int256[]'], values: [[1,2,3]], expected: '0000000000000000000000000000000000000000000000000000000000000003' + test({ types: ['int256[]'], values: [[1,2,3]], expected: '0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' + '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' + '0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'}); '0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['int[]', 'int[]'], values: [[1,2], [3,4]],
expected: '0000000000000000000000000000000000000000000000000000000000000040' +
'00000000000000000000000000000000000000000000000000000000000000a0' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000004'});
test({ types: ['bytes32', 'int'], values: ['gavofyork', 5], test({ types: ['bytes32', 'int'], values: ['gavofyork', 5],
expected: '6761766f66796f726b0000000000000000000000000000000000000000000000' + expected: '6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000005'}); '0000000000000000000000000000000000000000000000000000000000000005'});
@ -66,25 +96,47 @@ describe('lib/solidity/coder', function () {
expected: '0000000000000000000000000000000000000000000000000000000000000005' + expected: '0000000000000000000000000000000000000000000000000000000000000005' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'}); '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['bytes', 'int'], values: ['gavofyork', 5], test({ types: ['bytes', 'int'], values: ['gavofyork', 5],
expected: '0000000000000000000000000000000000000000000000000000000000000009' + expected: '0000000000000000000000000000000000000000000000000000000000000040' +
'0000000000000000000000000000000000000000000000000000000000000005' + '0000000000000000000000000000000000000000000000000000000000000005' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'}); '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['bytes', 'bool', 'int[]'], values: ['gavofyork', true, [1, 2, 3]],
expected: '0000000000000000000000000000000000000000000000000000000000000060' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'00000000000000000000000000000000000000000000000000000000000000a0' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['bytes', 'int[]'], values: ['gavofyork', [1, 2, 3]],
expected: '0000000000000000000000000000000000000000000000000000000000000040' +
'0000000000000000000000000000000000000000000000000000000000000080' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['int', 'bytes'], values: [5, 'gavofyork'], test({ types: ['int', 'bytes'], values: [5, 'gavofyork'],
expected: '0000000000000000000000000000000000000000000000000000000000000009' + expected: '0000000000000000000000000000000000000000000000000000000000000005' +
'0000000000000000000000000000000000000000000000000000000000000005' + '0000000000000000000000000000000000000000000000000000000000000040' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'}); '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['int', 'bytes', 'int', 'int', 'int', 'int[]'], values: [1, 'gavofyork', 2, 3, 4, [5, 6, 7]], test({ types: ['int', 'bytes', 'int', 'int', 'int', 'int[]'], values: [1, 'gavofyork', 2, 3, 4, [5, 6, 7]],
expected: '0000000000000000000000000000000000000000000000000000000000000009' + expected: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003' + '00000000000000000000000000000000000000000000000000000000000000c0' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' + '0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003' + '0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000004' + '0000000000000000000000000000000000000000000000000000000000000004' +
'0000000000000000000000000000000000000000000000000000000000000100' +
'0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000' + '6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000005' + '0000000000000000000000000000000000000000000000000000000000000005' +
'0000000000000000000000000000000000000000000000000000000000000006' + '0000000000000000000000000000000000000000000000000000000000000006' +
'0000000000000000000000000000000000000000000000000000000000000007'}); '0000000000000000000000000000000000000000000000000000000000000007'});
}); });
}); });

1
libjsqrc/ethereumjs/test/contract.js

@ -345,6 +345,7 @@ describe('web3.eth.contract', function () {
assert.equal(payload.method, 'eth_call'); assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{ assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) + data: sha3.slice(0, 10) +
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000001' + '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003', '0000000000000000000000000000000000000000000000000000000000000003',
to: address to: address

26
libjsqrc/ethereumjs/test/event.encode.js

@ -119,6 +119,32 @@ var tests = [{
] ]
} }
}, { }, {
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}]
},
indexed: {
a: 1
},
options: {
fromBlock: 'latest',
toBlock: 'pending'
},
expected: {
address: address,
fromBlock: 'latest',
toBlock: 'pending',
topics: [
signature,
'0x0000000000000000000000000000000000000000000000000000000000000001'
]
}
},
{
abi: { abi: {
name: 'event1', name: 'event1',
inputs: [{ inputs: [{

70
libjsqrc/ethereumjs/test/formatters.inputTransactionFormatter.js

@ -3,24 +3,62 @@ var assert = chai.assert;
var formatters = require('../lib/web3/formatters.js'); var formatters = require('../lib/web3/formatters.js');
var BigNumber = require('bignumber.js'); var BigNumber = require('bignumber.js');
var tests = [{
input: {
data: '0x34234bf23bf4234',
value: new BigNumber(100),
from: '0x00000',
to: '0x00000',
nonce: 1000,
gas: 1000,
gasPrice: new BigNumber(1000)
},
result: {
data: '0x34234bf23bf4234',
value: '0x64',
from: '0x00000',
to: '0x00000',
nonce: '0x3e8',
gas: '0x3e8',
gasPrice: '0x3e8'
}
},{
input: {
data: '0x34234bf23bf4234',
value: new BigNumber(100),
from: '0x00000',
to: '0x00000',
},
result: {
data: '0x34234bf23bf4234',
value: '0x64',
from: '0x00000',
to: '0x00000',
}
},{
input: {
data: '0x34234bf23bf4234',
value: new BigNumber(100),
from: '0x00000',
to: '0x00000',
gas: '1000',
gasPrice: new BigNumber(1000)
},
result: {
data: '0x34234bf23bf4234',
value: '0x64',
from: '0x00000',
to: '0x00000',
gas: '0x3e8',
gasPrice: '0x3e8'
}
}];
describe('formatters', function () { describe('formatters', function () {
describe('inputTransactionFormatter', function () { describe('inputTransactionFormatter', function () {
it('should return the correct value', function () { tests.forEach(function(test){
it('should return the correct value', function () {
assert.deepEqual(formatters.inputTransactionFormatter({ assert.deepEqual(formatters.inputTransactionFormatter(test.input), test.result);
data: '0x34234bf23bf4234',
value: new BigNumber(100),
from: '0x00000',
to: '0x00000',
gas: 1000,
gasPrice: new BigNumber(1000)
}), {
data: '0x34234bf23bf4234',
value: '0x64',
from: '0x00000',
to: '0x00000',
gas: '0x3e8',
gasPrice: '0x3e8'
}); });
}); });
}); });

15
libjsqrc/ethereumjs/test/web3.eth.filter.js

@ -21,6 +21,21 @@ var tests = [{
result: '0xf', result: '0xf',
formattedResult: '0xf', formattedResult: '0xf',
call: 'eth_newFilter' call: 'eth_newFilter'
},{
args: [{
fromBlock: 'latest',
toBlock: 'latest',
address: '0x47d33b27bb249a2dbab4c0612bf9caf4c1950855'
}],
formattedArgs: [{
fromBlock: 'latest',
toBlock: 'latest',
address: '0x47d33b27bb249a2dbab4c0612bf9caf4c1950855',
topics: []
}],
result: '0xf',
formattedResult: '0xf',
call: 'eth_newFilter'
},{ },{
args: ['pending'], args: ['pending'],
formattedArgs: ['pending'], formattedArgs: ['pending'],

38
libjsqrc/ethereumjs/test/web3.eth.hashRate.js

@ -0,0 +1,38 @@
var chai = require('chai');
var assert = chai.assert;
var web3 = require('../index');
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var method = 'hashrate';
var tests = [{
result: '0x788a8',
formattedResult: 493736,
call: 'eth_'+ method
}];
describe('web3.eth', function () {
describe(method, function () {
tests.forEach(function (test, index) {
it('property test: ' + index, function () {
// given
var provider = new FakeHttpProvider();
web3.setProvider(provider);
provider.injectResult(test.result);
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call);
assert.deepEqual(payload.params, []);
});
// when
var result = web3.eth[method];
// then
assert.strictEqual(test.formattedResult, result);
});
});
});
});

10
libp2p/Host.cpp

@ -389,6 +389,16 @@ string Host::pocHost()
return "poc-" + strs[1] + ".ethdev.com"; return "poc-" + strs[1] + ".ethdev.com";
} }
std::unordered_map<Public, std::string> const& Host::pocHosts()
{
static const std::unordered_map<Public, std::string> c_ret = {
// { Public(""), "poc-9.ethdev.com:30303" },
{ Public("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c"), "52.16.188.185:30303" },
{ Public("7f25d3eab333a6b98a8b5ed68d962bb22c876ffcd5561fca54e3c2ef27f754df6f7fd7c9b74cc919067abac154fb8e1f8385505954f161ae440abc355855e034"), "54.207.93.166:30303" }
};
return c_ret;
}
void Host::addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint) void Host::addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint)
{ {
// return if network is stopped while waiting on Host::run() or nodeTable to start // return if network is stopped while waiting on Host::run() or nodeTable to start

2
libp2p/Host.h

@ -95,6 +95,8 @@ public:
/// Default host for current version of client. /// Default host for current version of client.
static std::string pocHost(); static std::string pocHost();
static std::unordered_map<Public, std::string> const& pocHosts();
/// Register a peer-capability; all new peer connections will have this capability. /// Register a peer-capability; all new peer connections will have this capability.
template <class T> std::shared_ptr<T> registerCapability(T* _t) { _t->m_host = this; std::shared_ptr<T> ret(_t); m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = ret; return ret; } template <class T> std::shared_ptr<T> registerCapability(T* _t) { _t->m_host = this; std::shared_ptr<T> ret(_t); m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = ret; return ret; }

78
libp2p/NodeTable.cpp

@ -127,20 +127,19 @@ void NodeTable::discover()
list<NodeId> NodeTable::nodes() const list<NodeId> NodeTable::nodes() const
{ {
list<NodeId> nodes; list<NodeId> nodes;
Guard l(x_nodes); DEV_GUARDED(x_nodes)
for (auto& i: m_nodes) for (auto& i: m_nodes)
nodes.push_back(i.second->id); nodes.push_back(i.second->id);
return move(nodes); return move(nodes);
} }
list<NodeEntry> NodeTable::snapshot() const list<NodeEntry> NodeTable::snapshot() const
{ {
list<NodeEntry> ret; list<NodeEntry> ret;
Guard l(x_state); DEV_GUARDED(x_state)
for (auto s: m_state) for (auto const& s: m_state)
for (auto np: s.nodes) for (auto const& np: s.nodes)
if (auto n = np.lock()) if (auto n = np.lock())
if (!!n)
ret.push_back(*n); ret.push_back(*n);
return move(ret); return move(ret);
} }
@ -151,8 +150,7 @@ Node NodeTable::node(NodeId const& _id)
if (m_nodes.count(_id)) if (m_nodes.count(_id))
{ {
auto entry = m_nodes[_id]; auto entry = m_nodes[_id];
Node n(_id, entry->endpoint, entry->required); return Node(_id, entry->endpoint, entry->required);
return move(n);
} }
return UnspecifiedNode; return UnspecifiedNode;
} }
@ -173,7 +171,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptr<set<shared_pt
clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds.";
return; return;
} }
else if(!_round && !_tried) else if (!_round && !_tried)
// initialized _tried on first round // initialized _tried on first round
_tried.reset(new set<shared_ptr<NodeEntry>>()); _tried.reset(new set<shared_ptr<NodeEntry>>());
@ -228,7 +226,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
while (head != tail && head < s_bins && count < s_bucketSize) while (head != tail && head < s_bins && count < s_bucketSize)
{ {
Guard l(x_state); Guard l(x_state);
for (auto n: m_state[head].nodes) for (auto const& n: m_state[head].nodes)
if (auto p = n.lock()) if (auto p = n.lock())
{ {
if (count < s_bucketSize) if (count < s_bucketSize)
@ -238,7 +236,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
} }
if (count < s_bucketSize && tail) if (count < s_bucketSize && tail)
for (auto n: m_state[tail].nodes) for (auto const& n: m_state[tail].nodes)
if (auto p = n.lock()) if (auto p = n.lock())
{ {
if (count < s_bucketSize) if (count < s_bucketSize)
@ -255,7 +253,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
while (head < s_bins && count < s_bucketSize) while (head < s_bins && count < s_bucketSize)
{ {
Guard l(x_state); Guard l(x_state);
for (auto n: m_state[head].nodes) for (auto const& n: m_state[head].nodes)
if (auto p = n.lock()) if (auto p = n.lock())
{ {
if (count < s_bucketSize) if (count < s_bucketSize)
@ -269,7 +267,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
while (tail > 0 && count < s_bucketSize) while (tail > 0 && count < s_bucketSize)
{ {
Guard l(x_state); Guard l(x_state);
for (auto n: m_state[tail].nodes) for (auto const& n: m_state[tail].nodes)
if (auto p = n.lock()) if (auto p = n.lock())
{ {
if (count < s_bucketSize) if (count < s_bucketSize)
@ -282,7 +280,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
vector<shared_ptr<NodeEntry>> ret; vector<shared_ptr<NodeEntry>> ret;
for (auto& nodes: found) for (auto& nodes: found)
for (auto n: nodes.second) for (auto const& n: nodes.second)
if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed()) if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed())
ret.push_back(n); ret.push_back(n);
return move(ret); return move(ret);
@ -306,12 +304,15 @@ void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _n
if (!m_socketPointer->isOpen()) if (!m_socketPointer->isOpen())
return; return;
unsigned ec;
DEV_GUARDED(x_evictions)
{ {
Guard l(x_evictions);
m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id));
if (m_evictions.size() == 1) ec = m_evictions.size();
doCheckEvictions(boost::system::error_code());
} }
if (ec == 1)
doCheckEvictions(boost::system::error_code());
ping(_leastSeen.get()); ping(_leastSeen.get());
} }
@ -428,24 +429,27 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
Pong in = Pong::fromBytesConstRef(_from, rlpBytes); Pong in = Pong::fromBytesConstRef(_from, rlpBytes);
// whenever a pong is received, check if it's in m_evictions // whenever a pong is received, check if it's in m_evictions
Guard le(x_evictions); bool found = false;
bool evictionEntry = false; EvictionTimeout evictionEntry;
for (auto it = m_evictions.begin(); it != m_evictions.end(); it++) DEV_GUARDED(x_evictions)
if (it->first.first == nodeid && it->first.second > std::chrono::steady_clock::now()) for (auto it = m_evictions.begin(); it != m_evictions.end(); ++it)
{ if (it->first.first == nodeid && it->first.second > std::chrono::steady_clock::now())
evictionEntry = true; {
if (auto n = nodeEntry(it->second)) found = true;
dropNode(n); evictionEntry = *it;
m_evictions.erase(it);
if (auto n = nodeEntry(it->first.first)) break;
n->pending = false; }
if (found)
it = m_evictions.erase(it); {
} if (auto n = nodeEntry(evictionEntry.second))
dropNode(n);
// if not, check if it's known/pending or a pubk discovery ping if (auto n = nodeEntry(evictionEntry.first.first))
if (!evictionEntry) n->pending = false;
}
else
{ {
// if not, check if it's known/pending or a pubk discovery ping
if (auto n = nodeEntry(nodeid)) if (auto n = nodeEntry(nodeid))
n->pending = false; n->pending = false;
else else
@ -584,7 +588,7 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec)
if (chrono::steady_clock::now() - e.first.second > c_reqTimeout) if (chrono::steady_clock::now() - e.first.second > c_reqTimeout)
if (m_nodes.count(e.second)) if (m_nodes.count(e.second))
drop.push_back(m_nodes[e.second]); drop.push_back(m_nodes[e.second]);
evictionsRemain = m_evictions.size() - drop.size() > 0; evictionsRemain = (m_evictions.size() - drop.size() > 0);
} }
drop.unique(); drop.unique();

4
libp2p/NodeTable.h

@ -45,10 +45,12 @@ struct NodeEntry: public Node
bool pending = true; ///< Node will be ignored until Pong is received bool pending = true; ///< Node will be ignored until Pong is received
}; };
enum NodeTableEventType { enum NodeTableEventType
{
NodeEntryAdded, NodeEntryAdded,
NodeEntryDropped NodeEntryDropped
}; };
class NodeTable; class NodeTable;
class NodeTableEventHandler class NodeTableEventHandler
{ {

46
libsolidity/Compiler.cpp

@ -206,16 +206,9 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory)
{ {
// We do not check the calldata size, everything is zero-padded. // We do not check the calldata size, everything is zero-paddedd
unsigned offset(CompilerUtils::dataStartOffset);
bigint parameterHeadEnd = offset; m_context << u256(CompilerUtils::dataStartOffset);
for (TypePointer const& type: _typeParameters)
parameterHeadEnd += type->isDynamicallySized() ? 32 : type->getCalldataEncodedSize();
solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large.");
unsigned stackHeightOfPreviousDynamicArgument = 0;
ArrayType const* previousDynamicType = nullptr;
for (TypePointer const& type: _typeParameters) for (TypePointer const& type: _typeParameters)
{ {
switch (type->getCategory()) switch (type->getCategory())
@ -223,34 +216,31 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
case Type::Category::Array: case Type::Category::Array:
if (type->isDynamicallySized()) if (type->isDynamicallySized())
{ {
// put on stack: data_offset length // put on stack: data_pointer length
unsigned newStackHeight = m_context.getStackHeight(); CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory);
if (previousDynamicType) // stack: data_offset next_pointer
{ //@todo once we support nested arrays, this offset needs to be dynamic.
// Retrieve data start offset by adding length to start offset of previous dynamic type m_context << eth::Instruction::SWAP1 << u256(CompilerUtils::dataStartOffset);
unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument; m_context << eth::Instruction::ADD;
solAssert(stackDepth <= 16, "Stack too deep."); // stack: next_pointer data_pointer
m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth); // retrieve length
ArrayUtils(m_context).convertLengthToSize(*previousDynamicType, true); CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true);
m_context << eth::Instruction::ADD; // stack: next_pointer length data_pointer
} m_context << eth::Instruction::SWAP2;
else
m_context << u256(parameterHeadEnd);
stackHeightOfPreviousDynamicArgument = newStackHeight;
previousDynamicType = &dynamic_cast<ArrayType const&>(*type);
offset += CompilerUtils(m_context).loadFromMemory(offset, IntegerType(256), !_fromMemory);
} }
else else
{ {
m_context << u256(offset); // leave the pointer on the stack
offset += type->getCalldataEncodedSize(); m_context << eth::Instruction::DUP1;
m_context << u256(type->getCalldataEncodedSize()) << eth::Instruction::ADD;
} }
break; break;
default: default:
solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, true); CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true);
} }
} }
m_context << eth::Instruction::POP;
} }
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)

14
libsolidity/InterfaceHandler.cpp

@ -55,15 +55,19 @@ std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinitio
for (auto it: _contractDef.getInterfaceFunctions()) for (auto it: _contractDef.getInterfaceFunctions())
{ {
auto externalFunctionType = it.second->externalFunctionType();
Json::Value method; Json::Value method;
method["type"] = "function"; method["type"] = "function";
method["name"] = it.second->getDeclaration().getName(); method["name"] = it.second->getDeclaration().getName();
method["constant"] = it.second->isConstant(); method["constant"] = it.second->isConstant();
method["inputs"] = populateParameters(it.second->getParameterNames(), method["inputs"] = populateParameters(
it.second->getParameterTypeNames()); externalFunctionType->getParameterNames(),
method["outputs"] = populateParameters(it.second->getReturnParameterNames(), externalFunctionType->getParameterTypeNames()
it.second->getReturnParameterTypeNames()); );
method["outputs"] = populateParameters(
externalFunctionType->getReturnParameterNames(),
externalFunctionType->getReturnParameterTypeNames()
);
abi.append(method); abi.append(method);
} }
if (_contractDef.getConstructor()) if (_contractDef.getConstructor())

5
libtestutils/FixedWebThreeServer.cpp

@ -16,7 +16,12 @@
*/ */
/** @file FixedWebThreeStubServer.cpp /** @file FixedWebThreeStubServer.cpp
* @author Marek Kotewicz <marek@ethdev.com> * @author Marek Kotewicz <marek@ethdev.com>
* @author Gav Wood <i@gavwood.com>
* @date 2015 * @date 2015
*/ */
#include "FixedWebThreeServer.h" #include "FixedWebThreeServer.h"
#include <libethereum/Interface.h>
using namespace std;
using namespace dev;
using namespace eth;

6
libtestutils/FixedWebThreeServer.h

@ -23,6 +23,7 @@
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libweb3jsonrpc/WebThreeStubServerBase.h> #include <libweb3jsonrpc/WebThreeStubServerBase.h>
#include <libweb3jsonrpc/AccountHolder.h>
/** /**
* @brief dummy JSON-RPC api implementation * @brief dummy JSON-RPC api implementation
@ -33,7 +34,10 @@
class FixedWebThreeServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace class FixedWebThreeServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace
{ {
public: public:
FixedWebThreeServer(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client): WebThreeStubServerBase(_conn, _accounts), m_client(_client) {}; FixedWebThreeServer(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _allAccounts, dev::eth::Interface* _client):
WebThreeStubServerBase(_conn, std::make_shared<dev::eth::FixedAccountHolder>([=](){return _client;}, _allAccounts), _allAccounts),
m_client(_client)
{}
private: private:
dev::eth::Interface* client() override { return m_client; } dev::eth::Interface* client() override { return m_client; }

51
libweb3jsonrpc/AccountHolder.cpp

@ -26,6 +26,7 @@
#include <ctime> #include <ctime>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/KeyManager.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -35,31 +36,23 @@ vector<TransactionSkeleton> g_emptyQueue;
static std::mt19937 g_randomNumberGenerator(time(0)); static std::mt19937 g_randomNumberGenerator(time(0));
static Mutex x_rngMutex; static Mutex x_rngMutex;
void AccountHolder::setAccounts(vector<KeyPair> const& _accounts) vector<Address> AccountHolder::allAccounts() const
{ {
m_accounts.clear(); vector<Address> accounts;
for (auto const& keyPair: _accounts) accounts += realAccounts();
{
m_accounts.push_back(keyPair.address());
m_keyPairs[keyPair.address()] = keyPair;
}
}
vector<Address> AccountHolder::getAllAccounts() const
{
vector<Address> accounts = m_accounts;
for (auto const& pair: m_proxyAccounts) for (auto const& pair: m_proxyAccounts)
if (!isRealAccount(pair.first)) if (!isRealAccount(pair.first))
accounts.push_back(pair.first); accounts.push_back(pair.first);
return accounts; return accounts;
} }
Address const& AccountHolder::getDefaultTransactAccount() const Address const& AccountHolder::defaultTransactAccount() const
{ {
if (m_accounts.empty()) auto accounts = realAccounts();
if (accounts.empty())
return ZeroAddress; return ZeroAddress;
Address const* bestMatch = &m_accounts.front(); Address const* bestMatch = &*accounts.begin();
for (auto const& account: m_accounts) for (auto const& account: accounts)
if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch))
bestMatch = &account; bestMatch = &account;
return *bestMatch; return *bestMatch;
@ -94,7 +87,7 @@ void AccountHolder::queueTransaction(TransactionSkeleton const& _transaction)
m_transactionQueues[id].second.push_back(_transaction); m_transactionQueues[id].second.push_back(_transaction);
} }
vector<TransactionSkeleton> const& AccountHolder::getQueuedTransactions(int _id) const vector<TransactionSkeleton> const& AccountHolder::queuedTransactions(int _id) const
{ {
if (!m_transactionQueues.count(_id)) if (!m_transactionQueues.count(_id))
return g_emptyQueue; return g_emptyQueue;
@ -106,3 +99,27 @@ void AccountHolder::clearQueue(int _id)
if (m_transactionQueues.count(_id)) if (m_transactionQueues.count(_id))
m_transactionQueues.at(_id).second.clear(); m_transactionQueues.at(_id).second.clear();
} }
AddressHash SimpleAccountHolder::realAccounts() const
{
return m_keyManager.accounts();
}
void SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
{
if (isRealAccount(_t.from))
m_client()->submitTransaction(m_keyManager.secret(_t.from, [&](){ return m_getPassword(_t.from); }), _t);
else if (isProxyAccount(_t.from))
queueTransaction(_t);
}
void FixedAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t)
{
if (isRealAccount(_t.from))
m_client()->submitTransaction(m_accounts[_t.from], _t);
else if (isProxyAccount(_t.from))
queueTransaction(_t);
}

85
libweb3jsonrpc/AccountHolder.h

@ -24,17 +24,20 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <algorithm>
#include <vector> #include <vector>
#include <map> #include <map>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libethereum/Transaction.h>
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
class KeyManager;
class Interface; class Interface;
}
/** /**
* Manages real accounts (where we know the secret key) and proxy accounts (where transactions * Manages real accounts (where we know the secret key) and proxy accounts (where transactions
@ -43,32 +46,84 @@ class Interface;
class AccountHolder class AccountHolder
{ {
public: public:
explicit AccountHolder(std::function<eth::Interface*()> const& _client): m_client(_client) {} explicit AccountHolder(std::function<Interface*()> const& _client): m_client(_client) {}
// easiest to return keyManager.addresses();
virtual AddressHash realAccounts() const = 0;
// use m_web3's submitTransaction
// or use AccountHolder::queueTransaction(_t) to accept
virtual void authenticate(dev::eth::TransactionSkeleton const& _t) = 0;
/// Sets or resets the list of real accounts. Addresses allAccounts() const;
void setAccounts(std::vector<KeyPair> const& _accounts); bool isRealAccount(Address const& _account) const { return realAccounts().count(_account) > 0; }
std::vector<Address> const& getRealAccounts() const { return m_accounts; }
bool isRealAccount(Address const& _account) const { return m_keyPairs.count(_account) > 0; }
bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; } bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; }
Secret const& secretKey(Address const& _account) const { return m_keyPairs.at(_account).secret(); } Address const& defaultTransactAccount() const;
std::vector<Address> getAllAccounts() const;
Address const& getDefaultTransactAccount() const;
int addProxyAccount(Address const& _account); int addProxyAccount(Address const& _account);
bool removeProxyAccount(unsigned _id); bool removeProxyAccount(unsigned _id);
void queueTransaction(eth::TransactionSkeleton const& _transaction); void queueTransaction(eth::TransactionSkeleton const& _transaction);
std::vector<eth::TransactionSkeleton> const& getQueuedTransactions(int _id) const; std::vector<eth::TransactionSkeleton> const& queuedTransactions(int _id) const;
void clearQueue(int _id); void clearQueue(int _id);
protected:
std::function<Interface*()> m_client;
private: private:
using TransactionQueue = std::vector<eth::TransactionSkeleton>; using TransactionQueue = std::vector<eth::TransactionSkeleton>;
std::map<Address, KeyPair> m_keyPairs; std::unordered_map<Address, int> m_proxyAccounts;
std::vector<Address> m_accounts; std::unordered_map<int, std::pair<Address, TransactionQueue>> m_transactionQueues;
std::map<Address, int> m_proxyAccounts; };
std::map<int, std::pair<Address, TransactionQueue>> m_transactionQueues;
std::function<eth::Interface*()> m_client; class SimpleAccountHolder: public AccountHolder
{
public:
SimpleAccountHolder(std::function<Interface*()> const& _client, std::function<std::string(Address)> const& _getPassword, KeyManager& _keyman):
AccountHolder(_client),
m_getPassword(_getPassword),
m_keyManager(_keyman)
{}
AddressHash realAccounts() const override;
void authenticate(dev::eth::TransactionSkeleton const& _t) override;
private:
std::function<std::string(Address)> m_getPassword;
KeyManager& m_keyManager;
};
class FixedAccountHolder: public AccountHolder
{
public:
FixedAccountHolder(std::function<Interface*()> const& _client, std::vector<dev::KeyPair> const& _accounts):
AccountHolder(_client)
{
setAccounts(_accounts);
}
void setAccounts(std::vector<dev::KeyPair> const& _accounts)
{
for (auto const& i: _accounts)
m_accounts[i.address()] = i.secret();
}
dev::AddressHash realAccounts() const override
{
dev::AddressHash ret;
for (auto const& i: m_accounts)
ret.insert(i.first);
return ret;
}
// use m_web3's submitTransaction
// or use AccountHolder::queueTransaction(_t) to accept
void authenticate(dev::eth::TransactionSkeleton const& _t) override;
private:
std::unordered_map<dev::Address, dev::Secret> m_accounts;
}; };
}
} }

4
libweb3jsonrpc/WebThreeStubServer.cpp

@ -33,8 +33,8 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts): WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, shared_ptr<AccountHolder> const& _ethAccounts, std::vector<dev::KeyPair> const& _shhAccounts):
WebThreeStubServerBase(_conn, _accounts), WebThreeStubServerBase(_conn, _ethAccounts, _shhAccounts),
m_web3(_web3) m_web3(_web3)
{ {
auto path = getDataDir() + "/.web3"; auto path = getDataDir() + "/.web3";

2
libweb3jsonrpc/WebThreeStubServer.h

@ -41,7 +41,7 @@ class WebThreeDirect;
class WebThreeStubServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace class WebThreeStubServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace
{ {
public: public:
WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts); WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr<dev::eth::AccountHolder> const& _ethAccounts, std::vector<dev::KeyPair> const& _shhAccounts);
virtual std::string web3_clientVersion(); virtual std::string web3_clientVersion();

43
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -297,10 +297,11 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message
return res; return res;
} }
WebThreeStubServerBase::WebThreeStubServerBase(AbstractServerConnector& _conn, vector<dev::KeyPair> const& _accounts): WebThreeStubServerBase::WebThreeStubServerBase(AbstractServerConnector& _conn, std::shared_ptr<dev::eth::AccountHolder> const& _ethAccounts, vector<dev::KeyPair> const& _sshAccounts):
AbstractWebThreeStubServer(_conn), m_ethAccounts(make_shared<AccountHolder>(bind(&WebThreeStubServerBase::client, this))) AbstractWebThreeStubServer(_conn),
m_ethAccounts(_ethAccounts)
{ {
m_ethAccounts->setAccounts(_accounts); setIdentities(_sshAccounts);
} }
void WebThreeStubServerBase::setIdentities(vector<dev::KeyPair> const& _ids) void WebThreeStubServerBase::setIdentities(vector<dev::KeyPair> const& _ids)
@ -353,7 +354,7 @@ string WebThreeStubServerBase::eth_gasPrice()
Json::Value WebThreeStubServerBase::eth_accounts() Json::Value WebThreeStubServerBase::eth_accounts()
{ {
Json::Value ret(Json::arrayValue); Json::Value ret(Json::arrayValue);
for (auto const& i: m_ethAccounts->getAllAccounts()) for (auto const& i: m_ethAccounts->allAccounts())
ret.append(toJS(i)); ret.append(toJS(i));
return ret; return ret;
} }
@ -499,7 +500,7 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
TransactionSkeleton t = toTransaction(_json); TransactionSkeleton t = toTransaction(_json);
if (!t.from) if (!t.from)
t.from = m_ethAccounts->getDefaultTransactAccount(); t.from = m_ethAccounts->defaultTransactAccount();
if (t.creation) if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));; ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (t.gasPrice == UndefinedU256) if (t.gasPrice == UndefinedU256)
@ -507,10 +508,7 @@ string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json)
if (t.gas == UndefinedU256) if (t.gas == UndefinedU256)
t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice); t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
if (m_ethAccounts->isRealAccount(t.from)) m_ethAccounts->authenticate(t);
authenticate(t, false);
else if (m_ethAccounts->isProxyAccount(t.from))
authenticate(t, true);
return ret; return ret;
} }
@ -528,7 +526,7 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json)
TransactionSkeleton t = toTransaction(_json); TransactionSkeleton t = toTransaction(_json);
if (!t.from) if (!t.from)
t.from = m_ethAccounts->getDefaultTransactAccount(); t.from = m_ethAccounts->defaultTransactAccount();
if (t.creation) if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));; ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (t.gasPrice == UndefinedU256) if (t.gasPrice == UndefinedU256)
@ -536,10 +534,7 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json)
if (t.gas == UndefinedU256) if (t.gas == UndefinedU256)
t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice); t.gas = min<u256>(client()->gasLimitRemaining() / 5, client()->balanceAt(t.from) / t.gasPrice);
if (m_ethAccounts->isRealAccount(t.from)) m_ethAccounts->authenticate(t);
authenticate(t, false);
else if (m_ethAccounts->isProxyAccount(t.from))
authenticate(t, true);
return toJS((t.creation ? Transaction(t.value, t.gasPrice, t.gas, t.data) : Transaction(t.value, t.gasPrice, t.gas, t.to, t.data)).sha3(WithoutSignature)); return toJS((t.creation ? Transaction(t.value, t.gasPrice, t.gas, t.data) : Transaction(t.value, t.gasPrice, t.gas, t.to, t.data)).sha3(WithoutSignature));
} }
@ -579,7 +574,7 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const&
{ {
TransactionSkeleton t = toTransaction(_json); TransactionSkeleton t = toTransaction(_json);
if (!t.from) if (!t.from)
t.from = m_ethAccounts->getDefaultTransactAccount(); t.from = m_ethAccounts->defaultTransactAccount();
// if (!m_accounts->isRealAccount(t.from)) // if (!m_accounts->isRealAccount(t.from))
// return ret; // return ret;
if (t.gasPrice == UndefinedU256) if (t.gasPrice == UndefinedU256)
@ -593,7 +588,6 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const&
{ {
BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS));
} }
} }
bool WebThreeStubServerBase::eth_flush() bool WebThreeStubServerBase::eth_flush()
@ -906,7 +900,7 @@ Json::Value WebThreeStubServerBase::eth_fetchQueuedTransactions(string const& _a
auto id = jsToInt(_accountId); auto id = jsToInt(_accountId);
Json::Value ret(Json::arrayValue); Json::Value ret(Json::arrayValue);
// TODO: throw an error on no account with given id // TODO: throw an error on no account with given id
for (TransactionSkeleton const& t: m_ethAccounts->getQueuedTransactions(id)) for (TransactionSkeleton const& t: m_ethAccounts->queuedTransactions(id))
ret.append(toJson(t)); ret.append(toJson(t));
m_ethAccounts->clearQueue(id); m_ethAccounts->clearQueue(id);
return ret; return ret;
@ -1077,18 +1071,3 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId)
BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS));
} }
} }
void WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool _toProxy)
{
if (_toProxy)
m_ethAccounts->queueTransaction(_t);
else if (_t.to)
client()->submitTransaction(m_ethAccounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice);
else
client()->submitTransaction(m_ethAccounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice);
}
void WebThreeStubServerBase::setAccounts(const vector<KeyPair>& _accounts)
{
m_ethAccounts->setAccounts(_accounts);
}

10
libweb3jsonrpc/WebThreeStubServerBase.h

@ -36,10 +36,10 @@
namespace dev namespace dev
{ {
class WebThreeNetworkFace; class WebThreeNetworkFace;
class AccountHolder;
class KeyPair; class KeyPair;
namespace eth namespace eth
{ {
class AccountHolder;
struct TransactionSkeleton; struct TransactionSkeleton;
class Interface; class Interface;
} }
@ -68,7 +68,7 @@ public:
class WebThreeStubServerBase: public AbstractWebThreeStubServer class WebThreeStubServerBase: public AbstractWebThreeStubServer
{ {
public: public:
WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts); WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::shared_ptr<dev::eth::AccountHolder> const& _ethAccounts, std::vector<dev::KeyPair> const& _sshAccounts);
virtual std::string web3_sha3(std::string const& _param1); virtual std::string web3_sha3(std::string const& _param1);
virtual std::string web3_clientVersion() { return "C++ (ethereum-cpp)"; } virtual std::string web3_clientVersion() { return "C++ (ethereum-cpp)"; }
@ -134,20 +134,16 @@ public:
virtual Json::Value shh_getFilterChanges(std::string const& _filterId); virtual Json::Value shh_getFilterChanges(std::string const& _filterId);
virtual Json::Value shh_getMessages(std::string const& _filterId); virtual Json::Value shh_getMessages(std::string const& _filterId);
void setAccounts(std::vector<dev::KeyPair> const& _accounts);
void setIdentities(std::vector<dev::KeyPair> const& _ids); void setIdentities(std::vector<dev::KeyPair> const& _ids);
std::map<dev::Public, dev::Secret> const& ids() const { return m_shhIds; } std::map<dev::Public, dev::Secret> const& ids() const { return m_shhIds; }
protected:
virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
protected: protected:
virtual dev::eth::Interface* client() = 0; virtual dev::eth::Interface* client() = 0;
virtual std::shared_ptr<dev::shh::Interface> face() = 0; virtual std::shared_ptr<dev::shh::Interface> face() = 0;
virtual dev::WebThreeNetworkFace* network() = 0; virtual dev::WebThreeNetworkFace* network() = 0;
virtual dev::WebThreeStubDatabaseFace* db() = 0; virtual dev::WebThreeStubDatabaseFace* db() = 0;
std::shared_ptr<dev::AccountHolder> m_ethAccounts; std::shared_ptr<dev::eth::AccountHolder> m_ethAccounts;
std::map<dev::Public, dev::Secret> m_shhIds; std::map<dev::Public, dev::Secret> m_shhIds;
std::map<unsigned, dev::Public> m_shhWatches; std::map<unsigned, dev::Public> m_shhWatches;

5
mix/ClientModel.cpp

@ -85,7 +85,8 @@ ClientModel::ClientModel():
connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection);
m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString()));
m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), std::vector<KeyPair>(), m_client.get())); m_ethAccounts = make_shared<FixedAccountHolder>([=](){return m_client.get();}, std::vector<KeyPair>());
m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector<KeyPair>(), m_client.get()));
connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection);
} }
@ -280,7 +281,7 @@ void ClientModel::setupState(QVariantMap _state)
transactionSequence.push_back(transactionSettings); transactionSequence.push_back(transactionSettings);
} }
} }
m_web3Server->setAccounts(userAccounts); m_ethAccounts->setAccounts(userAccounts);
executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString())); executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString()));
} }

3
mix/ClientModel.h

@ -35,7 +35,7 @@
namespace dev namespace dev
{ {
namespace eth { class Account; } namespace eth { class Account; class FixedAccountHolder; }
namespace mix namespace mix
{ {
@ -235,6 +235,7 @@ private:
std::unique_ptr<MixClient> m_client; std::unique_ptr<MixClient> m_client;
std::unique_ptr<RpcConnector> m_rpcConnector; std::unique_ptr<RpcConnector> m_rpcConnector;
std::unique_ptr<Web3Server> m_web3Server; std::unique_ptr<Web3Server> m_web3Server;
std::shared_ptr<eth::FixedAccountHolder> m_ethAccounts;
QList<u256> m_gasCosts; QList<u256> m_gasCosts;
std::map<QString, Address> m_contractAddresses; std::map<QString, Address> m_contractAddresses;
std::map<Address, QString> m_contractNames; std::map<Address, QString> m_contractNames;

18
mix/ContractCallDataEncoder.cpp

@ -36,6 +36,14 @@ using namespace dev::mix;
bytes ContractCallDataEncoder::encodedData() bytes ContractCallDataEncoder::encodedData()
{ {
bytes r(m_encodedData); bytes r(m_encodedData);
size_t headerSize = m_encodedData.size() & ~0x1fUL; //ignore any prefix that is not 32-byte aligned
//apply offsets
for (auto const& p: m_offsetMap)
{
vector_ref<byte> offsetRef(r.data() + p.first, 32);
toBigEndian<size_t, vector_ref<byte>>(p.second + headerSize, offsetRef); //add header size minus signature hash
}
r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end());
return r; return r;
} }
@ -64,6 +72,9 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const&
if (_type.dynamicSize) if (_type.dynamicSize)
{ {
bytes empty(32);
size_t sizePos = m_dynamicData.size();
m_dynamicData += empty; //reserve space for count
if (_type.type == SolidityType::Type::Bytes) if (_type.type == SolidityType::Type::Bytes)
count = encodeSingleItem(_data.toString(), _type, m_dynamicData); count = encodeSingleItem(_data.toString(), _type, m_dynamicData);
else else
@ -72,9 +83,10 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const&
for (auto const& item: strList) for (auto const& item: strList)
encodeSingleItem(item, _type, m_dynamicData); encodeSingleItem(item, _type, m_dynamicData);
} }
bytes sizeEnc(32); vector_ref<byte> sizeRef(m_dynamicData.data() + sizePos, 32);
toBigEndian(count, sizeEnc); toBigEndian(count, sizeRef);
m_encodedData.insert(m_encodedData.end(), sizeEnc.begin(), sizeEnc.end()); m_offsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos));
m_encodedData += empty; //reserve space for offset
} }
else else
{ {

1
mix/ContractCallDataEncoder.h

@ -73,6 +73,7 @@ private:
private: private:
bytes m_encodedData; bytes m_encodedData;
bytes m_dynamicData; bytes m_dynamicData;
std::vector<std::pair<size_t, size_t>> m_offsetMap;
}; };
} }

33
mix/MixClient.cpp

@ -98,22 +98,30 @@ void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts
m_executions.clear(); m_executions.clear();
} }
Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas) Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secret const& _secret)
{ {
Transaction ret; Transaction ret;
if (_t.isCreation()) if (_secret)
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce()); {
if (_t.isCreation())
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret);
else
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret);
}
else else
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce()); {
ret.forceSender(_t.safeSender()); if (_t.isCreation())
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce());
else
ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce());
ret.forceSender(_t.safeSender());
}
return ret; return ret;
} }
void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto) void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret)
{ {
Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t;
bytes rlp = t.rlp();
// do debugging run first // do debugging run first
LastHashes lastHashes(256); LastHashes lastHashes(256);
lastHashes[0] = bc().numberHash(bc().number()); lastHashes[0] = bc().numberHash(bc().number());
@ -123,7 +131,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
State execState = _state; State execState = _state;
execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation
Executive execution(execState, lastHashes, 0); Executive execution(execState, lastHashes, 0);
execution.initialize(&rlp); execution.initialize(t);
execution.execute(); execution.execute();
std::vector<MachineState> machineStates; std::vector<MachineState> machineStates;
std::vector<unsigned> levels; std::vector<unsigned> levels;
@ -222,7 +230,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
// execute on a state // execute on a state
if (!_call) if (!_call)
{ {
t = _gasAuto ? replaceGas(_t, d.gasUsed) : _t; t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t;
er =_state.execute(lastHashes, t); er =_state.execute(lastHashes, t);
if (t.isCreation() && _state.code(d.contractAddress).empty()) if (t.isCreation() && _state.code(d.contractAddress).empty())
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
@ -285,7 +293,7 @@ void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, by
WriteGuard l(x_state); WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret)); u256 n = m_state.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
executeTransaction(t, m_state, false, _gasAuto); executeTransaction(t, m_state, false, _gasAuto, _secret);
} }
Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto) Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto)
@ -293,7 +301,7 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons
WriteGuard l(x_state); WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret)); u256 n = m_state.transactionsFrom(toAddress(_secret));
eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
executeTransaction(t, m_state, false, _gasAuto); executeTransaction(t, m_state, false, _gasAuto, _secret);
Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); Address address = right160(sha3(rlpList(t.sender(), t.nonce())));
return address; return address;
} }
@ -307,7 +315,6 @@ dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Add
t.forceSender(_from); t.forceSender(_from);
if (_ff == FudgeFactor::Lenient) if (_ff == FudgeFactor::Lenient)
temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
bytes rlp = t.rlp();
WriteGuard lw(x_state); //TODO: lock is required only for last execution state WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true, _gasAuto); executeTransaction(t, temp, true, _gasAuto);
return lastExecution().result; return lastExecution().result;

4
mix/MixClient.h

@ -87,9 +87,9 @@ protected:
virtual void prepareForTransaction() override {} virtual void prepareForTransaction() override {}
private: private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto); void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret = dev::Secret());
void noteChanged(h256Set const& _filters); void noteChanged(h256Set const& _filters);
dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas); dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas, dev::Secret const& _secret = dev::Secret());
eth::State m_state; eth::State m_state;
eth::State m_startState; eth::State m_startState;

5
mix/Web3Server.cpp

@ -24,6 +24,7 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libethereum/Interface.h> #include <libethereum/Interface.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libweb3jsonrpc/AccountHolder.h>
#include "Web3Server.h" #include "Web3Server.h"
using namespace dev::mix; using namespace dev::mix;
@ -108,8 +109,8 @@ class EmptyNetwork : public dev::WebThreeNetworkFace
} }
Web3Server::Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client): Web3Server::Web3Server(jsonrpc::AbstractServerConnector& _conn, std::shared_ptr<eth::AccountHolder> const& _ethAccounts, std::vector<dev::KeyPair> const& _shhAccounts, dev::eth::Interface* _client):
WebThreeStubServerBase(_conn, _accounts), WebThreeStubServerBase(_conn, _ethAccounts, _shhAccounts),
m_client(_client), m_client(_client),
m_network(new EmptyNetwork()) m_network(new EmptyNetwork())
{ {

3
mix/Web3Server.h

@ -25,6 +25,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <QObject> #include <QObject>
#include <libweb3jsonrpc/AccountHolder.h>
#include <libweb3jsonrpc/WebThreeStubServerBase.h> #include <libweb3jsonrpc/WebThreeStubServerBase.h>
namespace dev namespace dev
@ -38,7 +39,7 @@ class Web3Server: public QObject, public dev::WebThreeStubServerBase, public dev
Q_OBJECT Q_OBJECT
public: public:
Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client); Web3Server(jsonrpc::AbstractServerConnector& _conn, std::shared_ptr<eth::AccountHolder> const& _ethAccounts, std::vector<dev::KeyPair> const& _shhAccounts, dev::eth::Interface* _client);
virtual ~Web3Server(); virtual ~Web3Server();
signals: signals:

9
neth/main.cpp

@ -36,8 +36,9 @@
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#if ETH_JSONRPC #if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/AccountHolder.h>
#include <jsonrpccpp/server/connectors/httpserver.h> #include <jsonrpccpp/server/connectors/httpserver.h>
#endif #endif
#include "BuildInfo.h" #include "BuildInfo.h"
@ -573,13 +574,13 @@ int main(int argc, char** argv)
if (c && mining) if (c && mining)
c->startMining(); c->startMining();
#if ETH_JSONRPC #if ETH_JSONRPC || !ETH_TRUE
shared_ptr<WebThreeStubServer> jsonrpcServer; shared_ptr<WebThreeStubServer> jsonrpcServer;
unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector; unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector;
if (jsonrpc > -1) if (jsonrpc > -1)
{ {
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads));
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us}))); jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<dev::eth::FixedAccountHolder>([&](){ return web3.ethereum(); }, vector<KeyPair>({us})), vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us}); jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }
@ -793,7 +794,7 @@ int main(int argc, char** argv)
#else #else
jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", 4)); jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::HttpServer(jsonrpc, "", "", 4));
#endif #endif
jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector<KeyPair>({us}))); jsonrpcServer = shared_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared<dev::eth::FixedAccountHolder>([&](){ return web3.ethereum(); }, vector<KeyPair>({us})), vector<KeyPair>({us})));
jsonrpcServer->setIdentities({us}); jsonrpcServer->setIdentities({us});
jsonrpcServer->StartListening(); jsonrpcServer->StartListening();
} }

10
test/libevm/vm.cpp

@ -492,16 +492,10 @@ BOOST_AUTO_TEST_CASE(vmPerformanceTest)
dev::test::executeTests("vmPerformanceTest", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests); dev::test::executeTests("vmPerformanceTest", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests);
} }
BOOST_AUTO_TEST_CASE(vmInputLimitsTest1) BOOST_AUTO_TEST_CASE(vmInputLimitsTest)
{ {
if (test::Options::get().inputLimits) if (test::Options::get().inputLimits)
dev::test::executeTests("vmInputLimits1", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests); dev::test::executeTests("vmInputLimits", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests);
}
BOOST_AUTO_TEST_CASE(vmInputLimitsTest2)
{
if (test::Options::get().inputLimits)
dev::test::executeTests("vmInputLimits2", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests);
} }
BOOST_AUTO_TEST_CASE(vmInputLimitsLightTest) BOOST_AUTO_TEST_CASE(vmInputLimitsLightTest)

43
test/libsolidity/SolidityABIJSON.cpp

@ -525,6 +525,49 @@ BOOST_AUTO_TEST_CASE(constructor_abi)
checkInterface(sourceCode, interface); checkInterface(sourceCode, interface);
} }
BOOST_AUTO_TEST_CASE(return_param_in_abi)
{
// bug #1801
char const* sourceCode = R"(
contract test {
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
function test(ActionChoices param) {}
function ret() returns(ActionChoices){
ActionChoices action = ActionChoices.GoLeft;
return action;
}
}
)";
char const* interface = R"(
[
{
"constant" : false,
"inputs" : [],
"name" : "ret",
"outputs" : [
{
"name" : "",
"type" : "uint8"
}
],
"type" : "function"
},
{
"inputs": [
{
"name": "param",
"type": "uint8"
}
],
"type": "constructor"
}
]
)";
checkInterface(sourceCode, interface);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

10
test/libsolidity/SolidityCompiler.cpp

@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 70; unsigned boilerplateSize = 73;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x0, // initialize local variable x
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
@ -114,8 +114,8 @@ BOOST_AUTO_TEST_CASE(ifStatement)
" function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 57; unsigned shift = 60;
unsigned boilerplateSize = 70; unsigned boilerplateSize = 73;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), byte(Instruction::DUP1),
@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(loops)
" function f() { while(true){1;break;2;continue;3;return;4;} }" " function f() { while(true){1;break;2;continue;3;return;4;} }"
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 57; unsigned shift = 60;
unsigned boilerplateSize = 70; unsigned boilerplateSize = 73;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,

17
test/libsolidity/SolidityEndToEndTest.cpp

@ -2962,12 +2962,13 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments)
} }
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9));
bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13);
string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3));
bytes calldata = encodeArgs( bytes calldata = encodeArgs(
12, u256(innercalldata1.length()), u256(innercalldata2.length()), 13, 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13,
innercalldata1, innercalldata2); u256(innercalldata1.length()), innercalldata1,
u256(innercalldata2.length()), innercalldata2);
BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata) BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata)
== encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))); == encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())));
} }
@ -3383,9 +3384,10 @@ BOOST_AUTO_TEST_CASE(external_array_args)
compileAndRun(sourceCode); compileAndRun(sourceCode);
bytes params = encodeArgs( bytes params = encodeArgs(
1, 2, 3, 4, 5, 6, 7, 8, // a 1, 2, 3, 4, 5, 6, 7, 8, // a
3, // b.length 32 * (8 + 1 + 5 + 1 + 1 + 1), // offset to b
21, 22, 23, 24, 25, // c 21, 22, 23, 24, 25, // c
0, 1, 2, // (a,b,c)_index 0, 1, 2, // (a,b,c)_index
3, // b.length
11, 12, 13 // b 11, 12, 13 // b
); );
BOOST_CHECK(callContractFunction("test(uint256[8],uint256[],uint256[5],uint256,uint256,uint256)", params) == encodeArgs(1, 12, 23)); BOOST_CHECK(callContractFunction("test(uint256[8],uint256[],uint256[5],uint256,uint256,uint256)", params) == encodeArgs(1, 12, 23));
@ -3422,8 +3424,8 @@ BOOST_AUTO_TEST_CASE(bytes_index_access)
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33}; 30, 31, 32, 33};
BOOST_CHECK(callContractFunction("direct(bytes,uint256)", u256(array.length()), 32, array) == encodeArgs(32)); BOOST_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array) == encodeArgs(33));
BOOST_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", u256(array.length()), 32, array) == encodeArgs(32)); BOOST_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array) == encodeArgs(33));
BOOST_CHECK(callContractFunction("storageWrite()") == encodeArgs(0x193)); BOOST_CHECK(callContractFunction("storageWrite()") == encodeArgs(0x193));
} }
@ -3474,6 +3476,7 @@ BOOST_AUTO_TEST_CASE(array_copy_calldata_storage)
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs( BOOST_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs(
21, 22, 23, 24, 25, 26, 27, 28, 29, // a 21, 22, 23, 24, 25, 26, 27, 28, 29, // a
u256(32 * (9 + 1)),
4, // size of b 4, // size of b
1, 2, 3, // b[0] 1, 2, 3, // b[0]
11, 12, 13, // b[1] 11, 12, 13, // b[1]
@ -3502,7 +3505,7 @@ BOOST_AUTO_TEST_CASE(array_copy_nested_array)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test(uint256[2][])", encodeArgs( BOOST_CHECK(callContractFunction("test(uint256[2][])", encodeArgs(
3, 32, 3,
7, 8, 7, 8,
9, 10, 9, 10,
11, 12 11, 12

22
test/libsolidity/SolidityNameAndTypeResolution.cpp

@ -508,6 +508,28 @@ BOOST_AUTO_TEST_CASE(function_external_types)
} }
} }
BOOST_AUTO_TEST_CASE(enum_external_type)
{
// bug #1801
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
contract Test {
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
function boo(ActionChoices enumArg) external returns (uint ret) {
ret = 5;
}
})";
ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
auto functions = contract->getDefinedFunctions();
if (functions.empty())
continue;
BOOST_CHECK_EQUAL("boo(uint8)", functions[0]->externalSignature());
}
}
BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion) BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
{ {
char const* text = R"( char const* text = R"(

28
test/libweb3jsonrpc/AccountHolder.cpp

@ -22,6 +22,9 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <libweb3jsonrpc/AccountHolder.h> #include <libweb3jsonrpc/AccountHolder.h>
using namespace std;
using namespace dev;
using namespace eth;
namespace dev namespace dev
{ {
@ -32,16 +35,17 @@ BOOST_AUTO_TEST_SUITE(AccountHolderTest)
BOOST_AUTO_TEST_CASE(ProxyAccountUseCase) BOOST_AUTO_TEST_CASE(ProxyAccountUseCase)
{ {
AccountHolder h = AccountHolder(std::function<eth::Interface*()>()); FixedAccountHolder h = FixedAccountHolder(function<Interface*()>(), vector<KeyPair>());
BOOST_CHECK(h.getAllAccounts().empty());
BOOST_CHECK(h.getRealAccounts().empty()); BOOST_CHECK(h.allAccounts().empty());
BOOST_CHECK(h.realAccounts().empty());
Address addr("abababababababababababababababababababab"); Address addr("abababababababababababababababababababab");
Address addr2("abababababababababababababababababababab"); Address addr2("abababababababababababababababababababab");
int id = h.addProxyAccount(addr); int id = h.addProxyAccount(addr);
BOOST_CHECK(h.getQueuedTransactions(id).empty()); BOOST_CHECK(h.queuedTransactions(id).empty());
// register it again // register it again
int secondID = h.addProxyAccount(addr); int secondID = h.addProxyAccount(addr);
BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); BOOST_CHECK(h.queuedTransactions(secondID).empty());
eth::TransactionSkeleton t1; eth::TransactionSkeleton t1;
eth::TransactionSkeleton t2; eth::TransactionSkeleton t2;
@ -49,20 +53,20 @@ BOOST_AUTO_TEST_CASE(ProxyAccountUseCase)
t1.data = fromHex("12345678"); t1.data = fromHex("12345678");
t2.from = addr; t2.from = addr;
t2.data = fromHex("abcdef"); t2.data = fromHex("abcdef");
BOOST_CHECK(h.getQueuedTransactions(id).empty()); BOOST_CHECK(h.queuedTransactions(id).empty());
h.queueTransaction(t1); h.queueTransaction(t1);
BOOST_CHECK_EQUAL(1, h.getQueuedTransactions(id).size()); BOOST_CHECK_EQUAL(1, h.queuedTransactions(id).size());
h.queueTransaction(t2); h.queueTransaction(t2);
BOOST_REQUIRE_EQUAL(2, h.getQueuedTransactions(id).size()); BOOST_REQUIRE_EQUAL(2, h.queuedTransactions(id).size());
// second proxy should not see transactions // second proxy should not see transactions
BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); BOOST_CHECK(h.queuedTransactions(secondID).empty());
BOOST_CHECK(h.getQueuedTransactions(id)[0].data == t1.data); BOOST_CHECK(h.queuedTransactions(id)[0].data == t1.data);
BOOST_CHECK(h.getQueuedTransactions(id)[1].data == t2.data); BOOST_CHECK(h.queuedTransactions(id)[1].data == t2.data);
h.clearQueue(id); h.clearQueue(id);
BOOST_CHECK(h.getQueuedTransactions(id).empty()); BOOST_CHECK(h.queuedTransactions(id).empty());
// removing fails because it never existed // removing fails because it never existed
BOOST_CHECK(!h.removeProxyAccount(secondID)); BOOST_CHECK(!h.removeProxyAccount(secondID));
BOOST_CHECK(h.removeProxyAccount(id)); BOOST_CHECK(h.removeProxyAccount(id));

Loading…
Cancel
Save