Browse Source

Merge remote-tracking branch 'up/develop' into bugFix2

Conflicts:
	test/webthreestubclient.h
cl-refactor
yann300 10 years ago
parent
commit
13fa394f60
  1. 1
      CMakeLists.txt
  2. 2
      alethzero/Context.h
  3. 129
      alethzero/MainWin.cpp
  4. 2
      alethzero/MainWin.h
  5. 33
      alethzero/Transact.cpp
  6. 2
      alethzero/Transact.ui
  7. 13
      cmake/EthCompilerSettings.cmake
  8. 43
      docker/Dockerfile
  9. 31
      docker/README.md
  10. 23
      docker/supervisord.conf
  11. 51
      eth/main.cpp
  12. 41
      ethminer/CMakeLists.txt
  13. 39
      ethminer/Farm.h
  14. 28
      ethminer/PhoneHome.h
  15. 4
      ethminer/farm.json
  16. 483
      ethminer/main.cpp
  17. 3
      ethminer/phonehome.json
  18. 2
      evmjit/libevmjit-cpp/CMakeLists.txt
  19. 21
      libdevcore/Base64.h
  20. 6
      libdevcore/CMakeLists.txt
  21. 28
      libdevcore/CommonData.h
  22. 1
      libdevcore/Exceptions.h
  23. 2
      libdevcore/Log.h
  24. 6
      libdevcrypto/CMakeLists.txt
  25. 4
      libdevcrypto/Common.cpp
  26. 4
      libethash/CMakeLists.txt
  27. 0
      libethcore/ABI.cpp
  28. 8
      libethcore/ABI.h
  29. 6
      libethcore/CMakeLists.txt
  30. 5
      libethcore/Common.cpp
  31. 2
      libethcore/Common.h
  32. 4
      libethcore/Ethash.cpp
  33. 4
      libethcore/EthashAux.cpp
  34. 2
      libethcore/EthashAux.h
  35. 158
      libethcore/ICAP.cpp
  36. 107
      libethcore/ICAP.h
  37. 19
      libethereum/BlockChain.cpp
  38. 2
      libethereum/BlockChain.h
  39. 6
      libethereum/CMakeLists.txt
  40. 60
      libethereum/Client.cpp
  41. 9
      libethereum/Client.h
  42. 4
      libethereum/ClientBase.cpp
  43. 3
      libethereum/ClientBase.h
  44. 6
      libethereum/Interface.h
  45. 2
      libethereum/Transaction.cpp
  46. 8
      libethereum/Transaction.h
  47. 6
      libethereumx/CMakeLists.txt
  48. 6
      libevm/CMakeLists.txt
  49. 13
      libevmcore/AssemblyItem.h
  50. 6
      libevmcore/CMakeLists.txt
  51. 176
      libevmcore/CommonSubexpressionEliminator.cpp
  52. 20
      libevmcore/CommonSubexpressionEliminator.h
  53. 24
      libevmcore/ExpressionClasses.cpp
  54. 10
      libevmcore/ExpressionClasses.h
  55. 1
      libjsqrc/ethereumjs/.travis.yml
  56. 34
      libjsqrc/ethereumjs/README.md
  57. 2
      libjsqrc/ethereumjs/bower.json
  58. 1644
      libjsqrc/ethereumjs/dist/web3-light.js
  59. 46
      libjsqrc/ethereumjs/dist/web3-light.js.map
  60. 3
      libjsqrc/ethereumjs/dist/web3-light.min.js
  61. 6998
      libjsqrc/ethereumjs/dist/web3.js
  62. 50
      libjsqrc/ethereumjs/dist/web3.js.map
  63. 4
      libjsqrc/ethereumjs/dist/web3.min.js
  64. 57
      libjsqrc/ethereumjs/example/contract.html
  65. 77
      libjsqrc/ethereumjs/example/contract_with_array.html
  66. 119
      libjsqrc/ethereumjs/example/event.html
  67. 65
      libjsqrc/ethereumjs/example/event_inc.html
  68. 143
      libjsqrc/ethereumjs/lib/solidity/abi.js
  69. 329
      libjsqrc/ethereumjs/lib/solidity/coder.js
  70. 114
      libjsqrc/ethereumjs/lib/solidity/formatters.js
  71. 105
      libjsqrc/ethereumjs/lib/solidity/param.js
  72. 77
      libjsqrc/ethereumjs/lib/solidity/types.js
  73. 30
      libjsqrc/ethereumjs/lib/solidity/utils.js
  74. 3
      libjsqrc/ethereumjs/lib/utils/config.js
  75. 42
      libjsqrc/ethereumjs/lib/utils/utils.js
  76. 2
      libjsqrc/ethereumjs/lib/version.json
  77. 17
      libjsqrc/ethereumjs/lib/web3.js
  78. 184
      libjsqrc/ethereumjs/lib/web3/contract.js
  79. 22
      libjsqrc/ethereumjs/lib/web3/errors.js
  80. 13
      libjsqrc/ethereumjs/lib/web3/eth.js
  81. 246
      libjsqrc/ethereumjs/lib/web3/event.js
  82. 57
      libjsqrc/ethereumjs/lib/web3/filter.js
  83. 15
      libjsqrc/ethereumjs/lib/web3/formatters.js
  84. 151
      libjsqrc/ethereumjs/lib/web3/function.js
  85. 18
      libjsqrc/ethereumjs/lib/web3/httpprovider.js
  86. 2
      libjsqrc/ethereumjs/lib/web3/method.js
  87. 6
      libjsqrc/ethereumjs/lib/web3/requestmanager.js
  88. 2
      libjsqrc/ethereumjs/lib/web3/shh.js
  89. 42
      libjsqrc/ethereumjs/lib/web3/signature.js
  90. 2
      libjsqrc/ethereumjs/package-init.js
  91. 7
      libjsqrc/ethereumjs/package.js
  92. 4
      libjsqrc/ethereumjs/package.json
  93. 14
      libjsqrc/ethereumjs/test/abi.inputParser.js
  94. 96
      libjsqrc/ethereumjs/test/abi.outputParser.js
  95. 68
      libjsqrc/ethereumjs/test/coder.decodeParam.js
  96. 91
      libjsqrc/ethereumjs/test/coder.encodeParam.js
  97. 147
      libjsqrc/ethereumjs/test/contract.js
  98. 180
      libjsqrc/ethereumjs/test/event.decode.js
  99. 206
      libjsqrc/ethereumjs/test/event.encode.js
  100. 113
      libjsqrc/ethereumjs/test/event.inputParser.js

1
CMakeLists.txt

@ -354,6 +354,7 @@ if (TOOLS)
add_subdirectory(rlp) add_subdirectory(rlp)
add_subdirectory(abi) add_subdirectory(abi)
add_subdirectory(ethminer)
add_subdirectory(eth) add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")

2
alethzero/Context.h

@ -62,7 +62,7 @@ public:
virtual QString pretty(dev::Address _a) const = 0; virtual QString pretty(dev::Address _a) const = 0;
virtual QString prettyU256(dev::u256 _n) const = 0; virtual QString prettyU256(dev::u256 _n) const = 0;
virtual QString render(dev::Address _a) const = 0; virtual QString render(dev::Address _a) const = 0;
virtual dev::Address fromString(QString const& _a) const = 0; virtual std::pair<dev::Address, dev::bytes> fromString(QString 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;
}; };

129
alethzero/MainWin.cpp

@ -46,6 +46,7 @@
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libethcore/CommonJS.h> #include <libethcore/CommonJS.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libethcore/ICAP.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
@ -217,6 +218,7 @@ Main::Main(QWidget *parent) :
Main::~Main() Main::~Main()
{ {
m_httpConnector->StopListening();
writeSettings(); writeSettings();
// Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor) // Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor)
// *after* the client is dead. // *after* the client is dead.
@ -326,7 +328,8 @@ void Main::installWatches()
Address Main::getNameReg() const Address Main::getNameReg() const
{ {
return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)).output); return Address("c6d9d2cd449a754c494264e1809c50e34d64562b");
// return abiOut<Address>(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)1)).output);
} }
Address Main::getCurrencies() const Address Main::getCurrencies() const
@ -512,137 +515,65 @@ QString Main::pretty(dev::Address _a) const
if (g_newNameReg) if (g_newNameReg)
{ {
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)).output))); QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("getName(address)", _a)).output)));
if (s.size()) if (s.size())
return s; return s;
} }
h256 n; return QString();
return fromRaw(n);
}
template <size_t N> inline string toBase36(FixedHash<N> const& _h)
{
static char const* c_alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
typename FixedHash<N>::Arith a = _h;
std::string ret;
for (; a > 0; a /= 36)
ret = c_alphabet[(unsigned)a % 36] + ret;
return ret;
}
template <size_t N> inline FixedHash<N> fromBase36(string const& _h)
{
typename FixedHash<N>::Arith ret = 0;
for (char c: _h)
ret = ret * 36 + (c < 'A' ? c - '0' : (c - 'A' + 10));
return ret;
}
static string iban(std::string _c, std::string _d)
{
boost::to_upper(_c);
boost::to_upper(_d);
auto totStr = _d + _c + "00";
bigint tot = 0;
for (char x: totStr)
if (x >= 'A')
tot = tot * 100 + x - 'A' + 10;
else
tot = tot * 10 + x - '0';
unsigned check = (unsigned)(u256)(98 - tot % 97);
ostringstream out;
out << _c << setfill('0') << setw(2) << check << _d;
return out.str();
}
static std::pair<string, string> fromIban(std::string _iban)
{
if (_iban.size() < 4)
return std::make_pair(string(), string());
boost::to_upper(_iban);
std::string c = _iban.substr(0, 2);
std::string d = _iban.substr(4);
if (iban(c, d) != _iban)
return std::make_pair(string(), string());
return make_pair(c, d);
}
static string directICAP(dev::Address _a)
{
if (!!_a[0])
return string();
std::string d = toBase36<Address::size>(_a);
while (d.size() < 30)
d = "0" + d;
return iban("XE", d);
}
static Address fromICAP(std::string const& _s)
{
std::string country;
std::string data;
std::tie(country, data) = fromIban(_s);
if (country.empty())
return Address();
if (country == "XE" && data.size() == 30)
// Direct ICAP
return fromBase36<Address::size>(data);
// TODO: Indirect ICAP
return Address();
} }
QString Main::render(dev::Address _a) const QString Main::render(dev::Address _a) const
{ {
QString p = pretty(_a); QString p = pretty(_a);
if (!_a[0]) QString n;
p += QString(p.isEmpty() ? "" : " ") + QString::fromStdString(directICAP(_a)); try {
if (!p.isEmpty()) n = QString::fromStdString(ICAP(_a).encoded());
return p + " (" + QString::fromStdString(_a.abridged()) + ")"; }
return QString::fromStdString(_a.abridged()); catch (...) {
} n = QString::fromStdString(_a.abridged());
}
string32 fromString(string const& _s) return p.isEmpty() ? n : (p + " " + n);
{
string32 ret;
for (unsigned i = 0; i < 32 && i <= _s.size(); ++i)
ret[i] = i < _s.size() ? _s[i] : 0;
return ret;
} }
Address Main::fromString(QString const& _n) const pair<Address, bytes> Main::fromString(QString const& _n) const
{ {
if (_n == "(Create Contract)") if (_n == "(Create Contract)")
return Address(); return make_pair(Address(), bytes());
auto g_newNameReg = getNameReg(); auto g_newNameReg = getNameReg();
if (g_newNameReg) if (g_newNameReg)
{ {
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))).output); Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addr(bytes32)", ::toString32(_n.toStdString()))).output);
if (a) if (a)
return a; return make_pair(a, bytes());
} }
if (_n.size() == 40) if (_n.size() == 40)
{ {
try try
{ {
return Address(fromHex(_n.toStdString(), WhenError::Throw)); return make_pair(Address(fromHex(_n.toStdString(), WhenError::Throw)), bytes());
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {
cwarn << "invalid hex character, address rejected"; cwarn << "invalid hex character, address rejected";
cwarn << boost::diagnostic_information(_e); cwarn << boost::diagnostic_information(_e);
return Address(); return make_pair(Address(), bytes());
} }
catch (...) catch (...)
{ {
cwarn << "address rejected"; cwarn << "address rejected";
return Address(); return make_pair(Address(), bytes());
} }
} }
else if (Address a = fromICAP(_n.toStdString()))
return a;
else else
return Address(); try {
return ICAP::decoded(_n.toStdString()).address([&](Address const& a, bytes const& b) -> bytes
{
return ethereum()->call(a, b).output;
}, g_newNameReg);
}
catch (...) {}
return make_pair(Address(), bytes());
} }
QString Main::lookup(QString const& _a) const QString Main::lookup(QString const& _a) const
@ -1440,7 +1371,7 @@ void Main::on_inject_triggered()
try try
{ {
bytes b = fromHex(s.toStdString(), WhenError::Throw); bytes b = fromHex(s.toStdString(), WhenError::Throw);
ethereum()->inject(&b); ethereum()->injectTransaction(b);
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
{ {

2
alethzero/MainWin.h

@ -83,7 +83,7 @@ public:
QString pretty(dev::Address _a) const override; QString pretty(dev::Address _a) const override;
QString prettyU256(dev::u256 _n) const override; QString prettyU256(dev::u256 _n) const override;
QString render(dev::Address _a) const override; QString render(dev::Address _a) const override;
dev::Address fromString(QString const& _a) const override; std::pair<dev::Address, dev::bytes> fromString(QString 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 + m_myKeys; }

33
alethzero/Transact.cpp

@ -30,10 +30,12 @@
#include <QMessageBox> #include <QMessageBox>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <liblll/CodeFragment.h> #include <liblll/CodeFragment.h>
#if ETH_SOLIDITY || !ETH_TRUE
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
#endif
#include <libnatspec/NatspecExpressionEvaluator.h> #include <libnatspec/NatspecExpressionEvaluator.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Utility.h> #include <libethereum/Utility.h>
@ -113,7 +115,7 @@ void Transact::updateDestination()
if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1) if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1)
ui->destination->addItem(s); ui->destination->addItem(s);
for (int i = 0; i < ui->destination->count(); ++i) for (int i = 0; i < ui->destination->count(); ++i)
if (ui->destination->itemText(i) != "(Create Contract)" && !m_context->fromString(ui->destination->itemText(i))) if (ui->destination->itemText(i) != "(Create Contract)" && !m_context->fromString(ui->destination->itemText(i)).first)
ui->destination->removeItem(i--); ui->destination->removeItem(i--);
} }
@ -139,10 +141,25 @@ void Transact::updateFee()
void Transact::on_destination_currentTextChanged(QString) void Transact::on_destination_currentTextChanged(QString)
{ {
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)") if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)")
if (Address a = m_context->fromString(ui->destination->currentText())) {
ui->calculatedName->setText(m_context->render(a)); auto p = m_context->fromString(ui->destination->currentText());
if (p.first)
ui->calculatedName->setText(m_context->render(p.first));
else else
ui->calculatedName->setText("Unknown Address"); ui->calculatedName->setText("Unknown Address");
if (!p.second.empty())
{
m_data = p.second;
ui->data->setPlainText(QString::fromStdString("0x" + toHex(m_data)));
ui->data->setEnabled(false);
}
else if (!ui->data->isEnabled())
{
m_data.clear();
ui->data->setPlainText("");
ui->data->setEnabled(true);
}
}
else else
ui->calculatedName->setText("Create Contract"); ui->calculatedName->setText("Create Contract");
rejigData(); rejigData();
@ -199,7 +216,7 @@ static tuple<vector<string>, bytes, string> userInputToCode(string const& _user,
boost::replace_all_copy(u, " ", ""); boost::replace_all_copy(u, " ", "");
data = fromHex(u); data = fromHex(u);
} }
#if ETH_SOLIDITY #if ETH_SOLIDITY || !ETH_TRUE
else if (sourceIsSolidity(_user)) else if (sourceIsSolidity(_user))
{ {
dev::solidity::CompilerStack compiler(true); dev::solidity::CompilerStack compiler(true);
@ -329,7 +346,8 @@ void Transact::rejigData()
er = ethereum()->create(s, value(), m_data, gasNeeded, gasPrice()); er = ethereum()->create(s, value(), m_data, gasNeeded, gasPrice());
else else
{ {
to = m_context->fromString(ui->destination->currentText()); // TODO: cache like m_data.
to = m_context->fromString(ui->destination->currentText()).first;
er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice()); er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
} }
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded); gasNeeded = (qint64)(er.gasUsed + er.gasRefunded);
@ -415,7 +433,8 @@ void Transact::on_send_clicked()
#endif #endif
} }
else else
ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); // TODO: cache like m_data.
ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText()).first, m_data, ui->gas->value(), gasPrice());
close(); close();
} }
@ -434,7 +453,7 @@ 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(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()), m_data, st.transactionsFrom(dev::toAddress(s)), s); Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()).first, m_data, st.transactionsFrom(dev::toAddress(s)), s);
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);

2
alethzero/Transact.ui

@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</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="2" column="1" colspan="2">

13
cmake/EthCompilerSettings.cmake

@ -8,7 +8,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE")
set(ETH_SHARED 1)
if (PROFILING) if (PROFILING)
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")
@ -31,7 +30,6 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG")
set(ETH_SHARED 1)
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX")
@ -55,8 +53,10 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# stack size 16MB # stack size 16MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216")
# windows likes static # windows likes static
set(ETH_STATIC 1) if (NOT ETH_STATIC)
message("Forcing static linkage for MSVC.")
set(ETH_STATIC 1)
endif ()
else () else ()
message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.") message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.")
endif () endif ()
@ -72,3 +72,8 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
endif () endif ()
endif () endif ()
if(ETH_STATIC)
set(BUILD_SHARED_LIBS OFF)
else()
set(BUILD_SHARED_LIBS ON)
endif(ETH_STATIC)

43
docker/Dockerfile

@ -1,36 +1,31 @@
FROM ubuntu:14.04 FROM ubuntu:utopic
MAINTAINER caktux
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive
# Usual update / upgrade
RUN apt-get update RUN apt-get update
RUN apt-get upgrade -y RUN apt-get upgrade -q -y
RUN apt-get dist-upgrade -q -y
# Ethereum dependencies # Let our containers upgrade themselves
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget RUN apt-get install -q -y unattended-upgrades
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
RUN apt-get install -qy libncurses5-dev libcurl4-openssl-dev wget
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev libmicrohttpd-dev
# Ethereum PPA # Install Ethereum
RUN apt-get install -qy software-properties-common RUN apt-get install -q -y software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum RUN add-apt-repository ppa:ethereum/ethereum
RUN add-apt-repository ppa:ethereum/ethereum-dev RUN add-apt-repository ppa:ethereum/ethereum-dev
RUN apt-get update RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev RUN apt-get install -q -y eth
# LLVM-3.5 # Install supervisor
RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - RUN apt-get install -q -y supervisor
RUN echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main\ndeb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main" > /etc/apt/sources.list.d/llvm-trusty.list
RUN apt-get update
RUN apt-get install -qy llvm-3.5 libedit-dev
# Fix llvm-3.5 cmake paths # Add supervisor configs
RUN mkdir -p /usr/lib/llvm-3.5/share/llvm && ln -s /usr/share/llvm-3.5/cmake /usr/lib/llvm-3.5/share/llvm/cmake ADD supervisord.conf supervisord.conf
# Build Ethereum (HEADLESS) EXPOSE 8080
RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum EXPOSE 30303
RUN mkdir -p cpp-ethereum/build
RUN cd cpp-ethereum/build && cmake .. -DHEADLESS=1 -DLLVM_DIR=/usr/share/llvm-3.5/cmake -DEVMJIT=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install
RUN ldconfig
ENTRYPOINT ["/usr/local/bin/eth"] CMD ["-n", "-c", "/supervisord.conf"]
ENTRYPOINT ["/usr/bin/supervisord"]

31
docker/README.md

@ -1,17 +1,30 @@
# Dockerfile for cpp-ethereum # Dockerfile for cpp-ethereum
Dockerfile to build a bleeding edge cpp-ethereum docker image from source
docker build -t cppeth < Dockerfile ### Quick usage
Run a simple peer server docker run -d ethereum/client-cpp
docker run -i cppeth -m off -o peer -x 256 ### Building
GUI is compiled but not exposed. You can mount /cpp-ethereum/build to access binaries: Dockerfile to build a cpp-ethereum docker image from source
cid = $(docker run -i -v /cpp-ethereum/build cppeth -m off -o peer -x 256) docker build -t cpp-ethereum .
docker inspect $cid # <-- Find volume path in JSON output
You may also modify the Docker image to run the GUI and expose a ### Running
ssh/VNC server in order to tunnel an X11 or VNC session.
docker run -d cpp-ethereum
### Usage
First enter the container:
docker exec -it <container name> bash
Inspect logs:
cat /var/log/cpp-ethereum.log
cat /var/log/cpp-ethereum.err
Restart supervisor service:
supervisorctl restart cpp-ethereum

23
docker/supervisord.conf

@ -0,0 +1,23 @@
[supervisord]
nodaemon=false
[program:eth]
priority=30
directory=/
command=eth --bootstrap --json-rpc
user=root
autostart=true
autorestart=true
startsecs=10
stopsignal=QUIT
stdout_logfile=/var/log/eth.log
stderr_logfile=/var/log/eth.err
[unix_http_server]
file=%(here)s/supervisor.sock
[supervisorctl]
serverurl=unix://%(here)s/supervisor.sock
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

51
eth/main.cpp

