> altCoins;
+ Address coinsAddr = getCurrencies();
for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, 0); ++i)
{
auto n = ethereum()->stateAt(coinsAddr, i + 1);
@@ -872,7 +893,7 @@ void Main::refreshBalances()
denom = 1;
// cdebug << n << addr << denom << sha3(h256(n).asBytes());
altCoins[addr] = make_tuple(fromRaw(n), 0, denom);
- }
+ }*/
for (auto i: m_myKeys)
{
u256 b = ethereum()->balanceAt(i.address());
@@ -880,18 +901,18 @@ void Main::refreshBalances()
->setData(Qt::UserRole, QByteArray((char const*)i.address().data(), Address::size));
totalBalance += b;
- for (auto& c: altCoins)
- get<1>(c.second) += (u256)ethereum()->stateAt(c.first, (u160)i.address());
+// for (auto& c: altCoins)
+// get<1>(c.second) += (u256)ethereum()->stateAt(c.first, (u160)i.address());
}
QString b;
- for (auto const& c: altCoins)
+/* for (auto const& c: altCoins)
if (get<1>(c.second))
{
stringstream s;
s << setw(toString(get<2>(c.second) - 1).size()) << setfill('0') << (get<1>(c.second) % get<2>(c.second));
b += QString::fromStdString(toString(get<1>(c.second) / get<2>(c.second)) + "." + s.str() + " ") + get<0>(c.second).toUpper() + " | ";
- }
+ }*/
ui->balance->setText(b + QString::fromStdString(formatBalance(totalBalance)));
}
@@ -1150,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
@@ -1224,6 +1248,7 @@ void Main::on_transactionQueue_currentItemChanged()
if (i >= 0 && i < (int)ethereum()->pending().size())
{
Transaction tx(ethereum()->pending()[i]);
+ TransactionReceipt receipt(ethereum()->postState().receipt(i));
auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce()));
s << "" << th << "
";
@@ -1246,12 +1271,15 @@ void Main::on_transactionQueue_currentItemChanged()
if (tx.data().size())
s << dev::memDump(tx.data(), 16, true);
}
+ s << "Hex: " << toHex(tx.rlp()) << "
";
s << "
";
-
+ s << "Log Bloom: " << receipt.bloom() << "
";
+ auto r = receipt.rlp();
+ s << "Receipt: " << toString(RLP(r)) << "
";
+ s << "Receipt-Hex: " << toHex(receipt.rlp()) << "
";
+ s << renderDiff(ethereum()->diff(i, 0));
// s << "Pre: " << fs.rootHash() << "
";
// s << "Post: " << ts.rootHash() << "";
-
- s << renderDiff(ethereum()->diff(i, 0));
}
ui->pendingInfo->setHtml(QString::fromStdString(s.str()));
@@ -1364,11 +1392,6 @@ void Main::on_blocks_currentItemChanged()
s << "
R: " << hex << nouppercase << tx.signature().r << "";
s << "
S: " << hex << nouppercase << tx.signature().s << "";
s << "
Msg: " << tx.sha3(eth::WithoutSignature) << "";
- s << "Log Bloom: " << receipt.bloom() << "
";
- s << "Hex: " << toHex(block[1][txi].data()) << "
";
- auto r = receipt.rlp();
- s << "Receipt: " << toString(RLP(r)) << "
";
- s << "Receipt-Hex: " << toHex(receipt.rlp()) << "
";
if (tx.isCreation())
{
if (tx.data().size())
@@ -1379,6 +1402,12 @@ void Main::on_blocks_currentItemChanged()
if (tx.data().size())
s << dev::memDump(tx.data(), 16, true);
}
+ s << "Hex: " << toHex(block[1][txi].data()) << "
";
+ s << "
";
+ s << "Log Bloom: " << receipt.bloom() << "
";
+ auto r = receipt.rlp();
+ s << "Receipt: " << toString(RLP(r)) << "
";
+ s << "Receipt-Hex: " << toHex(receipt.rlp()) << "
";
s << renderDiff(ethereum()->diff(txi, h));
ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true);
@@ -1619,12 +1648,15 @@ void Main::on_data_textChanged()
{
m_data = fromHex(src);
}
- else if (src.substr(0, 8) == "contract") // improve this heuristic
+ else if (src.substr(0, 8) == "contract" || src.substr(0, 5) == "//sol") // improve this heuristic
{
dev::solidity::CompilerStack compiler;
try
{
m_data = compiler.compile(src, m_enableOptimizer);
+ solidity = "Solidity
";
+ solidity += "" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "
";
+ solidity += "" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
";
}
catch (dev::Exception const& exception)
{
@@ -1699,6 +1731,18 @@ void Main::on_data_textChanged()
updateFee();
}
+void Main::on_clearPending_triggered()
+{
+ writeSettings();
+ ui->mine->setChecked(false);
+ ui->net->setChecked(false);
+ web3()->stopNetwork();
+ ethereum()->clearPending();
+ readSettings(true);
+ installWatches();
+ refreshAll();
+}
+
void Main::on_killBlockchain_triggered()
{
writeSettings();
@@ -1770,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 ed5d275eb..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
@@ -128,6 +130,7 @@ private slots:
void on_debugTimeline_valueChanged();
void on_jsInput_returnPressed();
void on_killBlockchain_triggered();
+ void on_clearPending_triggered();
void on_importKey_triggered();
void on_exportKey_triggered();
void on_inject_triggered();
@@ -155,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();
@@ -170,6 +174,8 @@ private:
QString prettyU256(dev::u256 _n) const;
QString lookup(QString const& _n) const;
+ dev::Address getNameReg() const;
+ dev::Address getCurrencies() const;
void populateDebugger(dev::bytesConstRef r);
void initDebugger();
@@ -191,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();
@@ -225,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/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 dae61e114..dfe020763 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
#include
#if ETH_READLINE
@@ -121,7 +122,11 @@ void help()
<< " -u,--public-ip Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl
- << " -V,--version Show the version and exit." << endl;
+ << " -V,--version Show the version and exit." << endl
+#if ETH_EVMJIT
+ << " --jit Use EVM JIT (default: off)." << endl
+#endif
+ ;
exit(0);
}
@@ -175,6 +180,12 @@ void sighandler(int)
g_exit = true;
}
+enum class NodeMode
+{
+ PeerServer,
+ Full
+};
+
int main(int argc, char** argv)
{
unsigned short listenPort = 30303;
@@ -193,6 +204,7 @@ int main(int argc, char** argv)
bool upnp = true;
bool useLocal = false;
bool forceMining = false;
+ bool jit = false;
string clientName;
// Init defaults
@@ -295,6 +307,15 @@ int main(int argc, char** argv)
return -1;
}
}
+ else if (arg == "--jit")
+ {
+#if ETH_EVMJIT
+ jit = true;
+#else
+ cerr << "EVM JIT not enabled" << endl;
+ return -1;
+#endif
+ }
else if (arg == "-h" || arg == "--help")
help();
else if (arg == "-V" || arg == "--version")
@@ -308,9 +329,10 @@ int main(int argc, char** argv)
cout << credits();
+ VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
dev::WebThreeDirect web3(
- "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM),
+ "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""),
dbPath,
false,
mode == NodeMode::Full ? set{"eth", "shh"} : set(),
diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt
index 26a8010d1..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()
@@ -24,4 +25,4 @@ 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/evmcc/evmcc.cpp b/evmjit/evmcc/evmcc.cpp
index 3c43ab78b..e86f948f2 100644
--- a/evmjit/evmcc/evmcc.cpp
+++ b/evmjit/evmcc/evmcc.cpp
@@ -190,7 +190,6 @@ int main(int argc, char** argv)
data.set(RuntimeData::CallValue, 0xabcd);
data.set(RuntimeData::CallDataSize, 3);
data.set(RuntimeData::GasPrice, 1003);
- data.set(RuntimeData::PrevHash, 1003);
data.set(RuntimeData::CoinBase, (u160)Address(101010101010101015));
data.set(RuntimeData::TimeStamp, 1005);
data.set(RuntimeData::Number, 1006);
diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp
index 1dcd38162..6320aa222 100644
--- a/evmjit/libevmjit-cpp/Env.cpp
+++ b/evmjit/libevmjit-cpp/Env.cpp
@@ -42,16 +42,15 @@ extern "C"
*o_value = eth2llvm(u);
}
- EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address)
+ EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash)
{
- if (_env->depth == 1024)
- jit::terminate(jit::ReturnCode::OutOfGas);
-
- assert(_env->depth < 1024);
+ *o_hash = _env->blockhash(llvm2eth(*_number));
+ }
+ EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address)
+ {
auto endowment = llvm2eth(*_endowment);
-
- if (_env->balance(_env->myAddress) >= endowment)
+ if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024)
{
_env->subBalance(endowment);
auto gas = llvm2eth(*io_gas);
@@ -66,13 +65,8 @@ extern "C"
EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress)
{
- if (_env->depth == 1024)
- jit::terminate(jit::ReturnCode::OutOfGas);
-
- assert(_env->depth < 1024);
-
auto value = llvm2eth(*_value);
- if (_env->balance(_env->myAddress) >= value)
+ if (_env->balance(_env->myAddress) >= value && _env->depth < 1024)
{
_env->subBalance(value);
auto receiveAddress = right160(*_receiveAddress);
diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp
index 815aa6332..dda8133a8 100644
--- a/evmjit/libevmjit-cpp/JitVM.cpp
+++ b/evmjit/libevmjit-cpp/JitVM.cpp
@@ -20,7 +20,6 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
m_data.set(RuntimeData::CallValue, _ext.value);
m_data.set(RuntimeData::CallDataSize, _ext.data.size());
m_data.set(RuntimeData::GasPrice, _ext.gasPrice);
- m_data.set(RuntimeData::PrevHash, _ext.previousBlock.hash);
m_data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress));
m_data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp);
m_data.set(RuntimeData::Number, _ext.currentBlock.number);
diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp
index d233ea744..dda0fbc36 100644
--- a/evmjit/libevmjit/BasicBlock.cpp
+++ b/evmjit/libevmjit/BasicBlock.cpp
@@ -20,20 +20,21 @@ namespace jit
const char* BasicBlock::NamePrefix = "Instr.";
-BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) :
- m_beginInstIdx(_beginInstIdx),
- m_endInstIdx(_endInstIdx),
- m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)),
+BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
+ m_begin(_begin),
+ m_end(_end),
+ // TODO: Add begin index to name
+ m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)),
m_stack(*this),
- m_builder(_builder)
+ m_builder(_builder),
+ m_isJumpDest(isJumpDest)
{}
-BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) :
- m_beginInstIdx(0),
- m_endInstIdx(0),
+BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
m_stack(*this),
- m_builder(_builder)
+ m_builder(_builder),
+ m_isJumpDest(isJumpDest)
{}
BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) :
diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h
index f0643f342..7a5364a4e 100644
--- a/evmjit/libevmjit/BasicBlock.h
+++ b/evmjit/libevmjit/BasicBlock.h
@@ -1,9 +1,7 @@
#pragma once
-
#include
-
#include
-
+#include "Common.h"
#include "Stack.h"
namespace dev
@@ -52,20 +50,21 @@ public:
BasicBlock& m_bblock;
};
- /// Basic block name prefix. The rest is beging instruction index.
+ /// Basic block name prefix. The rest is instruction index.
static const char* NamePrefix;
- explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder);
- explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder);
+ explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
+ explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
BasicBlock(const BasicBlock&) = delete;
void operator=(const BasicBlock&) = delete;
- operator llvm::BasicBlock*() { return m_llvmBB; }
llvm::BasicBlock* llvm() { return m_llvmBB; }
- ProgramCounter begin() { return m_beginInstIdx; }
- ProgramCounter end() { return m_endInstIdx; }
+ bytes::const_iterator begin() { return m_begin; }
+ bytes::const_iterator end() { return m_end; }
+
+ bool isJumpDest() const { return m_isJumpDest; }
LocalStack& localStack() { return m_stack; }
@@ -82,8 +81,8 @@ public:
void dump(std::ostream& os, bool _dotOutput = false);
private:
- ProgramCounter const m_beginInstIdx;
- ProgramCounter const m_endInstIdx;
+ bytes::const_iterator const m_begin;
+ bytes::const_iterator const m_end;
llvm::BasicBlock* const m_llvmBB;
@@ -99,16 +98,20 @@ private:
/// the item below the top and so on. The stack grows as the code
/// accesses more items on the EVM stack but once a value is put on
/// the stack, it will never be replaced.
- std::vector m_initialStack = {};
+ std::vector m_initialStack;
/// This stack tracks the contents of the EVM stack as the basic block
/// executes. It may grow on both sides, as the code pushes items on
/// top of the stack or changes existing items.
- std::vector m_currentStack = {};
+ std::vector m_currentStack;
/// How many items higher is the current stack than the initial one.
/// May be negative.
int m_tosOffset = 0;
+
+ /// Is the basic block a valid jump destination.
+ /// JUMPDEST is the first instruction of the basic block.
+ bool const m_isJumpDest = false;
};
}
diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp
index a887d91e9..3ac9f4a73 100644
--- a/evmjit/libevmjit/Cache.cpp
+++ b/evmjit/libevmjit/Cache.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -23,6 +24,33 @@ ObjectCache* Cache::getObjectCache()
return &objectCache;
}
+namespace
+{
+ llvm::MemoryBuffer* lastObject;
+}
+
+std::unique_ptr Cache::getObject(std::string const& id)
+{
+ assert(!lastObject);
+ llvm::SmallString<256> cachePath;
+ llvm::sys::path::system_temp_directory(false, cachePath);
+ llvm::sys::path::append(cachePath, "evm_objs", id);
+
+ if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
+ lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
+ else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
+ std::cerr << r.getError().message(); // TODO: Add log
+
+ if (lastObject) // if object found create fake module
+ {
+ 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;
+ }
+ return nullptr;
+}
+
void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object)
{
@@ -43,16 +71,10 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory
llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
{
- auto&& id = _module->getModuleIdentifier();
- llvm::SmallString<256> cachePath;
- llvm::sys::path::system_temp_directory(false, cachePath);
- llvm::sys::path::append(cachePath, "evm_objs", id);
-
- if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
- return llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
- else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
- std::cerr << r.getError().message(); // TODO: Add log
- return nullptr;
+ (void)_module;
+ auto o = lastObject;
+ lastObject = nullptr;
+ return o;
}
}
diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h
index 80fe47ade..1cad537cd 100644
--- a/evmjit/libevmjit/Cache.h
+++ b/evmjit/libevmjit/Cache.h
@@ -2,7 +2,6 @@
#include
#include
-#include
#include
@@ -34,6 +33,7 @@ class Cache
{
public:
static ObjectCache* getObjectCache();
+ static std::unique_ptr getObject(std::string const& id);
};
}
diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h
index d98cc0acb..1d8451c74 100644
--- a/evmjit/libevmjit/Common.h
+++ b/evmjit/libevmjit/Common.h
@@ -37,13 +37,15 @@ enum class ReturnCode
// TODO: Replace with h256
struct i256
{
- uint64_t a;
- uint64_t b;
- uint64_t c;
- uint64_t d;
+ uint64_t a = 0;
+ uint64_t b = 0;
+ uint64_t c = 0;
+ uint64_t d = 0;
};
static_assert(sizeof(i256) == 32, "Wrong i265 size");
+#define UNTESTED assert(false)
+
}
}
}
diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp
index 48dc50d60..bfcb9cea1 100644
--- a/evmjit/libevmjit/Compiler.cpp
+++ b/evmjit/libevmjit/Compiler.cpp
@@ -5,8 +5,6 @@
#include
#include
-#include
-
#include
#include
#include
@@ -42,114 +40,87 @@ Compiler::Compiler(Options const& _options):
void Compiler::createBasicBlocks(bytes const& _bytecode)
{
- std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end
-
- std::map directJumpTargets;
- std::vector indirectJumpTargets;
- boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1)));
-
- splitPoints.insert(0); // First basic block
- validJumpTargets[0] = true;
-
- for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr)
+ /// Helper function that skips push data and finds next iterator (can be the end)
+ auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end)
{
- ProgramCounter currentPC = curr - _bytecode.begin();
- validJumpTargets[currentPC] = true;
-
- auto inst = Instruction(*curr);
- switch (inst)
- {
+ static const auto push1 = static_cast(Instruction::PUSH1);
+ static const auto push32 = static_cast(Instruction::PUSH32);
+ size_t offset = 1;
+ if (*_curr >= push1 && *_curr <= push32)
+ offset += std::min(*_curr - push1 + 1, (_end - _curr) - 1);
+ return _curr + offset;
+ };
+
+ auto begin = _bytecode.begin();
+ bool nextJumpDest = false;
+ for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next)
+ {
+ next = skipPushDataAndGetNext(curr, _bytecode.end());
- case Instruction::ANY_PUSH:
+ bool isEnd = false;
+ switch (Instruction(*curr))
{
- auto val = readPushData(curr, _bytecode.end());
- auto next = curr + 1;
- if (next == _bytecode.end())
- break;
-
- auto nextInst = Instruction(*next);
- if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI)
- {
- // Create a block for the JUMP target.
- ProgramCounter targetPC = val.ult(_bytecode.size()) ? val.getZExtValue() : _bytecode.size();
- splitPoints.insert(targetPC);
-
- ProgramCounter jumpPC = (next - _bytecode.begin());
- directJumpTargets[jumpPC] = targetPC;
- }
- break;
- }
-
- case Instruction::JUMPDEST:
- {
- // A basic block starts here.
- splitPoints.insert(currentPC);
- indirectJumpTargets.push_back(currentPC);
- break;
- }
-
case Instruction::JUMP:
case Instruction::JUMPI:
case Instruction::RETURN:
case Instruction::STOP:
case Instruction::SUICIDE:
- {
- // Create a basic block starting at the following instruction.
- if (curr + 1 < _bytecode.end())
- splitPoints.insert(currentPC + 1);
+ isEnd = true;
+ break;
+
+ case Instruction::JUMPDEST:
+ nextJumpDest = true;
break;
- }
default:
break;
}
- }
- // Remove split points generated from jumps out of code or into data.
- for (auto it = splitPoints.cbegin(); it != splitPoints.cend();)
- {
- if (*it > _bytecode.size() || !validJumpTargets[*it])
- it = splitPoints.erase(it);
- else
- ++it;
- }
+ assert(next <= _bytecode.end());
+ if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST)
+ isEnd = true;
- for (auto it = splitPoints.cbegin(); it != splitPoints.cend();)
- {
- auto beginInstIdx = *it;
- ++it;
- auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size();
- basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder));
+ if (isEnd)
+ {
+ auto beginIdx = begin - _bytecode.begin();
+ m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx),
+ std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest));
+ nextJumpDest = false;
+ begin = next;
+ }
}
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
- m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder));
- m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder));
+}
- for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
+llvm::BasicBlock* Compiler::getJumpTableBlock()
+{
+ if (!m_jumpTableBlock)
{
- if (it->second >= _bytecode.size())
- {
- // Jumping out of code means STOP
- m_directJumpTargets[it->first] = m_stopBB;
- continue;
- }
-
- auto blockIter = basicBlocks.find(it->second);
- if (blockIter != basicBlocks.end())
- {
- m_directJumpTargets[it->first] = blockIter->second.llvm();
- }
- else
+ m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true));
+ InsertPointGuard g{m_builder};
+ m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
+ auto dest = m_jumpTableBlock->localStack().pop();
+ auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock());
+ for (auto&& p : m_basicBlocks)
{
- clog(JIT) << "Bad JUMP at PC " << it->first
- << ": " << it->second << " is not a valid PC";
- m_directJumpTargets[it->first] = m_badJumpBlock->llvm();
+ if (p.second.isJumpDest())
+ switchInstr->addCase(Constant::get(p.first), p.second.llvm());
}
}
+ return m_jumpTableBlock->llvm();
+}
- for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it)
- m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second);
+llvm::BasicBlock* Compiler::getBadJumpBlock()
+{
+ if (!m_badJumpBlock)
+ {
+ m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true));
+ InsertPointGuard g{m_builder};
+ m_builder.SetInsertPoint(m_badJumpBlock->llvm());
+ m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination));
+ }
+ return m_badJumpBlock->llvm();
}
std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id)
@@ -176,14 +147,14 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str
Stack stack(m_builder, runtimeManager);
Arith256 arith(m_builder);
- m_builder.CreateBr(basicBlocks.begin()->second);
+ m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm());
- for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt)
+ for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt)
{
auto& basicBlock = basicBlockPairIt->second;
auto iterCopy = basicBlockPairIt;
++iterCopy;
- auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
+ auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock);
}
@@ -192,25 +163,6 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str
m_builder.SetInsertPoint(m_stopBB);
m_builder.CreateRet(Constant::get(ReturnCode::Stop));
- m_builder.SetInsertPoint(m_badJumpBlock->llvm());
- m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination));
-
- m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
- if (m_indirectJumpTargets.size() > 0)
- {
- auto dest = m_jumpTableBlock->localStack().pop();
- auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
- m_indirectJumpTargets.size());
- for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
- {
- auto& bb = *it;
- auto dest = Constant::get(bb->begin());
- switchInstr->addCase(dest, bb->llvm());
- }
- }
- else
- m_builder.CreateBr(m_badJumpBlock->llvm());
-
removeDeadBlocks();
dumpCFGifRequired("blocks-init.dot");
@@ -218,7 +170,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str
if (m_options.optimizeStack)
{
std::vector blockList;
- for (auto& entry : basicBlocks)
+ for (auto& entry : m_basicBlocks)
blockList.push_back(&entry.second);
if (m_jumpTableBlock)
@@ -229,7 +181,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str
dumpCFGifRequired("blocks-opt.dot");
}
- for (auto& entry : basicBlocks)
+ for (auto& entry : m_basicBlocks)
entry.second.synchronizeLocalStack(stack);
if (m_jumpTableBlock)
m_jumpTableBlock->synchronizeLocalStack(stack);
@@ -259,9 +211,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
m_builder.SetInsertPoint(_basicBlock.llvm());
auto& stack = _basicBlock.localStack();
- for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC)
+ for (auto it = _basicBlock.begin(); it != _basicBlock.end(); ++it)
{
- auto inst = static_cast(_bytecode[currentPC]);
+ auto inst = Instruction(*it);
_gasMeter.count(inst);
@@ -523,10 +475,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::ANY_PUSH:
{
- auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator
- auto value = readPushData(curr, _bytecode.end());
- currentPC = curr - _bytecode.begin();
-
+ auto value = readPushData(it, _basicBlock.end());
stack.push(Constant::get(value));
break;
}
@@ -596,46 +545,45 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::JUMP:
case Instruction::JUMPI:
{
- // Generate direct jump iff:
- // 1. this is not the first instruction in the block
- // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH)
- // Otherwise generate a indirect jump (a switch).
llvm::BasicBlock* targetBlock = nullptr;
- if (currentPC != _basicBlock.begin())
+ auto target = stack.pop();
+ if (auto constant = llvm::dyn_cast(target))
{
- auto pairIter = m_directJumpTargets.find(currentPC);
- if (pairIter != m_directJumpTargets.end())
- targetBlock = pairIter->second;
+ auto&& c = constant->getValue();
+ auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1;
+ auto it = m_basicBlocks.find(targetIdx);
+ targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock();
}
+ // TODO: Improve; check for constants
if (inst == Instruction::JUMP)
{
if (targetBlock)
{
- // The target address is computed at compile time,
- // just pop it without looking...
- stack.pop();
m_builder.CreateBr(targetBlock);
}
else
- m_builder.CreateBr(m_jumpTableBlock->llvm());
+ {
+ stack.push(target);
+ m_builder.CreateBr(getJumpTableBlock());
+ }
}
else // JUMPI
{
- stack.swap(1);
auto val = stack.pop();
auto zero = Constant::get(0);
auto cond = m_builder.CreateICmpNE(val, zero, "nonzero");
if (targetBlock)
{
- stack.pop();
m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock);
}
else
- m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock);
+ {
+ stack.push(target);
+ m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock);
+ }
}
-
break;
}
@@ -647,7 +595,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::PC:
{
- auto value = Constant::get(currentPC);
+ auto value = Constant::get(it - _bytecode.begin());
stack.push(value);
break;
}
@@ -666,7 +614,6 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::CALLDATASIZE:
case Instruction::CODESIZE:
case Instruction::GASPRICE:
- case Instruction::PREVHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
@@ -678,6 +625,14 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
break;
}
+ case Instruction::BLOCKHASH:
+ {
+ auto number = stack.pop();
+ auto hash = _ext.blockhash(number);
+ stack.push(hash);
+ break;
+ }
+
case Instruction::BALANCE:
{
auto address = stack.pop();
@@ -835,6 +790,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
default: // Invalid instruction - runtime exception
{
+ // TODO: Replace with return statement
_runtimeManager.raiseException(ReturnCode::BadInstruction);
}
@@ -857,13 +813,13 @@ void Compiler::removeDeadBlocks()
do
{
sthErased = false;
- for (auto it = basicBlocks.begin(); it != basicBlocks.end();)
+ for (auto it = m_basicBlocks.begin(); it != m_basicBlocks.end();)
{
auto llvmBB = it->second.llvm();
if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB))
{
llvmBB->eraseFromParent();
- basicBlocks.erase(it++);
+ m_basicBlocks.erase(it++);
sthErased = true;
}
else
@@ -871,13 +827,6 @@ void Compiler::removeDeadBlocks()
}
}
while (sthErased);
-
- // Remove jump table block if no predecessors
- if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm()))
- {
- m_jumpTableBlock->llvm()->eraseFromParent();
- m_jumpTableBlock.reset();
- }
}
void Compiler::dumpCFGifRequired(std::string const& _dotfilePath)
@@ -898,7 +847,7 @@ void Compiler::dumpCFGtoStream(std::ostream& _out)
<< " entry [share=record, label=\"entry block\"];\n";
std::vector blocks;
- for (auto& pair : basicBlocks)
+ for (auto& pair : m_basicBlocks)
blocks.push_back(&pair.second);
if (m_jumpTableBlock)
blocks.push_back(m_jumpTableBlock.get());
@@ -937,7 +886,7 @@ void Compiler::dumpCFGtoStream(std::ostream& _out)
void Compiler::dump()
{
- for (auto& entry : basicBlocks)
+ for (auto& entry : m_basicBlocks)
entry.second.dump();
if (m_jumpTableBlock != nullptr)
m_jumpTableBlock->dump();
diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h
index 8e3bf357c..720a48cf9 100644
--- a/evmjit/libevmjit/Compiler.h
+++ b/evmjit/libevmjit/Compiler.h
@@ -20,19 +20,13 @@ public:
struct Options
{
/// Optimize stack operations between basic blocks
- bool optimizeStack;
+ bool optimizeStack = true;
/// Rewrite switch instructions to sequences of branches
- bool rewriteSwitchToBranches;
+ bool rewriteSwitchToBranches = true;
/// Dump CFG as a .dot file for graphviz
- bool dumpCFG;
-
- Options():
- optimizeStack(true),
- rewriteSwitchToBranches(true),
- dumpCFG(false)
- {}
+ bool dumpCFG = false;
};
using ProgramCounter = uint64_t;
@@ -47,6 +41,10 @@ private:
void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock);
+ llvm::BasicBlock* getJumpTableBlock();
+
+ llvm::BasicBlock* getBadJumpBlock();
+
void removeDeadBlocks();
/// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled.
@@ -65,22 +63,16 @@ private:
llvm::IRBuilder<> m_builder;
/// Maps a program counter pc to a basic block that starts at pc (if any).
- std::map basicBlocks = {};
-
- /// Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
- std::map m_directJumpTargets = {};
-
- /// A list of possible blocks to which there may be indirect jumps.
- std::vector m_indirectJumpTargets = {};
+ std::map m_basicBlocks;
/// Stop basic block - terminates execution with STOP code (0)
llvm::BasicBlock* m_stopBB = nullptr;
/// Block with a jump table.
- std::unique_ptr m_jumpTableBlock = nullptr;
+ std::unique_ptr m_jumpTableBlock;
- /// Default destination for indirect jumps.
- std::unique_ptr m_badJumpBlock = nullptr;
+ /// Destination for invalid jumps
+ std::unique_ptr m_badJumpBlock;
/// Main program function
llvm::Function* m_mainFunc = nullptr;
diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp
index badf9d889..9cccecd79 100644
--- a/evmjit/libevmjit/CompilerHelper.cpp
+++ b/evmjit/libevmjit/CompilerHelper.cpp
@@ -35,6 +35,11 @@ llvm::Function* CompilerHelper::getMainFunction()
return nullptr;
}
+llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args)
+{
+ return getBuilder().CreateCall(_func, {_args.begin(), _args.size()});
+}
+
RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager):
CompilerHelper(_runtimeManager.getBuilder()),
diff --git a/evmjit/libevmjit/CompilerHelper.h b/evmjit/libevmjit/CompilerHelper.h
index 19315fe4a..62733ca72 100644
--- a/evmjit/libevmjit/CompilerHelper.h
+++ b/evmjit/libevmjit/CompilerHelper.h
@@ -31,12 +31,7 @@ protected:
llvm::IRBuilder<>& m_builder;
llvm::IRBuilder<>& getBuilder() { return m_builder; }
- template
- llvm::CallInst* createCall(llvm::Function* _func, _Args*... _args)
- {
- llvm::Value* args[] = {_args...};
- return getBuilder().CreateCall(_func, args);
- }
+ llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args);
friend class RuntimeHelper;
};
diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp
index 862586575..7e99932c3 100644
--- a/evmjit/libevmjit/ExecutionEngine.cpp
+++ b/evmjit/libevmjit/ExecutionEngine.cpp
@@ -4,8 +4,13 @@
#include
#include
+#pragma warning(push)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
#include
#include
+#pragma warning(pop)
+#pragma GCC diagnostic pop
#include
#include
#include
@@ -69,7 +74,13 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
}
else
{
- auto module = Compiler({}).compile(_code, mainFuncName);
+ bool objectCacheEnabled = true;
+ auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr;
+ std::unique_ptr module;
+ if (objectCache)
+ module = Cache::getObject(mainFuncName);
+ if (!module)
+ module = Compiler({}).compile(_code, mainFuncName);
//module->dump();
if (!ee)
{
@@ -95,7 +106,8 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
memoryManager.release(); // and memory manager
- ee->setObjectCache(Cache::getObjectCache());
+ if (objectCache)
+ ee->setObjectCache(objectCache);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
}
else
diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp
index 38adffd3f..b92a07bf8 100644
--- a/evmjit/libevmjit/Ext.cpp
+++ b/evmjit/libevmjit/Ext.cpp
@@ -23,114 +23,137 @@ 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{}*/
{
- auto module = getModule();
-
- m_args[0] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.index");
- m_args[1] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.value");
- m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg2");
- m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg3");
- m_arg4 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg4");
- m_arg5 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg5");
- m_arg6 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg6");
- m_arg7 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg7");
- m_arg8 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg8");
m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size");
+}
- using Linkage = llvm::GlobalValue::LinkageTypes;
-
- llvm::Type* argsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr};
-
- m_sload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sload", module);
- m_sstore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sstore", module);
-
- llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr};
- m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module);
-
- llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr};
- m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, createArgsTypes, false), Linkage::ExternalLinkage, "env_create", module);
- llvm::Type* callArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr};
- m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, callArgsTypes, false), Linkage::ExternalLinkage, "env_call", module);
+using FuncDesc = std::tuple;
- llvm::Type* logArgsTypes[] = {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr};
- m_log = llvm::Function::Create(llvm::FunctionType::get(Type::Void, logArgsTypes, false), Linkage::ExternalLinkage, "env_log", module);
+llvm::FunctionType* getFunctionType(llvm::Type* _returnType, std::initializer_list const& _argsTypes)
+{
+ return llvm::FunctionType::get(_returnType, llvm::ArrayRef{_argsTypes.begin(), _argsTypes.size()}, false);
+}
- llvm::Type* getExtCodeArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()};
- m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module);
+std::array::value> const& getEnvFuncDescs()
+{
+ static std::array::value> descs{{
+ FuncDesc{"env_sload", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
+ FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
+ FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})},
+ FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
+ FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})},
+ FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})},
+ FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})},
+ FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
+ FuncDesc{"env_getExtCode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})},
+ FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})},
+ }};
+
+ return descs;
+}
- // Helper function, not client Env interface
- llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr};
- m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module);
+llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module)
+{
+ auto&& desc = getEnvFuncDescs()[static_cast(_id)];
+ return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module);
}
-llvm::Function* Ext::getBalanceFunc()
+llvm::Value* Ext::getArgAlloca()
{
- if (!m_balance)
+ auto& a = m_argAllocas[m_argCounter++];
+ if (!a)
{
- llvm::Type* argsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr};
- m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), llvm::Function::ExternalLinkage, "env_balance", getModule());
+ // FIXME: Improve order and names
+ InsertPointGuard g{getBuilder()};
+ getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI());
+ a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg");
}
- return m_balance;
+
+ return a;
+}
+
+llvm::Value* Ext::byPtr(llvm::Value* _value)
+{
+ auto a = getArgAlloca();
+ getBuilder().CreateStore(_value, a);
+ return a;
+}
+
+llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list const& _args)
+{
+ auto& func = m_funcs[static_cast(_funcId)];
+ if (!func)
+ func = createFunc(_funcId, getModule());
+
+ m_argCounter = 0;
+ return getBuilder().CreateCall(func, {_args.begin(), _args.size()});
}
llvm::Value* Ext::sload(llvm::Value* _index)
{
- m_builder.CreateStore(_index, m_args[0]);
- m_builder.CreateCall3(m_sload, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness
- return m_builder.CreateLoad(m_args[1]);
+ auto ret = getArgAlloca();
+ createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), byPtr(_index), ret}); // Uses native endianness
+ return m_builder.CreateLoad(ret);
}
void Ext::sstore(llvm::Value* _index, llvm::Value* _value)
{
- m_builder.CreateStore(_index, m_args[0]);
- m_builder.CreateStore(_value, m_args[1]);
- m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness
+ createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), byPtr(_index), byPtr(_value)}); // Uses native endianness
}
llvm::Value* Ext::calldataload(llvm::Value* _index)
{
- m_builder.CreateStore(_index, m_args[0]);
- createCall(m_calldataload, getRuntimeManager().getDataPtr(), m_args[0], m_args[1]);
- auto ret = m_builder.CreateLoad(m_args[1]);
+ auto ret = getArgAlloca();
+ createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), byPtr(_index), ret});
+ ret = m_builder.CreateLoad(ret);
return Endianness::toNative(m_builder, ret);
}
llvm::Value* Ext::balance(llvm::Value* _address)
{
auto address = Endianness::toBE(m_builder, _address);
- m_builder.CreateStore(address, m_args[0]);
- createCall(getBalanceFunc(), getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]);
- return m_builder.CreateLoad(m_args[1]);
+ auto ret = getArgAlloca();
+ createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), byPtr(address), ret});
+ return m_builder.CreateLoad(ret);
+}
+
+llvm::Value* Ext::blockhash(llvm::Value* _number)
+{
+ auto hash = getArgAlloca();
+ createCall(EnvFunc::blockhash, {getRuntimeManager().getEnvPtr(), byPtr(_number), hash});
+ hash = m_builder.CreateLoad(hash);
+ return Endianness::toNative(getBuilder(), hash);
}
llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize)
{
- m_builder.CreateStore(_gas, m_args[0]);
- m_builder.CreateStore(_endowment, m_arg2);
+ auto gas = byPtr(_gas);
+ auto ret = getArgAlloca();
auto begin = m_memoryMan.getBytePtr(_initOff);
auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size");
- createCall(m_create, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, begin, size, m_args[1]);
- _gas = m_builder.CreateLoad(m_args[0]); // Return gas
- llvm::Value* address = m_builder.CreateLoad(m_args[1]);
+ createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret});
+ _gas = m_builder.CreateLoad(gas); // Return gas
+ llvm::Value* address = m_builder.CreateLoad(ret);
address = Endianness::toNative(m_builder, address);
return address;
}
llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress)
{
- m_builder.CreateStore(_gas, m_args[0]);
+ auto gas = byPtr(_gas);
auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress);
- m_builder.CreateStore(receiveAddress, m_arg2);
- m_builder.CreateStore(_value, m_arg3);
auto inBeg = m_memoryMan.getBytePtr(_inOff);
auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size");
auto outBeg = m_memoryMan.getBytePtr(_outOff);
auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size");
auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
- m_builder.CreateStore(codeAddress, m_arg8);
- auto ret = createCall(m_call, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8);
- _gas = m_builder.CreateLoad(m_args[0]); // Return gas
+ auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)});
+ _gas = m_builder.CreateLoad(gas); // Return gas
return m_builder.CreateZExt(ret, Type::Word, "ret");
}
@@ -138,8 +161,9 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize)
{
auto begin = m_memoryMan.getBytePtr(_inOff);
auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size");
- createCall(m_sha3, begin, size, m_args[1]);
- llvm::Value* hash = m_builder.CreateLoad(m_args[1]);
+ auto ret = getArgAlloca();
+ createCall(EnvFunc::sha3, {begin, size, ret});
+ llvm::Value* hash = m_builder.CreateLoad(ret);
hash = Endianness::toNative(m_builder, hash);
return hash;
}
@@ -147,8 +171,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize)
MemoryRef Ext::getExtCode(llvm::Value* _addr)
{
auto addr = Endianness::toBE(m_builder, _addr);
- m_builder.CreateStore(addr, m_args[0]);
- auto code = createCall(m_getExtCode, getRuntimeManager().getEnvPtr(), m_args[0], m_size);
+ auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size});
auto codeSize = m_builder.CreateLoad(m_size);
auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word);
return {code, codeSize256};
@@ -158,7 +181,7 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array
}
}
diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h
index be71dc1ff..86a8a6190 100644
--- a/evmjit/libevmjit/Ext.h
+++ b/evmjit/libevmjit/Ext.h
@@ -18,6 +18,28 @@ struct MemoryRef
llvm::Value* size;
};
+template
+struct sizeOf
+{
+ static const size_t value = static_cast(_EnumT::_size);
+};
+
+enum class EnvFunc
+{
+ sload,
+ sstore,
+ sha3,
+ balance,
+ create,
+ call,
+ log,
+ blockhash,
+ getExtCode,
+ calldataload, // Helper function, not client Env interface
+
+ _size
+};
+
class Ext : public RuntimeHelper
{
public:
@@ -30,6 +52,7 @@ public:
llvm::Value* calldataload(llvm::Value* _index);
llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize);
llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress);
+ llvm::Value* blockhash(llvm::Value* _number);
llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize);
MemoryRef getExtCode(llvm::Value* _addr);
@@ -39,27 +62,16 @@ public:
private:
Memory& m_memoryMan;
- llvm::Value* m_args[2];
- llvm::Value* m_arg2;
- llvm::Value* m_arg3;
- llvm::Value* m_arg4;
- llvm::Value* m_arg5;
- llvm::Value* m_arg6;
- llvm::Value* m_arg7;
- llvm::Value* m_arg8;
llvm::Value* m_size;
llvm::Value* m_data = nullptr;
- llvm::Function* m_sload;
- llvm::Function* m_sstore;
- llvm::Function* m_calldataload;
- llvm::Function* m_balance = nullptr;
- llvm::Function* m_create;
- llvm::Function* m_call;
- llvm::Function* m_sha3;
- llvm::Function* m_getExtCode;
- llvm::Function* m_log;
-
- llvm::Function* getBalanceFunc();
+
+ std::array::value> m_funcs;
+ std::array m_argAllocas;
+ size_t m_argCounter = 0;
+
+ llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args);
+ llvm::Value* getArgAlloca();
+ llvm::Value* byPtr(llvm::Value* _value);
};
diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp
index c31942a45..84266111e 100644
--- a/evmjit/libevmjit/GasMeter.cpp
+++ b/evmjit/libevmjit/GasMeter.cpp
@@ -41,7 +41,7 @@ uint64_t const c_logDataGas = 1;
uint64_t const c_logTopicGas = 32;
uint64_t const c_copyGas = 1;
-uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted)
+uint64_t getStepCost(Instruction inst)
{
switch (inst)
{
@@ -119,7 +119,7 @@ void GasMeter::count(Instruction _inst)
if (!m_checkCall)
{
// Create gas check call with mocked block cost at begining of current cost-block
- m_checkCall = createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word));
+ m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)});
}
m_blockCost += getStepCost(_inst);
@@ -127,7 +127,7 @@ void GasMeter::count(Instruction _inst)
void GasMeter::count(llvm::Value* _cost)
{
- createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), _cost);
+ createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost});
}
void GasMeter::countExp(llvm::Value* _exponent)
diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp
new file mode 100644
index 000000000..fdc40d043
--- /dev/null
+++ b/evmjit/libevmjit/Instruction.cpp
@@ -0,0 +1,40 @@
+
+#include "Instruction.h"
+#include
+
+namespace dev
+{
+namespace eth
+{
+namespace jit
+{
+
+llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
+{
+ auto pushInst = *_curr;
+ assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
+ auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1;
+ llvm::APInt value(256, 0);
+ ++_curr; // Point the data
+ for (decltype(numBytes) i = 0; i < numBytes; ++i)
+ {
+ byte b = (_curr != _end) ? *_curr++ : 0;
+ value <<= 8;
+ value |= b;
+ }
+ --_curr; // Point the last real byte read
+ return value;
+}
+
+void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
+{
+ auto pushInst = *_curr;
+ assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
+ auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1;
+ --_end;
+ for (decltype(numBytes) i = 0; i < numBytes && _curr < _end; ++i, ++_curr) {}
+}
+
+}
+}
+}
diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h
index 502c4b66e..158490dee 100644
--- a/evmjit/libevmjit/Instruction.h
+++ b/evmjit/libevmjit/Instruction.h
@@ -58,7 +58,7 @@ enum class Instruction: uint8_t
EXTCODESIZE, ///< get external code size (from another contract)
EXTCODECOPY, ///< copy external code (from another contract)
- PREVHASH = 0x40, ///< get hash of most recent complete block
+ BLOCKHASH = 0x40, ///< get hash of most recent complete block
COINBASE, ///< get the block's coinbase address
TIMESTAMP, ///< get the block's timestamp
NUMBER, ///< get the block's number
@@ -160,9 +160,13 @@ enum class Instruction: uint8_t
/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it
/// Reading out of bytecode means reading 0
-/// @param _curr is updates and points the last real byte read
+/// @param _curr is updated and points the last real byte read
llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end);
+/// Skips PUSH data in pointed fragment of bytecode.
+/// @param _curr is updated and points the last real byte skipped
+void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end);
+
#define ANY_PUSH PUSH1: \
case Instruction::PUSH2: \
case Instruction::PUSH3: \
diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp
index c60a5e554..9f57c7a4b 100644
--- a/evmjit/libevmjit/Memory.cpp
+++ b/evmjit/libevmjit/Memory.cpp
@@ -146,18 +146,18 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet
llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
- return createCall(m_loadWord, getRuntimeManager().getRuntimePtr(), _addr);
+ return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr});
}
void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
- createCall(m_storeWord, getRuntimeManager().getRuntimePtr(), _addr, _word);
+ createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word});
}
void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
- createCall(m_storeByte, getRuntimeManager().getRuntimePtr(), _addr, byte);
+ createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte});
}
llvm::Value* Memory::getData()
@@ -181,7 +181,7 @@ llvm::Value* Memory::getBytePtr(llvm::Value* _index)
void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
- createCall(m_require, getRuntimeManager().getRuntimePtr(), _offset, _size);
+ createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size});
}
void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp
index 27c81ea86..2522e8ace 100644
--- a/evmjit/libevmjit/Runtime.cpp
+++ b/evmjit/libevmjit/Runtime.cpp
@@ -11,29 +11,12 @@ namespace eth
{
namespace jit
{
-namespace
-{
- jmp_buf_ref g_currJmpBuf;
-}
-
-jmp_buf_ref Runtime::getCurrJmpBuf()
-{
- return g_currJmpBuf;
-}
-Runtime::Runtime(RuntimeData* _data, Env* _env):
+Runtime::Runtime(RuntimeData* _data, Env* _env) :
m_data(*_data),
m_env(*_env),
- m_currJmpBuf(m_jmpBuf),
- m_prevJmpBuf(g_currJmpBuf)
-{
- g_currJmpBuf = m_jmpBuf;
-}
-
-Runtime::~Runtime()
-{
- g_currJmpBuf = m_prevJmpBuf;
-}
+ m_currJmpBuf(m_jmpBuf)
+{}
bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy
{
diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h
index e11dac319..8cc5b7968 100644
--- a/evmjit/libevmjit/Runtime.h
+++ b/evmjit/libevmjit/Runtime.h
@@ -32,7 +32,6 @@ class Runtime
{
public:
Runtime(RuntimeData* _data, Env* _env);
- ~Runtime();
Runtime(const Runtime&) = delete;
void operator=(const Runtime&) = delete;
@@ -43,15 +42,13 @@ public:
bytes getReturnData() const;
jmp_buf_ref getJmpBuf() { return m_jmpBuf; }
- static jmp_buf_ref getCurrJmpBuf();
private:
RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract.
Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract.
jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract.
byte* m_memoryData = nullptr;
- i256 m_memorySize = {};
- jmp_buf_ref m_prevJmpBuf;
+ i256 m_memorySize;
std::jmp_buf m_jmpBuf;
StackImpl m_stack;
MemoryImpl m_memory;
diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h
index 89987bdeb..bb52f7864 100644
--- a/evmjit/libevmjit/RuntimeData.h
+++ b/evmjit/libevmjit/RuntimeData.h
@@ -21,7 +21,6 @@ struct RuntimeData
CallValue,
CallDataSize,
GasPrice,
- PrevHash,
CoinBase,
TimeStamp,
Number,
diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp
index 14280f80f..ea2fe20b5 100644
--- a/evmjit/libevmjit/RuntimeManager.cpp
+++ b/evmjit/libevmjit/RuntimeManager.cpp
@@ -63,7 +63,6 @@ llvm::Twine getName(RuntimeData::Index _index)
case RuntimeData::CallValue: return "callvalue";
case RuntimeData::CallDataSize: return "calldatasize";
case RuntimeData::GasPrice: return "gasprice";
- case RuntimeData::PrevHash: return "prevhash";
case RuntimeData::CoinBase: return "coinbase";
case RuntimeData::TimeStamp: return "timestamp";
case RuntimeData::Number: return "number";
@@ -154,7 +153,6 @@ llvm::Value* RuntimeManager::get(Instruction _inst)
case Instruction::CALLVALUE: return get(RuntimeData::CallValue);
case Instruction::CALLDATASIZE: return get(RuntimeData::CallDataSize);
case Instruction::GASPRICE: return get(RuntimeData::GasPrice);
- case Instruction::PREVHASH: return get(RuntimeData::PrevHash);
case Instruction::COINBASE: return get(RuntimeData::CoinBase);
case Instruction::TIMESTAMP: return get(RuntimeData::TimeStamp);
case Instruction::NUMBER: return get(RuntimeData::Number);
diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp
index f1ffbf67f..0fd9c0e41 100644
--- a/evmjit/libevmjit/Utils.cpp
+++ b/evmjit/libevmjit/Utils.cpp
@@ -1,8 +1,5 @@
-#include
#include "Utils.h"
-#include "Instruction.h"
-#include "Runtime.h"
namespace dev
{
@@ -38,29 +35,6 @@ i256 eth2llvm(u256 _u)
return i;
}
-llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
-{
- auto pushInst = *_curr;
- assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
- auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1;
- llvm::APInt value(256, 0);
- ++_curr; // Point the data
- for (decltype(numBytes) i = 0; i < numBytes; ++i)
- {
- byte b = (_curr != _end) ? *_curr++ : 0;
- value <<= 8;
- value |= b;
- }
- --_curr; // Point the last real byte read
- return value;
-}
-
-void terminate(ReturnCode _returnCode)
-{
- auto jmpBuf = Runtime::getCurrJmpBuf();
- std::longjmp(jmpBuf, static_cast(_returnCode));
-}
-
}
}
}
diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h
index db0647fdf..f672365c6 100644
--- a/evmjit/libevmjit/Utils.h
+++ b/evmjit/libevmjit/Utils.h
@@ -17,8 +17,6 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } };
u256 llvm2eth(i256);
i256 eth2llvm(u256);
-void terminate(ReturnCode _returnCode);
-
}
}
}
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/libdevcore/vector_ref.h b/libdevcore/vector_ref.h
index 2771c739a..0cd3f8064 100644
--- a/libdevcore/vector_ref.h
+++ b/libdevcore/vector_ref.h
@@ -28,7 +28,7 @@ public:
bool contentsEqual(std::vector const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); }
std::vector toVector() const { return std::vector(m_data, m_data + m_count); }
- std::vector toBytes() const { return std::vector((unsigned char const*)m_data, m_data + m_count * sizeof(_T)); }
+ std::vector toBytes() const { return std::vector((unsigned char const*)m_data, (unsigned char const*)m_data + m_count * sizeof(_T)); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); }
template operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); }
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 d8967c084..c963ee401 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,29 @@ 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);
+ {
+ 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 +207,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 +223,82 @@ 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++;
+ try {
+ i.second.changes += m_filters.at(i.second.id).changes;
+ } catch(...){}
}
+ // 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();
+}
+
+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::appendFromNewBlock(h256 _block, h256Set& o_changed) const
+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 +525,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);
@@ -534,7 +592,7 @@ eth::State Client::state(unsigned _txi) const
StateDiff Client::diff(unsigned _txi, int _block) const
{
- State st = state(_block);
+ State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
@@ -591,16 +649,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 +672,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 +707,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 6a3d7ec22..d0dce4cc1 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,6 +78,7 @@ struct InstalledFilter
LogFilter filter;
unsigned refCount = 1;
+ LocalisedLogEntries changes;
};
static const h256 PendingChangedFilter = u256(0);
@@ -95,7 +90,7 @@ struct ClientWatch
explicit ClientWatch(h256 _id): id(_id) {}
h256 id;
- unsigned changes = 1;
+ LocalisedLogEntries changes;
};
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; };
@@ -108,9 +103,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 {}; }
@@ -119,15 +114,15 @@ template bytes abiInAux(T const& _t, U const& ... _u)
return ABISerialiser::serialise(_t) + abiInAux(_u ...);
}
-template bytes abiIn(byte _id, T const& ... _t)
+template bytes abiIn(std::string _id, T const& ... _t)
{
- return bytes(1, _id) + abiInAux(_t ...);
+ return sha3(_id).ref().cropped(0, 4).toBytes() + abiInAux(_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 +183,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 +287,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 +308,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 +316,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/Executive.cpp b/libethereum/Executive.cpp
index f79bb4a3b..c4ce543d6 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -146,9 +146,17 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception);
// Execute _init.
- m_vm = VMFactory::create(_gas);
- m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
- return _init.empty();
+ if (_init.empty())
+ {
+ m_s.m_cache[m_newAddress].setCode({});
+ m_endGas = _gas;
+ }
+ else
+ {
+ m_vm = VMFactory::create(_gas);
+ m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
+ }
+ return !m_ext;
}
OnOpFunc Executive::simpleTrace()
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..4307d9da0 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] = 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/libevm/VM.h b/libevm/VM.h
index b8a33909c..ecf5de292 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -77,768 +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);
- u256 inOff = m_stack[m_stack.size() - 2];
- u256 inSize = m_stack[m_stack.size() - 3];
- newTempSize = (bigint)inOff + inSize;
- 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/libevmcore/Instruction.h b/libevmcore/Instruction.h
index a28e8f8da..5cf002c4c 100644
--- a/libevmcore/Instruction.h
+++ b/libevmcore/Instruction.h
@@ -215,6 +215,14 @@ inline Instruction swapInstruction(unsigned _number)
return Instruction(unsigned(Instruction::SWAP1) + _number - 1);
}
+/// @returns the LOG<_number> instruction
+inline Instruction logInstruction(unsigned _number)
+{
+ if (asserts(_number <= 4))
+ BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("Invalid LOG instruction requested."));
+ return Instruction(unsigned(Instruction::LOG0) + _number);
+}
+
/// Information structure for a particular instruction.
struct InstructionInfo
{
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 e496c30f4..400a66815 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.js
+++ b/libjsqrc/ethereumjs/dist/ethereum.js
@@ -93,6 +93,12 @@ var setupInputTypes = function () {
}
var padding = calcPadding(type, expected);
+ 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);
if (typeof value === "number")
value = value.toString(16);
else if (typeof value === "string")
@@ -111,6 +117,8 @@ var setupInputTypes = function () {
return false;
}
+ padding = 32; //override as per the new ABI.
+
return padLeft(formatter ? formatter(value) : value, padding * 2);
};
};
@@ -141,7 +149,6 @@ var toAbiInput = function (json, methodName, params) {
return;
}
- bytes = "0x" + padLeft(index.toString(16), 2);
var method = json[index];
for (var i = 0; i < method.inputs.length; i++) {
@@ -167,12 +174,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;
};
};
@@ -260,11 +271,25 @@ var outputParser = function (json) {
return parser;
};
+var methodSignature = function (json, name) {
+ var method = json[findMethodIndex(json, name)];
+ var result = name + '(';
+ var inputTypes = method.inputs.map(function (inp) {
+ return inp.type;
+ });
+ result += inputTypes.join(',');
+ result += ')';
+
+ return web3.sha3(web3.fromAscii(result));
+};
+
module.exports = {
inputParser: inputParser,
- outputParser: outputParser
+ outputParser: outputParser,
+ methodSignature: methodSignature
};
+
},{}],2:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -298,7 +323,7 @@ module.exports = {
// TODO: is these line is supposed to be here?
if ("build" !== 'build') {/*
var WebSocket = require('ws'); // jshint ignore:line
- var web3 = require('./main.js'); // jshint ignore:line
+ var web3 = require('./web3'); // jshint ignore:line
*/}
var AutoProvider = function (userOptions) {
@@ -399,6 +424,9 @@ if ("build" !== 'build') {/*
var abi = require('./abi');
+// method signature length in bytes
+var ETH_METHOD_SIGNATURE_LENGTH = 4;
+
var contract = function (address, desc) {
var inputParser = abi.inputParser(desc);
var outputParser = abi.outputParser(desc);
@@ -418,14 +446,18 @@ var contract = function (address, desc) {
call: function (extra) {
extra = extra || {};
extra.to = address;
- extra.data = parsed;
- return web3.eth.call(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.call(extra).then(onSuccess);
+ });
},
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);
+ });
}
};
};
@@ -549,6 +581,53 @@ module.exports = HttpRpcProvider;
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see .
*/
+/** @file qt.js
+ * @authors:
+ * Jeffrey Wilcke
+ * Marek Kotewicz
+ * @date 2014
+ */
+
+var QtProvider = function() {
+ this.handlers = [];
+
+ var self = this;
+ navigator.qt.onmessage = function (message) {
+ self.handlers.forEach(function (handler) {
+ handler.call(self, JSON.parse(message.data));
+ });
+ };
+};
+
+QtProvider.prototype.send = function(payload) {
+ navigator.qt.postMessage(JSON.stringify(payload));
+};
+
+Object.defineProperty(QtProvider.prototype, "onmessage", {
+ set: function(handler) {
+ this.handlers.push(handler);
+ }
+});
+
+module.exports = QtProvider;
+
+},{}],6:[function(require,module,exports){
+/*
+ This file is part of ethereum.js.
+
+ ethereum.js is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ ethereum.js is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with ethereum.js. If not, see .
+*/
/** @file main.js
* @authors:
* Jeffrey Wilcke
@@ -791,7 +870,7 @@ var web3 = {
},
fromAscii: function(str, pad) {
- pad = pad === undefined ? 32 : pad;
+ pad = pad === undefined ? 0 : pad;
var hex = this.toHex(str);
while(hex.length < pad*2)
hex += "00";
@@ -1040,54 +1119,8 @@ function messageHandler(data) {
}
}
-module.exports = web3;
-
-},{}],6:[function(require,module,exports){
-/*
- This file is part of ethereum.js.
-
- ethereum.js is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- ethereum.js is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with ethereum.js. If not, see .
-*/
-/** @file qt.js
- * @authors:
- * Jeffrey Wilcke
- * Marek Kotewicz
- * @date 2014
- */
-
-var QtProvider = function() {
- this.handlers = [];
-
- var self = this;
- navigator.qt.onmessage = function (message) {
- self.handlers.forEach(function (handler) {
- handler.call(self, JSON.parse(message.data));
- });
- };
-};
-
-QtProvider.prototype.send = function(payload) {
- navigator.qt.postMessage(JSON.stringify(payload));
-};
-
-Object.defineProperty(QtProvider.prototype, "onmessage", {
- set: function(handler) {
- this.handlers.push(handler);
- }
-});
-
-module.exports = QtProvider;
+if (typeof(module) !== "undefined")
+ module.exports = web3;
},{}],7:[function(require,module,exports){
/*
@@ -1166,10 +1199,11 @@ Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
set: function(provider) { this.onMessage(provider); }
});
-module.exports = WebSocketProvider;
+if (typeof(module) !== "undefined")
+ module.exports = WebSocketProvider;
},{}],"web3":[function(require,module,exports){
-var web3 = require('./lib/main');
+var web3 = require('./lib/web3');
web3.providers.WebSocketProvider = require('./lib/websocket');
web3.providers.HttpRpcProvider = require('./lib/httprpc');
web3.providers.QtProvider = require('./lib/qt');
@@ -1178,7 +1212,7 @@ web3.contract = require('./lib/contract');
module.exports = web3;
-},{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/main":5,"./lib/qt":6,"./lib/websocket":7}]},{},["web3"])
+},{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/qt":5,"./lib/web3":6,"./lib/websocket":7}]},{},["web3"])
//# sourceMappingURL=ethereum.js.map
\ No newline at end of file
diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map
index b54a294d7..e60f94922 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.js.map
+++ b/libjsqrc/ethereumjs/dist/ethereum.js.map
@@ -6,24 +6,24 @@
"lib/autoprovider.js",
"lib/contract.js",
"lib/httprpc.js",
- "lib/main.js",
"lib/qt.js",
+ "lib/web3.js",
"lib/websocket.js",
"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;;ACzQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC7EA;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;;AClSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 bytes = \"0x\" + padLeft(index.toString(16), 2);\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\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser\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('./main.js'); // 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\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 extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\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 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 (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 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 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 ? '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 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 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 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 ? 32 : 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\nmodule.exports = web3;\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 websocket.js\n * @authors:\n * Jeffrey Wilcke \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 WebSocket = require('ws'); // jshint ignore:line\n*/}\n\nvar WebSocketProvider = function(host) {\n // onmessage handlers\n this.handlers = [];\n // queue will be filled with messages if send is invoked before the ws is ready\n this.queued = [];\n this.ready = false;\n\n this.ws = new WebSocket(host);\n\n var self = this;\n this.ws.onmessage = function(event) {\n for(var i = 0; i < self.handlers.length; i++) {\n self.handlers[i].call(self, JSON.parse(event.data), event);\n }\n };\n\n this.ws.onopen = function() {\n self.ready = true;\n\n for(var i = 0; i < self.queued.length; i++) {\n // Resend\n self.send(self.queued[i]);\n }\n };\n};\n\nWebSocketProvider.prototype.send = function(payload) {\n if(this.ready) {\n var data = JSON.stringify(payload);\n\n this.ws.send(data);\n } else {\n this.queued.push(payload);\n }\n};\n\nWebSocketProvider.prototype.onMessage = function(handler) {\n this.handlers.push(handler);\n};\n\nWebSocketProvider.prototype.unload = function() {\n this.ws.close();\n};\nObject.defineProperty(WebSocketProvider.prototype, \"onmessage\", {\n set: function(provider) { this.onMessage(provider); }\n});\n\nmodule.exports = WebSocketProvider;\n",
- "var web3 = require('./lib/main');\nweb3.providers.WebSocketProvider = require('./lib/websocket');\nweb3.providers.HttpRpcProvider = require('./lib/httprpc');\nweb3.providers.QtProvider = require('./lib/qt');\nweb3.providers.AutoProvider = require('./lib/autoprovider');\nweb3.contract = require('./lib/contract');\n\nmodule.exports = web3;\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",
+ "/*\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