const& _f)
+unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f)
{
auto ret = ethereum()->installWatch(_tf);
m_handlers[ret] = _f;
@@ -265,10 +266,10 @@ void Main::uninstallWatch(unsigned _w)
void Main::installWatches()
{
- installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installNameRegWatch(); });
- installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installCurrenciesWatch(); });
- installWatch(dev::eth::PendingChangedFilter, [=](){ onNewPending(); });
- installWatch(dev::eth::ChainChangedFilter, [=](){ onNewBlock(); });
+ installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); });
+ installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); });
+ installWatch(dev::eth::PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); });
+ installWatch(dev::eth::ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); });
}
Address Main::getNameReg() const
@@ -284,13 +285,13 @@ Address Main::getCurrencies() const
void Main::installNameRegWatch()
{
uninstallWatch(m_nameRegFilter);
- m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](){ onNameRegChange(); });
+ m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](LocalisedLogEntries const&){ onNameRegChange(); });
}
void Main::installCurrenciesWatch()
{
uninstallWatch(m_currenciesFilter);
- m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](){ onCurrenciesChange(); });
+ m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](LocalisedLogEntries const&){ onCurrenciesChange(); });
}
void Main::installBalancesWatch()
@@ -308,7 +309,7 @@ void Main::installBalancesWatch()
tf.address(c).topic(h256(i.address(), h256::AlignRight));
uninstallWatch(m_balancesFilter);
- m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); });
+ m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); });
}
void Main::onNameRegChange()
@@ -644,6 +645,7 @@ void Main::writeSettings()
s.setValue("url", ui->urlEdit->text());
s.setValue("privateChain", m_privateChain);
s.setValue("verbosity", ui->verbosity->value());
+ s.setValue("jitvm", ui->jitvm->isChecked());
bytes d = m_webThree->saveNodes();
if (d.size())
@@ -718,6 +720,7 @@ void Main::readSettings(bool _skipGeometry)
m_privateChain = s.value("privateChain", "").toString();
ui->usePrivate->setChecked(m_privateChain.size());
ui->verbosity->setValue(s.value("verbosity", 1).toInt());
+ ui->jitvm->setChecked(s.value("jitvm", true).toBool());
ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html
on_urlEdit_returnPressed();
@@ -817,6 +820,12 @@ void Main::on_usePrivate_triggered()
on_killBlockchain_triggered();
}
+void Main::on_jitvm_triggered()
+{
+ bool jit = ui->jitvm->isChecked();
+ VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
+}
+
void Main::on_urlEdit_returnPressed()
{
QString s = ui->urlEdit->text();
@@ -1162,8 +1171,11 @@ void Main::timerEvent(QTimerEvent*)
m_qweb->poll();
for (auto const& i: m_handlers)
- if (ethereum()->checkWatch(i.first))
- i.second();
+ {
+ auto ls = ethereum()->checkWatch(i.first);
+ if (ls.size())
+ i.second(ls);
+ }
}
string Main::renderDiff(dev::eth::StateDiff const& _d) const
@@ -1265,7 +1277,7 @@ void Main::on_transactionQueue_currentItemChanged()
auto r = receipt.rlp();
s << "Receipt: " << toString(RLP(r)) << "
";
s << "Receipt-Hex: " << toHex(receipt.rlp()) << "
";
- s << renderDiff(ethereum()->diff(i, -1));
+ s << renderDiff(ethereum()->diff(i, 0));
// s << "Pre: " << fs.rootHash() << "
";
// s << "Post: " << ts.rootHash() << "";
}
@@ -1802,8 +1814,6 @@ void Main::on_net_triggered()
web3()->setClientVersion(n);
if (ui->net->isChecked())
{
- // TODO: alter network stuff?
- //ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0);
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index bb79e59ef..18cf5113b 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -34,7 +34,7 @@
#include
#include
#include
-#include
+#include
#include
namespace Ui {
@@ -66,6 +66,8 @@ struct WorldState
std::vector levels;
};
+using WatchHandler = std::function;
+
class Main : public QMainWindow
{
Q_OBJECT
@@ -156,6 +158,7 @@ private slots:
void on_importKeyFile_triggered();
void on_post_clicked();
void on_newIdentity_triggered();
+ void on_jitvm_triggered();
void refreshWhisper();
void refreshBlockChain();
@@ -194,8 +197,8 @@ private:
dev::u256 value() const;
dev::u256 gasPrice() const;
- unsigned installWatch(dev::eth::LogFilter const& _tf, std::function const& _f);
- unsigned installWatch(dev::h256 _tf, std::function const& _f);
+ unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f);
+ unsigned installWatch(dev::h256 _tf, WatchHandler const& _f);
void uninstallWatch(unsigned _w);
void keysChanged();
@@ -228,7 +231,7 @@ private:
std::unique_ptr m_webThree;
- std::map> m_handlers;
+ std::map m_handlers;
unsigned m_nameRegFilter = (unsigned)-1;
unsigned m_currenciesFilter = (unsigned)-1;
unsigned m_balancesFilter = (unsigned)-1;
diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake
old mode 100644
new mode 100755
index 24252cc0b..12adc1d02
--- a/cmake/EthCompilerSettings.cmake
+++ b/cmake/EthCompilerSettings.cmake
@@ -28,8 +28,17 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# specify Exception Handling Model in msvc
- set(CMAKE_C_FLAGS "/EHsc")
- set(CMAKE_CXX_FLAGS "/EHsc")
+ # disable unknown pragma warning (4068)
+ # disable unsafe function warning (4996)
+ # disable decorated name length exceeded, name was truncated (4503)
+ # disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests)
+ # declare Windows XP requirement
+ add_compile_options(/EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501)
+ # disable empty object file warning
+ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
+ # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification
+ # warning LNK4099: pdb was not found with lib
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075")
# windows likes static
set(ETH_STATIC 1)
diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake
index 136c86799..9b00a182f 100644
--- a/cmake/EthDependencies.cmake
+++ b/cmake/EthDependencies.cmake
@@ -113,6 +113,15 @@ if (NOT HEADLESS)
message(" - macdeployqt path: ${MACDEPLOYQT_APP}")
endif()
+# TODO check node && npm version
+ find_program(ETH_NODE node)
+ string(REGEX REPLACE "node" "" ETH_NODE_DIRECTORY ${ETH_NODE})
+ message(" - nodejs location : ${ETH_NODE}")
+
+ find_program(ETH_NPM npm)
+ string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM})
+ message(" - npm location : ${ETH_NPM}")
+
endif() #HEADLESS
# use multithreaded boost libraries, with -mt suffix
diff --git a/eth/main.cpp b/eth/main.cpp
index a0a605193..515197ddc 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -180,6 +180,12 @@ void sighandler(int)
g_exit = true;
}
+enum class NodeMode
+{
+ PeerServer,
+ Full
+};
+
int main(int argc, char** argv)
{
unsigned short listenPort = 30303;
@@ -264,13 +270,14 @@ int main(int argc, char** argv)
mining = ~(unsigned)0;
else if (isFalse(m))
mining = 0;
- else if (int i = stoi(m))
- mining = i;
else
- {
- cerr << "Unknown -m/--mining option: " << m << endl;
- return -1;
- }
+ try {
+ mining = stoi(m);
+ }
+ catch (...) {
+ cerr << "Unknown -m/--mining option: " << m << endl;
+ return -1;
+ }
}
else if (arg == "-b" || arg == "--bootstrap")
bootstrap = true;
diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt
index 222fa5b72..18601b921 100644
--- a/evmjit/CMakeLists.txt
+++ b/evmjit/CMakeLists.txt
@@ -9,6 +9,7 @@ if(LLVM_DIR) # local LLVM build
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
+ add_definitions(${LLVM_DEFINITIONS})
# TODO: bitwriter is needed only for evmcc
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter)
else()
@@ -19,11 +20,9 @@ else()
set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm")
endif()
-add_definitions(-D_SCL_SECURE_NO_WARNINGS) # LLVM needs it on Windows
-
# Boost
find_package(Boost REQUIRED)
add_subdirectory(libevmjit)
add_subdirectory(libevmjit-cpp)
-add_subdirectory(evmcc)
\ No newline at end of file
+add_subdirectory(evmcc)
diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp
index 10d3e3449..b5319bda7 100644
--- a/evmjit/libevmjit/Arith256.cpp
+++ b/evmjit/libevmjit/Arith256.cpp
@@ -178,7 +178,10 @@ extern "C"
auto arg1 = llvm2eth(*_arg1);
auto arg2 = llvm2eth(*_arg2);
auto arg3 = llvm2eth(*_arg3);
- *o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3));
+ if (arg3 != 0)
+ *o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3));
+ else
+ *o_result = {};
}
EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
@@ -186,7 +189,10 @@ extern "C"
auto arg1 = llvm2eth(*_arg1);
auto arg2 = llvm2eth(*_arg2);
auto arg3 = llvm2eth(*_arg3);
- *o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3));
+ if (arg3 != 0)
+ *o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3));
+ else
+ *o_result = {};
}
}
diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp
index dda0fbc36..5868c0f43 100644
--- a/evmjit/libevmjit/BasicBlock.cpp
+++ b/evmjit/libevmjit/BasicBlock.cpp
@@ -168,16 +168,13 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
if (val == nullptr)
continue;
- assert(llvm::isa(val));
llvm::PHINode* phi = llvm::cast(val);
- if (! phi->use_empty())
- {
- // Insert call to get() just before the PHI node and replace
- // the uses of PHI with the uses of this new instruction.
- m_builder.SetInsertPoint(phi);
- auto newVal = _evmStack.get(idx);
- phi->replaceAllUsesWith(newVal);
- }
+ // Insert call to get() just before the PHI node and replace
+ // the uses of PHI with the uses of this new instruction.
+ m_builder.SetInsertPoint(phi);
+ auto newVal = _evmStack.get(idx); // OPT: Value may be never user but we need to check stack heigth
+ // It is probably a good idea to keep heigth as a local variable accesible by LLVM directly
+ phi->replaceAllUsesWith(newVal);
phi->eraseFromParent();
}
diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp
index 3ac9f4a73..0b725bc24 100644
--- a/evmjit/libevmjit/Cache.cpp
+++ b/evmjit/libevmjit/Cache.cpp
@@ -45,8 +45,7 @@ std::unique_ptr Cache::getObject(std::string const& id)
{
auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext()));
auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false);
- auto func = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
- (void)func;
+ llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
}
return nullptr;
}
@@ -69,9 +68,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory
cacheFile << _object->getBuffer();
}
-llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
+llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*)
{
- (void)_module;
auto o = lastObject;
lastObject = nullptr;
return o;
diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp
index b92a07bf8..f0767d9e0 100644
--- a/evmjit/libevmjit/Ext.cpp
+++ b/evmjit/libevmjit/Ext.cpp
@@ -22,11 +22,9 @@ namespace jit
Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan):
RuntimeHelper(_runtimeManager),
- m_memoryMan(_memoryMan)
- // TODO: fix: either initialise properly or don't specify in constructor.
- /*,
- m_funcs{},
- m_argAllocas{}*/
+ m_memoryMan(_memoryMan),
+ m_funcs({}), // The only std::array initialization that works in both Visual Studio & GCC
+ m_argAllocas({})
{
m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size");
}
diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp
index 84266111e..4aa6a738d 100644
--- a/evmjit/libevmjit/GasMeter.cpp
+++ b/evmjit/libevmjit/GasMeter.cpp
@@ -173,10 +173,12 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength)
assert(m_blockCost > 0); // SHA3 instruction is already counted
// TODO: This round ups to 32 happens in many places
- // FIXME: Overflow possible but Memory::require() also called. Probably 64-bit arith can be used.
+ // FIXME: 64-bit arith used, but not verified
static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter");
- auto words = m_builder.CreateUDiv(m_builder.CreateAdd(_dataLength, Constant::get(31)), Constant::get(32));
- auto cost = m_builder.CreateNUWMul(Constant::get(c_sha3WordGas), words);
+ auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision);
+ auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32));
+ auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64);
+ auto cost = getBuilder().CreateZExt(cost64, Type::Word);
count(cost);
}
diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp
index 2522e8ace..911dc469d 100644
--- a/evmjit/libevmjit/Runtime.cpp
+++ b/evmjit/libevmjit/Runtime.cpp
@@ -24,8 +24,10 @@ bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy
auto offset = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset]));
auto size = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize]));
- assert(offset + size <= m_memory.size());
- // TODO: Handle invalid data access by returning empty ref
+ assert(offset + size <= m_memory.size() || size == 0);
+ if (offset + size > m_memory.size())
+ return {};
+
auto dataBeg = m_memory.begin() + offset;
return {dataBeg, dataBeg + size};
}
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index 0967596e2..9fefea45a 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -80,6 +80,9 @@ using StringMap = std::map;
using u256Map = std::map;
using HexMap = std::map;
+// String types.
+using strings = std::vector;
+
// Fixed-length string types.
using string32 = std::array;
diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h
index 5d03c195f..061f181b3 100644
--- a/libdevcore/Exceptions.h
+++ b/libdevcore/Exceptions.h
@@ -22,6 +22,7 @@
#pragma once
#include
+#include
#include
#include
#include "CommonData.h"
@@ -40,6 +41,7 @@ struct NoNetworking: virtual Exception {};
struct NoUPnPDevice: virtual Exception {};
struct RootNotFound: virtual Exception {};
struct FileError: virtual Exception {};
+struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): m_f("Interface " + _f + " not supported.") {} virtual const char* what() const noexcept { return m_f.c_str(); } private: std::string m_f; };
// error information to be added to exceptions
typedef boost::error_info errinfo_invalidSymbol;
diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp
index f4803bd52..adcf70b61 100644
--- a/libdevcrypto/Common.cpp
+++ b/libdevcrypto/Common.cpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include "SHA3.h"
#include "FileSystem.h"
#include "CryptoPP.h"
@@ -139,7 +140,7 @@ h256 Nonce::get(bool _commit)
static h256 s_seed;
static string s_seedFile(getDataDir() + "/seed");
static mutex s_x;
- lock_guard l(s_x);
+ Guard l(s_x);
if (!s_seed)
{
static Nonce s_nonce;
diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp
index d73e3fa43..acd59184f 100644
--- a/libdevcrypto/CryptoPP.cpp
+++ b/libdevcrypto/CryptoPP.cpp
@@ -20,6 +20,7 @@
*/
#include "CryptoPP.h"
+#include
using namespace std;
using namespace dev;
@@ -40,7 +41,7 @@ void Secp256k1::encrypt(Public const& _k, bytes& io_cipher)
ciphertext.resize(e.CiphertextLength(plen));
{
- lock_guard l(x_rng);
+ Guard l(x_rng);
e.Encrypt(m_rng, io_cipher.data(), plen, ciphertext.data());
}
@@ -65,7 +66,7 @@ void Secp256k1::decrypt(Secret const& _k, bytes& io_text)
DecodingResult r;
{
- lock_guard l(x_rng);
+ Guard l(x_rng);
r = d.Decrypt(m_rng, io_text.data(), clen, plain.data());
}
@@ -99,7 +100,7 @@ Signature Secp256k1::sign(Secret const& _key, h256 const& _hash)
ECP::Point rp;
Integer r;
{
- lock_guard l(x_params);
+ Guard l(x_params);
rp = m_params.ExponentiateBase(k);
r = m_params.ConvertElementToInteger(rp);
}
@@ -149,7 +150,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message)
ECP::Element x;
{
- lock_guard l(x_curve);
+ Guard l(x_curve);
m_curve.DecodePoint(x, encodedpoint, 33);
if (!m_curve.VerifyPoint(x))
return recovered;
@@ -158,7 +159,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message)
// if (_signature[64] & 2)
// {
// r += m_q;
-// lock_guard l(x_params);
+// Guard l(x_params);
// if (r >= m_params.GetMaxExponent())
// return recovered;
// }
@@ -171,7 +172,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message)
ECP::Point p;
byte recoveredbytes[65];
{
- lock_guard l(x_curve);
+ Guard l(x_curve);
// todo: make generator member
p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator());
m_curve.EncodePoint(recoveredbytes, p, false);
@@ -210,7 +211,7 @@ void Secp256k1::exportPublicKey(CryptoPP::DL_PublicKey_EC const&
bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true));
{
- lock_guard l(x_params);
+ Guard l(x_params);
m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false);
assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true));
}
@@ -223,7 +224,7 @@ void Secp256k1::exponentToPublic(Integer const& _e, Public& o_p)
CryptoPP::DL_PublicKey_EC pk;
{
- lock_guard l(x_params);
+ Guard l(x_params);
pk.Initialize(m_params, m_params.ExponentiateBase(_e));
}
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index a57faf546..41f0bcfbc 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -159,9 +159,10 @@ void Client::clearPending()
WriteGuard l(x_stateDB);
if (!m_postMine.pending().size())
return;
- for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
- appendFromNewPending(m_postMine.logBloom(i), changeds);
+// for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
+// appendFromNewPending(m_postMine.logBloom(i), changeds);
changeds.insert(PendingChangedFilter);
+ m_tq.clear();
m_postMine = m_preMine;
}
@@ -176,21 +177,31 @@ void Client::clearPending()
unsigned Client::installWatch(h256 _h)
{
- auto ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
- m_watches[ret] = ClientWatch(_h);
- cwatch << "+++" << ret << _h;
+ unsigned ret;
+ {
+ Guard l(m_filterLock);
+ ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0;
+ m_watches[ret] = ClientWatch(_h);
+ cwatch << "+++" << ret << _h;
+ }
+ auto ch = logs(ret);
+ if (ch.empty())
+ ch.push_back(InitialChange);
+ {
+ Guard l(m_filterLock);
+ swap(m_watches[ret].changes, ch);
+ }
return ret;
}
unsigned Client::installWatch(LogFilter const& _f)
{
- lock_guard l(m_filterLock);
-
h256 h = _f.sha3();
-
- if (!m_filters.count(h))
- m_filters.insert(make_pair(h, _f));
-
+ {
+ Guard l(m_filterLock);
+ if (!m_filters.count(h))
+ m_filters.insert(make_pair(h, _f));
+ }
return installWatch(h);
}
@@ -198,7 +209,7 @@ void Client::uninstallWatch(unsigned _i)
{
cwatch << "XXX" << _i;
- lock_guard l(m_filterLock);
+ Guard l(m_filterLock);
auto it = m_watches.find(_i);
if (it == m_watches.end())
@@ -214,33 +225,83 @@ void Client::uninstallWatch(unsigned _i)
void Client::noteChanged(h256Set const& _filters)
{
- lock_guard l(m_filterLock);
+ Guard l(m_filterLock);
+ // accrue all changes left in each filter into the watches.
for (auto& i: m_watches)
if (_filters.count(i.second.id))
{
// cwatch << "!!!" << i.first << i.second.id;
- i.second.changes++;
+ if (m_filters.count(i.second.id))
+ i.second.changes += m_filters.at(i.second.id).changes;
+ else
+ i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0));
}
+ // clear the filters now.
+ for (auto& i: m_filters)
+ i.second.changes.clear();
}
-void Client::appendFromNewPending(LogBloom _bloom, h256Set& o_changed) const
+LocalisedLogEntries Client::peekWatch(unsigned _watchId) const
{
- // TODO: more precise check on whether the txs match.
- lock_guard l(m_filterLock);
- for (pair const& i: m_filters)
- if ((unsigned)i.second.filter.latest() > m_bc.number() && i.second.filter.matches(_bloom))
- o_changed.insert(i.first);
+ Guard l(m_filterLock);
+
+ try {
+ return m_watches.at(_watchId).changes;
+ } catch (...) {}
+ return LocalisedLogEntries();
}
-void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const
+LocalisedLogEntries Client::checkWatch(unsigned _watchId)
+{
+ Guard l(m_filterLock);
+ LocalisedLogEntries ret;
+
+ try {
+ std::swap(ret, m_watches.at(_watchId).changes);
+ } catch (...) {}
+
+ return ret;
+}
+
+void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed)
+{
+ Guard l(m_filterLock);
+ for (pair& i: m_filters)
+ if ((unsigned)i.second.filter.latest() > m_bc.number())
+ {
+ // acceptable number.
+ auto m = i.second.filter.matches(_receipt);
+ if (m.size())
+ {
+ // filter catches them
+ for (LogEntry const& l: m)
+ i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1));
+ io_changed.insert(i.first);
+ }
+ }
+}
+
+void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed)
{
// TODO: more precise check on whether the txs match.
auto d = m_bc.info(_block);
+ auto br = m_bc.receipts(_block);
- lock_guard l(m_filterLock);
- for (pair const& i: m_filters)
+ Guard l(m_filterLock);
+ for (pair& i: m_filters)
if ((unsigned)i.second.filter.latest() >= d.number && (unsigned)i.second.filter.earliest() <= d.number && i.second.filter.matches(d.logBloom))
- o_changed.insert(i.first);
+ // acceptable number & looks like block may contain a matching log entry.
+ for (TransactionReceipt const& tr: br.receipts)
+ {
+ auto m = i.second.filter.matches(tr);
+ if (m.size())
+ {
+ // filter catches them
+ for (LogEntry const& l: m)
+ i.second.changes.push_back(LocalisedLogEntry(l, (unsigned)d.number));
+ io_changed.insert(i.first);
+ }
+ }
}
void Client::setForceMining(bool _enable)
@@ -467,10 +528,10 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ";
- h512s newPendingBlooms = m_postMine.sync(m_bc, m_tq);
- if (newPendingBlooms.size())
+ TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq);
+ if (newPendingReceipts.size())
{
- for (auto i: newPendingBlooms)
+ for (auto i: newPendingReceipts)
appendFromNewPending(i, changeds);
changeds.insert(PendingChangedFilter);
@@ -591,16 +652,16 @@ BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
return BlockInfo::fromHeader(b[2][_i].data());
}
-LogEntries Client::logs(LogFilter const& _f) const
+LocalisedLogEntries Client::logs(LogFilter const& _f) const
{
- LogEntries ret;
- unsigned begin = min(m_bc.number(), (unsigned)_f.latest());
- unsigned end = min(begin, (unsigned)_f.earliest());
+ LocalisedLogEntries ret;
+ unsigned begin = min(m_bc.number() + 1, (unsigned)_f.latest());
+ unsigned end = min(m_bc.number(), min(begin, (unsigned)_f.earliest()));
unsigned m = _f.max();
unsigned s = _f.skip();
// Handle pending transactions differently as they're not on the block chain.
- if (begin == m_bc.number())
+ if (begin > m_bc.number())
{
ReadGuard l(x_stateDB);
for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
@@ -614,9 +675,10 @@ LogEntries Client::logs(LogFilter const& _f) const
if (s)
s--;
else
- ret.insert(ret.begin(), le[j]);
+ ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin));
}
}
+ begin = m_bc.number();
}
#if ETH_DEBUG
@@ -648,7 +710,7 @@ LogEntries Client::logs(LogFilter const& _f) const
if (s)
s--;
else
- ret.insert(ret.begin(), le[j]);
+ ret.insert(ret.begin(), LocalisedLogEntry(le[j], n));
}
}
}
diff --git a/libethereum/Client.h b/libethereum/Client.h
index efe076dab..9d2396e46 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -57,12 +57,6 @@ enum ClientWorkState
Deleted
};
-enum class NodeMode
-{
- PeerServer,
- Full
-};
-
class VersionChecker
{
public:
@@ -84,18 +78,22 @@ struct InstalledFilter
LogFilter filter;
unsigned refCount = 1;
+ LocalisedLogEntries changes;
};
static const h256 PendingChangedFilter = u256(0);
static const h256 ChainChangedFilter = u256(1);
+static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes());
+static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0);
+
struct ClientWatch
{
ClientWatch() {}
explicit ClientWatch(h256 _id): id(_id) {}
h256 id;
- unsigned changes = 1;
+ LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange };
};
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; };
@@ -108,9 +106,9 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-"
#define cworkout dev::LogOutputStream()
template struct ABISerialiser {};
-template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { return _t.asBytes(); } };
+template struct ABISerialiser> { static bytes serialise(FixedHash 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 { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } };
-template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return h160(_t).asBytes(); } };
+template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return bytes(12, 0) + h160(_t).asBytes(); } };
template <> struct ABISerialiser { static bytes serialise(string32 const& _t) { return bytesConstRef((byte const*)_t.data(), 32).toBytes(); } };
inline bytes abiInAux() { return {}; }
@@ -125,9 +123,9 @@ template bytes abiIn(std::string _id, T const& ... _t)
}
template struct ABIDeserialiser {};
-template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret; io_t.cropped(0, N).populate(ret.ref()); return ret; } };
+template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } };
template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } };
-template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } };
+template <> struct ABIDeserialiser { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } };
template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } };
template T abiOut(bytes const& _data)
@@ -188,11 +186,11 @@ public:
virtual unsigned installWatch(LogFilter const& _filter);
virtual unsigned installWatch(h256 _filterId);
virtual void uninstallWatch(unsigned _watchId);
- virtual bool peekWatch(unsigned _watchId) const { std::lock_guard l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } }
- virtual bool checkWatch(unsigned _watchId) { std::lock_guard l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; }
+ virtual LocalisedLogEntries peekWatch(unsigned _watchId) const;
+ virtual LocalisedLogEntries checkWatch(unsigned _watchId);
- virtual LogEntries logs(unsigned _watchId) const { try { std::lock_guard l(m_filterLock); return logs(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return LogEntries(); } }
- virtual LogEntries logs(LogFilter const& _filter) const;
+ virtual LocalisedLogEntries logs(unsigned _watchId) const { try { Guard l(m_filterLock); return logs(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return LocalisedLogEntries(); } }
+ virtual LocalisedLogEntries logs(LogFilter const& _filter) const;
// [EXTRA API]:
@@ -292,11 +290,11 @@ private:
/// Collate the changed filters for the bloom filter of the given pending transaction.
/// Insert any filters that are activated into @a o_changed.
- void appendFromNewPending(LogBloom _pendingTransactionBloom, h256Set& o_changed) const;
+ void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed);
/// Collate the changed filters for the hash of the given block.
/// Insert any filters that are activated into @a o_changed.
- void appendFromNewBlock(h256 _blockHash, h256Set& o_changed) const;
+ void appendFromNewBlock(h256 const& _blockHash, h256Set& io_changed);
/// Record that the set of filters @a _filters have changed.
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
@@ -313,7 +311,7 @@ private:
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
- mutable boost::shared_mutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
+ mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
@@ -321,7 +319,7 @@ private:
std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector m_miners;
- mutable boost::shared_mutex x_miners;
+ mutable SharedMutex x_miners;
bool m_paranoia = false; ///< Should we be paranoid about our state?
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending?
diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp
index 0901766bf..95e1aadda 100644
--- a/libethereum/EthereumPeer.cpp
+++ b/libethereum/EthereumPeer.cpp
@@ -317,6 +317,8 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
disable("Blacklisted client version.");
else if (host()->isBanned(session()->id()))
disable("Peer banned for previous bad behaviour.");
+ else
+ transition(Asking::Nothing);
break;
}
case GetTransactionsPacket: break; // DEPRECATED.
diff --git a/libethereum/Interface.h b/libethereum/Interface.h
index 28ac26819..35cd59663 100644
--- a/libethereum/Interface.h
+++ b/libethereum/Interface.h
@@ -86,15 +86,15 @@ public:
// [LOGS API]
- virtual LogEntries logs(unsigned _watchId) const = 0;
- virtual LogEntries logs(LogFilter const& _filter) const = 0;
+ virtual LocalisedLogEntries logs(unsigned _watchId) const = 0;
+ virtual LocalisedLogEntries logs(LogFilter const& _filter) const = 0;
/// Install, uninstall and query watches.
virtual unsigned installWatch(LogFilter const& _filter) = 0;
virtual unsigned installWatch(h256 _filterId) = 0;
virtual void uninstallWatch(unsigned _watchId) = 0;
- virtual bool peekWatch(unsigned _watchId) const = 0;
- virtual bool checkWatch(unsigned _watchId) = 0;
+ virtual LocalisedLogEntries peekWatch(unsigned _watchId) const = 0;
+ virtual LocalisedLogEntries checkWatch(unsigned _watchId) = 0;
// [BLOCK QUERY API]
@@ -178,10 +178,9 @@ public:
Watch(Interface& _c, LogFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {}
~Watch() { if (m_c) m_c->uninstallWatch(m_id); }
- bool check() { return m_c ? m_c->checkWatch(m_id) : false; }
- bool peek() { return m_c ? m_c->peekWatch(m_id) : false; }
-// PastMessages messages() const { return m_c->messages(m_id); }
- LogEntries logs() const { return m_c->logs(m_id); }
+ LocalisedLogEntries check() { return m_c ? m_c->checkWatch(m_id) : LocalisedLogEntries(); }
+ LocalisedLogEntries peek() { return m_c ? m_c->peekWatch(m_id) : LocalisedLogEntries(); }
+ LocalisedLogEntries logs() const { return m_c->logs(m_id); }
private:
Interface* m_c = nullptr;
diff --git a/libethereum/LogFilter.cpp b/libethereum/LogFilter.cpp
index 81cb439ba..eca428cfa 100644
--- a/libethereum/LogFilter.cpp
+++ b/libethereum/LogFilter.cpp
@@ -68,14 +68,15 @@ bool LogFilter::matches(State const& _s, unsigned _i) const
LogEntries LogFilter::matches(TransactionReceipt const& _m) const
{
LogEntries ret;
- for (LogEntry const& e: _m.log())
- {
- if (!m_addresses.empty() && !m_addresses.count(e.address))
- continue;
- for (auto const& t: m_topics)
- if (!std::count(e.topics.begin(), e.topics.end(), t))
+ if (matches(_m.bloom()))
+ for (LogEntry const& e: _m.log())
+ {
+ if (!m_addresses.empty() && !m_addresses.count(e.address))
continue;
- ret.push_back(e);
- }
+ for (auto const& t: m_topics)
+ if (!std::count(e.topics.begin(), e.topics.end(), t))
+ continue;
+ ret.push_back(e);
+ }
return ret;
}
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index e0705859f..3c59bf415 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -412,10 +412,10 @@ bool State::cull(TransactionQueue& _tq) const
return ret;
}
-h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged)
+TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
// TRANSACTIONS
- h512s ret;
+ TransactionReceipts ret;
auto ts = _tq.transactions();
auto lh = getLastHashes(_bc);
@@ -432,7 +432,7 @@ h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transact
uncommitToMine();
// boost::timer t;
execute(lh, i.second);
- ret.push_back(m_receipts.back().bloom());
+ ret.push_back(m_receipts.back());
_tq.noteGood(i);
++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
diff --git a/libethereum/State.h b/libethereum/State.h
index 921c82bb9..e7e1bbfab 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -140,10 +140,10 @@ public:
// TODO: Cleaner interface.
/// Sync our transactions, killing those from the queue that we have and assimilating those that we don't.
- /// @returns a list of bloom filters one for each transaction placed from the queue into the state.
+ /// @returns a list of receipts one for each transaction placed from the queue into the state.
/// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue
/// changed and the pointer is non-null
- h512s sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
+ TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
/// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const;
diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp
index b6653fe39..31c5e278a 100644
--- a/libethereum/Utility.cpp
+++ b/libethereum/Utility.cpp
@@ -23,6 +23,7 @@
#include
#include
+#include
using namespace std;
using namespace dev;
using namespace dev::eth;
@@ -32,7 +33,7 @@ bytes dev::eth::parseData(string const& _args)
bytes m_data;
boost::smatch what;
- static const boost::regex r("(@|\\$)?\"([^\"]*)\"(\\s.*)?");
+ static const boost::regex r("(!|#|@|\\$)?\"([^\"]*)\"(\\s.*)?");
static const boost::regex d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?");
static const boost::regex h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?");
@@ -67,13 +68,15 @@ bytes dev::eth::parseData(string const& _args)
}
else if (boost::regex_match(s, what, r))
{
- for (auto i: (string)what[2])
- m_data.push_back((byte)i);
- if (what[1] != "$")
- for (int i = what[2].length(); i < 32; ++i)
- m_data.push_back(0);
+ bytes d = asBytes(what[2]);
+ if (what[1] == "!")
+ m_data += FixedHash<4>(sha3(d)).asBytes();
+ else if (what[1] == "#")
+ m_data += sha3(d).asBytes();
+ else if (what[1] == "$")
+ m_data += d + bytes{0};
else
- m_data.push_back(0);
+ m_data += d + bytes(32 - what[2].length() % 32, 0);
s = what[3];
}
else
diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h
index 84cfe0a94..13e8712b8 100644
--- a/libevm/ExtVMFace.h
+++ b/libevm/ExtVMFace.h
@@ -60,6 +60,16 @@ struct LogEntry
using LogEntries = std::vector;
+struct LocalisedLogEntry: public LogEntry
+{
+ LocalisedLogEntry() {}
+ LocalisedLogEntry(LogEntry const& _le, unsigned _number): LogEntry(_le), number(_number) {}
+
+ unsigned number = 0;
+};
+
+using LocalisedLogEntries = std::vector;
+
inline LogBloom bloom(LogEntries const& _logs)
{
LogBloom ret;
diff --git a/libevm/VM.cpp b/libevm/VM.cpp
index b8452e4f5..aa3caff44 100644
--- a/libevm/VM.cpp
+++ b/libevm/VM.cpp
@@ -31,3 +31,763 @@ void VM::reset(u256 _gas) noexcept
m_curPC = 0;
m_jumpDests.clear();
}
+
+bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps)
+{
+ auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; };
+
+ if (m_jumpDests.empty())
+ for (unsigned i = 0; i < _ext.code.size(); ++i)
+ if (_ext.code[i] == (byte)Instruction::JUMPDEST)
+ m_jumpDests.insert(i);
+ else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32)
+ i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1;
+ u256 nextPC = m_curPC + 1;
+ auto osteps = _steps;
+ for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1)
+ {
+ // INSTRUCTION...
+ Instruction inst = (Instruction)_ext.getCode(m_curPC);
+
+ // FEES...
+ bigint runGas = c_stepGas;
+ bigint newTempSize = m_temp.size();
+ bigint copySize = 0;
+
+ auto onOperation = [&]()
+ {
+ if (_onOp)
+ _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext);
+ };
+ // should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird.
+ //m_onFail = std::function(onOperation);
+
+ switch (inst)
+ {
+ case Instruction::STOP:
+ runGas = 0;
+ break;
+
+ case Instruction::SUICIDE:
+ require(1);
+ runGas = 0;
+ break;
+
+ case Instruction::SSTORE:
+ require(2);
+ if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
+ runGas = c_sstoreSetGas;
+ else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
+ {
+ runGas = 0;
+ _ext.sub.refunds += c_sstoreRefundGas;
+ }
+ else
+ runGas = c_sstoreResetGas;
+ break;
+
+ case Instruction::SLOAD:
+ require(1);
+ runGas = c_sloadGas;
+ break;
+
+ // These all operate on memory and therefore potentially expand it:
+ case Instruction::MSTORE:
+ require(2);
+ newTempSize = (bigint)m_stack.back() + 32;
+ break;
+ case Instruction::MSTORE8:
+ require(2);
+ newTempSize = (bigint)m_stack.back() + 1;
+ break;
+ case Instruction::MLOAD:
+ require(1);
+ newTempSize = (bigint)m_stack.back() + 32;
+ break;
+ case Instruction::RETURN:
+ require(2);
+ newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
+ break;
+ case Instruction::SHA3:
+ require(2);
+ runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas;
+ newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
+ break;
+ case Instruction::CALLDATACOPY:
+ require(3);
+ copySize = m_stack[m_stack.size() - 3];
+ newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
+ break;
+ case Instruction::CODECOPY:
+ require(3);
+ copySize = m_stack[m_stack.size() - 3];
+ newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
+ break;
+ case Instruction::EXTCODECOPY:
+ require(4);
+ copySize = m_stack[m_stack.size() - 4];
+ newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]);
+ break;
+
+ case Instruction::BALANCE:
+ require(1);
+ runGas = c_balanceGas;
+ break;
+ case Instruction::LOG0:
+ case Instruction::LOG1:
+ case Instruction::LOG2:
+ case Instruction::LOG3:
+ case Instruction::LOG4:
+ {
+ unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0;
+ require(n + 2);
+ runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2];
+ newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]);
+ break;
+ }
+
+ case Instruction::CALL:
+ case Instruction::CALLCODE:
+ require(7);
+ runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1];
+ newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]));
+ break;
+
+ case Instruction::CREATE:
+ {
+ require(3);
+ newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]);
+ runGas = c_createGas;
+ break;
+ }
+ case Instruction::EXP:
+ {
+ require(2);
+ auto expon = m_stack[m_stack.size() - 2];
+ runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8));
+ break;
+ }
+
+ case Instruction::BLOCKHASH:
+ require(1);
+ break;
+
+ case Instruction::PC:
+ case Instruction::MSIZE:
+ case Instruction::GAS:
+ case Instruction::JUMPDEST:
+ case Instruction::ADDRESS:
+ case Instruction::ORIGIN:
+ case Instruction::CALLER:
+ case Instruction::CALLVALUE:
+ case Instruction::CALLDATASIZE:
+ case Instruction::CODESIZE:
+ case Instruction::GASPRICE:
+ case Instruction::COINBASE:
+ case Instruction::TIMESTAMP:
+ case Instruction::NUMBER:
+ case Instruction::DIFFICULTY:
+ case Instruction::GASLIMIT:
+ case Instruction::PUSH1:
+ case Instruction::PUSH2:
+ case Instruction::PUSH3:
+ case Instruction::PUSH4:
+ case Instruction::PUSH5:
+ case Instruction::PUSH6:
+ case Instruction::PUSH7:
+ case Instruction::PUSH8:
+ case Instruction::PUSH9:
+ case Instruction::PUSH10:
+ case Instruction::PUSH11:
+ case Instruction::PUSH12:
+ case Instruction::PUSH13:
+ case Instruction::PUSH14:
+ case Instruction::PUSH15:
+ case Instruction::PUSH16:
+ case Instruction::PUSH17:
+ case Instruction::PUSH18:
+ case Instruction::PUSH19:
+ case Instruction::PUSH20:
+ case Instruction::PUSH21:
+ case Instruction::PUSH22:
+ case Instruction::PUSH23:
+ case Instruction::PUSH24:
+ case Instruction::PUSH25:
+ case Instruction::PUSH26:
+ case Instruction::PUSH27:
+ case Instruction::PUSH28:
+ case Instruction::PUSH29:
+ case Instruction::PUSH30:
+ case Instruction::PUSH31:
+ case Instruction::PUSH32:
+ break;
+ case Instruction::NOT:
+ case Instruction::ISZERO:
+ case Instruction::CALLDATALOAD:
+ case Instruction::EXTCODESIZE:
+ case Instruction::POP:
+ case Instruction::JUMP:
+ require(1);
+ break;
+ case Instruction::ADD:
+ case Instruction::MUL:
+ case Instruction::SUB:
+ case Instruction::DIV:
+ case Instruction::SDIV:
+ case Instruction::MOD:
+ case Instruction::SMOD:
+ case Instruction::LT:
+ case Instruction::GT:
+ case Instruction::SLT:
+ case Instruction::SGT:
+ case Instruction::EQ:
+ case Instruction::AND:
+ case Instruction::OR:
+ case Instruction::XOR:
+ case Instruction::BYTE:
+ case Instruction::JUMPI:
+ case Instruction::SIGNEXTEND:
+ require(2);
+ break;
+ case Instruction::ADDMOD:
+ case Instruction::MULMOD:
+ require(3);
+ break;
+ case Instruction::DUP1:
+ case Instruction::DUP2:
+ case Instruction::DUP3:
+ case Instruction::DUP4:
+ case Instruction::DUP5:
+ case Instruction::DUP6:
+ case Instruction::DUP7:
+ case Instruction::DUP8:
+ case Instruction::DUP9:
+ case Instruction::DUP10:
+ case Instruction::DUP11:
+ case Instruction::DUP12:
+ case Instruction::DUP13:
+ case Instruction::DUP14:
+ case Instruction::DUP15:
+ case Instruction::DUP16:
+ require(1 + (int)inst - (int)Instruction::DUP1);
+ break;
+ case Instruction::SWAP1:
+ case Instruction::SWAP2:
+ case Instruction::SWAP3:
+ case Instruction::SWAP4:
+ case Instruction::SWAP5:
+ case Instruction::SWAP6:
+ case Instruction::SWAP7:
+ case Instruction::SWAP8:
+ case Instruction::SWAP9:
+ case Instruction::SWAP10:
+ case Instruction::SWAP11:
+ case Instruction::SWAP12:
+ case Instruction::SWAP13:
+ case Instruction::SWAP14:
+ case Instruction::SWAP15:
+ case Instruction::SWAP16:
+ require((int)inst - (int)Instruction::SWAP1 + 2);
+ break;
+ default:
+ BOOST_THROW_EXCEPTION(BadInstruction());
+ }
+
+ newTempSize = (newTempSize + 31) / 32 * 32;
+ if (newTempSize > m_temp.size())
+ runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32;
+ runGas += c_copyGas * (copySize + 31) / 32;
+
+ onOperation();
+// if (_onOp)
+// _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext);
+
+ if (m_gas < runGas)
+ {
+ // Out of gas!
+ m_gas = 0;
+ BOOST_THROW_EXCEPTION(OutOfGas());
+ }
+
+ m_gas = (u256)((bigint)m_gas - runGas);
+
+ if (newTempSize > m_temp.size())
+ m_temp.resize((size_t)newTempSize);
+
+ // EXECUTE...
+ switch (inst)
+ {
+ case Instruction::ADD:
+ //pops two items and pushes S[-1] + S[-2] mod 2^256.
+ m_stack[m_stack.size() - 2] += m_stack.back();
+ m_stack.pop_back();
+ break;
+ case Instruction::MUL:
+ //pops two items and pushes S[-1] * S[-2] mod 2^256.
+ m_stack[m_stack.size() - 2] *= m_stack.back();
+ m_stack.pop_back();
+ break;
+ case Instruction::SUB:
+ m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2];
+ m_stack.pop_back();
+ break;
+ case Instruction::DIV:
+ m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() / m_stack[m_stack.size() - 2] : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::SDIV:
+ m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::MOD:
+ m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() % m_stack[m_stack.size() - 2] : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::SMOD:
+ m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::EXP:
+ {
+ auto base = m_stack.back();
+ auto expon = m_stack[m_stack.size() - 2];
+ m_stack.pop_back();
+ m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256);
+ break;
+ }
+ case Instruction::NOT:
+ m_stack.back() = ~m_stack.back();
+ break;
+ case Instruction::LT:
+ m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::GT:
+ m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::SLT:
+ m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::SGT:
+ m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::EQ:
+ m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::ISZERO:
+ m_stack.back() = m_stack.back() ? 0 : 1;
+ break;
+ case Instruction::AND:
+ m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2];
+ m_stack.pop_back();
+ break;
+ case Instruction::OR:
+ m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2];
+ m_stack.pop_back();
+ break;
+ case Instruction::XOR:
+ m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2];
+ m_stack.pop_back();
+ break;
+ case Instruction::BYTE:
+ m_stack[m_stack.size() - 2] = m_stack.back() < 32 ? (m_stack[m_stack.size() - 2] >> (unsigned)(8 * (31 - m_stack.back()))) & 0xff : 0;
+ m_stack.pop_back();
+ break;
+ case Instruction::ADDMOD:
+ m_stack[m_stack.size() - 3] = m_stack[m_stack.size() - 3] ? u256((bigint(m_stack.back()) + bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]) : 0;
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::MULMOD:
+ m_stack[m_stack.size() - 3] = m_stack[m_stack.size() - 3] ? u256((bigint(m_stack.back()) * bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]) : 0;
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::SIGNEXTEND:
+ if (m_stack.back() < 31)
+ {
+ unsigned const testBit(m_stack.back() * 8 + 7);
+ u256& number = m_stack[m_stack.size() - 2];
+ u256 mask = ((u256(1) << testBit) - 1);
+ if (boost::multiprecision::bit_test(number, testBit))
+ number |= ~mask;
+ else
+ number &= mask;
+ }
+ m_stack.pop_back();
+ break;
+ case Instruction::SHA3:
+ {
+ unsigned inOff = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ unsigned inSize = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ m_stack.push_back(sha3(bytesConstRef(m_temp.data() + inOff, inSize)));
+ break;
+ }
+ case Instruction::ADDRESS:
+ m_stack.push_back(fromAddress(_ext.myAddress));
+ break;
+ case Instruction::ORIGIN:
+ m_stack.push_back(fromAddress(_ext.origin));
+ break;
+ case Instruction::BALANCE:
+ {
+ m_stack.back() = _ext.balance(asAddress(m_stack.back()));
+ break;
+ }
+ case Instruction::CALLER:
+ m_stack.push_back(fromAddress(_ext.caller));
+ break;
+ case Instruction::CALLVALUE:
+ m_stack.push_back(_ext.value);
+ break;
+ case Instruction::CALLDATALOAD:
+ {
+ if ((unsigned)m_stack.back() + (uint64_t)31 < _ext.data.size())
+ m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back());
+ else
+ {
+ h256 r;
+ for (uint64_t i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + (uint64_t)32, j = 0; i < e; ++i, ++j)
+ r[j] = i < _ext.data.size() ? _ext.data[i] : 0;
+ m_stack.back() = (u256)r;
+ }
+ break;
+ }
+ case Instruction::CALLDATASIZE:
+ m_stack.push_back(_ext.data.size());
+ break;
+ case Instruction::CODESIZE:
+ m_stack.push_back(_ext.code.size());
+ break;
+ case Instruction::EXTCODESIZE:
+ m_stack.back() = _ext.codeAt(asAddress(m_stack.back())).size();
+ break;
+ case Instruction::CALLDATACOPY:
+ case Instruction::CODECOPY:
+ case Instruction::EXTCODECOPY:
+ {
+ Address a;
+ if (inst == Instruction::EXTCODECOPY)
+ {
+ a = asAddress(m_stack.back());
+ m_stack.pop_back();
+ }
+ unsigned offset = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ u256 index = m_stack.back();
+ m_stack.pop_back();
+ unsigned size = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ unsigned sizeToBeCopied;
+ switch(inst)
+ {
+ case Instruction::CALLDATACOPY:
+ sizeToBeCopied = index + (bigint)size > (u256)_ext.data.size() ? (u256)_ext.data.size() < index ? 0 : _ext.data.size() - (unsigned)index : size;
+ memcpy(m_temp.data() + offset, _ext.data.data() + (unsigned)index, sizeToBeCopied);
+ break;
+ case Instruction::CODECOPY:
+ sizeToBeCopied = index + (bigint)size > (u256)_ext.code.size() ? (u256)_ext.code.size() < index ? 0 : _ext.code.size() - (unsigned)index : size;
+ memcpy(m_temp.data() + offset, _ext.code.data() + (unsigned)index, sizeToBeCopied);
+ break;
+ case Instruction::EXTCODECOPY:
+ sizeToBeCopied = index + (bigint)size > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < index ? 0 : _ext.codeAt(a).size() - (unsigned)index : size;
+ memcpy(m_temp.data() + offset, _ext.codeAt(a).data() + (unsigned)index, sizeToBeCopied);
+ break;
+ default:
+ // this is unreachable, but if someone introduces a bug in the future, he may get here.
+ assert(false);
+ BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("CALLDATACOPY, CODECOPY or EXTCODECOPY instruction requested."));
+ break;
+ }
+ memset(m_temp.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied);
+ break;
+ }
+ case Instruction::GASPRICE:
+ m_stack.push_back(_ext.gasPrice);
+ break;
+ case Instruction::BLOCKHASH:
+ m_stack.back() = (u256)_ext.blockhash(m_stack.back());
+ break;
+ case Instruction::COINBASE:
+ m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
+ break;
+ case Instruction::TIMESTAMP:
+ m_stack.push_back(_ext.currentBlock.timestamp);
+ break;
+ case Instruction::NUMBER:
+ m_stack.push_back(_ext.currentBlock.number);
+ break;
+ case Instruction::DIFFICULTY:
+ m_stack.push_back(_ext.currentBlock.difficulty);
+ break;
+ case Instruction::GASLIMIT:
+ m_stack.push_back(1000000);
+ break;
+ case Instruction::PUSH1:
+ case Instruction::PUSH2:
+ case Instruction::PUSH3:
+ case Instruction::PUSH4:
+ case Instruction::PUSH5:
+ case Instruction::PUSH6:
+ case Instruction::PUSH7:
+ case Instruction::PUSH8:
+ case Instruction::PUSH9:
+ case Instruction::PUSH10:
+ case Instruction::PUSH11:
+ case Instruction::PUSH12:
+ case Instruction::PUSH13:
+ case Instruction::PUSH14:
+ case Instruction::PUSH15:
+ case Instruction::PUSH16:
+ case Instruction::PUSH17:
+ case Instruction::PUSH18:
+ case Instruction::PUSH19:
+ case Instruction::PUSH20:
+ case Instruction::PUSH21:
+ case Instruction::PUSH22:
+ case Instruction::PUSH23:
+ case Instruction::PUSH24:
+ case Instruction::PUSH25:
+ case Instruction::PUSH26:
+ case Instruction::PUSH27:
+ case Instruction::PUSH28:
+ case Instruction::PUSH29:
+ case Instruction::PUSH30:
+ case Instruction::PUSH31:
+ case Instruction::PUSH32:
+ {
+ int i = (int)inst - (int)Instruction::PUSH1 + 1;
+ nextPC = m_curPC + 1;
+ m_stack.push_back(0);
+ for (; i--; nextPC++)
+ m_stack.back() = (m_stack.back() << 8) | _ext.getCode(nextPC);
+ break;
+ }
+ case Instruction::POP:
+ m_stack.pop_back();
+ break;
+ case Instruction::DUP1:
+ case Instruction::DUP2:
+ case Instruction::DUP3:
+ case Instruction::DUP4:
+ case Instruction::DUP5:
+ case Instruction::DUP6:
+ case Instruction::DUP7:
+ case Instruction::DUP8:
+ case Instruction::DUP9:
+ case Instruction::DUP10:
+ case Instruction::DUP11:
+ case Instruction::DUP12:
+ case Instruction::DUP13:
+ case Instruction::DUP14:
+ case Instruction::DUP15:
+ case Instruction::DUP16:
+ {
+ auto n = 1 + (int)inst - (int)Instruction::DUP1;
+ m_stack.push_back(m_stack[m_stack.size() - n]);
+ break;
+ }
+ case Instruction::SWAP1:
+ case Instruction::SWAP2:
+ case Instruction::SWAP3:
+ case Instruction::SWAP4:
+ case Instruction::SWAP5:
+ case Instruction::SWAP6:
+ case Instruction::SWAP7:
+ case Instruction::SWAP8:
+ case Instruction::SWAP9:
+ case Instruction::SWAP10:
+ case Instruction::SWAP11:
+ case Instruction::SWAP12:
+ case Instruction::SWAP13:
+ case Instruction::SWAP14:
+ case Instruction::SWAP15:
+ case Instruction::SWAP16:
+ {
+ unsigned n = (int)inst - (int)Instruction::SWAP1 + 2;
+ auto d = m_stack.back();
+ m_stack.back() = m_stack[m_stack.size() - n];
+ m_stack[m_stack.size() - n] = d;
+ break;
+ }
+ case Instruction::MLOAD:
+ {
+ m_stack.back() = (u256)*(h256 const*)(m_temp.data() + (unsigned)m_stack.back());
+ break;
+ }
+ case Instruction::MSTORE:
+ {
+ *(h256*)&m_temp[(unsigned)m_stack.back()] = (h256)m_stack[m_stack.size() - 2];
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ }
+ case Instruction::MSTORE8:
+ {
+ m_temp[(unsigned)m_stack.back()] = (byte)(m_stack[m_stack.size() - 2] & 0xff);
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ }
+ case Instruction::SLOAD:
+ m_stack.back() = _ext.store(m_stack.back());
+ break;
+ case Instruction::SSTORE:
+ _ext.setStore(m_stack.back(), m_stack[m_stack.size() - 2]);
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::JUMP:
+ nextPC = m_stack.back();
+ if (!m_jumpDests.count(nextPC))
+ BOOST_THROW_EXCEPTION(BadJumpDestination());
+ m_stack.pop_back();
+ break;
+ case Instruction::JUMPI:
+ if (m_stack[m_stack.size() - 2])
+ {
+ nextPC = m_stack.back();
+ if (!m_jumpDests.count(nextPC))
+ BOOST_THROW_EXCEPTION(BadJumpDestination());
+ }
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::PC:
+ m_stack.push_back(m_curPC);
+ break;
+ case Instruction::MSIZE:
+ m_stack.push_back(m_temp.size());
+ break;
+ case Instruction::GAS:
+ m_stack.push_back(m_gas);
+ break;
+ case Instruction::JUMPDEST:
+ break;
+/* case Instruction::LOG0:
+ _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
+ break;
+ case Instruction::LOG1:
+ _ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3]));
+ break;
+ case Instruction::LOG2:
+ _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4]));
+ break;
+ case Instruction::LOG3:
+ _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5]));
+ break;
+ case Instruction::LOG4:
+ _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6]));
+ break;*/
+ case Instruction::LOG0:
+ _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::LOG1:
+ _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::LOG2:
+ _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::LOG3:
+ _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::LOG4:
+ _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ m_stack.pop_back();
+ break;
+ case Instruction::CREATE:
+ {
+ u256 endowment = m_stack.back();
+ m_stack.pop_back();
+ unsigned initOff = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ unsigned initSize = (unsigned)m_stack.back();
+ m_stack.pop_back();
+
+ if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024)
+ {
+ _ext.subBalance(endowment);
+ m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp));
+ }
+ else
+ m_stack.push_back(0);
+ break;
+ }
+ case Instruction::CALL:
+ case Instruction::CALLCODE:
+ {
+ u256 gas = m_stack.back();
+ m_stack.pop_back();
+ Address receiveAddress = asAddress(m_stack.back());
+ m_stack.pop_back();
+ u256 value = m_stack.back();
+ m_stack.pop_back();
+
+ unsigned inOff = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ unsigned inSize = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ unsigned outOff = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ unsigned outSize = (unsigned)m_stack.back();
+ m_stack.pop_back();
+
+ if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024)
+ {
+ _ext.subBalance(value);
+ m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress));
+ }
+ else
+ m_stack.push_back(0);
+
+ m_gas += gas;
+ break;
+ }
+ case Instruction::RETURN:
+ {
+ unsigned b = (unsigned)m_stack.back();
+ m_stack.pop_back();
+ unsigned s = (unsigned)m_stack.back();
+ m_stack.pop_back();
+
+ return bytesConstRef(m_temp.data() + b, s);
+ }
+ case Instruction::SUICIDE:
+ {
+ Address dest = asAddress(m_stack.back());
+ _ext.suicide(dest);
+ // ...follow through to...
+ }
+ case Instruction::STOP:
+ return bytesConstRef();
+ }
+ }
+ if (_steps == (uint64_t)-1)
+ BOOST_THROW_EXCEPTION(StepsDone());
+ return bytesConstRef();
+}
diff --git a/libevm/VM.h b/libevm/VM.h
index 377effe11..ecf5de292 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -77,766 +77,5 @@ private:
std::function m_onFail;
};
-// TODO: Move it to cpp file. Not done to make review easier.
-inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps)
-{
- auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; };
-
- if (m_jumpDests.empty())
- for (unsigned i = 0; i < _ext.code.size(); ++i)
- if (_ext.code[i] == (byte)Instruction::JUMPDEST)
- m_jumpDests.insert(i);
- else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32)
- i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1;
- u256 nextPC = m_curPC + 1;
- auto osteps = _steps;
- for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1)
- {
- // INSTRUCTION...
- Instruction inst = (Instruction)_ext.getCode(m_curPC);
-
- // FEES...
- bigint runGas = c_stepGas;
- bigint newTempSize = m_temp.size();
- bigint copySize = 0;
-
- auto onOperation = [&]()
- {
- if (_onOp)
- _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext);
- };
- // should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird.
- //m_onFail = std::function(onOperation);
-
- switch (inst)
- {
- case Instruction::STOP:
- runGas = 0;
- break;
-
- case Instruction::SUICIDE:
- require(1);
- runGas = 0;
- break;
-
- case Instruction::SSTORE:
- require(2);
- if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
- runGas = c_sstoreSetGas;
- else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
- {
- runGas = 0;
- _ext.sub.refunds += c_sstoreRefundGas;
- }
- else
- runGas = c_sstoreResetGas;
- break;
-
- case Instruction::SLOAD:
- require(1);
- runGas = c_sloadGas;
- break;
-
- // These all operate on memory and therefore potentially expand it:
- case Instruction::MSTORE:
- require(2);
- newTempSize = (bigint)m_stack.back() + 32;
- break;
- case Instruction::MSTORE8:
- require(2);
- newTempSize = (bigint)m_stack.back() + 1;
- break;
- case Instruction::MLOAD:
- require(1);
- newTempSize = (bigint)m_stack.back() + 32;
- break;
- case Instruction::RETURN:
- require(2);
- newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
- break;
- case Instruction::SHA3:
- require(2);
- runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas;
- newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
- break;
- case Instruction::CALLDATACOPY:
- require(3);
- copySize = m_stack[m_stack.size() - 3];
- newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
- break;
- case Instruction::CODECOPY:
- require(3);
- copySize = m_stack[m_stack.size() - 3];
- newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
- break;
- case Instruction::EXTCODECOPY:
- require(4);
- copySize = m_stack[m_stack.size() - 4];
- newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]);
- break;
-
- case Instruction::BALANCE:
- require(1);
- runGas = c_balanceGas;
- break;
- case Instruction::LOG0:
- case Instruction::LOG1:
- case Instruction::LOG2:
- case Instruction::LOG3:
- case Instruction::LOG4:
- {
- unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0;
- require(n + 2);
- runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2];
- newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]);
- break;
- }
-
- case Instruction::CALL:
- case Instruction::CALLCODE:
- require(7);
- runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1];
- newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]));
- break;
-
- case Instruction::CREATE:
- {
- require(3);
- newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]);
- runGas = c_createGas;
- break;
- }
- case Instruction::EXP:
- {
- require(2);
- auto expon = m_stack[m_stack.size() - 2];
- runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8));
- break;
- }
-
- case Instruction::BLOCKHASH:
- require(1);
- break;
-
- case Instruction::PC:
- case Instruction::MSIZE:
- case Instruction::GAS:
- case Instruction::JUMPDEST:
- case Instruction::ADDRESS:
- case Instruction::ORIGIN:
- case Instruction::CALLER:
- case Instruction::CALLVALUE:
- case Instruction::CALLDATASIZE:
- case Instruction::CODESIZE:
- case Instruction::GASPRICE:
- case Instruction::COINBASE:
- case Instruction::TIMESTAMP:
- case Instruction::NUMBER:
- case Instruction::DIFFICULTY:
- case Instruction::GASLIMIT:
- case Instruction::PUSH1:
- case Instruction::PUSH2:
- case Instruction::PUSH3:
- case Instruction::PUSH4:
- case Instruction::PUSH5:
- case Instruction::PUSH6:
- case Instruction::PUSH7:
- case Instruction::PUSH8:
- case Instruction::PUSH9:
- case Instruction::PUSH10:
- case Instruction::PUSH11:
- case Instruction::PUSH12:
- case Instruction::PUSH13:
- case Instruction::PUSH14:
- case Instruction::PUSH15:
- case Instruction::PUSH16:
- case Instruction::PUSH17:
- case Instruction::PUSH18:
- case Instruction::PUSH19:
- case Instruction::PUSH20:
- case Instruction::PUSH21:
- case Instruction::PUSH22:
- case Instruction::PUSH23:
- case Instruction::PUSH24:
- case Instruction::PUSH25:
- case Instruction::PUSH26:
- case Instruction::PUSH27:
- case Instruction::PUSH28:
- case Instruction::PUSH29:
- case Instruction::PUSH30:
- case Instruction::PUSH31:
- case Instruction::PUSH32:
- break;
- case Instruction::NOT:
- case Instruction::ISZERO:
- case Instruction::CALLDATALOAD:
- case Instruction::EXTCODESIZE:
- case Instruction::POP:
- case Instruction::JUMP:
- require(1);
- break;
- case Instruction::ADD:
- case Instruction::MUL:
- case Instruction::SUB:
- case Instruction::DIV:
- case Instruction::SDIV:
- case Instruction::MOD:
- case Instruction::SMOD:
- case Instruction::LT:
- case Instruction::GT:
- case Instruction::SLT:
- case Instruction::SGT:
- case Instruction::EQ:
- case Instruction::AND:
- case Instruction::OR:
- case Instruction::XOR:
- case Instruction::BYTE:
- case Instruction::JUMPI:
- case Instruction::SIGNEXTEND:
- require(2);
- break;
- case Instruction::ADDMOD:
- case Instruction::MULMOD:
- require(3);
- break;
- case Instruction::DUP1:
- case Instruction::DUP2:
- case Instruction::DUP3:
- case Instruction::DUP4:
- case Instruction::DUP5:
- case Instruction::DUP6:
- case Instruction::DUP7:
- case Instruction::DUP8:
- case Instruction::DUP9:
- case Instruction::DUP10:
- case Instruction::DUP11:
- case Instruction::DUP12:
- case Instruction::DUP13:
- case Instruction::DUP14:
- case Instruction::DUP15:
- case Instruction::DUP16:
- require(1 + (int)inst - (int)Instruction::DUP1);
- break;
- case Instruction::SWAP1:
- case Instruction::SWAP2:
- case Instruction::SWAP3:
- case Instruction::SWAP4:
- case Instruction::SWAP5:
- case Instruction::SWAP6:
- case Instruction::SWAP7:
- case Instruction::SWAP8:
- case Instruction::SWAP9:
- case Instruction::SWAP10:
- case Instruction::SWAP11:
- case Instruction::SWAP12:
- case Instruction::SWAP13:
- case Instruction::SWAP14:
- case Instruction::SWAP15:
- case Instruction::SWAP16:
- require((int)inst - (int)Instruction::SWAP1 + 2);
- break;
- default:
- BOOST_THROW_EXCEPTION(BadInstruction());
- }
-
- newTempSize = (newTempSize + 31) / 32 * 32;
- if (newTempSize > m_temp.size())
- runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32;
- runGas += c_copyGas * (copySize + 31) / 32;
-
- onOperation();
-// if (_onOp)
-// _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext);
-
- if (m_gas < runGas)
- {
- // Out of gas!
- m_gas = 0;
- BOOST_THROW_EXCEPTION(OutOfGas());
- }
-
- m_gas = (u256)((bigint)m_gas - runGas);
-
- if (newTempSize > m_temp.size())
- m_temp.resize((size_t)newTempSize);
-
- // EXECUTE...
- switch (inst)
- {
- case Instruction::ADD:
- //pops two items and pushes S[-1] + S[-2] mod 2^256.
- m_stack[m_stack.size() - 2] += m_stack.back();
- m_stack.pop_back();
- break;
- case Instruction::MUL:
- //pops two items and pushes S[-1] * S[-2] mod 2^256.
- m_stack[m_stack.size() - 2] *= m_stack.back();
- m_stack.pop_back();
- break;
- case Instruction::SUB:
- m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2];
- m_stack.pop_back();
- break;
- case Instruction::DIV:
- m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() / m_stack[m_stack.size() - 2] : 0;
- m_stack.pop_back();
- break;
- case Instruction::SDIV:
- m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0;
- m_stack.pop_back();
- break;
- case Instruction::MOD:
- m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() % m_stack[m_stack.size() - 2] : 0;
- m_stack.pop_back();
- break;
- case Instruction::SMOD:
- m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0;
- m_stack.pop_back();
- break;
- case Instruction::EXP:
- {
- auto base = m_stack.back();
- auto expon = m_stack[m_stack.size() - 2];
- m_stack.pop_back();
- m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256);
- break;
- }
- case Instruction::NOT:
- m_stack.back() = ~m_stack.back();
- break;
- case Instruction::LT:
- m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0;
- m_stack.pop_back();
- break;
- case Instruction::GT:
- m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0;
- m_stack.pop_back();
- break;
- case Instruction::SLT:
- m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
- m_stack.pop_back();
- break;
- case Instruction::SGT:
- m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
- m_stack.pop_back();
- break;
- case Instruction::EQ:
- m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0;
- m_stack.pop_back();
- break;
- case Instruction::ISZERO:
- m_stack.back() = m_stack.back() ? 0 : 1;
- break;
- case Instruction::AND:
- m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2];
- m_stack.pop_back();
- break;
- case Instruction::OR:
- m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2];
- m_stack.pop_back();
- break;
- case Instruction::XOR:
- m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2];
- m_stack.pop_back();
- break;
- case Instruction::BYTE:
- m_stack[m_stack.size() - 2] = m_stack.back() < 32 ? (m_stack[m_stack.size() - 2] >> (unsigned)(8 * (31 - m_stack.back()))) & 0xff : 0;
- m_stack.pop_back();
- break;
- case Instruction::ADDMOD:
- m_stack[m_stack.size() - 3] = u256((bigint(m_stack.back()) + bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]);
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::MULMOD:
- m_stack[m_stack.size() - 3] = u256((bigint(m_stack.back()) * bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]);
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::SIGNEXTEND:
- if (m_stack.back() < 31)
- {
- unsigned const testBit(m_stack.back() * 8 + 7);
- u256& number = m_stack[m_stack.size() - 2];
- u256 mask = ((u256(1) << testBit) - 1);
- if (boost::multiprecision::bit_test(number, testBit))
- number |= ~mask;
- else
- number &= mask;
- }
- m_stack.pop_back();
- break;
- case Instruction::SHA3:
- {
- unsigned inOff = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned inSize = (unsigned)m_stack.back();
- m_stack.pop_back();
- m_stack.push_back(sha3(bytesConstRef(m_temp.data() + inOff, inSize)));
- break;
- }
- case Instruction::ADDRESS:
- m_stack.push_back(fromAddress(_ext.myAddress));
- break;
- case Instruction::ORIGIN:
- m_stack.push_back(fromAddress(_ext.origin));
- break;
- case Instruction::BALANCE:
- {
- m_stack.back() = _ext.balance(asAddress(m_stack.back()));
- break;
- }
- case Instruction::CALLER:
- m_stack.push_back(fromAddress(_ext.caller));
- break;
- case Instruction::CALLVALUE:
- m_stack.push_back(_ext.value);
- break;
- case Instruction::CALLDATALOAD:
- {
- if ((unsigned)m_stack.back() + (uint64_t)31 < _ext.data.size())
- m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back());
- else
- {
- h256 r;
- for (uint64_t i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + (uint64_t)32, j = 0; i < e; ++i, ++j)
- r[j] = i < _ext.data.size() ? _ext.data[i] : 0;
- m_stack.back() = (u256)r;
- }
- break;
- }
- case Instruction::CALLDATASIZE:
- m_stack.push_back(_ext.data.size());
- break;
- case Instruction::CODESIZE:
- m_stack.push_back(_ext.code.size());
- break;
- case Instruction::EXTCODESIZE:
- m_stack.back() = _ext.codeAt(asAddress(m_stack.back())).size();
- break;
- case Instruction::CALLDATACOPY:
- case Instruction::CODECOPY:
- case Instruction::EXTCODECOPY:
- {
- Address a;
- if (inst == Instruction::EXTCODECOPY)
- {
- a = asAddress(m_stack.back());
- m_stack.pop_back();
- }
- unsigned offset = (unsigned)m_stack.back();
- m_stack.pop_back();
- u256 index = m_stack.back();
- m_stack.pop_back();
- unsigned size = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned sizeToBeCopied;
- switch(inst)
- {
- case Instruction::CALLDATACOPY:
- sizeToBeCopied = index + (bigint)size > (u256)_ext.data.size() ? (u256)_ext.data.size() < index ? 0 : _ext.data.size() - (unsigned)index : size;
- memcpy(m_temp.data() + offset, _ext.data.data() + (unsigned)index, sizeToBeCopied);
- break;
- case Instruction::CODECOPY:
- sizeToBeCopied = index + (bigint)size > (u256)_ext.code.size() ? (u256)_ext.code.size() < index ? 0 : _ext.code.size() - (unsigned)index : size;
- memcpy(m_temp.data() + offset, _ext.code.data() + (unsigned)index, sizeToBeCopied);
- break;
- case Instruction::EXTCODECOPY:
- sizeToBeCopied = index + (bigint)size > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < index ? 0 : _ext.codeAt(a).size() - (unsigned)index : size;
- memcpy(m_temp.data() + offset, _ext.codeAt(a).data() + (unsigned)index, sizeToBeCopied);
- break;
- default:
- // this is unreachable, but if someone introduces a bug in the future, he may get here.
- assert(false);
- BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("CALLDATACOPY, CODECOPY or EXTCODECOPY instruction requested."));
- break;
- }
- memset(m_temp.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied);
- break;
- }
- case Instruction::GASPRICE:
- m_stack.push_back(_ext.gasPrice);
- break;
- case Instruction::BLOCKHASH:
- m_stack.back() = (u256)_ext.blockhash(m_stack.back());
- break;
- case Instruction::COINBASE:
- m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
- break;
- case Instruction::TIMESTAMP:
- m_stack.push_back(_ext.currentBlock.timestamp);
- break;
- case Instruction::NUMBER:
- m_stack.push_back(_ext.currentBlock.number);
- break;
- case Instruction::DIFFICULTY:
- m_stack.push_back(_ext.currentBlock.difficulty);
- break;
- case Instruction::GASLIMIT:
- m_stack.push_back(1000000);
- break;
- case Instruction::PUSH1:
- case Instruction::PUSH2:
- case Instruction::PUSH3:
- case Instruction::PUSH4:
- case Instruction::PUSH5:
- case Instruction::PUSH6:
- case Instruction::PUSH7:
- case Instruction::PUSH8:
- case Instruction::PUSH9:
- case Instruction::PUSH10:
- case Instruction::PUSH11:
- case Instruction::PUSH12:
- case Instruction::PUSH13:
- case Instruction::PUSH14:
- case Instruction::PUSH15:
- case Instruction::PUSH16:
- case Instruction::PUSH17:
- case Instruction::PUSH18:
- case Instruction::PUSH19:
- case Instruction::PUSH20:
- case Instruction::PUSH21:
- case Instruction::PUSH22:
- case Instruction::PUSH23:
- case Instruction::PUSH24:
- case Instruction::PUSH25:
- case Instruction::PUSH26:
- case Instruction::PUSH27:
- case Instruction::PUSH28:
- case Instruction::PUSH29:
- case Instruction::PUSH30:
- case Instruction::PUSH31:
- case Instruction::PUSH32:
- {
- int i = (int)inst - (int)Instruction::PUSH1 + 1;
- nextPC = m_curPC + 1;
- m_stack.push_back(0);
- for (; i--; nextPC++)
- m_stack.back() = (m_stack.back() << 8) | _ext.getCode(nextPC);
- break;
- }
- case Instruction::POP:
- m_stack.pop_back();
- break;
- case Instruction::DUP1:
- case Instruction::DUP2:
- case Instruction::DUP3:
- case Instruction::DUP4:
- case Instruction::DUP5:
- case Instruction::DUP6:
- case Instruction::DUP7:
- case Instruction::DUP8:
- case Instruction::DUP9:
- case Instruction::DUP10:
- case Instruction::DUP11:
- case Instruction::DUP12:
- case Instruction::DUP13:
- case Instruction::DUP14:
- case Instruction::DUP15:
- case Instruction::DUP16:
- {
- auto n = 1 + (int)inst - (int)Instruction::DUP1;
- m_stack.push_back(m_stack[m_stack.size() - n]);
- break;
- }
- case Instruction::SWAP1:
- case Instruction::SWAP2:
- case Instruction::SWAP3:
- case Instruction::SWAP4:
- case Instruction::SWAP5:
- case Instruction::SWAP6:
- case Instruction::SWAP7:
- case Instruction::SWAP8:
- case Instruction::SWAP9:
- case Instruction::SWAP10:
- case Instruction::SWAP11:
- case Instruction::SWAP12:
- case Instruction::SWAP13:
- case Instruction::SWAP14:
- case Instruction::SWAP15:
- case Instruction::SWAP16:
- {
- unsigned n = (int)inst - (int)Instruction::SWAP1 + 2;
- auto d = m_stack.back();
- m_stack.back() = m_stack[m_stack.size() - n];
- m_stack[m_stack.size() - n] = d;
- break;
- }
- case Instruction::MLOAD:
- {
- m_stack.back() = (u256)*(h256 const*)(m_temp.data() + (unsigned)m_stack.back());
- break;
- }
- case Instruction::MSTORE:
- {
- *(h256*)&m_temp[(unsigned)m_stack.back()] = (h256)m_stack[m_stack.size() - 2];
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- }
- case Instruction::MSTORE8:
- {
- m_temp[(unsigned)m_stack.back()] = (byte)(m_stack[m_stack.size() - 2] & 0xff);
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- }
- case Instruction::SLOAD:
- m_stack.back() = _ext.store(m_stack.back());
- break;
- case Instruction::SSTORE:
- _ext.setStore(m_stack.back(), m_stack[m_stack.size() - 2]);
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::JUMP:
- nextPC = m_stack.back();
- if (!m_jumpDests.count(nextPC))
- BOOST_THROW_EXCEPTION(BadJumpDestination());
- m_stack.pop_back();
- break;
- case Instruction::JUMPI:
- if (m_stack[m_stack.size() - 2])
- {
- nextPC = m_stack.back();
- if (!m_jumpDests.count(nextPC))
- BOOST_THROW_EXCEPTION(BadJumpDestination());
- }
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::PC:
- m_stack.push_back(m_curPC);
- break;
- case Instruction::MSIZE:
- m_stack.push_back(m_temp.size());
- break;
- case Instruction::GAS:
- m_stack.push_back(m_gas);
- break;
- case Instruction::JUMPDEST:
- break;
-/* case Instruction::LOG0:
- _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
- break;
- case Instruction::LOG1:
- _ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3]));
- break;
- case Instruction::LOG2:
- _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4]));
- break;
- case Instruction::LOG3:
- _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5]));
- break;
- case Instruction::LOG4:
- _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6]));
- break;*/
- case Instruction::LOG0:
- _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::LOG1:
- _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::LOG2:
- _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::LOG3:
- _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::LOG4:
- _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- m_stack.pop_back();
- break;
- case Instruction::CREATE:
- {
- u256 endowment = m_stack.back();
- m_stack.pop_back();
- unsigned initOff = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned initSize = (unsigned)m_stack.back();
- m_stack.pop_back();
-
- if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024)
- {
- _ext.subBalance(endowment);
- m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp));
- }
- else
- m_stack.push_back(0);
- break;
- }
- case Instruction::CALL:
- case Instruction::CALLCODE:
- {
- u256 gas = m_stack.back();
- m_stack.pop_back();
- Address receiveAddress = asAddress(m_stack.back());
- m_stack.pop_back();
- u256 value = m_stack.back();
- m_stack.pop_back();
-
- unsigned inOff = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned inSize = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned outOff = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned outSize = (unsigned)m_stack.back();
- m_stack.pop_back();
-
- if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024)
- {
- _ext.subBalance(value);
- m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress));
- }
- else
- m_stack.push_back(0);
-
- m_gas += gas;
- break;
- }
- case Instruction::RETURN:
- {
- unsigned b = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned s = (unsigned)m_stack.back();
- m_stack.pop_back();
-
- return bytesConstRef(m_temp.data() + b, s);
- }
- case Instruction::SUICIDE:
- {
- Address dest = asAddress(m_stack.back());
- _ext.suicide(dest);
- // ...follow through to...
- }
- case Instruction::STOP:
- return bytesConstRef();
- }
- }
- if (_steps == (uint64_t)-1)
- BOOST_THROW_EXCEPTION(StepsDone());
- return bytesConstRef();
-}
-
}
}
diff --git a/libjsqrc/CMakeLists.txt b/libjsqrc/CMakeLists.txt
index a6dbf023b..2635bc558 100644
--- a/libjsqrc/CMakeLists.txt
+++ b/libjsqrc/CMakeLists.txt
@@ -12,4 +12,14 @@ qt5_add_resources(JSQRC js.qrc)
add_library(jsqrc STATIC ${JSQRC})
target_link_libraries(jsqrc Qt5::Core)
+if (ETH_NODE AND ETH_NPM)
+ add_custom_target(ethereumjs)
+ add_custom_command(TARGET ethereumjs
+ POST_BUILD
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND bash compilejs.sh ${ETH_NPM_DIRECTORY} ${ETH_NODE_DIRECTORY}
+ )
+ add_dependencies(jsqrc ethereumjs)
+endif()
+
install( TARGETS jsqrc ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
diff --git a/libjsqrc/compilejs.sh b/libjsqrc/compilejs.sh
new file mode 100644
index 000000000..ba99e2415
--- /dev/null
+++ b/libjsqrc/compilejs.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+cd ethereumjs
+export PATH=$PATH:$1:$2
+npm install
+npm run-script build
+
diff --git a/libjsqrc/ethereumjs/.travis.yml b/libjsqrc/ethereumjs/.travis.yml
index fafacbd5a..83b21d840 100644
--- a/libjsqrc/ethereumjs/.travis.yml
+++ b/libjsqrc/ethereumjs/.travis.yml
@@ -8,4 +8,6 @@ before_script:
script:
- "jshint *.js lib"
after_script:
- - npm run-script gulp
+ - npm run-script build
+ - npm test
+
diff --git a/libjsqrc/ethereumjs/README.md b/libjsqrc/ethereumjs/README.md
index 865b62c6b..f18d382bd 100644
--- a/libjsqrc/ethereumjs/README.md
+++ b/libjsqrc/ethereumjs/README.md
@@ -50,13 +50,35 @@ web3.eth.coinbase.then(function(result){
For another example see `example/index.html`.
+## Contribute!
+
+### Requirements
+
+* Node.js
+* npm
+* gulp (build)
+* mocha (tests)
+
+```bash
+sudo apt-get update
+sudo apt-get install nodejs
+sudo apt-get install npm
+sudo apt-get install nodejs-legacy
+```
+
## Building
-* `gulp build`
+```bash (gulp)
+npm run-script build
+```
### Testing
+```bash (mocha)
+npm test
+```
+
**Please note this repo is in it's early stage.**
If you'd like to run a WebSocket ethereum node check out
@@ -76,4 +98,4 @@ ethereum -ws -loglevel=4
[dep-image]: https://david-dm.org/ethereum/ethereum.js.svg
[dep-url]: https://david-dm.org/ethereum/ethereum.js
[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg
-[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies
\ No newline at end of file
+[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies
diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js
index 26de2c02e..a422171be 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.js
+++ b/libjsqrc/ethereumjs/dist/ethereum.js
@@ -85,6 +85,18 @@ var calcRealPadding = function (type, expected) {
var setupInputTypes = function () {
+ // convert from int, decimal-string, prefixed hex string whatever into a bare hex string.
+ var formatStandard = function (value) {
+ if (typeof value === "number")
+ return value.toString(16);
+ else if (typeof value === "string" && value.indexOf('0x') === 0)
+ return value.substr(2);
+ else if (typeof value === "string")
+ return web3.toHex(value);
+ else
+ return (+value).toString(16);
+ };
+
var prefixedType = function (prefix, calcPadding) {
return function (type, value) {
var expected = prefix;
@@ -93,15 +105,13 @@ var setupInputTypes = function () {
}
var padding = calcPadding(type, expected);
- if (typeof value === "number")
- value = value.toString(16);
- else if (typeof value === "string")
- value = web3.toHex(value);
- else if (value.indexOf('0x') === 0)
- value = value.substr(2);
- else
- value = (+value).toString(16);
- return padLeft(value, padding * 2);
+ if (padding > 32)
+ return false; // not allowed to be so big.
+ padding = 32; // override as per the new ABI.
+
+ if (prefix === "string")
+ return web3.fromAscii(value, padding).substr(2);
+ return padLeft(formatStandard(value), padding * 2);
};
};
@@ -111,12 +121,14 @@ var setupInputTypes = function () {
return false;
}
+ padding = 32; //override as per the new ABI.
+
return padLeft(formatter ? formatter(value) : value, padding * 2);
};
};
var formatBool = function (value) {
- return value ? '0x1' : '0x0';
+ return value ? '01' : '00';
};
return [
@@ -126,7 +138,7 @@ var setupInputTypes = function () {
prefixedType('string', calcBytePadding),
prefixedType('real', calcRealPadding),
prefixedType('ureal', calcRealPadding),
- namedType('address', 20),
+ namedType('address', 20, formatStandard),
namedType('bool', 1, formatBool),
];
};
@@ -166,12 +178,16 @@ var setupOutputTypes = function () {
}
var padding = calcPadding(type, expected);
+ if (padding > 32)
+ return -1; // not allowed to be so big.
+ padding = 32; // override as per the new ABI.
return padding * 2;
};
};
var namedType = function (name, padding) {
return function (type) {
+ padding = 32; // override as per the new ABI.
return name === type ? padding * 2 : -1;
};
};
@@ -277,6 +293,7 @@ module.exports = {
methodSignature: methodSignature
};
+
},{}],2:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -441,8 +458,10 @@ var contract = function (address, desc) {
transact: function (extra) {
extra = extra || {};
extra.to = address;
- extra.data = parsed;
- return web3.eth.transact(extra).then(onSuccess);
+ return abi.methodSignature(desc, method.name).then(function (signature) {
+ extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;
+ return web3.eth.transact(extra).then(onSuccess);
+ });
}
};
};
diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map
index bb29b435d..4a38cddfd 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.js.map
+++ b/libjsqrc/ethereumjs/dist/ethereum.js.map
@@ -12,14 +12,14 @@
"index.js"
],
"names": [],
- "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
+ "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
"file": "generated.js",
"sourceRoot": "",
"sourcesContent": [
"(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o.\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n return findIndex(json, function (method) {\n return method.name === methodName;\n });\n};\n\nvar padLeft = function (string, chars) {\n return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n var sizes = value.split('x');\n for (var padding = 0, i = 0; i < sizes; i++) {\n padding += (sizes[i] / 8);\n }\n return padding;\n};\n\nvar setupInputTypes = function () {\n \n var prefixedType = function (prefix, calcPadding) {\n return function (type, value) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return false;\n }\n\n var padding = calcPadding(type, expected);\n if (typeof value === \"number\")\n value = value.toString(16);\n else if (typeof value === \"string\")\n value = web3.toHex(value); \n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else\n value = (+value).toString(16);\n return padLeft(value, padding * 2);\n };\n };\n\n var namedType = function (name, padding, formatter) {\n return function (type, value) {\n if (type !== name) {\n return false;\n }\n\n return padLeft(formatter ? formatter(value) : value, padding * 2);\n };\n };\n\n var formatBool = function (value) {\n return value ? '0x1' : '0x0';\n };\n\n return [\n prefixedType('uint', calcBitPadding),\n prefixedType('int', calcBitPadding),\n prefixedType('hash', calcBitPadding),\n prefixedType('string', calcBytePadding),\n prefixedType('real', calcRealPadding),\n prefixedType('ureal', calcRealPadding),\n namedType('address', 20),\n namedType('bool', 1, formatBool),\n ];\n};\n\nvar inputTypes = setupInputTypes();\n\nvar toAbiInput = function (json, methodName, params) {\n var bytes = \"\";\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n var method = json[index];\n\n for (var i = 0; i < method.inputs.length; i++) {\n var found = false;\n for (var j = 0; j < inputTypes.length && !found; j++) {\n found = inputTypes[j](method.inputs[i].type, params[i]);\n }\n if (!found) {\n console.error('unsupported json type: ' + method.inputs[i].type);\n }\n bytes += found;\n }\n return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return -1;\n }\n\n var padding = calcPadding(type, expected);\n return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\n return name === type ? padding * 2 : -1;\n };\n };\n\n var formatInt = function (value) {\n return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n };\n\n var formatHash = function (value) {\n return \"0x\" + value;\n };\n\n var formatBool = function (value) {\n return value === '1' ? true : false;\n };\n\n var formatString = function (value) {\n return web3.toAscii(value);\n };\n\n return [\n { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n { padding: prefixedType('int', calcBitPadding), format: formatInt },\n { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n { padding: prefixedType('string', calcBytePadding), format: formatString },\n { padding: prefixedType('real', calcRealPadding), format: formatInt },\n { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n { padding: namedType('address', 20) },\n { padding: namedType('bool', 1), format: formatBool }\n ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n output = output.slice(2);\n\n var result = [];\n var method = json[index];\n for (var i = 0; i < method.outputs.length; i++) {\n var padding = -1;\n for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n padding = outputTypes[j].padding(method.outputs[i].type);\n }\n\n if (padding === -1) {\n // not found output parsing\n continue;\n }\n var res = output.slice(0, padding);\n var formatter = outputTypes[j - 1].format;\n result.push(formatter ? formatter(res) : (\"0x\" + res));\n output = output.slice(padding);\n }\n\n return result;\n};\n\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n return toAbiInput(json, method.name, params);\n };\n });\n\n return parser;\n};\n\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function (output) {\n return fromAbiOutput(json, method.name, output);\n };\n });\n\n return parser;\n};\n\nvar methodSignature = function (json, name) {\n var method = json[findMethodIndex(json, name)];\n var result = name + '(';\n var inputTypes = method.inputs.map(function (inp) {\n return inp.type;\n });\n result += inputTypes.join(',');\n result += ')';\n\n return web3.sha3(web3.fromAscii(result));\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\n};\n",
+ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n return findIndex(json, function (method) {\n return method.name === methodName;\n });\n};\n\nvar padLeft = function (string, chars) {\n return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n var sizes = value.split('x');\n for (var padding = 0, i = 0; i < sizes; i++) {\n padding += (sizes[i] / 8);\n }\n return padding;\n};\n\nvar setupInputTypes = function () {\n \n // convert from int, decimal-string, prefixed hex string whatever into a bare hex string.\n var formatStandard = function (value) {\n if (typeof value === \"number\")\n return value.toString(16);\n else if (typeof value === \"string\" && value.indexOf('0x') === 0)\n return value.substr(2);\n else if (typeof value === \"string\")\n return web3.toHex(value);\n else\n return (+value).toString(16);\n };\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type, value) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return false;\n }\n\n var padding = calcPadding(type, expected);\n if (padding > 32)\n return false; // not allowed to be so big.\n padding = 32; // override as per the new ABI.\n\n if (prefix === \"string\")\n return web3.fromAscii(value, padding).substr(2);\n return padLeft(formatStandard(value), padding * 2);\n };\n };\n\n var namedType = function (name, padding, formatter) {\n return function (type, value) {\n if (type !== name) {\n return false;\n }\n\n padding = 32; //override as per the new ABI.\n\n return padLeft(formatter ? formatter(value) : value, padding * 2);\n };\n };\n\n var formatBool = function (value) {\n return value ? '01' : '00';\n };\n\n return [\n prefixedType('uint', calcBitPadding),\n prefixedType('int', calcBitPadding),\n prefixedType('hash', calcBitPadding),\n prefixedType('string', calcBytePadding),\n prefixedType('real', calcRealPadding),\n prefixedType('ureal', calcRealPadding),\n namedType('address', 20, formatStandard),\n namedType('bool', 1, formatBool),\n ];\n};\n\nvar inputTypes = setupInputTypes();\n\nvar toAbiInput = function (json, methodName, params) {\n var bytes = \"\";\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n var method = json[index];\n\n for (var i = 0; i < method.inputs.length; i++) {\n var found = false;\n for (var j = 0; j < inputTypes.length && !found; j++) {\n found = inputTypes[j](method.inputs[i].type, params[i]);\n }\n if (!found) {\n console.error('unsupported json type: ' + method.inputs[i].type);\n }\n bytes += found;\n }\n return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return -1;\n }\n\n var padding = calcPadding(type, expected);\n if (padding > 32)\n return -1; // not allowed to be so big.\n padding = 32; // override as per the new ABI.\n return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\n padding = 32; // override as per the new ABI.\n return name === type ? padding * 2 : -1;\n };\n };\n\n var formatInt = function (value) {\n return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n };\n\n var formatHash = function (value) {\n return \"0x\" + value;\n };\n\n var formatBool = function (value) {\n return value === '1' ? true : false;\n };\n\n var formatString = function (value) {\n return web3.toAscii(value);\n };\n\n return [\n { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n { padding: prefixedType('int', calcBitPadding), format: formatInt },\n { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n { padding: prefixedType('string', calcBytePadding), format: formatString },\n { padding: prefixedType('real', calcRealPadding), format: formatInt },\n { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n { padding: namedType('address', 20) },\n { padding: namedType('bool', 1), format: formatBool }\n ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n output = output.slice(2);\n\n var result = [];\n var method = json[index];\n for (var i = 0; i < method.outputs.length; i++) {\n var padding = -1;\n for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n padding = outputTypes[j].padding(method.outputs[i].type);\n }\n\n if (padding === -1) {\n // not found output parsing\n continue;\n }\n var res = output.slice(0, padding);\n var formatter = outputTypes[j - 1].format;\n result.push(formatter ? formatter(res) : (\"0x\" + res));\n output = output.slice(padding);\n }\n\n return result;\n};\n\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n return toAbiInput(json, method.name, params);\n };\n });\n\n return parser;\n};\n\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function (output) {\n return fromAbiOutput(json, method.name, output);\n };\n });\n\n return parser;\n};\n\nvar methodSignature = function (json, name) {\n var method = json[findMethodIndex(json, name)];\n var result = name + '(';\n var inputTypes = method.inputs.map(function (inp) {\n return inp.type;\n });\n result += inputTypes.join(',');\n result += ')';\n\n return web3.sha3(web3.fromAscii(result));\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\n};\n\n",
"/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file autoprovider.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n/*\n * @brief if qt object is available, uses QtProvider,\n * if not tries to connect over websockets\n * if it fails, it uses HttpRpcProvider\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var WebSocket = require('ws'); // jshint ignore:line\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar AutoProvider = function (userOptions) {\n if (web3.haveProvider()) {\n return;\n }\n\n // before we determine what provider we are, we have to cache request\n this.sendQueue = [];\n this.onmessageQueue = [];\n\n if (navigator.qt) {\n this.provider = new web3.providers.QtProvider();\n return;\n }\n\n userOptions = userOptions || {};\n var options = {\n httprpc: userOptions.httprpc || 'http://localhost:8080',\n websockets: userOptions.websockets || 'ws://localhost:40404/eth'\n };\n\n var self = this;\n var closeWithSuccess = function (success) {\n ws.close();\n if (success) {\n self.provider = new web3.providers.WebSocketProvider(options.websockets);\n } else {\n self.provider = new web3.providers.HttpRpcProvider(options.httprpc);\n self.poll = self.provider.poll.bind(self.provider);\n }\n self.sendQueue.forEach(function (payload) {\n self.provider(payload);\n });\n self.onmessageQueue.forEach(function (handler) {\n self.provider.onmessage = handler;\n });\n };\n\n var ws = new WebSocket(options.websockets);\n\n ws.onopen = function() {\n closeWithSuccess(true);\n };\n\n ws.onerror = function() {\n closeWithSuccess(false);\n };\n};\n\nAutoProvider.prototype.send = function (payload) {\n if (this.provider) {\n this.provider.send(payload);\n return;\n }\n this.sendQueue.push(payload);\n};\n\nObject.defineProperty(AutoProvider.prototype, 'onmessage', {\n set: function (handler) {\n if (this.provider) {\n this.provider.onmessage = handler;\n return;\n }\n this.onmessageQueue.push(handler);\n }\n});\n\nmodule.exports = AutoProvider;\n",
- "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar abi = require('./abi');\n\n// method signature length in bytes\nvar ETH_METHOD_SIGNATURE_LENGTH = 4;\n\nvar contract = function (address, desc) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n var contract = {};\n\n desc.forEach(function (method) {\n contract[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n var parsed = inputParser[method.name].apply(null, params);\n\n var onSuccess = function (result) {\n return outputParser[method.name](result);\n };\n\n return {\n call: function (extra) {\n extra = extra || {};\n extra.to = address;\n return abi.methodSignature(desc, method.name).then(function (signature) {\n extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n return web3.eth.call(extra).then(onSuccess);\n });\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\n }\n };\n };\n });\n\n return contract;\n};\n\nmodule.exports = contract;\n",
+ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar abi = require('./abi');\n\n// method signature length in bytes\nvar ETH_METHOD_SIGNATURE_LENGTH = 4;\n\nvar contract = function (address, desc) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n var contract = {};\n\n desc.forEach(function (method) {\n contract[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n var parsed = inputParser[method.name].apply(null, params);\n\n var onSuccess = function (result) {\n return outputParser[method.name](result);\n };\n\n return {\n call: function (extra) {\n extra = extra || {};\n extra.to = address;\n return abi.methodSignature(desc, method.name).then(function (signature) {\n extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n return web3.eth.call(extra).then(onSuccess);\n });\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n return abi.methodSignature(desc, method.name).then(function (signature) {\n extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n return web3.eth.transact(extra).then(onSuccess);\n });\n }\n };\n };\n });\n\n return contract;\n};\n\nmodule.exports = contract;\n",
"/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httprpc.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpRpcProvider = function (host) {\n this.handlers = [];\n this.host = host;\n};\n\nfunction formatJsonRpcObject(object) {\n return {\n jsonrpc: '2.0',\n method: object.call,\n params: object.args,\n id: object._id\n };\n}\n\nfunction formatJsonRpcMessage(message) {\n var object = JSON.parse(message);\n\n return {\n _id: object.id,\n data: object.result,\n error: object.error\n };\n}\n\nHttpRpcProvider.prototype.sendRequest = function (payload, cb) {\n var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open(\"POST\", this.host, true);\n request.send(JSON.stringify(data));\n request.onreadystatechange = function () {\n if (request.readyState === 4 && cb) {\n cb(request);\n }\n };\n};\n\nHttpRpcProvider.prototype.send = function (payload) {\n var self = this;\n this.sendRequest(payload, function (request) {\n self.handlers.forEach(function (handler) {\n handler.call(self, formatJsonRpcMessage(request.responseText));\n });\n });\n};\n\nHttpRpcProvider.prototype.poll = function (payload, id) {\n var self = this;\n this.sendRequest(payload, function (request) {\n var parsed = JSON.parse(request.responseText);\n if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {\n return;\n }\n self.handlers.forEach(function (handler) {\n handler.call(self, {_event: payload.call, _id: id, data: parsed.result});\n });\n });\n};\n\nObject.defineProperty(HttpRpcProvider.prototype, \"onmessage\", {\n set: function (handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = HttpRpcProvider;\n",
"/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\n",
"/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nif (typeof(module) !== \"undefined\")\n module.exports = web3;\n",
diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js
index a0054b65e..1eae35bd3 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.min.js
+++ b/libjsqrc/ethereumjs/dist/ethereum.min.js
@@ -1 +1 @@
-require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i++)o+=r[i]/8;return o},c=function(){var t=function(t,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),i(r,2*a)}},e=function(t,e,n){return function(r,o){return r!==t?!1:i(n?n(o):o,2*e)}},n=function(t){return t?"0x1":"0x0"};return[t("uint",a),t("int",a),t("hash",a),t("string",s),t("real",u),t("ureal",u),e("address",20),e("bool",1,n)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&∋i++)o+=r[i]/8;return o},c=function(){var t=function(t){return"number"==typeof t?t.toString(16):"string"==typeof t&&0===t.indexOf("0x")?t.substr(2):"string"==typeof t?web3.toHex(t):(+t).toString(16)},e=function(e,n){return function(r,o){var a=e;if(0!==r.indexOf(a))return!1;var s=n(r,a);return s>32?!1:(s=32,"string"===e?web3.fromAscii(o,s).substr(2):i(t(o),2*s))}},n=function(t,e,n){return function(r,o){return r!==t?!1:(e=32,i(n?n(o):o,2*e))}},r=function(t){return t?"01":"00"};return[e("uint",a),e("int",a),e("hash",a),e("string",s),e("real",u),e("ureal",u),n("address",20,t),n("bool",1,r)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;s32?-1:(o=32,2*o)}},e=function(t,e){return function(n){return e=32,t===n?2*e:-1}},r=function(t){return t.length<=8?+parseInt(t,16):n(t)},o=function(t){return"0x"+t},i=function(t){return"1"===t?!0:!1},c=function(t){return web3.toAscii(t)};return[{padding:t("uint",a),format:r},{padding:t("int",a),format:r},{padding:t("hash",a),format:o},{padding:t("string",s),format:c},{padding:t("real",u),format:r},{padding:t("ureal",u),format:r},{padding:e("address",20)},{padding:e("bool",1),format:i}]},p=f(),d=function(t,e,n){var r=o(t,e);if(-1!==r){n=n.slice(2);for(var i=[],a=t[r],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&n 32)
+ return false; // not allowed to be so big.
+ padding = 32; // override as per the new ABI.
+
+ if (prefix === "string")
+ return web3.fromAscii(value, padding).substr(2);
+ return padLeft(formatStandard(value), padding * 2);
};
};
@@ -110,12 +120,14 @@ var setupInputTypes = function () {
return false;
}
+ padding = 32; //override as per the new ABI.
+
return padLeft(formatter ? formatter(value) : value, padding * 2);
};
};
var formatBool = function (value) {
- return value ? '0x1' : '0x0';
+ return value ? '01' : '00';
};
return [
@@ -125,7 +137,7 @@ var setupInputTypes = function () {
prefixedType('string', calcBytePadding),
prefixedType('real', calcRealPadding),
prefixedType('ureal', calcRealPadding),
- namedType('address', 20),
+ namedType('address', 20, formatStandard),
namedType('bool', 1, formatBool),
];
};
@@ -165,12 +177,16 @@ var setupOutputTypes = function () {
}
var padding = calcPadding(type, expected);
+ if (padding > 32)
+ return -1; // not allowed to be so big.
+ padding = 32; // override as per the new ABI.
return padding * 2;
};
};
var namedType = function (name, padding) {
return function (type) {
+ padding = 32; // override as per the new ABI.
return name === type ? padding * 2 : -1;
};
};
@@ -275,3 +291,4 @@ module.exports = {
outputParser: outputParser,
methodSignature: methodSignature
};
+
diff --git a/libjsqrc/ethereumjs/lib/contract.js b/libjsqrc/ethereumjs/lib/contract.js
index 4cb202255..eb7fbf018 100644
--- a/libjsqrc/ethereumjs/lib/contract.js
+++ b/libjsqrc/ethereumjs/lib/contract.js
@@ -57,8 +57,10 @@ var contract = function (address, desc) {
transact: function (extra) {
extra = extra || {};
extra.to = address;
- extra.data = parsed;
- return web3.eth.transact(extra).then(onSuccess);
+ return abi.methodSignature(desc, method.name).then(function (signature) {
+ extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;
+ return web3.eth.transact(extra).then(onSuccess);
+ });
}
};
};
diff --git a/libjsqrc/ethereumjs/package.json b/libjsqrc/ethereumjs/package.json
index fc34be487..b4f180d10 100644
--- a/libjsqrc/ethereumjs/package.json
+++ b/libjsqrc/ethereumjs/package.json
@@ -25,12 +25,14 @@
"jshint": ">=2.5.0",
"uglifyify": "^2.6.0",
"unreachable-branch-transform": "^0.1.0",
- "vinyl-source-stream": "^1.0.0"
+ "vinyl-source-stream": "^1.0.0",
+ "mocha": ">=2.1.0"
},
"scripts": {
"build": "gulp",
"watch": "gulp watch",
- "lint": "gulp lint"
+ "lint": "gulp lint",
+ "test": "mocha"
},
"repository": {
"type": "git",
diff --git a/libjsqrc/ethereumjs/test/abi.parsers.js b/libjsqrc/ethereumjs/test/abi.parsers.js
new file mode 100644
index 000000000..06a77fb86
--- /dev/null
+++ b/libjsqrc/ethereumjs/test/abi.parsers.js
@@ -0,0 +1,37 @@
+var assert = require('assert');
+var abi = require('../lib/abi.js');
+
+describe('abi', function() {
+ describe('inputParser', function() {
+ it('should parse ...', function() {
+
+ var desc = [{
+ "name": "multiply",
+ "inputs": [
+ {
+ "name": "a",
+ "type": "uint256"
+ }
+ ],
+ "outputs": [
+ {
+ "name": "d",
+ "type": "uint256"
+ }
+ ]
+ }];
+
+ var iParser = abi.inputParser(desc);
+ assert.equal(iParser.multiply(1), "0x000000000000000000000000000000000000000000000000000000000000000001");
+
+ });
+ });
+
+
+ describe('outputParser', function() {
+ it('parse ...', function() {
+
+ });
+ });
+});
+
diff --git a/libjsqrc/ethereumjs/test/db.methods.js b/libjsqrc/ethereumjs/test/db.methods.js
new file mode 100644
index 000000000..b4abfc4d7
--- /dev/null
+++ b/libjsqrc/ethereumjs/test/db.methods.js
@@ -0,0 +1,18 @@
+require('es6-promise').polyfill();
+
+var assert = require('assert');
+var web3 = require('../index.js');
+var u = require('./utils.js');
+web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
+
+describe('web3', function() {
+ describe('db', function() {
+ it('should have all methods implemented', function() {
+ u.methodExists(web3.db, 'put');
+ u.methodExists(web3.db, 'get');
+ u.methodExists(web3.db, 'putString');
+ u.methodExists(web3.db, 'getString');
+ });
+ });
+});
+
diff --git a/libjsqrc/ethereumjs/test/eth.methods.js b/libjsqrc/ethereumjs/test/eth.methods.js
new file mode 100644
index 000000000..7190b27d2
--- /dev/null
+++ b/libjsqrc/ethereumjs/test/eth.methods.js
@@ -0,0 +1,42 @@
+require('es6-promise').polyfill();
+
+var assert = require('assert');
+var web3 = require('../index.js');
+var u = require('./utils.js');
+web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
+
+describe('web3', function() {
+ describe('eth', function() {
+ it('should have all methods implemented', function() {
+ u.methodExists(web3.eth, 'balanceAt');
+ u.methodExists(web3.eth, 'stateAt');
+ u.methodExists(web3.eth, 'storageAt');
+ u.methodExists(web3.eth, 'countAt');
+ u.methodExists(web3.eth, 'codeAt');
+ u.methodExists(web3.eth, 'transact');
+ u.methodExists(web3.eth, 'call');
+ u.methodExists(web3.eth, 'block');
+ u.methodExists(web3.eth, 'transaction');
+ u.methodExists(web3.eth, 'uncle');
+ u.methodExists(web3.eth, 'compilers');
+ u.methodExists(web3.eth, 'lll');
+ u.methodExists(web3.eth, 'solidity');
+ u.methodExists(web3.eth, 'serpent');
+ u.methodExists(web3.eth, 'logs');
+ });
+
+ it('should have all properties implemented', function () {
+ u.propertyExists(web3.eth, 'coinbase');
+ u.propertyExists(web3.eth, 'listening');
+ u.propertyExists(web3.eth, 'mining');
+ u.propertyExists(web3.eth, 'gasPrice');
+ u.propertyExists(web3.eth, 'account');
+ u.propertyExists(web3.eth, 'accounts');
+ u.propertyExists(web3.eth, 'peerCount');
+ u.propertyExists(web3.eth, 'defaultBlock');
+ u.propertyExists(web3.eth, 'number');
+ });
+ });
+});
+
+
diff --git a/libjsqrc/ethereumjs/test/mocha.opts b/libjsqrc/ethereumjs/test/mocha.opts
new file mode 100644
index 000000000..b2db8d5a7
--- /dev/null
+++ b/libjsqrc/ethereumjs/test/mocha.opts
@@ -0,0 +1,2 @@
+--reporter Spec
+
diff --git a/libjsqrc/ethereumjs/test/shh.methods.js b/libjsqrc/ethereumjs/test/shh.methods.js
new file mode 100644
index 000000000..08f573a3c
--- /dev/null
+++ b/libjsqrc/ethereumjs/test/shh.methods.js
@@ -0,0 +1,19 @@
+require('es6-promise').polyfill();
+
+var assert = require('assert');
+var web3 = require('../index.js');
+var u = require('./utils.js');
+web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
+
+describe('web3', function() {
+ describe('shh', function() {
+ it('should have all methods implemented', function() {
+ u.methodExists(web3.shh, 'post');
+ u.methodExists(web3.shh, 'newIdentity');
+ u.methodExists(web3.shh, 'haveIdentity');
+ u.methodExists(web3.shh, 'newGroup');
+ u.methodExists(web3.shh, 'addToGroup');
+ });
+ });
+});
+
diff --git a/libjsqrc/ethereumjs/test/utils.js b/libjsqrc/ethereumjs/test/utils.js
new file mode 100644
index 000000000..4c508da67
--- /dev/null
+++ b/libjsqrc/ethereumjs/test/utils.js
@@ -0,0 +1,15 @@
+var assert = require('assert');
+
+var methodExists = function (object, method) {
+ assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented');
+};
+
+var propertyExists = function (object, property) {
+ assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented');
+};
+
+module.exports = {
+ methodExists: methodExists,
+ propertyExists: propertyExists
+};
+
diff --git a/libjsqrc/ethereumjs/test/web3.methods.js b/libjsqrc/ethereumjs/test/web3.methods.js
new file mode 100644
index 000000000..a7e020978
--- /dev/null
+++ b/libjsqrc/ethereumjs/test/web3.methods.js
@@ -0,0 +1,18 @@
+require('es6-promise').polyfill();
+
+var assert = require('assert');
+var web3 = require('../index.js');
+var u = require('./utils.js');
+web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
+
+describe('web3', function() {
+ it('should have all methods implemented', function() {
+ u.methodExists(web3, 'sha3');
+ u.methodExists(web3, 'toAscii');
+ u.methodExists(web3, 'fromAscii');
+ u.methodExists(web3, 'toFixed');
+ u.methodExists(web3, 'fromFixed');
+ u.methodExists(web3, 'offset');
+ });
+});
+
diff --git a/libjsqrc/js.qrc b/libjsqrc/js.qrc
index eee8f6652..896ab472f 100644
--- a/libjsqrc/js.qrc
+++ b/libjsqrc/js.qrc
@@ -1,7 +1,7 @@
-
-
- es6-promise-2.0.0.js
- setup.js
- ethereumjs/dist/ethereum.js
-
+
+
+ es6-promise-2.0.0.js
+ setup.js
+ ethereumjs/dist/ethereum.js
+
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index d7546bb11..f566af6e1 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -177,6 +177,7 @@ void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps)
void Host::onNodeTableEvent(NodeId _n, NodeTableEventType _e)
{
+
if (_e == NodeEntryAdded)
{
clog(NetNote) << "p2p.host.nodeTable.events.nodeEntryAdded " << _n;
@@ -360,7 +361,7 @@ string Host::pocHost()
void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPeerPort, unsigned short _udpNodePort)
{
if (_tcpPeerPort < 30300 || _tcpPeerPort > 30305)
- cwarn << "Weird port being recorded: " << _tcpPeerPort;
+ cwarn << "Non-standard port being recorded: " << _tcpPeerPort;
if (_tcpPeerPort >= /*49152*/32768)
{
@@ -464,27 +465,27 @@ unsigned PeerInfo::fallbackSeconds() const
// TODO: P2P migrate grow/prunePeers into 'maintainPeers' & evaluate reputation instead of availability. schedule via deadline timer.
//void Host::growPeers()
//{
-// RecursiveGuard l(x_sessions);
-// int morePeers = (int)m_idealPeerCount - m_sessions.size();
+// RecursiveGuard l(x_peers);
+// int morePeers = (int)m_idealPeerCount - m_peers.size();
// if (morePeers > 0)
// {
// auto toTry = m_ready;
// if (!m_netPrefs.localNetworking)
// toTry -= m_private;
-// set ns;
+// set ns;
// for (auto i: toTry)
// if (m_nodes[m_nodesList[i]]->shouldReconnect())
// ns.insert(*m_nodes[m_nodesList[i]]);
//
// if (ns.size())
-// for (PeerInfo const& i: ns)
+// for (Node const& i: ns)
// {
// connect(m_nodes[i.id]);
// if (!--morePeers)
// return;
// }
// else
-// for (auto const& i: m_sessions)
+// for (auto const& i: m_peers)
// if (auto p = i.second.lock())
// p->ensureNodesRequested();
// }
@@ -492,20 +493,20 @@ unsigned PeerInfo::fallbackSeconds() const
//
//void Host::prunePeers()
//{
-// RecursiveGuard l(x_sessions);
+// RecursiveGuard l(x_peers);
// // We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
// set dc;
-// for (unsigned old = 15000; m_sessions.size() - dc.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
-// if (m_sessions.size() - dc.size() > m_idealPeerCount)
+// for (unsigned old = 15000; m_peers.size() - dc.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
+// if (m_peers.size() - dc.size() > m_idealPeerCount)
// {
// // look for worst peer to kick off
// // first work out how many are old enough to kick off.
// shared_ptr worst;
// unsigned agedPeers = 0;
-// for (auto i: m_sessions)
+// for (auto i: m_peers)
// if (!dc.count(i.first))
// if (auto p = i.second.lock())
-// if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
+// if (chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
// {
// ++agedPeers;
// if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones
@@ -518,11 +519,11 @@ unsigned PeerInfo::fallbackSeconds() const
// }
//
// // Remove dead peers from list.
-// for (auto i = m_sessions.begin(); i != m_sessions.end();)
+// for (auto i = m_peers.begin(); i != m_peers.end();)
// if (i->second.lock().get())
// ++i;
// else
-// i = m_sessions.erase(i);
+// i = m_peers.erase(i);
//}
PeerSessionInfos Host::peers() const
diff --git a/libqethereum/CMakeLists.txt b/libqwebthree/CMakeLists.txt
similarity index 98%
rename from libqethereum/CMakeLists.txt
rename to libqwebthree/CMakeLists.txt
index 683bfec56..4de131ead 100644
--- a/libqethereum/CMakeLists.txt
+++ b/libqwebthree/CMakeLists.txt
@@ -15,7 +15,7 @@ aux_source_directory(. SRC_LIST)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(..)
-set(EXECUTABLE qethereum)
+set(EXECUTABLE qwebthree)
file(GLOB HEADERS "*.h")
diff --git a/libqethereum/QEthereum.cpp b/libqwebthree/QWebThree.cpp
similarity index 89%
rename from libqethereum/QEthereum.cpp
rename to libqwebthree/QWebThree.cpp
index daf773a22..891d84ffa 100644
--- a/libqethereum/QEthereum.cpp
+++ b/libqwebthree/QWebThree.cpp
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see .
*/
-/** @file QEthereum.cpp
+/** @file QWebThree.cpp
* @authors:
* Gav Wood
* Marek Kotewicz
@@ -22,7 +22,7 @@
*/
#include
-#include "QEthereum.h"
+#include "QWebThree.h"
using namespace std;
@@ -134,24 +134,7 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo)
if (!_addInfo.compare("internal"))
return;
- if (!_addInfo.compare("eth_changed"))
- {
- QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array();
- for (int i = 0; i < resultsArray.size(); i++)
- {
- QJsonObject elem = resultsArray[i].toObject();
- if (elem.contains("result") && elem["result"].toBool() == true)
- {
- QJsonObject res;
- res["_event"] = _addInfo;
- res["_id"] = (int)m_watches[i]; // we can do that couse poll is synchronous
- response(QString::fromUtf8(QJsonDocument(res).toJson()));
- }
- }
- return;
- }
-
- if (!_addInfo.compare("shh_changed"))
+ if (!_addInfo.compare("shh_changed") || !_addInfo.compare("eth_changed"))
{
QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array();
for (int i = 0; i < resultsArray.size(); i++)
@@ -161,13 +144,18 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo)
{
QJsonObject res;
res["_event"] = _addInfo;
- res["_id"] = (int)m_shhWatches[i];
+
+ if (!_addInfo.compare("shh_changed"))
+ res["_id"] = (int)m_shhWatches[i]; // we can do that couse poll is synchronous
+ else
+ res["_id"] = (int)m_watches[i];
+
res["data"] = elem["result"].toArray();
response(QString::fromUtf8(QJsonDocument(res).toJson()));
}
}
}
-
+
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if ((!_addInfo.compare("eth_newFilter") || !_addInfo.compare("eth_newFilterString")) && f.contains("result"))
diff --git a/libqethereum/QEthereum.h b/libqwebthree/QWebThree.h
similarity index 96%
rename from libqethereum/QEthereum.h
rename to libqwebthree/QWebThree.h
index 657986b36..b223d45d0 100644
--- a/libqethereum/QEthereum.h
+++ b/libqwebthree/QWebThree.h
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see .
*/
-/** @file QEthereum.h
+/** @file QWebThree.h
* @authors:
* Gav Wood
* Marek Kotewicz
@@ -85,7 +85,7 @@ private:
_frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \
- _frame->evaluateJavaScript(contentsOfQResource(":/js/ethereum.js")); \
+ _frame->evaluateJavaScript(contentsOfQResource(":/js/webthree.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \
}
diff --git a/libserpent/rewriteutils.cpp b/libserpent/rewriteutils.cpp
old mode 100644
new mode 100755
index e6429434a..7296a5e27
--- a/libserpent/rewriteutils.cpp
+++ b/libserpent/rewriteutils.cpp
@@ -54,7 +54,7 @@ bool isValidFunctionName(std::string f) {
vfMap[validFunctions[i][0]] = true;
}
}
- return vfMap.count(f);
+ return vfMap.count(f) != 0;
}
// Cool function for debug purposes (named cerrStringList to make
diff --git a/libserpent/util.cpp b/libserpent/util.cpp
old mode 100644
new mode 100755
index 4b99a5ea5..18a8bafc2
--- a/libserpent/util.cpp
+++ b/libserpent/util.cpp
@@ -260,7 +260,7 @@ std::string get_file_contents(std::string filename)
{
std::string contents;
in.seekg(0, std::ios::end);
- contents.resize(in.tellg());
+ contents.resize((unsigned)in.tellg());
in.seekg(0, std::ios::beg);
in.read(&contents[0], contents.size());
in.close();
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index d171006a8..7b6335645 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -50,18 +50,27 @@ void ContractDefinition::checkTypeRequirements()
for (ASTPointer const& function: getDefinedFunctions())
function->checkTypeRequirements();
+
+ // check for hash collisions in function signatures
+ vector, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList();
+ set> hashes;
+ for (auto const& hashAndFunction: getInterfaceFunctionList())
+ {
+ FixedHash<4> const& hash = hashAndFunction.first;
+ if (hashes.count(hash))
+ BOOST_THROW_EXCEPTION(createTypeError("Function signature hash collision for " +
+ hashAndFunction.second->getCanonicalSignature()));
+ hashes.insert(hash);
+ }
}
map, FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const
{
- map, FunctionDefinition const*> exportedFunctions;
- for (ASTPointer const& f: m_definedFunctions)
- if (f->isPublic() && f->getName() != getName())
- {
- FixedHash<4> hash(dev::sha3(f->getCanonicalSignature()));
- auto res = exportedFunctions.insert(std::make_pair(hash,f.get()));
- solAssert(res.second, "Hash collision at Function Definition Hash calculation");
- }
+ vector, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList();
+ map, FunctionDefinition const*> exportedFunctions(exportedFunctionList.begin(),
+ exportedFunctionList.end());
+ solAssert(exportedFunctionList.size() == exportedFunctions.size(),
+ "Hash collision at Function Definition Hash calculation");
return exportedFunctions;
}
@@ -74,6 +83,19 @@ FunctionDefinition const* ContractDefinition::getConstructor() const
return nullptr;
}
+vector, FunctionDefinition const*>> ContractDefinition::getInterfaceFunctionList() const
+{
+ vector, FunctionDefinition const*>> exportedFunctions;
+ for (ASTPointer const& f: m_definedFunctions)
+ if (f->isPublic() && f->getName() != getName())
+ {
+ FixedHash<4> hash(dev::sha3(f->getCanonicalSignature()));
+ exportedFunctions.push_back(make_pair(hash, f.get()));
+ }
+
+ return exportedFunctions;
+}
+
void StructDefinition::checkMemberTypes() const
{
for (ASTPointer const& member: getMembers())
@@ -309,20 +331,13 @@ bool FunctionCall::isTypeConversion() const
void NewExpression::checkTypeRequirements()
{
m_contractName->checkTypeRequirements();
- for (ASTPointer const& argument: m_arguments)
- argument->checkTypeRequirements();
-
m_contract = dynamic_cast(m_contractName->getReferencedDeclaration());
if (!m_contract)
BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract."));
- shared_ptr type = make_shared(*m_contract);
- m_type = type;
- TypePointers const& parameterTypes = type->getConstructorType()->getParameterTypes();
- if (parameterTypes.size() != m_arguments.size())
- BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call."));
- for (size_t i = 0; i < m_arguments.size(); ++i)
- if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
- BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in constructor call."));
+ shared_ptr contractType = make_shared(*m_contract);
+ TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes();
+ m_type = make_shared(parameterTypes, TypePointers{contractType},
+ FunctionType::Location::CREATION);
}
void MemberAccess::checkTypeRequirements()
diff --git a/libsolidity/AST.h b/libsolidity/AST.h
old mode 100644
new mode 100755
index 95121d4cb..409aed443
--- a/libsolidity/AST.h
+++ b/libsolidity/AST.h
@@ -191,6 +191,8 @@ public:
FunctionDefinition const* getConstructor() const;
private:
+ std::vector, FunctionDefinition const*>> getInterfaceFunctionList() const;
+
std::vector> m_definedStructs;
std::vector> m_stateVariables;
std::vector> m_definedFunctions;
@@ -790,26 +792,22 @@ private:
};
/**
- * Expression that creates a new contract, e.g. "new SomeContract(1, 2)".
+ * Expression that creates a new contract, e.g. the "new SomeContract" part in "new SomeContract(1, 2)".
*/
class NewExpression: public Expression
{
public:
- NewExpression(Location const& _location, ASTPointer const& _contractName,
- std::vector> const& _arguments):
- Expression(_location), m_contractName(_contractName), m_arguments(_arguments) {}
+ NewExpression(Location const& _location, ASTPointer const& _contractName):
+ Expression(_location), m_contractName(_contractName) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- std::vector> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
-
/// Returns the referenced contract. Can only be called after type checking.
ContractDefinition const* getContract() const { solAssert(m_contract, ""); return m_contract; }
private:
ASTPointer m_contractName;
- std::vector> m_arguments;
ContractDefinition const* m_contract = nullptr;
};
diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h
index 0e5a71b62..7f3db85a1 100644
--- a/libsolidity/AST_accept.h
+++ b/libsolidity/AST_accept.h
@@ -452,20 +452,14 @@ void FunctionCall::accept(ASTConstVisitor& _visitor) const
void NewExpression::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
- {
m_contractName->accept(_visitor);
- listAccept(m_arguments, _visitor);
- }
_visitor.endVisit(*this);
}
void NewExpression::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
- {
m_contractName->accept(_visitor);
- listAccept(m_arguments, _visitor);
- }
_visitor.endVisit(*this);
}
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index 4e5b7f558..782a7efe2 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -95,7 +95,7 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
// copy constructor arguments from code to memory and then to stack, they are supplied after the actual program
unsigned argumentSize = 0;
for (ASTPointer const& var: _constructor.getParameters())
- argumentSize += var->getType()->getCalldataEncodedSize();
+ argumentSize += CompilerUtils::getPaddedSize(var->getType()->getCalldataEncodedSize());
if (argumentSize > 0)
{
m_context << u256(argumentSize);
@@ -154,14 +154,15 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b
//@todo this can be done more efficiently, saving some CALLDATALOAD calls
for (ASTPointer const& var: _function.getParameters())
{
- unsigned const numBytes = var->getType()->getCalldataEncodedSize();
- if (numBytes > 32)
+ unsigned const c_numBytes = var->getType()->getCalldataEncodedSize();
+ if (c_numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
- bool leftAligned = var->getType()->getCategory() == Type::Category::STRING;
- CompilerUtils(m_context).loadFromMemory(dataOffset, numBytes, leftAligned, !_fromMemory);
- dataOffset += numBytes;
+ bool const c_leftAligned = var->getType()->getCategory() == Type::Category::STRING;
+ bool const c_padToWords = true;
+ dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned,
+ !_fromMemory, c_padToWords);
}
return dataOffset;
}
@@ -181,10 +182,11 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
<< errinfo_sourceLocation(parameters[i]->getLocation())
<< errinfo_comment("Type " + paramType.toString() + " not yet supported."));
CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
- bool const leftAligned = paramType.getCategory() == Type::Category::STRING;
- CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned);
+ ExpressionCompiler::appendTypeConversion(m_context, paramType, paramType, true);
+ bool const c_leftAligned = paramType.getCategory() == Type::Category::STRING;
+ bool const c_padToWords = true;
+ dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, c_leftAligned, c_padToWords);
stackDepth -= paramType.getSizeOnStack();
- dataOffset += numBytes;
}
// note that the stack is not cleaned up here
m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN;
@@ -230,16 +232,16 @@ bool Compiler::visit(FunctionDefinition const& _function)
// Note that the fact that the return arguments are of increasing index is vital for this
// algorithm to work.
- unsigned const argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters());
- unsigned const returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters());
- unsigned const localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables());
+ unsigned const c_argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters());
+ unsigned const c_returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters());
+ unsigned const c_localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables());
vector stackLayout;
- stackLayout.push_back(returnValuesSize); // target of return address
- stackLayout += vector(argumentsSize, -1); // discard all arguments
- for (unsigned i = 0; i < returnValuesSize; ++i)
+ stackLayout.push_back(c_returnValuesSize); // target of return address
+ stackLayout += vector(c_argumentsSize, -1); // discard all arguments
+ for (unsigned i = 0; i < c_returnValuesSize; ++i)
stackLayout.push_back(i);
- stackLayout += vector(localVariablesSize, -1);
+ stackLayout += vector(c_localVariablesSize, -1);
while (stackLayout.back() != int(stackLayout.size() - 1))
if (stackLayout.back() < 0)
diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp
index 18357bf0c..29e98eabf 100644
--- a/libsolidity/CompilerContext.cpp
+++ b/libsolidity/CompilerContext.cpp
@@ -53,8 +53,8 @@ void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _decla
{
addVariable(_declaration);
- unsigned const size = _declaration.getType()->getSizeOnStack();
- for (unsigned i = 0; i < size; ++i)
+ int const size = _declaration.getType()->getSizeOnStack();
+ for (int i = 0; i < size; ++i)
*this << u256(0);
m_asm.adjustDeposit(-size);
}
@@ -95,6 +95,11 @@ unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
return _baseOffset + m_asm.deposit();
}
+unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
+{
+ return -baseToCurrentStackOffset(-_offset);
+}
+
u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const
{
auto it = m_stateVariables.find(&_declaration);
diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h
index 795f447ab..cf505d654 100644
--- a/libsolidity/CompilerContext.h
+++ b/libsolidity/CompilerContext.h
@@ -51,10 +51,10 @@ public:
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
- bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration); }
- bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); }
+ bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; }
+ bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration) != 0; }
bool isLocalVariable(Declaration const* _declaration) const;
- bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); }
+ bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration) != 0; }
eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const;
/// Returns the distance of the given local variable from the top of the local variable stack.
@@ -62,6 +62,9 @@ public:
/// If supplied by a value returned by @ref getBaseStackOffsetOfVariable(variable), returns
/// the distance of that variable from the current top of the stack.
unsigned baseToCurrentStackOffset(unsigned _baseOffset) const;
+ /// Converts an offset relative to the current stack height to a value that can be used later
+ /// with baseToCurrentStackOffset to point to the same stack element.
+ unsigned currentToBaseStackOffset(unsigned _offset) const;
u256 getStorageLocationOfVariable(Declaration const& _declaration) const;
/// Appends a JUMPI instruction to a new tag and @returns the tag
diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp
index 174f9cd22..904c77c5a 100644
--- a/libsolidity/CompilerStack.cpp
+++ b/libsolidity/CompilerStack.cpp
@@ -39,7 +39,7 @@ namespace solidity
bool CompilerStack::addSource(string const& _name, string const& _content)
{
- bool existed = m_sources.count(_name);
+ bool existed = m_sources.count(_name) != 0;
reset(true);
m_sources[_name].scanner = make_shared(CharStream(_content), _name);
return existed;
diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp
index a5254b421..3101c1b44 100644
--- a/libsolidity/CompilerUtils.cpp
+++ b/libsolidity/CompilerUtils.cpp
@@ -33,17 +33,21 @@ namespace solidity
const unsigned int CompilerUtils::dataStartOffset = 4;
-void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, bool _fromCalldata)
+unsigned CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned,
+ bool _fromCalldata, bool _padToWordBoundaries)
{
if (_bytes == 0)
{
m_context << u256(0);
- return;
+ return 0;
}
eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD;
solAssert(_bytes <= 32, "Memory load of more than 32 bytes requested.");
- if (_bytes == 32)
+ if (_bytes == 32 || _padToWordBoundaries)
+ {
m_context << u256(_offset) << load;
+ return 32;
+ }
else
{
// load data and add leading or trailing zeros by dividing/multiplying depending on alignment
@@ -54,21 +58,24 @@ void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _left
m_context << u256(_offset) << load << eth::Instruction::DIV;
if (_leftAligned)
m_context << eth::Instruction::MUL;
+ return _bytes;
}
}
-void CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned)
+unsigned CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned,
+ bool _padToWordBoundaries)
{
if (_bytes == 0)
{
m_context << eth::Instruction::POP;
- return;
+ return 0;
}
solAssert(_bytes <= 32, "Memory store of more than 32 bytes requested.");
- if (_bytes != 32 && !_leftAligned)
+ if (_bytes != 32 && !_leftAligned && !_padToWordBoundaries)
// shift the value accordingly before storing
m_context << (u256(1) << ((32 - _bytes) * 8)) << eth::Instruction::MUL;
m_context << u256(_offset) << eth::Instruction::MSTORE;
+ return _padToWordBoundaries ? 32 : _bytes;
}
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h
index 6bd8d3155..b5a695282 100644
--- a/libsolidity/CompilerUtils.h
+++ b/libsolidity/CompilerUtils.h
@@ -40,12 +40,23 @@ public:
/// @param _bytes number of bytes to load
/// @param _leftAligned if true, store left aligned on stack (otherwise right aligned)
/// @param _fromCalldata if true, load from calldata, not from memory
- void loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, bool _fromCalldata = false);
+ /// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries
+ /// @returns the number of bytes consumed in memory (can be different from _bytes if
+ /// _padToWordBoundaries is true)
+ unsigned loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false,
+ bool _fromCalldata = false, bool _padToWordBoundaries = false);
/// Stores data from stack in memory.
/// @param _offset offset in memory
/// @param _bytes number of bytes to store
/// @param _leftAligned if true, data is left aligned on stack (otherwise right aligned)
- void storeInMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false);
+ /// @param _padToWordBoundaries if true, pad the data to word (32 byte) boundaries
+ /// @returns the number of bytes written to memory (can be different from _bytes if
+ /// _padToWordBoundaries is true)
+ unsigned storeInMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false,
+ bool _padToWordBoundaries = false);
+ /// @returns _size rounded up to the next multiple of 32 (the number of bytes occupied in the
+ /// padded calldata)
+ static unsigned getPaddedSize(unsigned _size) { return ((_size + 31) / 32) * 32; }
/// Moves the value that is at the top of the stack to a stack variable.
void moveToStackVariable(VariableDeclaration const& _variable);
diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp
index 5667098db..bcb577374 100644
--- a/libsolidity/ExpressionCompiler.cpp
+++ b/libsolidity/ExpressionCompiler.cpp
@@ -41,11 +41,11 @@ void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression
_expression.accept(compiler);
}
-void ExpressionCompiler::appendTypeConversion(CompilerContext& _context,
- Type const& _typeOnStack, Type const& _targetType)
+void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack,
+ Type const& _targetType, bool _cleanupNeeded)
{
ExpressionCompiler compiler(_context);
- compiler.appendTypeConversion(_typeOnStack, _targetType);
+ compiler.appendTypeConversion(_typeOnStack, _targetType, _cleanupNeeded);
}
bool ExpressionCompiler::visit(Assignment const& _assignment)
@@ -144,23 +144,23 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
Expression const& leftExpression = _binaryOperation.getLeftExpression();
Expression const& rightExpression = _binaryOperation.getRightExpression();
Type const& commonType = _binaryOperation.getCommonType();
- Token::Value const op = _binaryOperation.getOperator();
+ Token::Value const c_op = _binaryOperation.getOperator();
- if (op == Token::AND || op == Token::OR) // special case: short-circuiting
+ if (c_op == Token::AND || c_op == Token::OR) // special case: short-circuiting
appendAndOrOperatorCode(_binaryOperation);
else if (commonType.getCategory() == Type::Category::INTEGER_CONSTANT)
m_context << commonType.literalValue(nullptr);
else
{
bool cleanupNeeded = commonType.getCategory() == Type::Category::INTEGER &&
- (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD);
+ (Token::isCompareOp(c_op) || c_op == Token::DIV || c_op == Token::MOD);
// for commutative operators, push the literal as late as possible to allow improved optimization
auto isLiteral = [](Expression const& _e)
{
return dynamic_cast(&_e) || _e.getType()->getCategory() == Type::Category::INTEGER_CONSTANT;
};
- bool swap = m_optimize && Token::isCommutativeOp(op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
+ bool swap = m_optimize && Token::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
if (swap)
{
leftExpression.accept(*this);
@@ -175,10 +175,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
}
- if (Token::isCompareOp(op))
- appendCompareOperatorCode(op, commonType);
+ if (Token::isCompareOp(c_op))
+ appendCompareOperatorCode(c_op, commonType);
else
- appendOrdinaryBinaryOperatorCode(op, commonType);
+ appendOrdinaryBinaryOperatorCode(c_op, commonType);
}
// do not visit the child nodes, we already did that explicitly
@@ -194,13 +194,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert(_functionCall.getArguments().size() == 1, "");
Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this);
- if (firstArgument.getType()->getCategory() == Type::Category::CONTRACT &&
- _functionCall.getType()->getCategory() == Type::Category::INTEGER)
- {
- // explicit type conversion contract -> address, nothing to do.
- }
- else
- appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
+ appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
}
else
{
@@ -238,25 +232,73 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
}
case Location::EXTERNAL:
case Location::BARE:
+ _functionCall.getExpression().accept(*this);
+ appendExternalFunctionCall(function, arguments, function.getLocation() == Location::BARE);
+ break;
+ case Location::CREATION:
{
- FunctionCallOptions options;
- options.bare = function.getLocation() == Location::BARE;
- options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); };
- appendExternalFunctionCall(function, arguments, options);
+ _functionCall.getExpression().accept(*this);
+ solAssert(!function.gasSet(), "Gas limit set for contract creation.");
+ solAssert(function.getReturnParameterTypes().size() == 1, "");
+ ContractDefinition const& contract = dynamic_cast(
+ *function.getReturnParameterTypes().front()).getContractDefinition();
+ // copy the contract's code into memory
+ bytes const& bytecode = m_context.getCompiledContract(contract);
+ m_context << u256(bytecode.size());
+ //@todo could be done by actually appending the Assembly, but then we probably need to compile
+ // multiple times. Will revisit once external fuctions are inlined.
+ m_context.appendData(bytecode);
+ //@todo copy to memory position 0, shift as soon as we use memory
+ m_context << u256(0) << eth::Instruction::CODECOPY;
+
+ unsigned length = bytecode.size();
+ length += appendArgumentCopyToMemory(function.getParameterTypes(), arguments, length);
+ // size, offset, endowment
+ m_context << u256(length) << u256(0);
+ if (function.valueSet())
+ m_context << eth::dupInstruction(3);
+ else
+ m_context << u256(0);
+ m_context << eth::Instruction::CREATE;
+ if (function.valueSet())
+ m_context << eth::swapInstruction(1) << eth::Instruction::POP;
break;
}
- case Location::SEND:
+ case Location::SET_GAS:
{
- FunctionCallOptions options;
- options.bare = true;
- options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); };
- options.obtainValue = [&]() { arguments.front()->accept(*this); };
- appendExternalFunctionCall(FunctionType({}, {}, Location::EXTERNAL), {}, options);
+ // stack layout: contract_address function_id [gas] [value]
+ _functionCall.getExpression().accept(*this);
+ arguments.front()->accept(*this);
+ appendTypeConversion(*arguments.front()->getType(), IntegerType(256), true);
+ // Note that function is not the original function, but the ".gas" function.
+ // Its values of gasSet and valueSet is equal to the original function's though.
+ unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
+ if (stackDepth > 0)
+ m_context << eth::swapInstruction(stackDepth);
+ if (function.gasSet())
+ m_context << eth::Instruction::POP;
break;
}
+ case Location::SET_VALUE:
+ // stack layout: contract_address function_id [gas] [value]
+ _functionCall.getExpression().accept(*this);
+ // Note that function is not the original function, but the ".value" function.
+ // Its values of gasSet and valueSet is equal to the original function's though.
+ if (function.valueSet())
+ m_context << eth::Instruction::POP;
+ arguments.front()->accept(*this);
+ break;
+ case Location::SEND:
+ _functionCall.getExpression().accept(*this);
+ m_context << u256(0); // 0 gas, we do not want to execute code
+ arguments.front()->accept(*this);
+ appendTypeConversion(*arguments.front()->getType(),
+ *function.getParameterTypes().front(), true);
+ appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{},
+ Location::EXTERNAL, true, true), {}, true);
+ break;
case Location::SUICIDE:
arguments.front()->accept(*this);
- //@todo might not be necessary
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true);
m_context << eth::Instruction::SUICIDE;
break;
@@ -291,12 +333,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
static const map contractAddresses{{Location::ECRECOVER, 1},
{Location::SHA256, 2},
{Location::RIPEMD160, 3}};
- u256 contractAddress = contractAddresses.find(function.getLocation())->second;
- FunctionCallOptions options;
- options.bare = true;
- options.obtainAddress = [&]() { m_context << contractAddress; };
- options.packDensely = false;
- appendExternalFunctionCall(function, arguments, options);
+ m_context << contractAddresses.find(function.getLocation())->second;
+ appendExternalFunctionCall(function, arguments, true);
break;
}
default:
@@ -308,37 +346,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
bool ExpressionCompiler::visit(NewExpression const& _newExpression)
{
- ContractType const* type = dynamic_cast(_newExpression.getType().get());
- solAssert(type, "");
- TypePointers const& types = type->getConstructorType()->getParameterTypes();
- vector> arguments = _newExpression.getArguments();
- solAssert(arguments.size() == types.size(), "");
-
- // copy the contracts code into memory
- bytes const& bytecode = m_context.getCompiledContract(*_newExpression.getContract());
- m_context << u256(bytecode.size());
- //@todo could be done by actually appending the Assembly, but then we probably need to compile
- // multiple times. Will revisit once external fuctions are inlined.
- m_context.appendData(bytecode);
- //@todo copy to memory position 0, shift as soon as we use memory
- m_context << u256(0) << eth::Instruction::CODECOPY;
-
- unsigned dataOffset = bytecode.size();
- for (unsigned i = 0; i < arguments.size(); ++i)
- {
- arguments[i]->accept(*this);
- appendTypeConversion(*arguments[i]->getType(), *types[i]);
- unsigned const numBytes = types[i]->getCalldataEncodedSize();
- if (numBytes > 32)
- BOOST_THROW_EXCEPTION(CompilerError()
- << errinfo_sourceLocation(arguments[i]->getLocation())
- << errinfo_comment("Type " + types[i]->toString() + " not yet supported."));
- bool const leftAligned = types[i]->getCategory() == Type::Category::STRING;
- CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned);
- dataOffset += numBytes;
- }
- // size, offset, endowment
- m_context << u256(dataOffset) << u256(0) << u256(0) << eth::Instruction::CREATE;
+ // code is created for the function call (CREATION) only
return false;
}
@@ -347,6 +355,18 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
ASTString const& member = _memberAccess.getMemberName();
switch (_memberAccess.getExpression().getType()->getCategory())
{
+ case Type::Category::CONTRACT:
+ {
+ ContractType const& type = dynamic_cast(*_memberAccess.getExpression().getType());
+ u256 identifier = type.getFunctionIdentifier(member);
+ if (identifier != Invalid256)
+ {
+ appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true);
+ m_context << identifier;
+ break;
+ }
+ // fall-through to "integer" otherwise (address)
+ }
case Type::Category::INTEGER:
if (member == "balance")
{
@@ -360,12 +380,10 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
break;
- case Type::Category::CONTRACT:
- {
- ContractType const& type = dynamic_cast(*_memberAccess.getExpression().getType());
- m_context << type.getFunctionIdentifier(member);
+ case Type::Category::FUNCTION:
+ solAssert(!!_memberAccess.getExpression().getType()->getMemberType(member),
+ "Invalid member access to function.");
break;
- }
case Type::Category::MAGIC:
// we can ignore the kind of magic and only look at the name of the member
if (member == "coinbase")
@@ -463,12 +481,12 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation)
{
- Token::Value const op = _binaryOperation.getOperator();
- solAssert(op == Token::OR || op == Token::AND, "");
+ Token::Value const c_op = _binaryOperation.getOperator();
+ solAssert(c_op == Token::OR || c_op == Token::AND, "");
_binaryOperation.getLeftExpression().accept(*this);
m_context << eth::Instruction::DUP1;
- if (op == Token::AND)
+ if (c_op == Token::AND)
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem endLabel = m_context.appendConditionalJump();
m_context << eth::Instruction::POP;
@@ -487,23 +505,23 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
else
{
IntegerType const& type = dynamic_cast(_type);
- bool const isSigned = type.isSigned();
+ bool const c_isSigned = type.isSigned();
switch (_operator)
{
case Token::GTE:
- m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT)
+ m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT)
<< eth::Instruction::ISZERO;
break;
case Token::LTE:
- m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT)
+ m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT)
<< eth::Instruction::ISZERO;
break;
case Token::GT:
- m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
+ m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
break;
case Token::LT:
- m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
+ m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator."));
@@ -526,7 +544,7 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator
void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type)
{
IntegerType const& type = dynamic_cast(_type);
- bool const isSigned = type.isSigned();
+ bool const c_isSigned = type.isSigned();
switch (_operator)
{
@@ -540,10 +558,10 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
m_context << eth::Instruction::MUL;
break;
case Token::DIV:
- m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV);
+ m_context << (c_isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV);
break;
case Token::MOD:
- m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
+ m_context << (c_isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator."));
@@ -592,15 +610,36 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
return;
Type::Category stackTypeCategory = _typeOnStack.getCategory();
Type::Category targetTypeCategory = _targetType.getCategory();
- if (stackTypeCategory == Type::Category::INTEGER)
+ if (stackTypeCategory == Type::Category::INTEGER || stackTypeCategory == Type::Category::CONTRACT ||
+ stackTypeCategory == Type::Category::INTEGER_CONSTANT)
{
solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
- appendHighBitsCleanup(dynamic_cast(_typeOnStack));
+ IntegerType addressType(0, IntegerType::Modifier::ADDRESS);
+ IntegerType const& targetType = targetTypeCategory == Type::Category::INTEGER
+ ? dynamic_cast(_targetType) : addressType;
+ if (stackTypeCategory == Type::Category::INTEGER_CONSTANT)
+ {
+ IntegerConstantType const& constType = dynamic_cast(_typeOnStack);
+ // We know that the stack is clean, we only have to clean for a narrowing conversion
+ // where cleanup is forced.
+ if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded)
+ appendHighBitsCleanup(targetType);
+ }
+ else
+ {
+ IntegerType const& typeOnStack = stackTypeCategory == Type::Category::INTEGER
+ ? dynamic_cast(_typeOnStack) : addressType;
+ // Widening: clean up according to source type width
+ // Non-widening and force: clean up according to target type bits
+ if (targetType.getNumBits() > typeOnStack.getNumBits())
+ appendHighBitsCleanup(typeOnStack);
+ else if (_cleanupNeeded)
+ appendHighBitsCleanup(targetType);
+ }
}
- else if (stackTypeCategory == Type::Category::INTEGER_CONSTANT)
- solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
else if (stackTypeCategory == Type::Category::STRING)
{
+ solAssert(targetTypeCategory == Type::Category::STRING, "");
// nothing to do, strings are high-order-bit-aligned
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings
}
@@ -621,53 +660,88 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)
void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functionType,
vector> const& _arguments,
- FunctionCallOptions const& _options)
+ bool bare)
{
solAssert(_arguments.size() == _functionType.getParameterTypes().size(), "");
- _options.obtainAddress();
- if (!_options.bare)
- CompilerUtils(m_context).storeInMemory(0, CompilerUtils::dataStartOffset);
+ // Assumed stack content here:
+ //
+ // value [if _functionType.valueSet()]
+ // gas [if _functionType.gasSet()]
+ // function identifier [unless bare]
+ // contract address
- unsigned dataOffset = _options.bare ? 0 : CompilerUtils::dataStartOffset; // reserve 4 bytes for the function's hash identifier
- for (unsigned i = 0; i < _arguments.size(); ++i)
+ unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0);
+
+ unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + (bare ? 0 : 1));
+ unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
+ unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
+
+ if (!bare)
{
- _arguments[i]->accept(*this);
- Type const& type = *_functionType.getParameterTypes()[i];
- appendTypeConversion(*_arguments[i]->getType(), type);
- unsigned const numBytes = _options.packDensely ? type.getCalldataEncodedSize() : 32;
- if (numBytes == 0 || numBytes > 32)
- BOOST_THROW_EXCEPTION(CompilerError()
- << errinfo_sourceLocation(_arguments[i]->getLocation())
- << errinfo_comment("Type " + type.toString() + " not yet supported."));
- bool const leftAligned = type.getCategory() == Type::Category::STRING;
- CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned);
- dataOffset += numBytes;
+ // copy function identifier
+ m_context << eth::dupInstruction(gasValueSize + 1);
+ CompilerUtils(m_context).storeInMemory(0, CompilerUtils::dataStartOffset);
}
+
+ // reserve space for the function identifier
+ unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset;
+ dataOffset += appendArgumentCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset);
+
//@todo only return the first return value for now
Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr :
_functionType.getReturnParameterTypes().front().get();
- unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
- if (!_options.packDensely && retSize > 0)
- retSize = 32;
+ unsigned retSize = firstType ? CompilerUtils::getPaddedSize(firstType->getCalldataEncodedSize()) : 0;
// CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top)
m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0);
- if (_options.obtainValue)
- _options.obtainValue();
+ if (_functionType.valueSet())
+ m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos));
else
m_context << u256(0);
- m_context << eth::dupInstruction(6); //copy contract address
+ m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos));
- m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB
- << eth::Instruction::CALL
- << eth::Instruction::POP // @todo do not ignore failure indicator
- << eth::Instruction::POP; // pop contract address
+ if (_functionType.gasSet())
+ m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
+ else
+ // send all gas except for the 21 needed to execute "SUB" and "CALL"
+ m_context << u256(21) << eth::Instruction::GAS << eth::Instruction::SUB;
+ m_context << eth::Instruction::CALL
+ << eth::Instruction::POP; // @todo do not ignore failure indicator
+ if (_functionType.valueSet())
+ m_context << eth::Instruction::POP;
+ if (_functionType.gasSet())
+ m_context << eth::Instruction::POP;
+ if (!bare)
+ m_context << eth::Instruction::POP;
+ m_context << eth::Instruction::POP; // pop contract address
if (retSize > 0)
{
- bool const leftAligned = firstType->getCategory() == Type::Category::STRING;
- CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned);
+ bool const c_leftAligned = firstType->getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).loadFromMemory(0, retSize, c_leftAligned, false, true);
+ }
+}
+
+unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _types,
+ vector> const& _arguments,
+ unsigned _memoryOffset)
+{
+ unsigned length = 0;
+ for (unsigned i = 0; i < _arguments.size(); ++i)
+ {
+ _arguments[i]->accept(*this);
+ appendTypeConversion(*_arguments[i]->getType(), *_types[i], true);
+ unsigned const c_numBytes = _types[i]->getCalldataEncodedSize();
+ if (c_numBytes == 0 || c_numBytes > 32)
+ BOOST_THROW_EXCEPTION(CompilerError()
+ << errinfo_sourceLocation(_arguments[i]->getLocation())
+ << errinfo_comment("Type " + _types[i]->toString() + " not yet supported."));
+ bool const c_leftAligned = _types[i]->getCategory() == Type::Category::STRING;
+ bool const c_padToWords = true;
+ length += CompilerUtils(m_context).storeInMemory(_memoryOffset + length, c_numBytes,
+ c_leftAligned, c_padToWords);
}
+ return length;
}
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,
diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h
index abd7f7750..4a696c39d 100644
--- a/libsolidity/ExpressionCompiler.h
+++ b/libsolidity/ExpressionCompiler.h
@@ -51,7 +51,8 @@ public:
static void compileExpression(CompilerContext& _context, Expression const& _expression, bool _optimize = false);
/// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type.
- static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType);
+ static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack,
+ Type const& _targetType, bool _cleanupNeeded = false);
private:
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false):
@@ -86,24 +87,13 @@ private:
//// Appends code that cleans higher-order bits for integer types.
void appendHighBitsCleanup(IntegerType const& _typeOnStack);
- /// Additional options used in appendExternalFunctionCall.
- struct FunctionCallOptions
- {
- FunctionCallOptions() {}
- /// Invoked to copy the address to the stack
- std::function obtainAddress;
- /// Invoked to copy the ethe value to the stack (if not specified, value is 0).
- std::function obtainValue;
- /// If true, do not prepend function index to call data
- bool bare = false;
- /// If false, use calling convention that all arguments and return values are packed as
- /// 32 byte values with padding.
- bool packDensely = true;
- };
-
/// Appends code to call a function of the given type with the given arguments.
void appendExternalFunctionCall(FunctionType const& _functionType, std::vector> const& _arguments,
- FunctionCallOptions const& _options = FunctionCallOptions());
+ bool bare = false);
+ /// Appends code that copies the given arguments to memory (with optional offset).
+ /// @returns the number of bytes copied to memory
+ unsigned appendArgumentCopyToMemory(TypePointers const& _functionType, std::vector> const& _arguments,
+ unsigned _memoryOffset = 0);
/**
* Helper class to store and retrieve lvalues to and from various locations.
diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp
index 633331a90..92ca9548a 100644
--- a/libsolidity/GlobalContext.cpp
+++ b/libsolidity/GlobalContext.cpp
@@ -34,54 +34,29 @@ namespace solidity
{
GlobalContext::GlobalContext():
-// TODO: make this cleaner.
m_magicVariables(vector>{make_shared("block", make_shared(MagicType::Kind::BLOCK)),
make_shared("msg", make_shared(MagicType::Kind::MSG)),
make_shared("tx", make_shared(MagicType::Kind::TX)),
make_shared("suicide",
- make_shared(TypePointers({std::make_shared(0,
- IntegerType::Modifier::ADDRESS)}),
- TypePointers(),
- FunctionType::Location::SUICIDE)),
+ make_shared(strings{"address"}, strings{}, FunctionType::Location::SUICIDE)),
make_shared("sha3",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}),
- TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}),
- FunctionType::Location::SHA3)),
+ make_shared(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA3)),
make_shared("log0",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}),
- TypePointers(),
- FunctionType::Location::LOG0)),
+ make_shared(strings{"hash"},strings{}, FunctionType::Location::LOG0)),
make_shared("log1",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}),
- TypePointers(),
- FunctionType::Location::LOG1)),
+ make_shared(strings{"hash", "hash"},strings{}, FunctionType::Location::LOG1)),
make_shared("log2",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}),
- TypePointers(),
- FunctionType::Location::LOG2)),
+ make_shared(strings{"hash", "hash", "hash"},strings{}, FunctionType::Location::LOG2)),
make_shared("log3",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}),
- TypePointers(),
- FunctionType::Location::LOG3)),
+ make_shared(strings{"hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::LOG3)),
make_shared("log4",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}),
- TypePointers(),
- FunctionType::Location::LOG4)),
+ make_shared(strings{"hash", "hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::LOG4)),
make_shared("sha256",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}),
- TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}),
- FunctionType::Location::SHA256)),
+ make_shared(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA256)),
make_shared("ecrecover",
- make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH),
- std::make_shared