@ -1010,26 +1010,13 @@ int main(int argc, char** argv)
in.read((char*)block.data(), 8); in.read((char*)block.data(), 8);
block.resize(RLP(block, RLP::LaisezFaire).actualSize()); block.resize(RLP(block, RLP::LaisezFaire).actualSize());
in.read((char*)block.data() + 8, block.size() - 8); in.read((char*)block.data() + 8, block.size() - 8);
try switch (web3.ethereum()->injectBlock(block))
{
web3.ethereum()->injectBlock(block);
good++;
}
catch (AlreadyHaveBlock const&)
{
alreadyHave++;
}
catch (UnknownParent const&)
{
unknownParent++;
}
catch (FutureTime const&)
{ {
futureTime++; case ImportResult::Success: good++; break;
} case ImportResult::AlreadyKnown: alreadyHave++; break;
catch (...) case ImportResult::UnknownParent: unknownParent++; break;
{ case ImportResult::FutureTime: futureTime++; break;
bad++; default: bad++; break;
} }
} }
cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl; cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl;
@ -1137,13 +1124,33 @@ int main(int argc, char** argv)
else if (c && cmd == "setblockfees") else if (c && cmd == "setblockfees")
{ {
iss >> blockFees; iss >> blockFees;
gasPricer->setRefBlockFees(u256(blockFees * 1000)); try
{
gasPricer->setRefBlockFees(u256(blockFees * 1000));
}
catch (Overflow const& _e)
{
cout << boost::diagnostic_information(_e);
}
cout << "Block fees: " << blockFees << endl; cout << "Block fees: " << blockFees << endl;
} }
else if (c && cmd == "setetherprice") else if (c && cmd == "setetherprice")
{ {
iss >> etherPrice; iss >> etherPrice;
gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice)); if (etherPrice == 0)
cout << "ether price cannot be set to zero" << endl;
else
{
try
{
gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice));
}
catch (Overflow const& _e)
{
cout << boost::diagnostic_information(_e);
}
}
cout << "ether Price: " << etherPrice << endl; cout << "ether Price: " << etherPrice << endl;
} }
else if (c && cmd == "setpriority") else if (c && cmd == "setpriority")
@ -1317,9 +1324,9 @@ int main(int argc, char** argv)
{ {
string hexAddr; string hexAddr;
u256 amount; u256 amount;
int size = hexAddr.length();
iss >> hexAddr >> amount; iss >> hexAddr >> amount;
int size = hexAddr.length();
if (size < 40) if (size < 40)
{ {
if (size > 0) if (size > 0)

41
ethminer/CMakeLists.txt

@ -0,0 +1,41 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
set(EXECUTABLE ethminer)
file(GLOB HEADERS "*.h")
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
if (READLINE_FOUND)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
endif()
if (JSONRPC)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
endif()
endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} ethash)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS)
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin )

39
ethminer/Farm.h

@ -0,0 +1,39 @@
/**
* This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY!
*/
#ifndef JSONRPC_CPP_STUB_FARM_H_
#define JSONRPC_CPP_STUB_FARM_H_
#include <jsonrpccpp/client.h>
class Farm : public jsonrpc::Client
{
public:
Farm(jsonrpc::IClientConnector &conn, jsonrpc::clientVersion_t type = jsonrpc::JSONRPC_CLIENT_V2) : jsonrpc::Client(conn, type) {}
Json::Value eth_getWork() throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p = Json::nullValue;
Json::Value result = this->CallMethod("eth_getWork",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool eth_submitWork(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
p.append(param3);
Json::Value result = this->CallMethod("eth_submitWork",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
};
#endif //JSONRPC_CPP_STUB_FARM_H_

28
ethminer/PhoneHome.h

@ -0,0 +1,28 @@
/**
* This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY!
*/
#ifndef JSONRPC_CPP_STUB_PHONEHOME_H_
#define JSONRPC_CPP_STUB_PHONEHOME_H_
#include <jsonrpccpp/client.h>
class PhoneHome : public jsonrpc::Client
{
public:
PhoneHome(jsonrpc::IClientConnector &conn, jsonrpc::clientVersion_t type = jsonrpc::JSONRPC_CLIENT_V2) : jsonrpc::Client(conn, type) {}
int report_benchmark(const std::string& param1, int param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->CallMethod("report_benchmark",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
};
#endif //JSONRPC_CPP_STUB_PHONEHOME_H_

4
ethminer/farm.json

@ -0,0 +1,4 @@
[
{ "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": ["", "", ""], "order": [], "returns": true}
]

483
ethminer/main.cpp

@ -0,0 +1,483 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* Ethereum client.
*/
#include <thread>
#include <chrono>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <libdevcrypto/FileSystem.h>
#include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
#include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#endif
#include "BuildInfo.h"
#if ETH_JSONRPC || !ETH_TRUE
#include "PhoneHome.h"
#include "Farm.h"
#endif
using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::eth;
using namespace boost::algorithm;
using dev::eth::Instruction;
#undef RETURN
bool isTrue(std::string const& _m)
{
return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
}
bool isFalse(std::string const& _m)
{
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
void help()
{
cout
<< "Usage ethminer [OPTIONS]" << endl
<< "Options:" << endl << endl
#if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl
<< " -F,--farm <url> Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8080)" << endl
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
#endif
<< "Benchmarking mode:" << 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-trial <seconds> Set the duration for each trial for the benchmark tests (default: 3)." << endl
<< " --benchmark-trials <n> Set the duration of warmup for the benchmark tests (default: 5)." << endl
#if ETH_JSONRPC || !ETH_TRUE
<< " --phone-home <on/off> When benchmarking, publish results (default: on)" << endl
#endif
<< "DAG creation mode:" << endl
<< " -D,--create-dag <number> Create the DAG in preparation for mining on given block and exit." << endl
<< "General Options:" << endl
<< " -C,--cpu When mining, use the CPU." << endl
<< " -G,--opencl When mining use the GPU via OpenCL." << 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
<< " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl
;
exit(0);
}
string credits()
{
std::ostringstream cout;
cout
<< "Ethereum (++) " << dev::Version << endl
<< " Code by Gav Wood et al, (c) 2013, 2014, 2015." << endl
<< " Based on a design by Vitalik Buterin." << endl << endl;
return cout.str();
}
void version()
{
cout << "eth version " << dev::Version << endl;
cout << "eth network protocol version: " << dev::eth::c_protocolVersion << endl;
cout << "Client database version: " << dev::eth::c_databaseVersion << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethash::prep(bi);
exit(0);
}
enum class OperationMode
{
DAGInit,
Benchmark,
Farm
};
enum class MinerType
{
CPU,
GPU
};
void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18;
cdebug << genesis.boundary();
GenericFarm<Ethash> f;
f.onSolutionFound([&](ProofOfWork::Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : "";
cout << "Benchmarking on platform: " << platformInfo << endl;
cout << "Preparing DAG..." << endl;
Ethash::prep(genesis);
genesis.difficulty = u256(1) << 63;
genesis.noteDirty();
f.setWork(genesis);
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
map<uint64_t, MiningProgress> results;
uint64_t mean = 0;
uint64_t innerMean = 0;
for (unsigned i = 0; i <= _trials; ++i)
{
if (!i)
cout << "Warming up..." << endl;
else
cout << "Trial " << i << "... " << flush;
this_thread::sleep_for(chrono::seconds(i ? _trialDuration : _warmupDuration));
auto mp = f.miningProgress();
f.resetMiningProgress();
if (!i)
continue;
auto rate = mp.rate();
cout << rate << endl;
results[rate] = mp;
mean += rate;
if (i > 1 && i < 5)
innerMean += rate;
}
f.stop();
cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl;
(void)_phoneHome;
#if ETH_JSONRPC || !ETH_TRUE
if (_phoneHome)
{
cout << "Phoning home to find world ranking..." << endl;
jsonrpc::HttpClient client("http://gav.ethdev.com:3000/benchmark");
PhoneHome rpc(client);
try
{
unsigned ranking = rpc.report_benchmark(platformInfo, innerMean);
cout << "Ranked: " << ranking << " of all benchmarks." << endl;
}
catch (...)
{
cout << "Error phoning home. ET is sad." << endl;
}
}
#endif
exit(0);
}
struct HappyChannel: public LogChannel { static const char* name() { return ":-D"; } static const int verbosity = 1; };
struct SadChannel: public LogChannel { static const char* name() { return ":-("; } static const int verbosity = 1; };
void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod)
{
(void)_m;
(void)_remote;
(void)_recheckPeriod;
#if ETH_JSONRPC || !ETH_TRUE
jsonrpc::HttpClient client(_remote);
Farm rpc(client);
GenericFarm<Ethash> f;
if (_m == MinerType::CPU)
f.startCPU();
else if (_m == MinerType::GPU)
f.startGPU();
ProofOfWork::WorkPackage current;
while (true)
try
{
bool completed = false;
ProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol)
{
solution = sol;
return completed = true;
});
for (unsigned i = 0; !completed; ++i)
{
if (current)
cnote << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
else
cnote << "Getting work package...";
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
if (hh != current.headerHash)
{
current.headerHash = hh;
current.seedHash = h256(v[1].asString());
current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
cnote << "Got work package:" << current.headerHash << " < " << current.boundary;
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
}
cnote << "Solution found; submitting [" << solution.nonce << "," << current.headerHash << "," << solution.mixHash << "] to" << _remote << "...";
bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash));
if (ok)
clog(HappyChannel) << "Submitted and accepted.";
else
clog(SadChannel) << "Not accepted.";
current.reset();
}
catch (jsonrpc::JsonRpcException&)
{
for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1)))
cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r";
cerr << endl;
}
#endif
exit(0);
}
int main(int argc, char** argv)
{
// Init defaults
Defaults::get();
/// Operating mode.
OperationMode mode = OperationMode::Farm;
/// Mining options
MinerType minerType = MinerType::CPU;
unsigned openclPlatform = 0;
unsigned openclDevice = 0;
unsigned miningThreads = UINT_MAX;
/// DAG initialisation param.
unsigned initDAG = 0;
/// Benchmarking params
bool phoneHome = true;
unsigned benchmarkWarmup = 3;
unsigned benchmarkTrial = 3;
unsigned benchmarkTrials = 5;
/// Farm params
string farmURL = "http://127.0.0.1:8080";
unsigned farmRecheckPeriod = 500;
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if ((arg == "-F" || arg == "--farm") && i + 1 < argc)
{
mode = OperationMode::Farm;
farmURL = argv[++i];
}
else if (arg == "--farm-recheck" && i + 1 < argc)
try {
farmRecheckPeriod = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--opencl-platform" && i + 1 < argc)
try {
openclPlatform = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--opencl-device" && i + 1 < argc)
try {
openclDevice = stol(argv[++i]);
miningThreads = 1;
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--phone-home" && i + 1 < argc)
{
string m = argv[++i];
if (isTrue(m))
phoneHome = true;
else if (isFalse(m))
phoneHome = false;
else
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if (arg == "--benchmark-warmup" && i + 1 < argc)
try {
benchmarkWarmup = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-trial" && i + 1 < argc)
try {
benchmarkTrial = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-trials" && i + 1 < argc)
try {
benchmarkTrials = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "-C" || arg == "--cpu")
minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl")
minerType = MinerType::GPU;
else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
mode = OperationMode::DAGInit;
try
{
initDAG = stol(m);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
{
string m;
try
{
BlockInfo bi;
m = boost::to_lower_copy(string(argv[++i]));
h256 powHash(m);
m = boost::to_lower_copy(string(argv[++i]));
h256 seedHash;
if (m.size() == 64 || m.size() == 66)
seedHash = h256(m);
else
seedHash = EthashAux::seedHash(stol(m));
m = boost::to_lower_copy(string(argv[++i]));
bi.difficulty = u256(m);
auto boundary = bi.boundary();
m = boost::to_lower_copy(string(argv[++i]));
bi.nonce = h64(m);
auto r = EthashAux::eval(seedHash, powHash, bi.nonce);
bool valid = r.value < boundary;
cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
cout << " with seed as " << seedHash << endl;
if (valid)
cout << "(mixHash = " << r.mixHash << ")" << endl;
cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(seedHash)->data()) << endl;
exit(0);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << m << endl;
return -1;
}
}
else if (arg == "-M" || arg == "--benchmark")
mode = OperationMode::Benchmark;
else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc)
{
try {
miningThreads = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
}
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
g_logVerbosity = atoi(argv[++i]);
else if (arg == "-h" || arg == "--help")
help();
else if (arg == "-V" || arg == "--version")
version();
else
{
cerr << "Invalid argument: " << arg << endl;
exit(-1);
}
}
if (minerType == MinerType::CPU)
ProofOfWork::CPUMiner::setNumInstances(miningThreads);
else if (minerType == MinerType::GPU)
{
ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform);
ProofOfWork::GPUMiner::setDefaultDevice(openclDevice);
ProofOfWork::GPUMiner::setNumInstances(miningThreads);
}
if (mode == OperationMode::DAGInit)
doInitDAG(initDAG);
if (mode == OperationMode::Benchmark)
doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials);
if (mode == OperationMode::Farm)
doFarm(minerType, farmURL, farmRecheckPeriod);
return 0;
}

3
ethminer/phonehome.json

@ -0,0 +1,3 @@
[
{ "name": "report_benchmark", "params": [ "", 0 ], "order": [], "returns": 0 }
]

2
evmjit/libevmjit-cpp/CMakeLists.txt

@ -15,7 +15,7 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive
endif() endif()
add_library(${TARGET_NAME} ${SOURCES}) add_library(${TARGET_NAME} STATIC ${SOURCES})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")
include_directories(../..) include_directories(../..)

21
libdevcore/Base64.h

@ -30,7 +30,8 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <libdevcore/Common.h> #include "Common.h"
#include "FixedHash.h"
namespace dev namespace dev
{ {
@ -38,4 +39,22 @@ namespace dev
std::string toBase64(bytesConstRef _in); std::string toBase64(bytesConstRef _in);
bytes fromBase64(std::string const& _in); bytes fromBase64(std::string const& _in);
template <size_t N> inline std::string toBase36(FixedHash<N> const& _h)
{
static char const* c_alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
typename FixedHash<N>::Arith a = _h;
std::string ret;
for (; a > 0; a /= 36)
ret = c_alphabet[(unsigned)a % 36] + ret;
return ret;
}
template <size_t N> inline FixedHash<N> fromBase36(std::string const& _h)
{
typename FixedHash<N>::Arith ret = 0;
for (char c: _h)
ret = ret * 36 + (c < 'A' ? c - '0' : (c - 'A' + 10));
return ret;
}
} }

6
libdevcore/CMakeLists.txt

@ -20,11 +20,7 @@ set(EXECUTABLE devcore)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES})

28
libdevcore/CommonData.h

@ -41,17 +41,22 @@ enum class WhenError
Throw = 1, Throw = 1,
}; };
enum class HexPrefix
{
DontAdd = 0,
Add = 1,
};
/// Convert a series of bytes to the corresponding string of hex duplets. /// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte. /// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte.
/// @example toHex("A\x69") == "4169" /// @example toHex("A\x69") == "4169"
template <class _T> template <class _T>
std::string toHex(_T const& _data, int _w = 2) std::string toHex(_T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd)
{ {
std::ostringstream ret; std::ostringstream ret;
unsigned ii = 0; unsigned ii = 0;
for (auto i: _data) for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i; ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str(); return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str();
} }
/// Converts a (printable) ASCII hex character into the correspnding integer value. /// Converts a (printable) ASCII hex character into the correspnding integer value.
@ -128,9 +133,6 @@ inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toB
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
/// Convenience function for conversion of a u256 to hex
inline std::string toHex(u256 val) { return toHex(toBigEndian(val)); }
/// Convenience function for toBigEndian. /// Convenience function for toBigEndian.
/// @returns a byte array just big enough to represent @a _val. /// @returns a byte array just big enough to represent @a _val.
template <class _T> template <class _T>
@ -150,15 +152,27 @@ inline bytes toCompactBigEndian(byte _val, unsigned _min = 0)
/// Convenience function for toBigEndian. /// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val. /// @returns a string just big enough to represent @a _val.
template <class _T> template <class _T>
inline std::string toCompactBigEndianString(_T _val) inline std::string toCompactBigEndianString(_T _val, unsigned _min = 0)
{ {
int i = 0; int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {} for (_T v = _val; v; ++i, v >>= 8) {}
std::string ret(i, '\0'); std::string ret(std::max<unsigned>(_min, i), '\0');
toBigEndian(_val, ret); toBigEndian(_val, ret);
return ret; return ret;
} }
/// Convenience function for conversion of a u256 to hex
inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd)
{
std::string str = toHex(toBigEndian(val));
return (prefix == HexPrefix::Add) ? "0x" + str : str;
}
inline std::string toCompactHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd, unsigned _min = 0)
{
std::string str = toHex(toCompactBigEndian(val, _min));
return (prefix == HexPrefix::Add) ? "0x" + str : str;
}
// Algorithms for string and string-like collections. // Algorithms for string and string-like collections.

1
libdevcore/Exceptions.h

@ -51,6 +51,7 @@ struct NoUPnPDevice: virtual Exception {};
struct RootNotFound: virtual Exception {}; struct RootNotFound: virtual Exception {};
struct BadRoot: virtual Exception {}; struct BadRoot: virtual Exception {};
struct FileError: virtual Exception {}; struct FileError: virtual Exception {};
struct Overflow: virtual Exception {};
struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} }; struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} };
// error information to be added to exceptions // error information to be added to exceptions

2
libdevcore/Log.h

@ -181,7 +181,7 @@ protected:
bool m_autospacing = false; bool m_autospacing = false;
unsigned m_verbosity = 0; unsigned m_verbosity = 0;
std::stringstream m_sstr; ///< The accrued log entry. std::stringstream m_sstr; ///< The accrued log entry.
LogTag m_logTag; LogTag m_logTag = LogTag::None;
}; };
/// Logging class, iostream-like, that can be shifted to. /// Logging class, iostream-like, that can be shifted to.

6
libdevcrypto/CMakeLists.txt

@ -17,11 +17,7 @@ include_directories(${LEVELDB_INCLUDE_DIRS})
set(EXECUTABLE devcrypto) set(EXECUTABLE devcrypto)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})

4
libdevcrypto/Common.cpp

@ -40,8 +40,8 @@ bool dev::SignatureStruct::isValid() const
if (v > 1 || if (v > 1 ||
r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
s >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || s >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
s < h256("0x01") || s < h256(1) ||
r < h256("0x01")) r < h256(1))
return false; return false;
return true; return true;
} }

4
libethash/CMakeLists.txt

@ -43,3 +43,7 @@ add_library(${LIBRARY} ${FILES})
if (CRYPTOPP_FOUND) if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES}) TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
endif() endif()
if (NOT ETHASHCL)
install( TARGETS ${LIBRARY} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
endif ()

0
libethereum/ABI.cpp → libethcore/ABI.cpp

8
libethereum/ABI.h → libethcore/ABI.h

@ -31,6 +31,14 @@ namespace dev
namespace eth namespace eth
{ {
inline string32 toString32(std::string const& _s)
{
string32 ret;
for (unsigned i = 0; i < 32; ++i)
ret[i] = i < _s.size() ? _s[i] : 0;
return ret;
}
template <class T> struct ABISerialiser {}; template <class T> struct ABISerialiser {};
template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } }; template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } };
template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } };

6
libethcore/CMakeLists.txt

@ -24,11 +24,7 @@ set(EXECUTABLE ethcore)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)

5
libethcore/Common.cpp

@ -21,6 +21,8 @@
#include "Common.h" #include "Common.h"
#include <random> #include <random>
#include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Base64.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "ProofOfWork.h" #include "ProofOfWork.h"
@ -100,4 +102,5 @@ std::string formatBalance(bigint const& _b)
return ret.str(); return ret.str();
} }
}} }
}

2
libethcore/Common.h

@ -23,6 +23,8 @@
#pragma once #pragma once
#include <string>
#include <functional>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>

4
libethcore/Ethash.cpp

@ -121,7 +121,7 @@ bool Ethash::verify(BlockInfo const& _header)
return slow; return slow;
} }
unsigned Ethash::CPUMiner::s_numInstances = 1; unsigned Ethash::CPUMiner::s_numInstances = 0;
void Ethash::CPUMiner::workLoop() void Ethash::CPUMiner::workLoop()
{ {
@ -266,7 +266,7 @@ private:
unsigned Ethash::GPUMiner::s_platformId = 0; unsigned Ethash::GPUMiner::s_platformId = 0;
unsigned Ethash::GPUMiner::s_deviceId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0;
unsigned Ethash::GPUMiner::s_numInstances = 1; unsigned Ethash::GPUMiner::s_numInstances = 0;
Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci):
Miner(_ci), Miner(_ci),

4
libethcore/EthashAux.cpp

@ -64,7 +64,7 @@ ethash_params EthashAux::params(unsigned _n)
h256 EthashAux::seedHash(unsigned _number) h256 EthashAux::seedHash(unsigned _number)
{ {
unsigned epoch = _number / ETHASH_EPOCH_LENGTH; unsigned epoch = _number / ETHASH_EPOCH_LENGTH;
RecursiveGuard l(get()->x_this); Guard l(get()->x_epochs);
if (epoch >= get()->m_seedHashes.size()) if (epoch >= get()->m_seedHashes.size())
{ {
h256 ret; h256 ret;
@ -87,7 +87,7 @@ h256 EthashAux::seedHash(unsigned _number)
ethash_params EthashAux::params(h256 const& _seedHash) ethash_params EthashAux::params(h256 const& _seedHash)
{ {
RecursiveGuard l(get()->x_this); Guard l(get()->x_epochs);
unsigned epoch = 0; unsigned epoch = 0;
try try
{ {

2
libethcore/EthashAux.h

@ -78,6 +78,8 @@ private:
std::map<h256, std::shared_ptr<LightAllocation>> m_lights; std::map<h256, std::shared_ptr<LightAllocation>> m_lights;
std::map<h256, std::weak_ptr<FullAllocation>> m_fulls; std::map<h256, std::weak_ptr<FullAllocation>> m_fulls;
FullType m_lastUsedFull; FullType m_lastUsedFull;
Mutex x_epochs;
std::map<h256, unsigned> m_epochs; std::map<h256, unsigned> m_epochs;
h256s m_seedHashes; h256s m_seedHashes;
}; };

158
libethcore/ICAP.cpp

@ -0,0 +1,158 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ICAP.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "ICAP.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Base64.h>
#include <libdevcrypto/SHA3.h>
#include "Exceptions.h"
#include "ABI.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace dev
{
namespace eth
{
string ICAP::iban(std::string _c, std::string _d)
{
boost::to_upper(_c);
boost::to_upper(_d);
auto totStr = _d + _c + "00";
bigint tot = 0;
for (char x: totStr)
if (x >= 'A')
tot = tot * 100 + x - 'A' + 10;
else
tot = tot * 10 + x - '0';
unsigned check = (unsigned)(u256)(98 - tot % 97);
ostringstream out;
out << _c << setfill('0') << setw(2) << check << _d;
return out.str();
}
std::pair<string, string> ICAP::fromIBAN(std::string _iban)
{
if (_iban.size() < 4)
return std::make_pair(string(), string());
boost::to_upper(_iban);
std::string c = _iban.substr(0, 2);
std::string d = _iban.substr(4);
if (iban(c, d) != _iban)
return std::make_pair(string(), string());
return make_pair(c, d);
}
ICAP ICAP::decoded(std::string const& _encoded)
{
ICAP ret;
std::string country;
std::string data;
std::tie(country, data) = fromIBAN(_encoded);
if (country != "XE")
throw InvalidICAP();
if (data.size() == 30)
{
ret.m_type = Direct;
// Direct ICAP
ret.m_direct = fromBase36<Address::size>(data);
}
else if (data.size() == 16)
{
ret.m_type = Indirect;
ret.m_asset = data.substr(0, 3);
if (ret.m_asset == "XET" || ret.m_asset == "ETH")
{
ret.m_institution = data.substr(3, 4);
ret.m_client = data.substr(7);
}
else
throw InvalidICAP();
}
else
throw InvalidICAP();
return ret;
}
std::string ICAP::encoded() const
{
if (m_type == Direct)
{
if (!!m_direct[0])
throw InvalidICAP();
std::string d = toBase36<Address::size>(m_direct);
while (d.size() < 30)
d = "0" + d;
return iban("XE", d);
}
else if (m_type == Indirect)
{
if (
m_asset.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
m_institution.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
m_client.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos ||
m_asset.size() != 3 ||
(boost::to_upper_copy(m_asset) != "XET" && boost::to_upper_copy(m_asset) != "ETH") ||
m_institution.size() != 4 ||
m_client.size() != 9
)
throw InvalidICAP();
return iban("XE", m_asset + m_institution + m_client);
}
else
throw InvalidICAP();
}
pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const
{
auto resolve = [&](string const& s)
{
vector<string> ss;
boost::algorithm::split(ss, s, boost::is_any_of("/"));
Address r = _reg;
for (unsigned i = 0; i < ss.size() - 1; ++i)
r = abiOut<Address>(_call(r, abiIn("subRegistrar(bytes32)", toString32(ss[i]))));
return abiOut<Address>(_call(r, abiIn("addr(bytes32)", toString32(ss.back()))));
};
if (m_asset == "XET")
{
Address a = resolve(m_institution);
bytes d = abiIn("deposit(uint64)", fromBase36<8>(m_client));
return make_pair(a, d);
}
else if (m_asset == "ETH")
{
if (m_institution == "XREG")
return make_pair(resolve(m_client), bytes());
else if (m_institution[0] != 'X')
return make_pair(resolve(m_institution + "/" + m_client), bytes());
else
throw InterfaceNotSupported("ICAP::lookup(), bad institution");
}
throw InterfaceNotSupported("ICAP::lookup(), bad asset");
}
}
}

107
libethcore/ICAP.h

@ -0,0 +1,107 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ICAP.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Ethereum-specific data structures & algorithms.
*/
#pragma once
#include <string>
#include <functional>
#include <boost/algorithm/string/case_conv.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/FixedHash.h>
#include "Common.h"
namespace dev
{
namespace eth
{
struct InvalidICAP: virtual public dev::Exception {};
static const std::string EmptyString;
/**
* @brief Encapsulation of an ICAP address.
* Can be encoded, decoded, looked-up and inspected.
*/
class ICAP
{
public:
/// Construct null ICAP object.
ICAP() = default;
/// Construct a direct ICAP object for given target address. Must have a zero first byte.
ICAP(Address const& _target): m_type(Direct), m_direct(_target) {}
/// Construct an indirect ICAP object for given target name.
ICAP(std::string const& _target): m_type(Indirect), m_client(boost::algorithm::to_upper_copy(_target)), m_asset("ETH") {}
/// Construct an indirect ICAP object for given client and institution names.
ICAP(std::string const& _client, std::string const& _inst): m_type(Indirect), m_client(boost::algorithm::to_upper_copy(_client)), m_institution(boost::algorithm::to_upper_copy(_inst)), m_asset("XET") {}
/// Construct an indirect ICAP object for given client, institution and asset names. You generally don't want to use this.
ICAP(std::string const& _c, std::string const& _i, std::string const& _a): m_type(Indirect), m_client(boost::algorithm::to_upper_copy(_c)), m_institution(boost::algorithm::to_upper_copy(_i)), m_asset(boost::algorithm::to_upper_copy(_a)) {}
/// Type of ICAP address.
enum Type
{
Invalid,
Direct,
Indirect
};
/// @returns IBAN encoding of client and data.
static std::string iban(std::string _c, std::string _d);
/// @returns Client and data from given IBAN address.
static std::pair<std::string, std::string> fromIBAN(std::string _iban);
/// @returns the ICAP object for the ICAP address given.
static ICAP decoded(std::string const& _encoded);
/// @returns the encoded ICAP address.
std::string encoded() const;
/// @returns type of ICAP.
Type type() const { return m_type; }
/// @returns target address. Only valid when type() == Direct.
Address const& direct() const { return m_type == Direct ? m_direct : ZeroAddress; }
/// @returns asset. Only valid when type() == Indirect.
std::string const& asset() const { return m_type == Indirect ? m_asset : EmptyString; }
/// @returns target name. Only valid when type() == Indirect and asset() == "ETH".
std::string const& target() const { return m_type == Indirect && m_asset == "ETH" ? m_client : EmptyString; }
/// @returns institution name. Only valid when type() == Indirect and asset() == "XET".
std::string const& institution() const { return m_type == Indirect && m_asset == "XET" ? m_institution : EmptyString; }
/// @returns client name. Only valid when type() == Indirect and asset() == "XET".
std::string const& client() const { return m_type == Indirect && m_asset == "XET" ? m_client : EmptyString; }
/// @returns target address. Always valid, but requires the Registry address and a function to make calls.
std::pair<Address, bytes> address(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const { return m_type == Direct ? make_pair(direct(), bytes()) : m_type == Indirect ? lookup(_call, _reg) : make_pair(Address(), bytes()); }
/// @returns target address. Looks up through the given Registry and call function. Only valid when type() == Indirect.
std::pair<Address, bytes> lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const;
private:
Type m_type = Invalid;
Address m_direct;
std::string m_client;
std::string m_institution;
std::string m_asset;
};
}
}

19
libethereum/BlockChain.cpp

@ -336,16 +336,27 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); return make_tuple(fresh, dead, _bq.doneDrain(badBlocks));
} }
ImportRoute BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
{ {
try try
{ {
return import(_block, _stateDB, _ir); return make_pair(ImportResult::Success, import(_block, _stateDB, _ir));
}
catch (UnknownParent&)
{
return make_pair(ImportResult::UnknownParent, make_pair(h256s(), h256s()));
}
catch (AlreadyHaveBlock&)
{
return make_pair(ImportResult::AlreadyKnown, make_pair(h256s(), h256s()));
}
catch (FutureTime&)
{
return make_pair(ImportResult::FutureTime, make_pair(h256s(), h256s()));
} }
catch (...) catch (...)
{ {
cwarn << "Unexpected exception! Could not import block!" << boost::current_exception_diagnostic_information(); return make_pair(ImportResult::Malformed, make_pair(h256s(), h256s()));
return make_pair(h256s(), h256s());
} }
} }

2
libethereum/BlockChain.h

@ -105,7 +105,7 @@ public:
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
ImportRoute attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept;
/// Import block into disk-backed DB /// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain.

6
libethereum/CMakeLists.txt

@ -19,11 +19,7 @@ set(EXECUTABLE ethereum)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if (ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} lll)

60
libethereum/Client.cpp

@ -24,6 +24,7 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/math/distributions/normal.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h> #include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h> #include <libp2p/Host.h>
@ -81,8 +82,10 @@ void BasicGasPricer::update(BlockChain const& _bc)
h256 p = _bc.currentHash(); h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit; m_gasPerBlock = _bc.info(p).gasLimit;
map<u256, unsigned> dist; map<u256, u256> dist;
unsigned total = 0; u256 total = 0;
// make gasPrice versus gasUsed distribution for the last 1000 blocks
while (c < 1000 && p) while (c < 1000 && p)
{ {
BlockInfo bi = _bc.info(p); BlockInfo bi = _bc.info(p);
@ -91,29 +94,53 @@ void BasicGasPricer::update(BlockChain const& _bc)
auto bb = _bc.block(p); auto bb = _bc.block(p);
RLP r(bb); RLP r(bb);
BlockReceipts brs(_bc.receipts(bi.hash())); BlockReceipts brs(_bc.receipts(bi.hash()));
for (unsigned i = 0; i < r[1].size(); ++i) size_t i = 0;
for (auto const& tr: r[1])
{ {
auto gu = brs.receipts[i].gasUsed(); Transaction tx(tr.data(), CheckTransaction::None);
dist[Transaction(r[1][i].data(), CheckTransaction::None).gasPrice()] += (unsigned)brs.receipts[i].gasUsed(); u256 gu = brs.receipts[i].gasUsed();
total += (unsigned)gu; dist[tx.gasPrice()] += gu;
total += gu;
i++;
} }
} }
p = bi.parentHash; p = bi.parentHash;
++c; ++c;
} }
// fill m_octiles with weighted gasPrices
if (total > 0) if (total > 0)
{ {
unsigned t = 0;
unsigned q = 1;
m_octiles[0] = dist.begin()->first; m_octiles[0] = dist.begin()->first;
// calc mean
u256 mean = 0;
for (auto const& i: dist) for (auto const& i: dist)
mean += i.first * i.second;
mean /= total;
// calc standard deviation
u256 sdSquared = 0;
for (auto const& i: dist)
sdSquared += i.second * (i.first - mean) * (i.first - mean);
sdSquared /= total;
if (sdSquared)
{ {
for (; t <= total * q / 8 && t + i.second > total * q / 8; ++q) long double sd = sqrt(sdSquared.convert_to<long double>());
m_octiles[q] = i.first; long double normalizedSd = sd / mean.convert_to<long double>();
if (q > 7)
break; // calc octiles normalized to gaussian distribution
boost::math::normal gauss(1.0, (normalizedSd > 0.01) ? normalizedSd : 0.01);
for (size_t i = 1; i < 8; i++)
m_octiles[i] = u256(mean.convert_to<long double>() * boost::math::quantile(gauss, i / 8.0));
m_octiles[8] = dist.rbegin()->first;
}
else
{
for (size_t i = 0; i < 9; i++)
m_octiles[i] = (i + 1) * mean / 5;
} }
m_octiles[8] = dist.rbegin()->first;
} }
} }
@ -671,13 +698,6 @@ eth::State Client::state(unsigned _txi) const
return m_postMine.fromPending(_txi); return m_postMine.fromPending(_txi);
} }
void Client::inject(bytesConstRef _rlp)
{
startWorking();
m_tq.import(_rlp);
}
void Client::flushTransactions() void Client::flushTransactions()
{ {
doWork(); doWork();

9
libethereum/Client.h

@ -35,12 +35,12 @@
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/Worker.h> #include <libdevcore/Worker.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <libethcore/ABI.h>
#include <libp2p/Common.h> #include <libp2p/Common.h>
#include "CanonBlockChain.h" #include "CanonBlockChain.h"
#include "TransactionQueue.h" #include "TransactionQueue.h"
#include "State.h" #include "State.h"
#include "CommonNet.h" #include "CommonNet.h"
#include "ABI.h"
#include "Farm.h" #include "Farm.h"
#include "ClientBase.h" #include "ClientBase.h"
@ -77,8 +77,8 @@ class BasicGasPricer: public GasPricer
public: public:
explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {} explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {}
void setRefPrice(u256 _weiPerRef) { m_weiPerRef = _weiPerRef; } void setRefPrice(u256 _weiPerRef) { if ((bigint)m_refsPerBlock * _weiPerRef > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_weiPerRef = _weiPerRef; }
void setRefBlockFees(u256 _refsPerBlock) { m_refsPerBlock = _refsPerBlock; } void setRefBlockFees(u256 _refsPerBlock) { if ((bigint)m_weiPerRef * _refsPerBlock > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_refsPerBlock = _refsPerBlock; }
u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; } u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); } u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); }
@ -133,9 +133,6 @@ public:
/// Resets the gas pricer to some other object. /// Resets the gas pricer to some other object.
void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; } void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; }
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
virtual void inject(bytesConstRef _rlp);
/// Blocks until all pending transactions have been processed. /// Blocks until all pending transactions have been processed.
virtual void flushTransactions() override; virtual void flushTransactions() override;

4
libethereum/ClientBase.cpp

@ -114,9 +114,9 @@ ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _da
return ret; return ret;
} }
void ClientBase::injectBlock(bytes const& _block) ImportResult ClientBase::injectBlock(bytes const& _block)
{ {
bc().import(_block, preMine().db()); return bc().attemptImport(_block, preMine().db()).first;
} }
u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const

3
libethereum/ClientBase.h

@ -127,7 +127,8 @@ public:
virtual Transactions pending() const override; virtual Transactions pending() const override;
virtual h256s pendingHashes() const override; virtual h256s pendingHashes() const override;
void injectBlock(bytes const& _block); ImportResult injectTransaction(bytes const& _rlp) override { prepareForTransaction(); return m_tq.import(_rlp); }
ImportResult injectBlock(bytes const& _block);
using Interface::diff; using Interface::diff;
virtual StateDiff diff(unsigned _txi, h256 _block) const override; virtual StateDiff diff(unsigned _txi, h256 _block) const override;

6
libethereum/Interface.h

@ -85,6 +85,12 @@ public:
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0; virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, FudgeFactor _ff = FudgeFactor::Strict) = 0;
ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return create(_secret, _value, _data, _gas, _gasPrice, m_default, _ff); } ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, FudgeFactor _ff = FudgeFactor::Strict) { return create(_secret, _value, _data, _gas, _gasPrice, m_default, _ff); }
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
virtual ImportResult injectTransaction(bytes const& _rlp) = 0;
/// Injects the RLP-encoded block given by the _rlp into the block queue directly.
virtual ImportResult injectBlock(bytes const& _block) = 0;
// [STATE-QUERY API] // [STATE-QUERY API]
int getDefault() const { return m_default; } int getDefault() const { return m_default; }

2
libethereum/Transaction.cpp

@ -105,7 +105,7 @@ Address const& Transaction::safeSender() const noexcept
catch (...) catch (...)
{ {
cwarn << "safeSender() did throw an exception: " << boost::current_exception_diagnostic_information(); cwarn << "safeSender() did throw an exception: " << boost::current_exception_diagnostic_information();
return NullAddress; return ZeroAddress;
} }
} }

8
libethereum/Transaction.h

@ -97,8 +97,6 @@ struct ExecutionResult
std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er); std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er);
static const Address NullAddress;
/// Encodes a transaction, ready to be exported to or freshly imported from RLP. /// Encodes a transaction, ready to be exported to or freshly imported from RLP.
class Transaction class Transaction
{ {
@ -167,6 +165,12 @@ public:
/// @returns the receiving address of the message-call transaction (undefined for contract-creation transactions). /// @returns the receiving address of the message-call transaction (undefined for contract-creation transactions).
Address receiveAddress() const { return m_receiveAddress; } Address receiveAddress() const { return m_receiveAddress; }
/// Synonym for receiveAddress().
Address to() const { return m_receiveAddress; }
/// Synonym for safeSender().
Address from() const { return safeSender(); }
/// @returns the data associated with this (message-call) transaction. Synonym for initCode(). /// @returns the data associated with this (message-call) transaction. Synonym for initCode().
bytes const& data() const { return m_data; } bytes const& data() const { return m_data; }
/// @returns the initialisation code associated with this (contract-creation) transaction. Synonym for data(). /// @returns the initialisation code associated with this (contract-creation) transaction. Synonym for data().

6
libethereumx/CMakeLists.txt

@ -11,11 +11,7 @@ set(EXECUTABLE ethereumx)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if (ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS})

6
libevm/CMakeLists.txt

@ -20,11 +20,7 @@ set(EXECUTABLE evm)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if (ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)

13
libevmcore/AssemblyItem.h

@ -43,9 +43,16 @@ class AssemblyItem
public: public:
enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; enum class JumpType { Ordinary, IntoFunction, OutOfFunction };
AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} AssemblyItem(u256 _push, SourceLocation const& _location = SourceLocation()):
AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(Push, _push, _location) { }
AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} AssemblyItem(Instruction _i, SourceLocation const& _location = SourceLocation()):
AssemblyItem(Operation, byte(_i), _location) { }
AssemblyItem(AssemblyItemType _type, u256 _data = 0, SourceLocation const& _location = SourceLocation()):
m_type(_type),
m_data(_data),
m_location(_location)
{
}
AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(Tag, m_data); } AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(Tag, m_data); }
AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(PushTag, m_data); } AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(PushTag, m_data); }

6
libevmcore/CMakeLists.txt

@ -19,11 +19,7 @@ set(EXECUTABLE evmcore)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if (ETH_STATIC) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)

176
libevmcore/CommonSubexpressionEliminator.cpp

@ -41,9 +41,9 @@ vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems()
if (!m_stackElements.empty()) if (!m_stackElements.empty())
minHeight = min(minHeight, m_stackElements.begin()->first); minHeight = min(minHeight, m_stackElements.begin()->first);
for (int height = minHeight; height <= 0; ++height) for (int height = minHeight; height <= 0; ++height)
initialStackContents[height] = initialStackElement(height); initialStackContents[height] = initialStackElement(height, SourceLocation());
for (int height = minHeight; height <= m_stackHeight; ++height) for (int height = minHeight; height <= m_stackHeight; ++height)
targetStackContents[height] = stackElement(height); targetStackContents[height] = stackElement(height, SourceLocation());
// Debug info: // Debug info:
//stream(cout, initialStackContents, targetStackContents); //stream(cout, initialStackContents, targetStackContents);
@ -111,30 +111,46 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item, bool _co
if (SemanticInformation::isDupInstruction(_item)) if (SemanticInformation::isDupInstruction(_item))
setStackElement( setStackElement(
m_stackHeight + 1, m_stackHeight + 1,
stackElement(m_stackHeight - int(instruction) + int(Instruction::DUP1)) stackElement(
m_stackHeight - int(instruction) + int(Instruction::DUP1),
_item.getLocation()
)
); );
else if (SemanticInformation::isSwapInstruction(_item)) else if (SemanticInformation::isSwapInstruction(_item))
swapStackElements( swapStackElements(
m_stackHeight, m_stackHeight,
m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1) m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1),
_item.getLocation()
); );
else if (instruction != Instruction::POP) else if (instruction != Instruction::POP)
{ {
vector<Id> arguments(info.args); vector<Id> arguments(info.args);
for (int i = 0; i < info.args; ++i) for (int i = 0; i < info.args; ++i)
arguments[i] = stackElement(m_stackHeight - i); arguments[i] = stackElement(m_stackHeight - i, _item.getLocation());
if (_item.instruction() == Instruction::SSTORE) if (_item.instruction() == Instruction::SSTORE)
storeInStorage(arguments[0], arguments[1]); storeInStorage(arguments[0], arguments[1], _item.getLocation());
else if (_item.instruction() == Instruction::SLOAD) else if (_item.instruction() == Instruction::SLOAD)
setStackElement(m_stackHeight + _item.deposit(), loadFromStorage(arguments[0])); setStackElement(
m_stackHeight + _item.deposit(),
loadFromStorage(arguments[0], _item.getLocation())
);
else if (_item.instruction() == Instruction::MSTORE) else if (_item.instruction() == Instruction::MSTORE)
storeInMemory(arguments[0], arguments[1]); storeInMemory(arguments[0], arguments[1], _item.getLocation());
else if (_item.instruction() == Instruction::MLOAD) else if (_item.instruction() == Instruction::MLOAD)
setStackElement(m_stackHeight + _item.deposit(), loadFromMemory(arguments[0])); setStackElement(
m_stackHeight + _item.deposit(),
loadFromMemory(arguments[0], _item.getLocation())
);
else if (_item.instruction() == Instruction::SHA3) else if (_item.instruction() == Instruction::SHA3)
setStackElement(m_stackHeight + _item.deposit(), applySha3(arguments.at(0), arguments.at(1))); setStackElement(
m_stackHeight + _item.deposit(),
applySha3(arguments.at(0), arguments.at(1), _item.getLocation())
);
else else
setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, _copyItem)); setStackElement(
m_stackHeight + _item.deposit(),
m_expressionClasses.find(_item, arguments, _copyItem)
);
} }
m_stackHeight += _item.deposit(); m_stackHeight += _item.deposit();
} }
@ -145,22 +161,27 @@ void CommonSubexpressionEliminator::optimizeBreakingItem()
if (!m_breakingItem || *m_breakingItem != AssemblyItem(Instruction::JUMPI)) if (!m_breakingItem || *m_breakingItem != AssemblyItem(Instruction::JUMPI))
return; return;
static AssemblyItem s_jump = Instruction::JUMP; SourceLocation const& location = m_breakingItem->getLocation();
AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType();
Id condition = stackElement(m_stackHeight - 1); Id condition = stackElement(m_stackHeight - 1, location);
Id zero = m_expressionClasses.find(u256(0)); Id zero = m_expressionClasses.find(u256(0));
if (m_expressionClasses.knownToBeDifferent(condition, zero)) if (m_expressionClasses.knownToBeDifferent(condition, zero))
{ {
feedItem(Instruction::SWAP1, true); feedItem(AssemblyItem(Instruction::SWAP1, location), true);
feedItem(Instruction::POP, true); feedItem(AssemblyItem(Instruction::POP, location), true);
m_breakingItem = &s_jump;
AssemblyItem item(Instruction::JUMP, location);
item.setJumpType(jumpType);
m_breakingItem = m_expressionClasses.storeItem(item);
return; return;
} }
Id negatedCondition = m_expressionClasses.find(Instruction::ISZERO, {condition}); Id negatedCondition = m_expressionClasses.find(Instruction::ISZERO, {condition});
if (m_expressionClasses.knownToBeDifferent(negatedCondition, zero)) if (m_expressionClasses.knownToBeDifferent(negatedCondition, zero))
{ {
feedItem(Instruction::POP, true); AssemblyItem it(Instruction::POP, location);
feedItem(Instruction::POP, true); feedItem(it, true);
feedItem(it, true);
m_breakingItem = nullptr; m_breakingItem = nullptr;
} }
} }
@ -170,33 +191,43 @@ void CommonSubexpressionEliminator::setStackElement(int _stackHeight, Id _class)
m_stackElements[_stackHeight] = _class; m_stackElements[_stackHeight] = _class;
} }
void CommonSubexpressionEliminator::swapStackElements(int _stackHeightA, int _stackHeightB) void CommonSubexpressionEliminator::swapStackElements(
int _stackHeightA,
int _stackHeightB,
SourceLocation const& _location
)
{ {
assertThrow(_stackHeightA != _stackHeightB, OptimizerException, "Swap on same stack elements."); assertThrow(_stackHeightA != _stackHeightB, OptimizerException, "Swap on same stack elements.");
// ensure they are created // ensure they are created
stackElement(_stackHeightA); stackElement(_stackHeightA, _location);
stackElement(_stackHeightB); stackElement(_stackHeightB, _location);
swap(m_stackElements[_stackHeightA], m_stackElements[_stackHeightB]); swap(m_stackElements[_stackHeightA], m_stackElements[_stackHeightB]);
} }
ExpressionClasses::Id CommonSubexpressionEliminator::stackElement(int _stackHeight) ExpressionClasses::Id CommonSubexpressionEliminator::stackElement(
int _stackHeight,
SourceLocation const& _location
)
{ {
if (m_stackElements.count(_stackHeight)) if (m_stackElements.count(_stackHeight))
return m_stackElements.at(_stackHeight); return m_stackElements.at(_stackHeight);
// Stack element not found (not assigned yet), create new equivalence class. // Stack element not found (not assigned yet), create new equivalence class.
return m_stackElements[_stackHeight] = initialStackElement(_stackHeight); return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location);
} }
ExpressionClasses::Id CommonSubexpressionEliminator::initialStackElement(int _stackHeight) ExpressionClasses::Id CommonSubexpressionEliminator::initialStackElement(
int _stackHeight,
SourceLocation const& _location
)
{ {
assertThrow(_stackHeight <= 0, OptimizerException, "Initial stack element of positive height requested."); assertThrow(_stackHeight <= 0, OptimizerException, "Initial stack element of positive height requested.");
assertThrow(_stackHeight > -16, StackTooDeepException, ""); assertThrow(_stackHeight > -16, StackTooDeepException, "");
// This is a special assembly item that refers to elements pre-existing on the initial stack. // This is a special assembly item that refers to elements pre-existing on the initial stack.
return m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight))); return m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight), _location));
} }
void CommonSubexpressionEliminator::storeInStorage(Id _slot, Id _value) void CommonSubexpressionEliminator::storeInStorage(Id _slot, Id _value, SourceLocation const& _location)
{ {
if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value) if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value)
// do not execute the storage if we know that the value is already there // do not execute the storage if we know that the value is already there
@ -210,22 +241,25 @@ void CommonSubexpressionEliminator::storeInStorage(Id _slot, Id _value)
if (m_expressionClasses.knownToBeDifferent(storageItem.first, _slot) || storageItem.second == _value) if (m_expressionClasses.knownToBeDifferent(storageItem.first, _slot) || storageItem.second == _value)
storageContents.insert(storageItem); storageContents.insert(storageItem);
m_storageContent = move(storageContents); m_storageContent = move(storageContents);
Id id = m_expressionClasses.find(Instruction::SSTORE, {_slot, _value}, true, m_sequenceNumber);
AssemblyItem item(Instruction::SSTORE, _location);
Id id = m_expressionClasses.find(item, {_slot, _value}, true, m_sequenceNumber);
m_storeOperations.push_back(StoreOperation(StoreOperation::Storage, _slot, m_sequenceNumber, id)); m_storeOperations.push_back(StoreOperation(StoreOperation::Storage, _slot, m_sequenceNumber, id));
m_storageContent[_slot] = _value; m_storageContent[_slot] = _value;
// increment a second time so that we get unique sequence numbers for writes // increment a second time so that we get unique sequence numbers for writes
m_sequenceNumber++; m_sequenceNumber++;
} }
ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(Id _slot) ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(Id _slot, SourceLocation const& _location)
{ {
if (m_storageContent.count(_slot)) if (m_storageContent.count(_slot))
return m_storageContent.at(_slot); return m_storageContent.at(_slot);
else
return m_storageContent[_slot] = m_expressionClasses.find(Instruction::SLOAD, {_slot}, true, m_sequenceNumber); AssemblyItem item(Instruction::SLOAD, _location);
return m_storageContent[_slot] = m_expressionClasses.find(item, {_slot}, true, m_sequenceNumber);
} }
void CommonSubexpressionEliminator::storeInMemory(Id _slot, Id _value) void CommonSubexpressionEliminator::storeInMemory(Id _slot, Id _value, SourceLocation const& _location)
{ {
if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value) if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value)
// do not execute the store if we know that the value is already there // do not execute the store if we know that the value is already there
@ -237,34 +271,45 @@ void CommonSubexpressionEliminator::storeInMemory(Id _slot, Id _value)
if (m_expressionClasses.knownToBeDifferentBy32(memoryItem.first, _slot)) if (m_expressionClasses.knownToBeDifferentBy32(memoryItem.first, _slot))
memoryContents.insert(memoryItem); memoryContents.insert(memoryItem);
m_memoryContent = move(memoryContents); m_memoryContent = move(memoryContents);
Id id = m_expressionClasses.find(Instruction::MSTORE, {_slot, _value}, true, m_sequenceNumber);
AssemblyItem item(Instruction::MSTORE, _location);
Id id = m_expressionClasses.find(item, {_slot, _value}, true, m_sequenceNumber);
m_storeOperations.push_back(StoreOperation(StoreOperation::Memory, _slot, m_sequenceNumber, id)); m_storeOperations.push_back(StoreOperation(StoreOperation::Memory, _slot, m_sequenceNumber, id));
m_memoryContent[_slot] = _value; m_memoryContent[_slot] = _value;
// increment a second time so that we get unique sequence numbers for writes // increment a second time so that we get unique sequence numbers for writes
m_sequenceNumber++; m_sequenceNumber++;
} }
ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(Id _slot) ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(Id _slot, SourceLocation const& _location)
{ {
if (m_memoryContent.count(_slot)) if (m_memoryContent.count(_slot))
return m_memoryContent.at(_slot); return m_memoryContent.at(_slot);
else
return m_memoryContent[_slot] = m_expressionClasses.find(Instruction::MLOAD, {_slot}, true, m_sequenceNumber); AssemblyItem item(Instruction::MLOAD, _location);
return m_memoryContent[_slot] = m_expressionClasses.find(item, {_slot}, true, m_sequenceNumber);
} }
CommonSubexpressionEliminator::Id CommonSubexpressionEliminator::applySha3(Id _start, Id _length) CommonSubexpressionEliminator::Id CommonSubexpressionEliminator::applySha3(
Id _start,
Id _length,
SourceLocation const& _location
)
{ {
AssemblyItem sha3Item(Instruction::SHA3, _location);
// Special logic if length is a short constant, otherwise we cannot tell. // Special logic if length is a short constant, otherwise we cannot tell.
u256 const* l = m_expressionClasses.knownConstant(_length); u256 const* l = m_expressionClasses.knownConstant(_length);
// unknown or too large length // unknown or too large length
if (!l || *l > 128) if (!l || *l > 128)
return m_expressionClasses.find(Instruction::SHA3, {_start, _length}, true, m_sequenceNumber); return m_expressionClasses.find(sha3Item, {_start, _length}, true, m_sequenceNumber);
vector<Id> arguments; vector<Id> arguments;
for (u256 i = 0; i < *l; i += 32) for (u256 i = 0; i < *l; i += 32)
{ {
Id slot = m_expressionClasses.find(Instruction::ADD, {_start, m_expressionClasses.find(i)}); Id slot = m_expressionClasses.find(
arguments.push_back(loadFromMemory(slot)); AssemblyItem(Instruction::ADD, _location),
{_start, m_expressionClasses.find(i)}
);
arguments.push_back(loadFromMemory(slot, _location));
} }
if (m_knownSha3Hashes.count(arguments)) if (m_knownSha3Hashes.count(arguments))
return m_knownSha3Hashes.at(arguments); return m_knownSha3Hashes.at(arguments);
@ -276,10 +321,10 @@ CommonSubexpressionEliminator::Id CommonSubexpressionEliminator::applySha3(Id _s
for (Id a: arguments) for (Id a: arguments)
data += toBigEndian(*m_expressionClasses.knownConstant(a)); data += toBigEndian(*m_expressionClasses.knownConstant(a));
data.resize(size_t(*l)); data.resize(size_t(*l));
v = m_expressionClasses.find(u256(sha3(data))); v = m_expressionClasses.find(AssemblyItem(u256(sha3(data)), _location));
} }
else else
v = m_expressionClasses.find(Instruction::SHA3, {_start, _length}, true, m_sequenceNumber); v = m_expressionClasses.find(sha3Item, {_start, _length}, true, m_sequenceNumber);
return m_knownSha3Hashes[arguments] = v; return m_knownSha3Hashes[arguments] = v;
} }
@ -333,12 +378,13 @@ AssemblyItems CSECodeGenerator::generateCode(
assertThrow(position != c_invalidPosition, OptimizerException, ""); assertThrow(position != c_invalidPosition, OptimizerException, "");
if (position == targetItem.first) if (position == targetItem.first)
continue; continue;
SourceLocation const& location = m_expressionClasses.representative(targetItem.second).item->getLocation();
if (position < targetItem.first) if (position < targetItem.first)
// it is already at its target, we need another copy // it is already at its target, we need another copy
appendDup(position); appendDup(position, location);
else else
appendOrRemoveSwap(position); appendOrRemoveSwap(position, location);
appendOrRemoveSwap(targetItem.first); appendOrRemoveSwap(targetItem.first, location);
} }
// remove surplus elements // remove surplus elements
@ -404,7 +450,8 @@ void CSECodeGenerator::addDependencies(Id _c)
case Instruction::SHA3: case Instruction::SHA3:
{ {
Id length = expr.arguments.at(1); Id length = expr.arguments.at(1);
Id offsetToStart = m_expressionClasses.find(Instruction::SUB, {slot, slotToLoadFrom}); AssemblyItem offsetInstr(Instruction::SUB, expr.item->getLocation());
Id offsetToStart = m_expressionClasses.find(offsetInstr, {slot, slotToLoadFrom});
u256 const* o = m_expressionClasses.knownConstant(offsetToStart); u256 const* o = m_expressionClasses.knownConstant(offsetToStart);
u256 const* l = m_expressionClasses.knownConstant(length); u256 const* l = m_expressionClasses.knownConstant(length);
if (l && *l == 0) if (l && *l == 0)
@ -462,6 +509,7 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
for (Id arg: boost::adaptors::reverse(arguments)) for (Id arg: boost::adaptors::reverse(arguments))
generateClassElement(arg); generateClassElement(arg);
SourceLocation const& location = expr.item->getLocation();
// The arguments are somewhere on the stack now, so it remains to move them at the correct place. // The arguments are somewhere on the stack now, so it remains to move them at the correct place.
// This is quite difficult as sometimes, the values also have to removed in this process // This is quite difficult as sometimes, the values also have to removed in this process
// (if canBeRemoved() returns true) and the two arguments can be equal. For now, this is // (if canBeRemoved() returns true) and the two arguments can be equal. For now, this is
@ -469,42 +517,42 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
if (arguments.size() == 1) if (arguments.size() == 1)
{ {
if (canBeRemoved(arguments[0], _c)) if (canBeRemoved(arguments[0], _c))
appendOrRemoveSwap(classElementPosition(arguments[0])); appendOrRemoveSwap(classElementPosition(arguments[0]), location);
else else
appendDup(classElementPosition(arguments[0])); appendDup(classElementPosition(arguments[0]), location);
} }
else if (arguments.size() == 2) else if (arguments.size() == 2)
{ {
if (canBeRemoved(arguments[1], _c)) if (canBeRemoved(arguments[1], _c))
{ {
appendOrRemoveSwap(classElementPosition(arguments[1])); appendOrRemoveSwap(classElementPosition(arguments[1]), location);
if (arguments[0] == arguments[1]) if (arguments[0] == arguments[1])
appendDup(m_stackHeight); appendDup(m_stackHeight, location);
else if (canBeRemoved(arguments[0], _c)) else if (canBeRemoved(arguments[0], _c))
{ {
appendOrRemoveSwap(m_stackHeight - 1); appendOrRemoveSwap(m_stackHeight - 1, location);
appendOrRemoveSwap(classElementPosition(arguments[0])); appendOrRemoveSwap(classElementPosition(arguments[0]), location);
} }
else else
appendDup(classElementPosition(arguments[0])); appendDup(classElementPosition(arguments[0]), location);
} }
else else
{ {
if (arguments[0] == arguments[1]) if (arguments[0] == arguments[1])
{ {
appendDup(classElementPosition(arguments[0])); appendDup(classElementPosition(arguments[0]), location);
appendDup(m_stackHeight); appendDup(m_stackHeight, location);
} }
else if (canBeRemoved(arguments[0], _c)) else if (canBeRemoved(arguments[0], _c))
{ {
appendOrRemoveSwap(classElementPosition(arguments[0])); appendOrRemoveSwap(classElementPosition(arguments[0]), location);
appendDup(classElementPosition(arguments[1])); appendDup(classElementPosition(arguments[1]), location);
appendOrRemoveSwap(m_stackHeight - 1); appendOrRemoveSwap(m_stackHeight - 1, location);
} }
else else
{ {
appendDup(classElementPosition(arguments[1])); appendDup(classElementPosition(arguments[1]), location);
appendDup(classElementPosition(arguments[0])); appendDup(classElementPosition(arguments[0]), location);
} }
} }
} }
@ -521,7 +569,7 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
!m_generatedItems.empty() && !m_generatedItems.empty() &&
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1)) m_generatedItems.back() == AssemblyItem(Instruction::SWAP1))
// this will not append a swap but remove the one that is already there // this will not append a swap but remove the one that is already there
appendOrRemoveSwap(m_stackHeight - 1); appendOrRemoveSwap(m_stackHeight - 1, location);
for (auto arg: arguments) for (auto arg: arguments)
if (canBeRemoved(arg, _c)) if (canBeRemoved(arg, _c))
m_classPositions[arg] = c_invalidPosition; m_classPositions[arg] = c_invalidPosition;
@ -582,17 +630,17 @@ bool CSECodeGenerator::removeStackTopIfPossible()
return true; return true;
} }
void CSECodeGenerator::appendDup(int _fromPosition) void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _location)
{ {
assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); assertThrow(_fromPosition != c_invalidPosition, OptimizerException, "");
int instructionNum = 1 + m_stackHeight - _fromPosition; int instructionNum = 1 + m_stackHeight - _fromPosition;
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep.");
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
appendItem(AssemblyItem(dupInstruction(instructionNum))); appendItem(AssemblyItem(dupInstruction(instructionNum), _location));
m_stack[m_stackHeight] = m_stack[_fromPosition]; m_stack[m_stackHeight] = m_stack[_fromPosition];
} }
void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition) void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation const& _location)
{ {
assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); assertThrow(_fromPosition != c_invalidPosition, OptimizerException, "");
if (_fromPosition == m_stackHeight) if (_fromPosition == m_stackHeight)
@ -600,7 +648,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition)
int instructionNum = m_stackHeight - _fromPosition; int instructionNum = m_stackHeight - _fromPosition;
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep.");
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
appendItem(AssemblyItem(swapInstruction(instructionNum))); appendItem(AssemblyItem(swapInstruction(instructionNum), _location));
// The value of a class can be present in multiple locations on the stack. We only update the // The value of a class can be present in multiple locations on the stack. We only update the
// "canonical" one that is tracked by m_classPositions // "canonical" one that is tracked by m_classPositions
if (m_classPositions[m_stack[m_stackHeight]] == m_stackHeight) if (m_classPositions[m_stack[m_stackHeight]] == m_stackHeight)

20
libevmcore/CommonSubexpressionEliminator.h

@ -99,26 +99,26 @@ private:
/// Assigns a new equivalence class to the next sequence number of the given stack element. /// Assigns a new equivalence class to the next sequence number of the given stack element.
void setStackElement(int _stackHeight, Id _class); void setStackElement(int _stackHeight, Id _class);
/// Swaps the given stack elements in their next sequence number. /// Swaps the given stack elements in their next sequence number.
void swapStackElements(int _stackHeightA, int _stackHeightB); void swapStackElements(int _stackHeightA, int _stackHeightB, SourceLocation const& _location);
/// Retrieves the current equivalence class fo the given stack element (or generates a new /// Retrieves the current equivalence class fo the given stack element (or generates a new
/// one if it does not exist yet). /// one if it does not exist yet).
Id stackElement(int _stackHeight); Id stackElement(int _stackHeight, SourceLocation const& _location);
/// @returns the equivalence class id of the special initial stack element at the given height /// @returns the equivalence class id of the special initial stack element at the given height
/// (must not be positive). /// (must not be positive).
Id initialStackElement(int _stackHeight); Id initialStackElement(int _stackHeight, SourceLocation const& _location);
/// Increments the sequence number, deletes all storage information that might be overwritten /// Increments the sequence number, deletes all storage information that might be overwritten
/// and stores the new value at the given slot. /// and stores the new value at the given slot.
void storeInStorage(Id _slot, Id _value); void storeInStorage(Id _slot, Id _value, SourceLocation const& _location);
/// Retrieves the current value at the given slot in storage or creates a new special sload class. /// Retrieves the current value at the given slot in storage or creates a new special sload class.
Id loadFromStorage(Id _slot); Id loadFromStorage(Id _slot, SourceLocation const& _location);
/// Increments the sequence number, deletes all memory information that might be overwritten /// Increments the sequence number, deletes all memory information that might be overwritten
/// and stores the new value at the given slot. /// and stores the new value at the given slot.
void storeInMemory(Id _slot, Id _value); void storeInMemory(Id _slot, Id _value, SourceLocation const& _location);
/// Retrieves the current value at the given slot in memory or creates a new special mload class. /// Retrieves the current value at the given slot in memory or creates a new special mload class.
Id loadFromMemory(Id _slot); Id loadFromMemory(Id _slot, SourceLocation const& _location);
/// Finds or creates a new expression that applies the sha3 hash function to the contents in memory. /// Finds or creates a new expression that applies the sha3 hash function to the contents in memory.
Id applySha3(Id _start, Id _length); Id applySha3(Id _start, Id _length, SourceLocation const& _location);
/// Current stack height, can be negative. /// Current stack height, can be negative.
int m_stackHeight = 0; int m_stackHeight = 0;
@ -188,10 +188,10 @@ private:
bool removeStackTopIfPossible(); bool removeStackTopIfPossible();
/// Appends a dup instruction to m_generatedItems to retrieve the element at the given stack position. /// Appends a dup instruction to m_generatedItems to retrieve the element at the given stack position.
void appendDup(int _fromPosition); void appendDup(int _fromPosition, SourceLocation const& _location);
/// Appends a swap instruction to m_generatedItems to retrieve the element at the given stack position. /// Appends a swap instruction to m_generatedItems to retrieve the element at the given stack position.
/// @note this might also remove the last item if it exactly the same swap instruction. /// @note this might also remove the last item if it exactly the same swap instruction.
void appendOrRemoveSwap(int _fromPosition); void appendOrRemoveSwap(int _fromPosition, SourceLocation const& _location);
/// Appends the given assembly item. /// Appends the given assembly item.
void appendItem(AssemblyItem const& _item); void appendItem(AssemblyItem const& _item);

24
libevmcore/ExpressionClasses.cpp

@ -64,10 +64,7 @@ ExpressionClasses::Id ExpressionClasses::find(
return it->id; return it->id;
if (_copyItem) if (_copyItem)
{ exp.item = storeItem(_item);
m_spareAssemblyItem.push_back(make_shared<AssemblyItem>(_item));
exp.item = m_spareAssemblyItem.back().get();
}
ExpressionClasses::Id id = tryToSimplify(exp); ExpressionClasses::Id id = tryToSimplify(exp);
if (id < m_representatives.size()) if (id < m_representatives.size())
@ -115,6 +112,12 @@ u256 const* ExpressionClasses::knownConstant(Id _c)
return &constant.d(); return &constant.d();
} }
AssemblyItem const* ExpressionClasses::storeItem(AssemblyItem const& _item)
{
m_spareAssemblyItems.push_back(make_shared<AssemblyItem>(_item));
return m_spareAssemblyItems.back().get();
}
string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const
{ {
Expression const& expr = representative(_id); Expression const& expr = representative(_id);
@ -292,7 +295,7 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr,
//cout << "with rule " << rule.first.toString() << endl; //cout << "with rule " << rule.first.toString() << endl;
//ExpressionTemplate t(rule.second()); //ExpressionTemplate t(rule.second());
//cout << "to " << rule.second().toString() << endl; //cout << "to " << rule.second().toString() << endl;
return rebuildExpression(ExpressionTemplate(rule.second())); return rebuildExpression(ExpressionTemplate(rule.second(), _expr.item->getLocation()));
} }
} }
@ -350,6 +353,11 @@ bool Pattern::matches(Expression const& _expr, ExpressionClasses const& _classes
return true; return true;
} }
AssemblyItem Pattern::toAssemblyItem(SourceLocation const& _location) const
{
return AssemblyItem(m_type, m_data, _location);
}
string Pattern::toString() const string Pattern::toString() const
{ {
stringstream s; stringstream s;
@ -399,7 +407,7 @@ Pattern::Expression const& Pattern::matchGroupValue() const
} }
ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern) ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern, SourceLocation const& _location)
{ {
if (_pattern.matchGroup()) if (_pattern.matchGroup())
{ {
@ -409,10 +417,10 @@ ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern)
else else
{ {
hasId = false; hasId = false;
item = _pattern.toAssemblyItem(); item = _pattern.toAssemblyItem(_location);
} }
for (auto const& arg: _pattern.arguments()) for (auto const& arg: _pattern.arguments())
arguments.push_back(ExpressionTemplate(arg)); arguments.push_back(ExpressionTemplate(arg, _location));
} }
string ExpressionTemplate::toString() const string ExpressionTemplate::toString() const

10
libevmcore/ExpressionClasses.h

@ -88,6 +88,10 @@ public:
/// and a nullptr otherwise. /// and a nullptr otherwise.
u256 const* knownConstant(Id _c); u256 const* knownConstant(Id _c);
/// Stores a copy of the given AssemblyItem and returns a pointer to the copy that is valid for
/// the lifetime of the ExpressionClasses object.
AssemblyItem const* storeItem(AssemblyItem const& _item);
std::string fullDAGToString(Id _id) const; std::string fullDAGToString(Id _id) const;
private: private:
@ -105,7 +109,7 @@ private:
std::vector<Expression> m_representatives; std::vector<Expression> m_representatives;
/// All expression ever encountered. /// All expression ever encountered.
std::set<Expression> m_expressions; std::set<Expression> m_expressions;
std::vector<std::shared_ptr<AssemblyItem>> m_spareAssemblyItem; std::vector<std::shared_ptr<AssemblyItem>> m_spareAssemblyItems;
}; };
/** /**
@ -134,7 +138,7 @@ public:
unsigned matchGroup() const { return m_matchGroup; } unsigned matchGroup() const { return m_matchGroup; }
bool matches(Expression const& _expr, ExpressionClasses const& _classes) const; bool matches(Expression const& _expr, ExpressionClasses const& _classes) const;
AssemblyItem toAssemblyItem() const { return AssemblyItem(m_type, m_data); } AssemblyItem toAssemblyItem(SourceLocation const& _location) const;
std::vector<Pattern> arguments() const { return m_arguments; } std::vector<Pattern> arguments() const { return m_arguments; }
/// @returns the id of the matched expression if this pattern is part of a match group. /// @returns the id of the matched expression if this pattern is part of a match group.
@ -163,7 +167,7 @@ struct ExpressionTemplate
{ {
using Expression = ExpressionClasses::Expression; using Expression = ExpressionClasses::Expression;
using Id = ExpressionClasses::Id; using Id = ExpressionClasses::Id;
explicit ExpressionTemplate(Pattern const& _pattern); explicit ExpressionTemplate(Pattern const& _pattern, SourceLocation const& _location);
std::string toString() const; std::string toString() const;
bool hasId = false; bool hasId = false;
/// Id of the matched expression, if available. /// Id of the matched expression, if available.

1
libjsqrc/ethereumjs/.travis.yml

@ -2,7 +2,6 @@ language: node_js
node_js: node_js:
- "0.12" - "0.12"
- "0.11" - "0.11"
- "0.10"
before_script: before_script:
- npm install - npm install
- npm install jshint - npm install jshint

34
libjsqrc/ethereumjs/README.md

@ -1,6 +1,6 @@
# Ethereum JavaScript API # Ethereum JavaScript API
[![Join the chat at https://gitter.im/ethereum/ethereum.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/ethereum.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/ethereum/web3.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/web3.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API) This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API)
which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec. It's available on npm as a node module, for bower and component as an embeddable js and as a meteor.js package. which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec. It's available on npm as a node module, for bower and component as an embeddable js and as a meteor.js package.
@ -21,7 +21,7 @@ You need to run a local ethrereum node to use this library.
### Meteor.js ### Meteor.js
$ meteor add ethereum:js $ meteor add ethereum:web3
### As Browser module ### As Browser module
Bower Bower
@ -36,11 +36,7 @@ Component
* Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/) (not required for the meteor package) * Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/) (not required for the meteor package)
## Usage ## Usage
You can require the library (not required for the meteor package): Use the `web3` object directly from global namespace:
var web3 = require('ethereum.js');
Or use it directly from global namespace:
console.log(web3); // {eth: .., shh: ...} // it's here! console.log(web3); // {eth: .., shh: ...} // it's here!
@ -106,16 +102,16 @@ Install ethereum and spawn a node:
eth -j eth -j
``` ```
[npm-image]: https://badge.fury.io/js/ethereum.js.png [npm-image]: https://badge.fury.io/js/web3.png
[npm-url]: https://npmjs.org/package/ethereum.js [npm-url]: https://npmjs.org/package/web3
[travis-image]: https://travis-ci.org/ethereum/ethereum.js.svg [travis-image]: https://travis-ci.org/ethereum/web3.js.svg
[travis-url]: https://travis-ci.org/ethereum/ethereum.js [travis-url]: https://travis-ci.org/ethereum/web3.js
[dep-image]: https://david-dm.org/ethereum/ethereum.js.svg [dep-image]: https://david-dm.org/ethereum/web3.js.svg
[dep-url]: https://david-dm.org/ethereum/ethereum.js [dep-url]: https://david-dm.org/ethereum/web3.js
[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg [dep-dev-image]: https://david-dm.org/ethereum/web.js/dev-status.svg
[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies [dep-dev-url]: https://david-dm.org/ethereum/web3.js#info=devDependencies
[coveralls-image]: https://coveralls.io/repos/ethereum/ethereum.js/badge.svg?branch=master [coveralls-image]: https://coveralls.io/repos/ethereum/web3.js/badge.svg?branch=master
[coveralls-url]: https://coveralls.io/r/ethereum/ethereum.js?branch=master [coveralls-url]: https://coveralls.io/r/ethereum/web3.js?branch=master
[waffle-image]: https://badge.waffle.io/ethereum/ethereum.js.svg?label=ready&title=Ready [waffle-image]: https://badge.waffle.io/ethereum/web3.js.svg?label=ready&title=Ready
[waffle-url]: http://waffle.io/ethereum/ethereum.js [waffle-url]: http://waffle.io/ethereum/web3.js

2
libjsqrc/ethereumjs/bower.json

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

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

File diff suppressed because it is too large

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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

6998
libjsqrc/ethereumjs/dist/web3.js

File diff suppressed because it is too large

50
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

57
libjsqrc/ethereumjs/example/contract.html

@ -2,36 +2,34 @@
<html> <html>
<head> <head>
<script type="text/javascript" src="../dist/web3"></script> <script type="text/javascript" src="../dist/web3.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var web3 = require('web3'); var web3 = require('web3');
web3.setProvider(new web3.providers.HttpProvider()); web3.setProvider(new web3.providers.HttpProvider("http://localhost:8545"));
// solidity source code // solidity source code
var source = "" + /*var source = "" +*/
"contract test {\n" + /*"contract test {\n" +*/
" function multiply(uint a) returns(uint d) {\n" + /*" function multiply(uint a) constant returns(uint d) {\n" +*/
" return a * 7;\n" + /*" return a * 7;\n" +*/
" }\n" + /*" }\n" +*/
"}\n"; /*"}\n";*/
var source = "605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056";
// contract description, this will be autogenerated somehow // contract description, this is autogenerated using solc CLI
var desc = [{ var desc = [{
"name": "multiply(uint256)", "constant" : true,
"type": "function", "inputs" : [{
"inputs": [ "name" : "a",
{ "type" : "uint256"
"name": "a", }],
"type": "uint256" "name" : "multiply",
} "outputs" : [{
], "name" : "d",
"outputs": [ "type" : "uint256"
{ }],
"name": "d", "type" : "function"
"type": "uint256"
}
]
}]; }];
var myContract; var myContract;
@ -41,11 +39,12 @@
document.getElementById('create').style.visibility = 'hidden'; document.getElementById('create').style.visibility = 'hidden';
document.getElementById('source').innerText = source; document.getElementById('source').innerText = source;
// create contract // let's assume that coinbase is our account
var address = web3.eth.sendTransaction({data: web3.eth.compile.solidity(source)}), web3.eth.defaultAccount = web3.eth.coinbase;
Contract = web3.eth.contract(desc);
myContract = new Contract(address); // create contract
var Contract = web3.eth.contract(desc);
myContract = new Contract({data: source});
document.getElementById('call').style.visibility = 'visible'; document.getElementById('call').style.visibility = 'visible';
} }
@ -54,7 +53,7 @@
var param = parseInt(document.getElementById('value').value); var param = parseInt(document.getElementById('value').value);
// call the contract // call the contract
var res = myContract.call().multiply(param); var res = myContract.multiply(param);
document.getElementById('result').innerText = res.toString(10); document.getElementById('result').innerText = res.toString(10);
} }

77
libjsqrc/ethereumjs/example/contract_with_array.html

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

119
libjsqrc/ethereumjs/example/event.html

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

65
libjsqrc/ethereumjs/example/event_inc.html

@ -4,48 +4,61 @@
<script type="text/javascript" src="../dist/web3.js"></script> <script type="text/javascript" src="../dist/web3.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var web3 = require('web3'); var web3 = require('web3');
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8080')); web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
var source = "" + /*var source = "" + */
"contract Contract { " + /*"contract Contract { " +*/
" event Incremented(bool indexed odd, uint x); " + /*" event Incremented(bool indexed odd, uint x); " +*/
" function Contract() { " + /*" function Contract() { " +*/
" x = 69; " + /*" x = 69; " +*/
" } " + /*" } " +*/
" function inc() { " + /*" function inc() { " +*/
" ++x; " + /*" ++x; " +*/
" Incremented(x % 2 == 1, x); " + /*" Incremented(x % 2 == 1, x); " +*/
" } " + /*" } " +*/
" uint x; " + /*" uint x; " +*/
"}"; /*"}";*/
var source = "5b60456000600050819055505b608c8060196000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063371303c014602e57005b6034603a565b60006000f35b6000600081815054600101919050819055506001600260006000505406147f6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad600060006000505481526020016000a25b56";
var desc = [{ var desc = [{
"type":"event", "constant" : false,
"name":"Incremented", "inputs" : [],
"inputs": [{"name":"odd","type":"bool","indexed":true},{"name":"x","type":"uint","indexed":false}], "name" : "inc",
"outputs" : [],
"type" : "function"
}, { }, {
"type":"function", "anonymous" : false,
"name":"inc", "inputs" : [{
"inputs": [], "indexed" : true,
"outputs": [] "name" : "odd",
"type" : "bool"
}, {
"indexed" : false,
"name" : "x",
"type" : "uint256"
}],
"name" : "Incremented",
"type" : "event"
}]; }];
var address; var address;
var contract; var contract;
var update = function (x) { var update = function (err, x) {
document.getElementById('result').innerText = JSON.stringify(x); document.getElementById('result').innerText = JSON.stringify(x, null, 2);
}; };
var createContract = function () { var createContract = function () {
address = web3.eth.sendTransaction({data: web3.eth.compile.solidity(source)}); // let's assume that we have a private key to coinbase ;)
contract = web3.eth.contract(address, desc); web3.eth.defaultAccount = web3.eth.coinbase;
contract.Incremented({odd: true}).changed(update); var Contract = web3.eth.contract(desc);
contract = new Contract({data: source});
contract.Incremented({odd: true}).watch(update);
}; };
var callContract = function () { var callContract = function () {
contract.call().inc(); contract.inc();
}; };

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

@ -22,49 +22,9 @@
*/ */
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var c = require('../utils/config'); var coder = require('./coder');
var types = require('./types');
var f = require('./formatters');
var solUtils = require('./utils'); var solUtils = require('./utils');
/**
* throw incorrect type error
*
* @method throwTypeError
* @param {String} type
* @throws incorrect type error
*/
var throwTypeError = function (type) {
throw new Error('parser does not support type: ' + type);
};
/** This method should be called if we want to check if givent type is an array type
*
* @method isArrayType
* @param {String} type name
* @returns {Boolean} true if it is, otherwise false
*/
var isArrayType = function (type) {
return type.slice(-2) === '[]';
};
/**
* This method should be called to return dynamic type length in hex
*
* @method dynamicTypeBytes
* @param {String} type
* @param {String|Array} dynamic type
* @return {String} length of dynamic type in hex or empty string if type is not dynamic
*/
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
if (isArrayType(type) || type === 'bytes')
return f.formatInputInt(value.length);
return "";
};
var inputTypes = types.inputTypes();
/** /**
* Formats input params to bytes * Formats input params to bytes
* *
@ -74,57 +34,12 @@ var inputTypes = types.inputTypes();
* @returns bytes representation of input params * @returns bytes representation of input params
*/ */
var formatInput = function (inputs, params) { var formatInput = function (inputs, params) {
var bytes = ""; var i = inputs.map(function (input) {
var toAppendConstant = ""; return input.type;
var toAppendArrayContent = "";
/// first we iterate in search for dynamic
inputs.forEach(function (input, index) {
bytes += dynamicTypeBytes(input.type, params[index]);
}); });
return coder.encodeParams(i, params);
inputs.forEach(function (input, i) {
/*jshint maxcomplexity:5 */
var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
}
if (!typeMatch) {
throwTypeError(inputs[i].type);
}
var formatter = inputTypes[j - 1].format;
if (isArrayType(inputs[i].type))
toAppendArrayContent += params[i].reduce(function (acc, curr) {
return acc + formatter(curr);
}, "");
else if (inputs[i].type === 'bytes')
toAppendArrayContent += formatter(params[i]);
else
toAppendConstant += formatter(params[i]);
});
bytes += toAppendConstant + toAppendArrayContent;
return bytes;
};
/**
* This method should be called to predict the length of dynamic type
*
* @method dynamicBytesLength
* @param {String} type
* @returns {Number} length of dynamic type, 0 or multiplication of ETH_PADDING (32)
*/
var dynamicBytesLength = function (type) {
if (isArrayType(type) || type === 'bytes')
return c.ETH_PADDING * 2;
return 0;
}; };
var outputTypes = types.outputTypes();
/** /**
* Formats output bytes back to param list * Formats output bytes back to param list
* *
@ -133,52 +48,12 @@ var outputTypes = types.outputTypes();
* @param {String} bytes represention of output * @param {String} bytes represention of output
* @returns {Array} output params * @returns {Array} output params
*/ */
var formatOutput = function (outs, output) { var formatOutput = function (outs, bytes) {
var o = outs.map(function (out) {
output = output.slice(2); return out.type;
var result = [];
var padding = c.ETH_PADDING * 2;
var dynamicPartLength = outs.reduce(function (acc, curr) {
return acc + dynamicBytesLength(curr.type);
}, 0);
var dynamicPart = output.slice(0, dynamicPartLength);
output = output.slice(dynamicPartLength);
outs.forEach(function (out, i) {
/*jshint maxcomplexity:6 */
var typeMatch = false;
for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
typeMatch = outputTypes[j].type(outs[i].type);
}
if (!typeMatch) {
throwTypeError(outs[i].type);
}
var formatter = outputTypes[j - 1].format;
if (isArrayType(outs[i].type)) {
var size = f.formatOutputUInt(dynamicPart.slice(0, padding));
dynamicPart = dynamicPart.slice(padding);
var array = [];
for (var k = 0; k < size; k++) {
array.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
}
result.push(array);
}
else if (types.prefixedType('bytes')(outs[i].type)) {
dynamicPart = dynamicPart.slice(padding);
result.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
} else {
result.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
}
}); });
return result; return coder.decodeParams(o, bytes);
}; };
/** /**

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

@ -0,0 +1,329 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file coder.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var BigNumber = require('bignumber.js');
var utils = require('../utils/utils');
var f = require('./formatters');
var SolidityParam = require('./param');
/**
* Should be used to check if a type is an array type
*
* @method isArrayType
* @param {String} type
* @return {Bool} true is the type is an array, otherwise false
*/
var isArrayType = function (type) {
return type.slice(-2) === '[]';
};
/**
* SolidityType prototype is used to encode/decode solidity params of certain type
*/
var SolidityType = function (config) {
this._name = config.name;
this._match = config.match;
this._mode = config.mode;
this._inputFormatter = config.inputFormatter;
this._outputFormatter = config.outputFormatter;
};
/**
* Should be used to determine if this SolidityType do match given type
*
* @method isType
* @param {String} name
* @return {Bool} true if type match this SolidityType, otherwise false
*/
SolidityType.prototype.isType = function (name) {
if (this._match === 'strict') {
return this._name === name || (name.indexOf(this._name) === 0 && name.slice(this._name.length) === '[]');
} else if (this._match === 'prefix') {
// TODO better type detection!
return name.indexOf(this._name) === 0;
}
};
/**
* Should be used to transform plain param to SolidityParam object
*
* @method formatInput
* @param {Object} param - plain object, or an array of objects
* @param {Bool} arrayType - true if a param should be encoded as an array
* @return {SolidityParam} encoded param wrapped in SolidityParam object
*/
SolidityType.prototype.formatInput = function (param, arrayType) {
if (utils.isArray(param) && arrayType) { // TODO: should fail if this two are not the same
var self = this;
return param.map(function (p) {
return self._inputFormatter(p);
}).reduce(function (acc, current) {
acc.appendArrayElement(current);
return acc;
}, new SolidityParam('', f.formatInputInt(param.length).value));
}
return this._inputFormatter(param);
};
/**
* Should be used to transoform SolidityParam to plain param
*
* @method formatOutput
* @param {SolidityParam} byteArray
* @param {Bool} arrayType - true if a param should be decoded as an array
* @return {Object} plain decoded param
*/
SolidityType.prototype.formatOutput = function (param, arrayType) {
if (arrayType) {
// let's assume, that we solidity will never return long arrays :P
var result = [];
var length = new BigNumber(param.prefix, 16);
for (var i = 0; i < length * 64; i += 64) {
result.push(this._outputFormatter(new SolidityParam(param.suffix.slice(i, i + 64))));
}
return result;
}
return this._outputFormatter(param);
};
/**
* Should be used to check if a type is variadic
*
* @method isVariadicType
* @param {String} type
* @returns {Bool} true if the type is variadic
*/
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
* @returns {SolidityParam} shifted param
*/
SolidityType.prototype.shiftParam = function (type, param) {
if (this._mode === 'bytes') {
return param.shiftBytes();
} else if (isArrayType(type)) {
var length = new BigNumber(param.prefix.slice(0, 64), 16);
return param.shiftArray(length);
}
return param.shiftValue();
};
/**
* SolidityCoder prototype should be used to encode/decode solidity params of any type
*/
var SolidityCoder = function (types) {
this._types = types;
};
/**
* This method should be used to transform type to SolidityType
*
* @method _requireType
* @param {String} type
* @returns {SolidityType}
* @throws {Error} throws if no matching type is found
*/
SolidityCoder.prototype._requireType = function (type) {
var solidityType = this._types.filter(function (t) {
return t.isType(type);
})[0];
if (!solidityType) {
throw Error('invalid solidity type!: ' + type);
}
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
*
* @method _formatInput
* @param {String} type of param
* @param {Object} plain param
* @return {SolidityParam}
*/
SolidityCoder.prototype._formatInput = function (type, param) {
return this._requireType(type).formatInput(param, isArrayType(type));
};
/**
* Should be used to encode plain param
*
* @method encodeParam
* @param {String} type
* @param {Object} plain param
* @return {String} encoded plain param
*/
SolidityCoder.prototype.encodeParam = function (type, param) {
return this._formatInput(type, param).encode();
};
/**
* Should be used to encode list of params
*
* @method encodeParams
* @param {Array} types
* @param {Array} params
* @return {String} encoded list of params
*/
SolidityCoder.prototype.encodeParams = function (types, params) {
var self = this;
return types.map(function (type, index) {
return self._formatInput(type, params[index]);
}).reduce(function (acc, solidityParam) {
acc.append(solidityParam);
return acc;
}, new SolidityParam()).encode();
};
/**
* 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));
};
/**
* Should be used to decode bytes to plain param
*
* @method decodeParam
* @param {String} type
* @param {String} bytes
* @return {Object} plain param
*/
SolidityCoder.prototype.decodeParam = function (type, bytes) {
return this._formatOutput(type, this._bytesToParam([type], bytes));
};
/**
* Should be used to decode list of params
*
* @method decodeParam
* @param {Array} types
* @param {String} bytes
* @return {Array} array of plain params
*/
SolidityCoder.prototype.decodeParams = function (types, bytes) {
var self = this;
var param = this._bytesToParam(types, bytes);
return types.map(function (type) {
var solidityType = self._requireType(type);
var p = solidityType.shiftParam(type, param);
return solidityType.formatOutput(p, isArrayType(type));
});
};
var coder = new SolidityCoder([
new SolidityType({
name: 'address',
match: 'strict',
mode: 'value',
inputFormatter: f.formatInputInt,
outputFormatter: f.formatOutputAddress
}),
new SolidityType({
name: 'bool',
match: 'strict',
mode: 'value',
inputFormatter: f.formatInputBool,
outputFormatter: f.formatOutputBool
}),
new SolidityType({
name: 'int',
match: 'prefix',
mode: 'value',
inputFormatter: f.formatInputInt,
outputFormatter: f.formatOutputInt,
}),
new SolidityType({
name: 'uint',
match: 'prefix',
mode: 'value',
inputFormatter: f.formatInputInt,
outputFormatter: f.formatOutputUInt
}),
new SolidityType({
name: 'bytes',
match: 'strict',
mode: 'bytes',
inputFormatter: f.formatInputDynamicBytes,
outputFormatter: f.formatOutputDynamicBytes
}),
new SolidityType({
name: 'bytes',
match: 'prefix',
mode: 'value',
inputFormatter: f.formatInputBytes,
outputFormatter: f.formatOutputBytes
}),
new SolidityType({
name: 'real',
match: 'prefix',
mode: 'value',
inputFormatter: f.formatInputReal,
outputFormatter: f.formatOutputReal
}),
new SolidityType({
name: 'ureal',
match: 'prefix',
mode: 'value',
inputFormatter: f.formatInputReal,
outputFormatter: f.formatOutputUReal
})
]);
module.exports = coder;

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

@ -14,15 +14,17 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file formatters.js /**
* @authors: * @file formatters.js
* Marek Kotewicz <marek@ethdev.com> * @author Marek Kotewicz <marek@ethdev.com>
* @date 2015 * @date 2015
*/ */
var BigNumber = require('bignumber.js'); var BigNumber = require('bignumber.js');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var c = require('../utils/config'); var c = require('../utils/config');
var SolidityParam = require('./param');
/** /**
* Formats input value to byte representation of int * Formats input value to byte representation of int
@ -31,23 +33,37 @@ var c = require('../utils/config');
* *
* @method formatInputInt * @method formatInputInt
* @param {String|Number|BigNumber} value that needs to be formatted * @param {String|Number|BigNumber} value that needs to be formatted
* @returns {String} right-aligned byte representation of int * @returns {SolidityParam}
*/ */
var formatInputInt = function (value) { var formatInputInt = function (value) {
var padding = c.ETH_PADDING * 2; var padding = c.ETH_PADDING * 2;
BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE); BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);
return utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding); var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);
return new SolidityParam(result);
}; };
/** /**
* Formats input value to byte representation of string * Formats input value to byte representation of string
* *
* @method formatInputString * @method formatInputBytes
* @param {String} * @param {String}
* @returns {String} left-algined byte representation of string * @returns {SolidityParam}
*/ */
var formatInputString = function (value) { var formatInputBytes = function (value) {
return utils.fromAscii(value, c.ETH_PADDING).substr(2); var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);
return new SolidityParam(result);
};
/**
* Formats input value to byte representation of string
*
* @method formatInputDynamicBytes
* @param {String}
* @returns {SolidityParam}
*/
var formatInputDynamicBytes = function (value) {
var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);
return new SolidityParam('', formatInputInt(value.length).value, result);
}; };
/** /**
@ -55,10 +71,11 @@ var formatInputString = function (value) {
* *
* @method formatInputBool * @method formatInputBool
* @param {Boolean} * @param {Boolean}
* @returns {String} right-aligned byte representation bool * @returns {SolidityParam}
*/ */
var formatInputBool = function (value) { var formatInputBool = function (value) {
return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0'); var result = '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
return new SolidityParam(result);
}; };
/** /**
@ -67,10 +84,10 @@ var formatInputBool = function (value) {
* *
* @method formatInputReal * @method formatInputReal
* @param {String|Number|BigNumber} * @param {String|Number|BigNumber}
* @returns {String} byte representation of real * @returns {SolidityParam}
*/ */
var formatInputReal = function (value) { var formatInputReal = function (value) {
return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
}; };
/** /**
@ -88,12 +105,11 @@ var signedIsNegative = function (value) {
* Formats right-aligned output bytes to int * Formats right-aligned output bytes to int
* *
* @method formatOutputInt * @method formatOutputInt
* @param {String} bytes * @param {SolidityParam} param
* @returns {BigNumber} right-aligned output bytes formatted to big number * @returns {BigNumber} right-aligned output bytes formatted to big number
*/ */
var formatOutputInt = function (value) { var formatOutputInt = function (param) {
var value = param.value || "0";
value = value || "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
@ -107,11 +123,11 @@ var formatOutputInt = function (value) {
* Formats right-aligned output bytes to uint * Formats right-aligned output bytes to uint
* *
* @method formatOutputUInt * @method formatOutputUInt
* @param {String} bytes * @param {SolidityParam}
* @returns {BigNumeber} right-aligned output bytes formatted to uint * @returns {BigNumeber} right-aligned output bytes formatted to uint
*/ */
var formatOutputUInt = function (value) { var formatOutputUInt = function (param) {
value = value || "0"; var value = param.value || "0";
return new BigNumber(value, 16); return new BigNumber(value, 16);
}; };
@ -119,80 +135,84 @@ var formatOutputUInt = function (value) {
* Formats right-aligned output bytes to real * Formats right-aligned output bytes to real
* *
* @method formatOutputReal * @method formatOutputReal
* @param {String} * @param {SolidityParam}
* @returns {BigNumber} input bytes formatted to real * @returns {BigNumber} input bytes formatted to real
*/ */
var formatOutputReal = function (value) { var formatOutputReal = function (param) {
return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128));
}; };
/** /**
* Formats right-aligned output bytes to ureal * Formats right-aligned output bytes to ureal
* *
* @method formatOutputUReal * @method formatOutputUReal
* @param {String} * @param {SolidityParam}
* @returns {BigNumber} input bytes formatted to ureal * @returns {BigNumber} input bytes formatted to ureal
*/ */
var formatOutputUReal = function (value) { var formatOutputUReal = function (param) {
return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128));
}; };
/** /**
* Should be used to format output hash * Should be used to format output bool
* *
* @method formatOutputHash * @method formatOutputBool
* @param {String} * @param {SolidityParam}
* @returns {String} right-aligned output bytes formatted to hex * @returns {Boolean} right-aligned input bytes formatted to bool
*/ */
var formatOutputHash = function (value) { var formatOutputBool = function (param) {
return "0x" + value; return param.value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
}; };
/** /**
* Should be used to format output bool * Should be used to format output string
* *
* @method formatOutputBool * @method formatOutputBytes
* @param {String} * @param {SolidityParam} left-aligned hex representation of string
* @returns {Boolean} right-aligned input bytes formatted to bool * @returns {String} ascii string
*/ */
var formatOutputBool = function (value) { var formatOutputBytes = function (param) {
return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; // length might also be important!
return utils.toAscii(param.value);
}; };
/** /**
* Should be used to format output string * Should be used to format output string
* *
* @method formatOutputString * @method formatOutputDynamicBytes
* @param {Sttring} left-aligned hex representation of string * @param {SolidityParam} left-aligned hex representation of string
* @returns {String} ascii string * @returns {String} ascii string
*/ */
var formatOutputString = function (value) { var formatOutputDynamicBytes = function (param) {
return utils.toAscii(value); // length might also be important!
return utils.toAscii(param.suffix);
}; };
/** /**
* Should be used to format output address * Should be used to format output address
* *
* @method formatOutputAddress * @method formatOutputAddress
* @param {String} right-aligned input bytes * @param {SolidityParam} right-aligned input bytes
* @returns {String} address * @returns {String} address
*/ */
var formatOutputAddress = function (value) { var formatOutputAddress = function (param) {
var value = param.value;
return "0x" + value.slice(value.length - 40, value.length); return "0x" + value.slice(value.length - 40, value.length);
}; };
module.exports = { module.exports = {
formatInputInt: formatInputInt, formatInputInt: formatInputInt,
formatInputString: formatInputString, formatInputBytes: formatInputBytes,
formatInputDynamicBytes: formatInputDynamicBytes,
formatInputBool: formatInputBool, formatInputBool: formatInputBool,
formatInputReal: formatInputReal, formatInputReal: formatInputReal,
formatOutputInt: formatOutputInt, formatOutputInt: formatOutputInt,
formatOutputUInt: formatOutputUInt, formatOutputUInt: formatOutputUInt,
formatOutputReal: formatOutputReal, formatOutputReal: formatOutputReal,
formatOutputUReal: formatOutputUReal, formatOutputUReal: formatOutputUReal,
formatOutputHash: formatOutputHash,
formatOutputBool: formatOutputBool, formatOutputBool: formatOutputBool,
formatOutputString: formatOutputString, formatOutputBytes: formatOutputBytes,
formatOutputDynamicBytes: formatOutputDynamicBytes,
formatOutputAddress: formatOutputAddress formatOutputAddress: formatOutputAddress
}; };

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

@ -0,0 +1,105 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file param.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/**
* SolidityParam object prototype.
* Should be used when encoding, decoding solidity bytes
*/
var SolidityParam = function (value, prefix, suffix) {
this.prefix = prefix || '';
this.value = value || '';
this.suffix = suffix || '';
};
/**
* This method should be used to encode two params one after another
*
* @method append
* @param {SolidityParam} param that it appended after this
*/
SolidityParam.prototype.append = function (param) {
this.prefix += param.prefix;
this.value += param.value;
this.suffix += param.suffix;
};
/**
* This method should be used to encode next param in an array
*
* @method appendArrayElement
* @param {SolidityParam} param that is appended to an array
*/
SolidityParam.prototype.appendArrayElement = function (param) {
this.suffix += param.value;
this.prefix += param.prefix;
// TODO: suffix not supported = it's required for nested arrays;
};
/**
* This method should be used to create bytearrays from param
*
* @method encode
* @return {String} encoded param(s)
*/
SolidityParam.prototype.encode = function () {
return this.prefix + this.value + this.suffix;
};
/**
* This method should be used to shift first param from group of params
*
* @method shiftValue
* @return {SolidityParam} first value param
*/
SolidityParam.prototype.shiftValue = function () {
var value = this.value.slice(0, 64);
this.value = this.value.slice(64);
return new SolidityParam(value);
};
/**
* This method should be used to first bytes param from group of params
*
* @method shiftBytes
* @return {SolidityParam} first bytes param
*/
SolidityParam.prototype.shiftBytes = function () {
return this.shiftArray(1);
};
/**
* This method should be used to shift an array from group of params
*
* @method shiftArray
* @param {Number} size of an array to shift
* @return {SolidityParam} first array param
*/
SolidityParam.prototype.shiftArray = function (length) {
var prefix = this.prefix.slice(0, 64);
this.prefix = this.value.slice(64);
var suffix = this.suffix.slice(0, 64 * length);
this.suffix = this.suffix.slice(64 * length);
return new SolidityParam('', prefix, suffix);
};
module.exports = SolidityParam;

77
libjsqrc/ethereumjs/lib/solidity/types.js

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

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

@ -34,35 +34,7 @@ var getConstructor = function (abi, numberOfArgs) {
})[0]; })[0];
}; };
/**
* Filters all functions from input abi
*
* @method filterFunctions
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'function'
*/
var filterFunctions = function (json) {
return json.filter(function (current) {
return current.type === 'function';
});
};
/**
* Filters all events from input abi
*
* @method filterEvents
* @param {Array} abi
* @returns {Array} abi array with filtered objects of type 'event'
*/
var filterEvents = function (json) {
return json.filter(function (current) {
return current.type === 'event';
});
};
module.exports = { module.exports = {
getConstructor: getConstructor, getConstructor: getConstructor
filterFunctions: filterFunctions,
filterEvents: filterEvents
}; };

3
libjsqrc/ethereumjs/lib/utils/config.js

@ -64,6 +64,7 @@ module.exports = {
ETH_UNITS: ETH_UNITS, ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
ETH_POLLING_TIMEOUT: 1000, ETH_POLLING_TIMEOUT: 1000,
ETH_DEFAULTBLOCK: 'latest' defaultBlock: 'latest',
defaultAccount: undefined
}; };

42
libjsqrc/ethereumjs/lib/utils/utils.js

@ -14,9 +14,9 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file utils.js /**
* @authors: * @file utils.js
* Marek Kotewicz <marek@ethdev.com> * @author Marek Kotewicz <marek@ethdev.com>
* @date 2015 * @date 2015
*/ */
@ -67,22 +67,6 @@ var padLeft = function (string, chars, sign) {
return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; return new Array(chars - string.length + 1).join(sign ? sign : "0") + string;
}; };
/** Finds first index of array element matching pattern
*
* @method findIndex
* @param {Array}
* @param {Function} pattern
* @returns {Number} index of element
*/
var findIndex = function (array, callback) {
var end = false;
var i = 0;
for (; i < array.length && !end; i++) {
end = callback(array[i]);
}
return end ? i - 1 : -1;
};
/** /**
* Should be called to get sting from it's hex representation * Should be called to get sting from it's hex representation
* *
@ -112,7 +96,7 @@ var toAscii = function(hex) {
/** /**
* Shold be called to get hex representation (prefixed by 0x) of ascii string * Shold be called to get hex representation (prefixed by 0x) of ascii string
* *
* @method fromAscii * @method toHexNative
* @param {String} string * @param {String} string
* @returns {String} hex representation of input string * @returns {String} hex representation of input string
*/ */
@ -142,6 +126,22 @@ var fromAscii = function(str, pad) {
return "0x" + hex; return "0x" + hex;
}; };
/**
* Should be used to create full function/event name from json abi
*
* @method transformToFullName
* @param {Object} json-abi
* @return {String} full fnction/event name
*/
var transformToFullName = function (json) {
if (json.name.indexOf('(') !== -1) {
return json.name;
}
var typeName = json.inputs.map(function(i){return i.type; }).join();
return json.name + '(' + typeName + ')';
};
/** /**
* Should be called to get display name of contract function * Should be called to get display name of contract function
* *
@ -448,12 +448,12 @@ var isJson = function (str) {
module.exports = { module.exports = {
padLeft: padLeft, padLeft: padLeft,
findIndex: findIndex,
toHex: toHex, toHex: toHex,
toDecimal: toDecimal, toDecimal: toDecimal,
fromDecimal: fromDecimal, fromDecimal: fromDecimal,
toAscii: toAscii, toAscii: toAscii,
fromAscii: fromAscii, fromAscii: fromAscii,
transformToFullName: transformToFullName,
extractDisplayName: extractDisplayName, extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName, extractTypeName: extractTypeName,
toWei: toWei, toWei: toWei,

2
libjsqrc/ethereumjs/lib/version.json

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

17
libjsqrc/ethereumjs/lib/web3.js

@ -117,6 +117,8 @@ web3.setProvider = function (provider) {
}; };
web3.reset = function () { web3.reset = function () {
RequestManager.getInstance().reset(); RequestManager.getInstance().reset();
c.defaultBlock = 'latest';
c.defaultAccount = undefined;
}; };
web3.toHex = utils.toHex; web3.toHex = utils.toHex;
web3.toAscii = utils.toAscii; web3.toAscii = utils.toAscii;
@ -131,14 +133,23 @@ web3.isAddress = utils.isAddress;
// ADD defaultblock // ADD defaultblock
Object.defineProperty(web3.eth, 'defaultBlock', { Object.defineProperty(web3.eth, 'defaultBlock', {
get: function () { get: function () {
return c.ETH_DEFAULTBLOCK; return c.defaultBlock;
}, },
set: function (val) { set: function (val) {
c.ETH_DEFAULTBLOCK = val; c.defaultBlock = val;
return c.ETH_DEFAULTBLOCK; return val;
} }
}); });
Object.defineProperty(web3.eth, 'defaultAccount', {
get: function () {
return c.defaultAccount;
},
set: function (val) {
c.defaultAccount = val;
return val;
}
});
/// setups all api methods /// setups all api methods
setupMethods(web3, web3Methods); setupMethods(web3, web3Methods);

184
libjsqrc/ethereumjs/lib/web3/contract.js

@ -14,138 +14,38 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file contract.js /**
* @authors: * @file contract.js
* Marek Kotewicz <marek@ethdev.com> * @author Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
*/ */
var web3 = require('../web3'); var web3 = require('../web3');
var solAbi = require('../solidity/abi'); var solAbi = require('../solidity/abi');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var solUtils = require('../solidity/utils'); var SolidityEvent = require('./event');
var eventImpl = require('./event'); var SolidityFunction = require('./function');
var signature = require('./signature');
var addFunctionsToContract = function (contract, desc) {
var addFunctionRelatedPropertiesToContract = function (contract) { desc.filter(function (json) {
return json.type === 'function';
contract.call = function (options) { }).map(function (json) {
contract._isTransaction = false; return new SolidityFunction(json, contract.address);
contract._options = options; }).forEach(function (f) {
return contract; f.attachToContract(contract);
};
contract.sendTransaction = function (options) {
contract._isTransaction = true;
contract._options = options;
return contract;
};
};
var addFunctionsToContract = function (contract, desc, address) {
var inputParser = solAbi.inputParser(desc);
var outputParser = solAbi.outputParser(desc);
// create contract functions
solUtils.filterFunctions(desc).forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
var typeName = utils.extractTypeName(method.name);
var impl = function () {
/*jshint maxcomplexity:7 */
var params = Array.prototype.slice.call(arguments);
var sign = signature.functionSignatureFromAscii(method.name);
var parsed = inputParser[displayName][typeName].apply(null, params);
var options = contract._options || {};
options.to = address;
options.data = sign + parsed;
var isTransaction = contract._isTransaction === true || (contract._isTransaction !== false && !method.constant);
var collapse = options.collapse !== false;
// reset
contract._options = {};
contract._isTransaction = null;
if (isTransaction) {
// transactions do not have any output, cause we do not know, when they will be processed
web3.eth.sendTransaction(options);
return;
}
var output = web3.eth.call(options);
var ret = outputParser[displayName][typeName](output);
if (collapse)
{
if (ret.length === 1)
ret = ret[0];
else if (ret.length === 0)
ret = null;
}
return ret;
};
if (contract[displayName] === undefined) {
contract[displayName] = impl;
}
contract[displayName][typeName] = impl;
}); });
}; };
var addEventRelatedPropertiesToContract = function (contract, desc, address) { var addEventsToContract = function (contract, desc) {
contract.address = address; desc.filter(function (json) {
contract._onWatchEventResult = function (data) { return json.type === 'event';
var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc)); }).map(function (json) {
var parser = eventImpl.outputParser(matchingEvent); return new SolidityEvent(json, contract.address);
return parser(data); }).forEach(function (e) {
}; e.attachToContract(contract);
Object.defineProperty(contract, 'topics', {
get: function() {
return solUtils.filterEvents(desc).map(function (e) {
return signature.eventSignatureFromAscii(e.name);
});
}
}); });
}; };
var addEventsToContract = function (contract, desc, address) {
// create contract events
solUtils.filterEvents(desc).forEach(function (e) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
var sign = signature.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, sign, e);
var o = event.apply(null, params);
var outputFormatter = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.filter(o, undefined, undefined, outputFormatter);
};
// this property should be used by eth.filter to check if object is an event
impl._isEvent = true;
var displayName = utils.extractDisplayName(e.name);
var typeName = utils.extractTypeName(e.name);
if (contract[displayName] === undefined) {
contract[displayName] = impl;
}
contract[displayName][typeName] = impl;
});
};
/** /**
* This method should be called when we want to call / transact some solidity method from javascript * This method should be called when we want to call / transact some solidity method from javascript
* it returns an object which has same methods available as solidity contract description * it returns an object which has same methods available as solidity contract description
@ -174,39 +74,33 @@ var contract = function (abi) {
return Contract.bind(null, abi); return Contract.bind(null, abi);
}; };
function Contract(abi, options) { var Contract = function (abi, options) {
// workaround for invalid assumption that method.name is the full anonymous prototype of the method. this.address = '';
// it's not. it's just the name. the rest of the code assumes it's actually the anonymous
// prototype, so we make it so as a workaround.
// TODO: we may not want to modify input params, maybe use copy instead?
abi.forEach(function (method) {
if (method.name.indexOf('(') === -1) {
var displayName = method.name;
var typeName = method.inputs.map(function(i){return i.type; }).join();
method.name = displayName + '(' + typeName + ')';
}
});
var address = '';
if (utils.isAddress(options)) { if (utils.isAddress(options)) {
address = options; this.address = options;
} else { // is a source code! } else { // is an object!
// TODO, parse the rest of the args // TODO, parse the rest of the args
var code = options; options = options || {};
var args = Array.prototype.slice.call(arguments, 2); var args = Array.prototype.slice.call(arguments, 2);
var bytes = solAbi.formatConstructorParams(abi, args); var bytes = solAbi.formatConstructorParams(abi, args);
address = web3.eth.sendTransaction({data: code + bytes}); options.data += bytes;
this.address = web3.eth.sendTransaction(options);
} }
var result = {}; addFunctionsToContract(this, abi);
addFunctionRelatedPropertiesToContract(result); addEventsToContract(this, abi);
addFunctionsToContract(result, abi, address); };
addEventRelatedPropertiesToContract(result, abi, address);
addEventsToContract(result, abi, address); Contract.prototype.call = function () {
console.error('contract.call is deprecated');
return this;
};
return result; Contract.prototype.sendTransaction = function () {
} console.error('contract.sendTransact is deprecated');
return this;
};
module.exports = contract; module.exports = contract;

22
libjsqrc/ethereumjs/lib/web3/errors.js

@ -20,18 +20,18 @@
* @date 2015 * @date 2015
*/ */
var utils = require('../utils/utils');
module.exports = { module.exports = {
InvalidNumberOfParams: new Error('Invalid number of input parameters'), InvalidNumberOfParams: function () {
InvalidProvider: new Error('Providor not set or invalid'), return new Error('Invalid number of input parameters');
InvalidResponse: function(result){ },
var message = 'Invalid JSON RPC response'; InvalidConnection: function (host){
return new Error('CONNECTION ERROR: Couldn\'t connect to node '+ host +', is it running?');
if(utils.isObject(result) && result.error && result.error.message) { },
message = result.error.message; InvalidProvider: function () {
} return new Error('Providor not set or invalid');
},
InvalidResponse: function (result){
var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response';
return new Error(message); return new Error(message);
} }
}; };

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

@ -102,7 +102,7 @@ var getBlock = new Method({
name: 'getBlock', name: 'getBlock',
call: blockCall, call: blockCall,
params: 2, params: 2,
inputFormatter: [utils.toHex, function (val) { return !!val; }], inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],
outputFormatter: formatters.outputBlockFormatter outputFormatter: formatters.outputBlockFormatter
}); });
@ -110,7 +110,7 @@ var getUncle = new Method({
name: 'getUncle', name: 'getUncle',
call: uncleCall, call: uncleCall,
params: 2, params: 2,
inputFormatter: [utils.toHex, utils.toHex], inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],
outputFormatter: formatters.outputBlockFormatter, outputFormatter: formatters.outputBlockFormatter,
}); });
@ -148,7 +148,7 @@ var getTransactionFromBlock = new Method({
name: 'getTransactionFromBlock', name: 'getTransactionFromBlock',
call: transactionFromBlockCall, call: transactionFromBlockCall,
params: 2, params: 2,
inputFormatter: [utils.toHex, utils.toHex], inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],
outputFormatter: formatters.outputTransactionFormatter outputFormatter: formatters.outputTransactionFormatter
}); });
@ -192,12 +192,6 @@ var compileSerpent = new Method({
params: 1 params: 1
}); });
var flush = new Method({
name: 'flush',
call: 'eth_flush',
params: 0
});
var methods = [ var methods = [
getBalance, getBalance,
getStorageAt, getStorageAt,
@ -215,7 +209,6 @@ var methods = [
compileSolidity, compileSolidity,
compileLLL, compileLLL,
compileSerpent, compileSerpent,
flush
]; ];
/// @returns an array of objects describing web3.eth api properties /// @returns an array of objects describing web3.eth api properties

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

@ -14,125 +14,181 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file event.js /**
* @authors: * @file event.js
* Marek Kotewicz <marek@ethdev.com> * @author Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
*/ */
var abi = require('../solidity/abi');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var signature = require('./signature'); var coder = require('../solidity/coder');
var web3 = require('../web3');
/// filter inputs array && returns only indexed (or not) inputs var formatters = require('./formatters');
/// @param inputs array
/// @param bool if result should be an array of indexed params on not /**
/// @returns array of (not?) indexed params * This prototype should be used to create event filters
var filterInputs = function (inputs, indexed) { */
return inputs.filter(function (current) { var SolidityEvent = function (json, address) {
return current.indexed === indexed; this._params = json.inputs;
}); this._name = utils.transformToFullName(json);
this._address = address;
this._anonymous = json.anonymous;
}; };
var inputWithName = function (inputs, name) { /**
var index = utils.findIndex(inputs, function (input) { * Should be used to get filtered param types
return input.name === name; *
* @method types
* @param {Bool} decide if returned typed should be indexed
* @return {Array} array of types
*/
SolidityEvent.prototype.types = function (indexed) {
return this._params.filter(function (i) {
return i.indexed === indexed;
}).map(function (i) {
return i.type;
}); });
if (index === -1) {
console.error('indexed param with name ' + name + ' not found');
return undefined;
}
return inputs[index];
}; };
var indexedParamsToTopics = function (event, indexed) { /**
// sort keys? * Should be used to get event display name
return Object.keys(indexed).map(function (key) { *
var inputs = [inputWithName(filterInputs(event.inputs, true), key)]; * @method displayName
* @return {String} event display name
*/
SolidityEvent.prototype.displayName = function () {
return utils.extractDisplayName(this._name);
};
/**
* Should be used to get event type name
*
* @method typeName
* @return {String} event type name
*/
SolidityEvent.prototype.typeName = function () {
return utils.extractTypeName(this._name);
};
/**
* Should be used to get event signature
*
* @method signature
* @return {String} event signature
*/
SolidityEvent.prototype.signature = function () {
return web3.sha3(web3.fromAscii(this._name)).slice(2);
};
/**
* Should be used to encode indexed params and options to one final object
*
* @method encode
* @param {Object} indexed
* @param {Object} options
* @return {Object} everything combined together and encoded
*/
SolidityEvent.prototype.encode = function (indexed, options) {
indexed = indexed || {};
options = options || {};
var result = {};
['fromBlock', 'toBlock'].filter(function (f) {
return options[f] !== undefined;
}).forEach(function (f) {
result[f] = utils.toHex(options[f]);
});
result.topics = [];
if (!this._anonymous) {
result.address = this._address;
result.topics.push('0x' + this.signature());
}
var value = indexed[key]; var indexedTopics = this._params.filter(function (i) {
if (value instanceof Array) { return i.indexed === true;
}).map(function (i) {
var value = indexed[i.name];
if (value === undefined || value === null) {
return null;
}
if (utils.isArray(value)) {
return value.map(function (v) { return value.map(function (v) {
return abi.formatInput(inputs, [v]); return '0x' + coder.encodeParam(i.type, v);
}); });
} }
return '0x' + abi.formatInput(inputs, [value]); return '0x' + coder.encodeParam(i.type, value);
}); });
};
var inputParser = function (address, sign, event) { result.topics = result.topics.concat(indexedTopics);
// valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.filter'
return function (indexed, options) {
var o = options || {};
o.address = address;
o.topics = [];
o.topics.push(sign);
if (indexed) {
o.topics = o.topics.concat(indexedParamsToTopics(event, indexed));
}
return o;
};
};
var getArgumentsObject = function (inputs, indexed, notIndexed) { return result;
var indexedCopy = indexed.slice();
var notIndexedCopy = notIndexed.slice();
return inputs.reduce(function (acc, current) {
var value;
if (current.indexed)
value = indexedCopy.splice(0, 1)[0];
else
value = notIndexedCopy.splice(0, 1)[0];
acc[current.name] = value;
return acc;
}, {});
}; };
/**
* Should be used to decode indexed params and options
*
* @method decode
* @param {Object} data
* @return {Object} result object with decoded indexed && not indexed params
*/
SolidityEvent.prototype.decode = function (data) {
var outputParser = function (event) { data.data = data.data || '';
data.topics = data.topics || [];
var argTopics = this._anonymous ? data.topics : data.topics.slice(1);
var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join("");
var indexedParams = coder.decodeParams(this.types(true), indexedData);
var notIndexedData = data.data.slice(2);
var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData);
return function (output) { var result = formatters.outputLogFormatter(data);
var result = { result.event = this.displayName();
event: utils.extractDisplayName(event.name), result.address = data.address;
number: output.number,
hash: output.hash,
args: {}
};
if (!output.topics) {
return result;
}
output.data = output.data || '';
var indexedOutputs = filterInputs(event.inputs, true);
var indexedData = "0x" + output.topics.slice(1, output.topics.length).map(function (topics) { return topics.slice(2); }).join("");
var indexedRes = abi.formatOutput(indexedOutputs, indexedData);
var notIndexedOutputs = filterInputs(event.inputs, false); result.args = this._params.reduce(function (acc, current) {
var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data); acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift();
return acc;
}, {});
result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes); delete result.data;
delete result.topics;
return result; return result;
};
}; };
var getMatchingEvent = function (events, payload) { /**
for (var i = 0; i < events.length; i++) { * Should be used to create new filter object from event
var sign = signature.eventSignatureFromAscii(events[i].name); *
if (sign === payload.topics[0]) { * @method execute
return events[i]; * @param {Object} indexed
} * @param {Object} options
} * @return {Object} filter object
return undefined; */
SolidityEvent.prototype.execute = function (indexed, options) {
var o = this.encode(indexed, options);
var formatter = this.decode.bind(this);
return web3.eth.filter(o, undefined, undefined, formatter);
}; };
/**
module.exports = { * Should be used to attach event to contract object
inputParser: inputParser, *
outputParser: outputParser, * @method attachToContract
getMatchingEvent: getMatchingEvent * @param {Contract}
*/
SolidityEvent.prototype.attachToContract = function (contract) {
var execute = this.execute.bind(this);
var displayName = this.displayName();
if (!contract[displayName]) {
contract[displayName] = execute;
}
contract[displayName][this.typeName()] = this.execute.bind(this, contract);
}; };
module.exports = SolidityEvent;

57
libjsqrc/ethereumjs/lib/web3/filter.js

@ -28,6 +28,25 @@ var RequestManager = require('./requestmanager');
var formatters = require('./formatters'); var formatters = require('./formatters');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
/**
* Converts a given topic to a hex string, but also allows null values.
*
* @param {Mixed} value
* @return {String}
*/
var toTopic = function(value){
if(value === null || typeof value === 'undefined')
return null;
value = String(value);
if(value.indexOf('0x') === 0)
return value;
else
return utils.fromAscii(value);
};
/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones /// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones
/// @param should be string or object /// @param should be string or object
/// @returns options string or object /// @returns options string or object
@ -42,7 +61,7 @@ var getOptions = function (options) {
// make sure topics, get converted to hex // make sure topics, get converted to hex
options.topics = options.topics || []; options.topics = options.topics || [];
options.topics = options.topics.map(function(topic){ options.topics = options.topics.map(function(topic){
return utils.toHex(topic); return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic);
}); });
// lazy load // lazy load
@ -86,6 +105,20 @@ Filter.prototype.watch = function (callback) {
}); });
}; };
// call getFilterLogs on start
if (!utils.isString(this.options)) {
this.get(function (err, messages) {
// don't send all the responses to all the watches again... just to this one
if (err) {
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
});
});
}
RequestManager.getInstance().startPolling({ RequestManager.getInstance().startPolling({
method: this.implementation.poll.call, method: this.implementation.poll.call,
params: [this.filterId], params: [this.filterId],
@ -98,12 +131,24 @@ Filter.prototype.stopWatching = function () {
this.callbacks = []; this.callbacks = [];
}; };
Filter.prototype.get = function () { Filter.prototype.get = function (callback) {
var logs = this.implementation.getLogs(this.filterId);
var self = this; var self = this;
return logs.map(function (log) { if (utils.isFunction(callback)) {
return self.formatter ? self.formatter(log) : log; this.implementation.getLogs(this.filterId, function(err, res){
}); if (err) {
callback(err);
} else {
callback(null, res.map(function (log) {
return self.formatter ? self.formatter(log) : log;
}));
}
});
} else {
var logs = this.implementation.getLogs(this.filterId);
return logs.map(function (log) {
return self.formatter ? self.formatter(log) : log;
});
}
}; };
module.exports = Filter; module.exports = Filter;

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

@ -41,7 +41,7 @@ var isPredefinedBlockNumber = function (blockNumber) {
var inputDefaultBlockNumberFormatter = function (blockNumber) { var inputDefaultBlockNumberFormatter = function (blockNumber) {
if (blockNumber === undefined) { if (blockNumber === undefined) {
return config.ETH_DEFAULTBLOCK; return config.defaultBlock;
} }
return inputBlockNumberFormatter(blockNumber); return inputBlockNumberFormatter(blockNumber);
}; };
@ -64,6 +64,8 @@ var inputBlockNumberFormatter = function (blockNumber) {
*/ */
var inputTransactionFormatter = function (options){ var inputTransactionFormatter = function (options){
options.from = options.from || config.defaultAccount;
// make code -> data // make code -> data
if (options.code) { if (options.code) {
options.data = options.code; options.data = options.code;
@ -89,6 +91,7 @@ var inputTransactionFormatter = function (options){
var outputTransactionFormatter = function (tx){ var outputTransactionFormatter = function (tx){
tx.blockNumber = utils.toDecimal(tx.blockNumber); tx.blockNumber = utils.toDecimal(tx.blockNumber);
tx.transactionIndex = utils.toDecimal(tx.transactionIndex); tx.transactionIndex = utils.toDecimal(tx.transactionIndex);
tx.nonce = utils.toDecimal(tx.nonce);
tx.gas = utils.toDecimal(tx.gas); tx.gas = utils.toDecimal(tx.gas);
tx.gasPrice = utils.toBigNumber(tx.gasPrice); tx.gasPrice = utils.toBigNumber(tx.gasPrice);
tx.value = utils.toBigNumber(tx.value); tx.value = utils.toBigNumber(tx.value);
@ -111,7 +114,6 @@ var outputBlockFormatter = function(block) {
block.timestamp = utils.toDecimal(block.timestamp); block.timestamp = utils.toDecimal(block.timestamp);
block.number = utils.toDecimal(block.number); block.number = utils.toDecimal(block.number);
block.minGasPrice = utils.toBigNumber(block.minGasPrice);
block.difficulty = utils.toBigNumber(block.difficulty); block.difficulty = utils.toBigNumber(block.difficulty);
block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);
@ -155,10 +157,12 @@ var inputPostFormatter = function(post) {
post.payload = utils.toHex(post.payload); post.payload = utils.toHex(post.payload);
post.ttl = utils.fromDecimal(post.ttl); post.ttl = utils.fromDecimal(post.ttl);
post.workToProve = utils.fromDecimal(post.workToProve);
post.priority = utils.fromDecimal(post.priority); post.priority = utils.fromDecimal(post.priority);
if(!utils.isArray(post.topics)) { // fallback
post.topics = [post.topics]; if (!utils.isArray(post.topics)) {
post.topics = post.topics ? [post.topics] : [];
} }
// format the following options // format the following options
@ -190,6 +194,9 @@ var outputPostFormatter = function(post){
} }
// format the following options // format the following options
if (!post.topics) {
post.topics = [];
}
post.topics = post.topics.map(function(topic){ post.topics = post.topics.map(function(topic){
return utils.toAscii(topic); return utils.toAscii(topic);
}); });

151
libjsqrc/ethereumjs/lib/web3/function.js

@ -0,0 +1,151 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file function.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var web3 = require('../web3');
var coder = require('../solidity/coder');
var utils = require('../utils/utils');
/**
* This prototype should be used to call/sendTransaction to solidity functions
*/
var SolidityFunction = function (json, address) {
this._inputTypes = json.inputs.map(function (i) {
return i.type;
});
this._outputTypes = json.outputs.map(function (i) {
return i.type;
});
this._constant = json.constant;
this._name = utils.transformToFullName(json);
this._address = address;
};
/**
* Should be used to create payload from arguments
*
* @method toPayload
* @param {...} solidity function params
* @param {Object} optional payload options
*/
SolidityFunction.prototype.toPayload = function () {
var args = Array.prototype.slice.call(arguments);
var options = {};
if (args.length > this._inputTypes.length && utils.isObject(args[args.length -1])) {
options = args.pop();
}
options.to = this._address;
options.data = '0x' + this.signature() + coder.encodeParams(this._inputTypes, args);
return options;
};
/**
* Should be used to get function signature
*
* @method signature
* @return {String} function signature
*/
SolidityFunction.prototype.signature = function () {
return web3.sha3(web3.fromAscii(this._name)).slice(2, 10);
};
/**
* Should be used to call function
*
* @method call
* @param {Object} options
* @return {String} output bytes
*/
SolidityFunction.prototype.call = function () {
var payload = this.toPayload.apply(this, Array.prototype.slice.call(arguments));
var output = web3.eth.call(payload);
output = output.length >= 2 ? output.slice(2) : output;
var result = coder.decodeParams(this._outputTypes, output);
return result.length === 1 ? result[0] : result;
};
/**
* Should be used to sendTransaction to solidity function
*
* @method sendTransaction
* @param {Object} options
*/
SolidityFunction.prototype.sendTransaction = function () {
var payload = this.toPayload.apply(this, Array.prototype.slice.call(arguments));
web3.eth.sendTransaction(payload);
};
/**
* Should be used to get function display name
*
* @method displayName
* @return {String} display name of the function
*/
SolidityFunction.prototype.displayName = function () {
return utils.extractDisplayName(this._name);
};
/**
* Should be used to get function type name
*
* @method typeName
* @return {String} type name of the function
*/
SolidityFunction.prototype.typeName = function () {
return utils.extractTypeName(this._name);
};
/**
* Should be called to execute function
*
* @method execute
*/
SolidityFunction.prototype.execute = function () {
var transaction = !this._constant;
// send transaction
if (transaction) {
return this.sendTransaction.apply(this, Array.prototype.slice.call(arguments));
}
// call
return this.call.apply(this, Array.prototype.slice.call(arguments));
};
/**
* Should be called to attach function to contract
*
* @method attachToContract
* @param {Contract}
*/
SolidityFunction.prototype.attachToContract = function (contract) {
var execute = this.execute.bind(this);
execute.call = this.call.bind(this);
execute.sendTransaction = this.sendTransaction.bind(this);
var displayName = this.displayName();
if (!contract[displayName]) {
contract[displayName] = execute;
}
contract[displayName][this.typeName()] = execute; // circular!!!!
};
module.exports = SolidityFunction;

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

@ -25,16 +25,23 @@
"use strict"; "use strict";
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
var errors = require('./errors');
var HttpProvider = function (host) { var HttpProvider = function (host) {
this.host = host || 'http://localhost:8080'; this.host = host || 'http://localhost:8545';
}; };
HttpProvider.prototype.send = function (payload) { HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', this.host, false); request.open('POST', this.host, false);
request.send(JSON.stringify(payload));
try {
request.send(JSON.stringify(payload));
} catch(error) {
throw errors.InvalidConnection(this.host);
}
// check request.status // check request.status
// TODO: throw an error here! it cannot silently fail!!! // TODO: throw an error here! it cannot silently fail!!!
@ -54,7 +61,12 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
}; };
request.open('POST', this.host, true); request.open('POST', this.host, true);
request.send(JSON.stringify(payload));
try {
request.send(JSON.stringify(payload));
} catch(error) {
callback(errors.InvalidConnection(this.host));
}
}; };
module.exports = HttpProvider; module.exports = HttpProvider;

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

@ -66,7 +66,7 @@ Method.prototype.extractCallback = function (args) {
*/ */
Method.prototype.validateArgs = function (args) { Method.prototype.validateArgs = function (args) {
if (args.length !== this.params) { if (args.length !== this.params) {
throw errors.InvalidNumberOfParams; throw errors.InvalidNumberOfParams();
} }
}; };

6
libjsqrc/ethereumjs/lib/web3/requestmanager.js

@ -65,7 +65,7 @@ RequestManager.getInstance = function () {
*/ */
RequestManager.prototype.send = function (data) { RequestManager.prototype.send = function (data) {
if (!this.provider) { if (!this.provider) {
console.error(errors.InvalidProvider); console.error(errors.InvalidProvider());
return null; return null;
} }
@ -88,7 +88,7 @@ RequestManager.prototype.send = function (data) {
*/ */
RequestManager.prototype.sendAsync = function (data, callback) { RequestManager.prototype.sendAsync = function (data, callback) {
if (!this.provider) { if (!this.provider) {
return callback(errors.InvalidProvider); return callback(errors.InvalidProvider());
} }
var payload = Jsonrpc.getInstance().toPayload(data.method, data.params); var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);
@ -179,7 +179,7 @@ RequestManager.prototype.poll = function () {
} }
if (!this.provider) { if (!this.provider) {
console.error(errors.InvalidProvider); console.error(errors.InvalidProvider());
return; return;
} }

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

@ -27,7 +27,7 @@ var post = new Method({
name: 'post', name: 'post',
call: 'shh_post', call: 'shh_post',
params: 1, params: 1,
inputFormatter: formatters.inputPostFormatter inputFormatter: [formatters.inputPostFormatter]
}); });
var newIdentity = new Method({ var newIdentity = new Method({

42
libjsqrc/ethereumjs/lib/web3/signature.js

@ -1,42 +0,0 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file signature.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var web3 = require('../web3');
var c = require('../utils/config');
/// @param function name for which we want to get signature
/// @returns signature of function with given name
var functionSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);
};
/// @param event name for which we want to get signature
/// @returns signature of event with given name
var eventSignatureFromAscii = function (name) {
return web3.sha3(web3.fromAscii(name));
};
module.exports = {
functionSignatureFromAscii: functionSignatureFromAscii,
eventSignatureFromAscii: eventSignatureFromAscii
};

2
libjsqrc/ethereumjs/package-init.js

@ -1,7 +1,7 @@
/* jshint ignore:start */ /* jshint ignore:start */
if(typeof web3 === 'undefined') { if(typeof web3 === 'undefined') {
web3 = require('ethereum.js'); web3 = require('web3');
BigNumber = require('bignumber.js'); BigNumber = require('bignumber.js');
} }

7
libjsqrc/ethereumjs/package.js

@ -1,7 +1,7 @@
/* jshint ignore:start */ /* jshint ignore:start */
Package.describe({ Package.describe({
name: 'ethereum:js', name: 'ethereum:web3',
version: '0.2.6', version: '0.3.3',
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.
@ -14,10 +14,9 @@ Package.onUse(function(api) {
// api.use('3stack:bignumber@2.0.0', 'client'); // api.use('3stack:bignumber@2.0.0', 'client');
// api.export('BigNumber', 'client');
api.export(['web3', 'BigNumber'], 'client'); api.export(['web3', 'BigNumber'], 'client');
api.addFiles('dist/ethereum.js', 'client'); api.addFiles('dist/web3.js', 'client');
api.addFiles('package-init.js', 'client'); api.addFiles('package-init.js', 'client');
}); });

4
libjsqrc/ethereumjs/package.json

@ -1,14 +1,14 @@
{ {
"name": "web3", "name": "web3",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.2.6", "version": "0.3.3",
"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": {
"lib": "./lib" "lib": "./lib"
}, },
"dependencies": { "dependencies": {
"bignumber.js": ">=2.0.0", "bignumber.js": "debris/bignumber.js#master",
"xmlhttprequest": "*" "xmlhttprequest": "*"
}, },
"browser": { "browser": {

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

@ -469,10 +469,10 @@ describe('lib/solidity/abi', function () {
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
// then // then
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); assert.equal(parser.test(1), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); assert.equal(parser.test(2.125), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); assert.equal(parser.test(8.5), "0000000000000000000000000000000880000000000000000000000000000000");
assert.equal(parser.test([-1]), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000"); assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000");
}); });
@ -489,9 +489,9 @@ describe('lib/solidity/abi', function () {
var parser = abi.inputParser(d); var parser = abi.inputParser(d);
// then // then
assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); assert.equal(parser.test(1), "0000000000000000000000000000000100000000000000000000000000000000");
assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); assert.equal(parser.test(2.125), "0000000000000000000000000000000220000000000000000000000000000000");
assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); assert.equal(parser.test(8.5), "0000000000000000000000000000000880000000000000000000000000000000");
}); });

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

@ -35,13 +35,13 @@ describe('lib/solidity/abi', function() {
// then // then
assert.equal( assert.equal(
parser.test("0x" + parser.test(
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0], "68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
'hello' 'hello'
); );
assert.equal( assert.equal(
parser.test("0x" + parser.test(
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0], "776f726c64000000000000000000000000000000000000000000000000000000")[0],
'world' 'world'
@ -62,14 +62,14 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10); assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10), parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10) new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
); );
assert.equal( assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10), parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10) new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
); );
}); });
@ -87,14 +87,14 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10); assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10), parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10) new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
); );
assert.equal( assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10), parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10) new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
); );
}); });
@ -112,14 +112,14 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10); assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal( assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10), parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10) new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
); );
assert.equal( assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10), parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10) new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
); );
}); });
@ -137,10 +137,10 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10); assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1); assert.equal(parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16); assert.equal(parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
}); });
it('should parse output int256', function() { it('should parse output int256', function() {
@ -156,10 +156,10 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10); assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1); assert.equal(parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16); assert.equal(parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
}); });
it('should parse output int128', function() { it('should parse output int128', function() {
@ -175,10 +175,10 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10); assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1); assert.equal(parser.test("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16); assert.equal(parser.test("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
}); });
it('should parse output address', function() { it('should parse output address', function() {
@ -195,7 +195,7 @@ describe('lib/solidity/abi', function() {
// then // then
assert.equal( assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0], parser.test("000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x407d73d8a49eeb85d32cf465507dd71d507100c1" "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
); );
}); });
@ -213,8 +213,8 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], true); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], true);
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000000")[0], false); assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000000")[0], false);
}); });
@ -232,10 +232,10 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1); assert.equal(parser.test("0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125); assert.equal(parser.test("0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5); assert.equal(parser.test("0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000")[0], -1); assert.equal(parser.test("ffffffffffffffffffffffffffffffff00000000000000000000000000000000")[0], -1);
}); });
@ -252,9 +252,9 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1); assert.equal(parser.test("0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125); assert.equal(parser.test("0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5); assert.equal(parser.test("0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
}); });
@ -274,7 +274,7 @@ describe('lib/solidity/abi', function() {
// then // then
assert.equal( assert.equal(
parser.test("0x" + parser.test(
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" + "68656c6c6f000000000000000000000000000000000000000000000000000000" +
@ -282,7 +282,7 @@ describe('lib/solidity/abi', function() {
'hello' 'hello'
); );
assert.equal( assert.equal(
parser.test("0x" + parser.test(
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" + "68656c6c6f000000000000000000000000000000000000000000000000000000" +
@ -305,8 +305,8 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.helloworld("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.helloworld("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.helloworld['int']("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.helloworld['int']("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
}); });
@ -330,8 +330,8 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
//then //then
assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1); assert.equal(parser.test("00000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test2("0x" + assert.equal(parser.test2(
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0], "68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
"hello" "hello"
@ -351,13 +351,13 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x" + assert.equal(parser.test(
"0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][0], "0000000000000000000000000000000000000000000000000000000000000006")[0][0],
5 5
); );
assert.equal(parser.test("0x" + assert.equal(parser.test(
"0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][1], "0000000000000000000000000000000000000000000000000000000000000006")[0][1],
@ -366,7 +366,7 @@ describe('lib/solidity/abi', function() {
}); });
it('should parse 0x value', function () { it('should parse 0x0 value', function () {
// given // given
var d = clone(description); var d = clone(description);
@ -378,11 +378,11 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x")[0], 0); assert.equal(parser.test("0x0")[0], 0);
}); });
it('should parse 0x value', function () { it('should parse 0x0 value', function () {
// given // given
var d = clone(description); var d = clone(description);
@ -394,7 +394,7 @@ describe('lib/solidity/abi', function() {
var parser = abi.outputParser(d); var parser = abi.outputParser(d);
// then // then
assert.equal(parser.test("0x")[0], 0); assert.equal(parser.test("0x0")[0], 0);
}); });

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

@ -0,0 +1,68 @@
var chai = require('chai');
var assert = chai.assert;
var coder = require('../lib/solidity/coder');
var BigNumber = require('bignumber.js');
var bn = BigNumber;
describe('lib/solidity/coder', function () {
describe('decodeParam', function () {
var test = function (t) {
it('should turn ' + t.value + ' to ' + t.expected, function () {
assert.deepEqual(coder.decodeParam(t.type, t.value), t.expected);
});
};
test({ type: 'int', expected: new bn(1), value: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'int', expected: new bn(16), value: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ type: 'int', expected: new bn(-1), value: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ type: 'int256', expected: new bn(1), value: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'int256', expected: new bn(16), value: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ type: 'int256', expected: new bn(-1), value: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ type: 'bytes32', expected: 'gavofyork', value: '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'bytes', expected: 'gavofyork', value: '0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'int[]', expected: [new bn(3)], value: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int256[]', expected: [new bn(3)], value: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int[]', expected: [new bn(1), new bn(2), new bn(3)],
value: '0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'});
});
});
describe('lib/solidity/coder', function () {
describe('decodeParams', function () {
var test = function (t) {
it('should turn ' + t.values + ' to ' + t.expected, function () {
assert.deepEqual(coder.decodeParams(t.types, t.values), t.expected);
});
};
test({ types: ['int'], expected: [new bn(1)], values: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ types: ['bytes32', 'int'], expected: ['gavofyork', new bn(5)],
values: '6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000005'});
test({ types: ['int', 'bytes32'], expected: [new bn(5), 'gavofyork'],
values: '0000000000000000000000000000000000000000000000000000000000000005' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'});
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)]],
values: '0000000000000000000000000000000000000000000000000000000000000009' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000004' +
'6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000005' +
'0000000000000000000000000000000000000000000000000000000000000006' +
'0000000000000000000000000000000000000000000000000000000000000007'});
});
});

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

@ -0,0 +1,91 @@
var chai = require('chai');
var assert = chai.assert;
var coder = require('../lib/solidity/coder');
describe('lib/solidity/coder', function () {
describe('encodeParam', function () {
var test = function (t) {
it('should turn ' + t.value + ' to ' + t.expected, function () {
assert.equal(coder.encodeParam(t.type, t.value), t.expected);
});
};
test({ type: 'int', value: 1, expected: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'int', value: 16, expected: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ type: 'int', value: -1, expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ type: 'int256', value: 1, expected: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ type: 'int256', value: 16, expected: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ type: 'int256', value: -1, expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ type: 'bytes32', value: 'gavofyork', expected: '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'bytes', value: 'gavofyork', expected: '0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ type: 'int[]', value: [3], expected: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int256[]', value: [3], expected: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ type: 'int[]', value: [1,2,3], expected: '0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'});
});
});
describe('lib/solidity/coder', function () {
describe('encodeParams', function () {
var test = function (t) {
it('should turn ' + t.values + ' to ' + t.expected, function () {
assert.equal(coder.encodeParams(t.types, t.values), t.expected);
});
};
test({ types: ['int'], values: [1], expected: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ types: ['int'], values: [16], expected: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ types: ['int'], values: [-1], expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ types: ['int256'], values: [1], expected: '0000000000000000000000000000000000000000000000000000000000000001'});
test({ types: ['int256'], values: [16], expected: '0000000000000000000000000000000000000000000000000000000000000010'});
test({ types: ['int256'], values: [-1], expected: 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'});
test({ types: ['bytes32'], values: ['gavofyork'], expected: '6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['bytes'], values: ['gavofyork'], expected: '0000000000000000000000000000000000000000000000000000000000000009' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['int[]'], values: [[3]], expected: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['int256[]'], values: [[3]], expected: '0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['int256[]'], values: [[1,2,3]], expected: '0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003'});
test({ types: ['bytes32', 'int'], values: ['gavofyork', 5],
expected: '6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000005'});
test({ types: ['int', 'bytes32'], values: [5, 'gavofyork'],
expected: '0000000000000000000000000000000000000000000000000000000000000005' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['bytes', 'int'], values: ['gavofyork', 5],
expected: '0000000000000000000000000000000000000000000000000000000000000009' +
'0000000000000000000000000000000000000000000000000000000000000005' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['int', 'bytes'], values: [5, 'gavofyork'],
expected: '0000000000000000000000000000000000000000000000000000000000000009' +
'0000000000000000000000000000000000000000000000000000000000000005' +
'6761766f66796f726b0000000000000000000000000000000000000000000000'});
test({ types: ['int', 'bytes', 'int', 'int', 'int', 'int[]'], values: [1, 'gavofyork', 2, 3, 4, [5, 6, 7]],
expected: '0000000000000000000000000000000000000000000000000000000000000009' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000002' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'0000000000000000000000000000000000000000000000000000000000000004' +
'6761766f66796f726b0000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000005' +
'0000000000000000000000000000000000000000000000000000000000000006' +
'0000000000000000000000000000000000000000000000000000000000000007'});
});
});

147
libjsqrc/ethereumjs/test/contract.js

@ -2,7 +2,9 @@ var chai = require('chai');
var assert = chai.assert; var assert = chai.assert;
var web3 = require('../index'); var web3 = require('../index');
var FakeHttpProvider = require('./helpers/FakeHttpProvider'); var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var FakeHttpProvider2 = require('./helpers/FakeHttpProvider2');
var utils = require('../lib/utils/utils'); var utils = require('../lib/utils/utils');
var BigNumber = require('bignumber.js');
var desc = [{ var desc = [{
"name": "balance(address)", "name": "balance(address)",
@ -27,6 +29,18 @@ var desc = [{
"type": "uint256" "type": "uint256"
}], }],
"outputs": [] "outputs": []
}, {
"name": "testArr(int[])",
"type": "function",
"inputs": [{
"name": "value",
"type": "int[]"
}],
"constant": true,
"outputs": [{
"name": "d",
"type": "int"
}]
}, { }, {
"name":"Changed", "name":"Changed",
"type":"event", "type":"event",
@ -63,11 +77,27 @@ describe('web3.eth.contract', function () {
assert.deepEqual(payload.params[0], { assert.deepEqual(payload.params[0], {
topics: [ topics: [
sha3, sha3,
'0x1234567890123456789012345678901234567890' '0x0000000000000000000000001234567890123456789012345678901234567890',
null
], ],
address: '0x1234567890123456789012345678901234567890' address: '0x1234567890123456789012345678901234567890'
}); });
} else if (step === 2 && utils.isArray(payload)) { } else if (step === 2) {
step = 3;
provider.injectResult([{
address: address,
topics: [
sha3,
'0x0000000000000000000000001234567890123456789012345678901234567890',
'0x0000000000000000000000000000000000000000000000000000000000000001'
],
number: 2,
data: '0x0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000008'
}]);
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'eth_getFilterLogs');
} else if (step === 3 && utils.isArray(payload)) {
provider.injectBatchResults([[{ provider.injectBatchResults([[{
address: address, address: address,
topics: [ topics: [
@ -89,12 +119,16 @@ describe('web3.eth.contract', function () {
var Contract = web3.eth.contract(desc); var Contract = web3.eth.contract(desc);
var contract = new Contract(address); var contract = new Contract(address);
var res = 0;
contract.Changed({from: address}).watch(function(err, result) { contract.Changed({from: address}).watch(function(err, result) {
assert.equal(result.args.from, address); assert.equal(result.args.from, address);
assert.equal(result.args.amount, 1); assert.equal(result.args.amount, 1);
assert.equal(result.args.t1, 1); assert.equal(result.args.t1, 1);
assert.equal(result.args.t2, 8); assert.equal(result.args.t2, 8);
done(); res++;
if (res === 2) {
done();
}
}); });
}); });
@ -187,7 +221,40 @@ describe('web3.eth.contract', function () {
var Contract = web3.eth.contract(desc); var Contract = web3.eth.contract(desc);
var contract = new Contract(address); var contract = new Contract(address);
contract.call({from: address, gas: 50000}).balance(address); contract.balance(address, {from: address, gas: 50000});
});
it('should explicitly make a call with optional params', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
var sha3 = '0x5131231231231231231231';
var address = '0x1234567890123456789012345678901234567890';
provider.injectResult(sha3);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'web3_sha3');
assert.equal(payload.params[0], web3.fromAscii('balance(address)'));
} else if (step === 1) {
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) + '0000000000000000000000001234567890123456789012345678901234567890',
to: address,
from: address,
gas: '0xc350'
}, 'latest']);
}
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
contract.balance.call(address, {from: address, gas: 50000});
}); });
@ -223,7 +290,77 @@ describe('web3.eth.contract', function () {
var Contract = web3.eth.contract(desc); var Contract = web3.eth.contract(desc);
var contract = new Contract(address); var contract = new Contract(address);
contract.sendTransaction({from: address, gas: 50000, gasPrice: 3000, value: 10000}).send(address, 17); contract.send(address, 17, {from: address, gas: 50000, gasPrice: 3000, value: 10000});
});
it('should explicitly sendTransaction with optional params', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
var sha3 = '0x5131231231231231231231';
var address = '0x1234567890123456789012345678901234567890';
provider.injectResult(sha3);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'web3_sha3');
assert.equal(payload.params[0], web3.fromAscii('send(address,uint256)'));
} else if (step === 1) {
assert.equal(payload.method, 'eth_sendTransaction');
assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) +
'0000000000000000000000001234567890123456789012345678901234567890' +
'0000000000000000000000000000000000000000000000000000000000000011' ,
to: address,
from: address,
gas: '0xc350',
gasPrice: '0xbb8',
value: '0x2710'
}]);
}
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
contract.send.sendTransaction(address, 17, {from: address, gas: 50000, gasPrice: 3000, value: 10000});
});
it('should call testArr method and properly parse result', function () {
var provider = new FakeHttpProvider2();
web3.setProvider(provider);
web3.reset();
var sha3 = '0x5131231231231231231231';
var address = '0x1234567890123456789012345678901234567890';
provider.injectResultList([{
result: sha3
}, {
result: '0x0000000000000000000000000000000000000000000000000000000000000005'
}]);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 1) { // getting sha3 is first
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000003',
to: address
},
'latest'
]);
}
step++;
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
var result = contract.testArr([3]);
assert.deepEqual(new BigNumber(5), result);
}); });
}); });
}); });

180
libjsqrc/ethereumjs/test/event.decode.js

@ -0,0 +1,180 @@
var chai = require('chai');
var assert = chai.assert;
var BigNumber = require('bignumber.js');
var SolidityEvent = require('../lib/web3/event');
var name = 'event1';
var address = '0x1234567890123456789012345678901234567890';
var tests = [{
abi: {
name: name,
inputs: []
},
data: {
logIndex: '0x1',
transactionIndex: '0x10',
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: '0x1'
},
expected: {
event: name,
args: {},
logIndex: 1,
transactionIndex: 16,
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: 1
}
}, {
abi: {
name: name,
inputs: [{
name: 'a',
type: 'int',
indexed: false
}]
},
data: {
logIndex: '0x1',
transactionIndex: '0x10',
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: '0x1',
data: '0x0000000000000000000000000000000000000000000000000000000000000001'
},
expected: {
event: name,
args: {
a: new BigNumber(1)
},
logIndex: 1,
transactionIndex: 16,
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: 1
}
}, {
abi: {
name: name,
inputs: [{
name: 'a',
type: 'int',
indexed: false
}, {
name: 'b',
type: 'int',
indexed: true
}, {
name: 'c',
type: 'int',
indexed: false
}, {
name: 'd',
type: 'int',
indexed: true
}]
},
data: {
logIndex: '0x1',
transactionIndex: '0x10',
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: '0x1',
data: '0x' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000004',
topics: [
address,
'0x000000000000000000000000000000000000000000000000000000000000000a',
'0x0000000000000000000000000000000000000000000000000000000000000010'
]
},
expected: {
event: name,
args: {
a: new BigNumber(1),
b: new BigNumber(10),
c: new BigNumber(4),
d: new BigNumber(16)
},
logIndex: 1,
transactionIndex: 16,
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: 1
}
}, {
abi: {
name: name,
anonymous: true,
inputs: [{
name: 'a',
type: 'int',
indexed: false
}, {
name: 'b',
type: 'int',
indexed: true
}, {
name: 'c',
type: 'int',
indexed: false
}, {
name: 'd',
type: 'int',
indexed: true
}]
},
data: {
logIndex: '0x1',
transactionIndex: '0x10',
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: '0x1',
data: '0x' +
'0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000004',
topics: [
'0x000000000000000000000000000000000000000000000000000000000000000a',
'0x0000000000000000000000000000000000000000000000000000000000000010'
]
},
expected: {
event: name,
args: {
a: new BigNumber(1),
b: new BigNumber(10),
c: new BigNumber(4),
d: new BigNumber(16)
},
logIndex: 1,
transactionIndex: 16,
transactionHash: '0x1234567890',
address: address,
blockHash: '0x1234567890',
blockNumber: 1
}
}];
describe('lib/web3/event', function () {
describe('decode', function () {
tests.forEach(function (test, index) {
it('test no: ' + index, function () {
var event = new SolidityEvent(test.abi, address);
var result = event.decode(test.data);
assert.deepEqual(result, test.expected);
});
});
});
});

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

@ -0,0 +1,206 @@
var chai = require('chai');
var assert = chai.assert;
var SolidityEvent = require('../lib/web3/event');
var address = '0x1234567890123456789012345678901234567890';
var signature = '0xffff';
var tests = [{
abi: {
name: 'event1',
inputs: []
},
indexed: {},
options: {},
expected: {
address: address,
topics: [
signature
]
}
}, {
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}]
},
indexed: {
a: 16
},
options: {},
expected: {
address: address,
topics: [
signature,
'0x0000000000000000000000000000000000000000000000000000000000000010'
]
}
},{
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}, {
type: 'int',
name: 'b',
indexed: true
}, {
type: 'int',
name: 'c',
indexed: false
}, {
type: 'int',
name: 'd',
indexed: true
}]
},
indexed: {
b: 4
},
options: {},
expected: {
address: address,
topics: [
signature, // signature
null, // a
'0x0000000000000000000000000000000000000000000000000000000000000004', // b
null // d
]
}
}, {
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}, {
type: 'int',
name: 'b',
indexed: true
}]
},
indexed: {
a: [16, 1],
b: 2
},
options: {},
expected: {
address: address,
topics: [
signature,
['0x0000000000000000000000000000000000000000000000000000000000000010', '0x0000000000000000000000000000000000000000000000000000000000000001'],
'0x0000000000000000000000000000000000000000000000000000000000000002'
]
}
}, {
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}]
},
indexed: {
a: null
},
options: {},
expected: {
address: address,
topics: [
signature,
null
]
}
}, {
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}]
},
indexed: {
a: 1
},
options: {
fromBlock: 4,
toBlock: 10
},
expected: {
address: address,
fromBlock: '0x4',
toBlock: '0xa',
topics: [
signature,
'0x0000000000000000000000000000000000000000000000000000000000000001'
]
}
}, {
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}],
anonymous: true
},
indexed: {
a: 1
},
options: {},
expected: {
topics: [
'0x0000000000000000000000000000000000000000000000000000000000000001'
]
}
}, {
abi: {
name: 'event1',
inputs: [{
type: 'int',
name: 'a',
indexed: true
}, {
type: 'int',
name: 'b',
indexed: true
}],
anonymous: true
},
indexed: {
b: 1
},
options: {},
expected: {
topics: [
null,
'0x0000000000000000000000000000000000000000000000000000000000000001'
]
}
}];
describe('lib/web3/event', function () {
describe('encode', function () {
tests.forEach(function (test, index) {
it('test no: ' + index, function () {
var event = new SolidityEvent(test.abi, address);
event.signature = function () { // inject signature
return signature.slice(2);
};
var result = event.encode(test.indexed, test.options);
assert.deepEqual(result, test.expected);
});
});
});
});

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

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

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

Loading…
Cancel
Save