diff --git a/CMakeLists.txt b/CMakeLists.txt index a3a5702f1..221087884 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ endfunction() function(createBuildInfo) # Set build platform; to be written to BuildInfo.h + set(ETH_BUILD_PLATFORM ${TARGET_PLATFORM}) if (CMAKE_COMPILER_IS_MINGW) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw") elseif (CMAKE_COMPILER_IS_MSYS) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index e5e5a9f56..2ce00b0e3 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -173,6 +173,7 @@ + @@ -2055,6 +2056,17 @@ font-size: 14pt Clear Pe&nd&ing + + + true + + + false + + + Use &LLVM-EVM + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e15d08ab8..01b112b50 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -243,14 +244,14 @@ void Main::onKeysChanged() installBalancesWatch(); } -unsigned Main::installWatch(dev::eth::LogFilter const& _tf, std::function const& _f) +unsigned Main::installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; return ret; } -unsigned Main::installWatch(dev::h256 _tf, std::function const& _f) +unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; @@ -265,10 +266,10 @@ void Main::uninstallWatch(unsigned _w) void Main::installWatches() { - installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installNameRegWatch(); }); - installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installCurrenciesWatch(); }); - installWatch(dev::eth::PendingChangedFilter, [=](){ onNewPending(); }); - installWatch(dev::eth::ChainChangedFilter, [=](){ onNewBlock(); }); + installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); }); + installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); }); + installWatch(dev::eth::PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); }); + installWatch(dev::eth::ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); }); } Address Main::getNameReg() const @@ -284,13 +285,13 @@ Address Main::getCurrencies() const void Main::installNameRegWatch() { uninstallWatch(m_nameRegFilter); - m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](){ onNameRegChange(); }); + m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](LocalisedLogEntries const&){ onNameRegChange(); }); } void Main::installCurrenciesWatch() { uninstallWatch(m_currenciesFilter); - m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](){ onCurrenciesChange(); }); + m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](LocalisedLogEntries const&){ onCurrenciesChange(); }); } void Main::installBalancesWatch() @@ -308,7 +309,7 @@ void Main::installBalancesWatch() tf.address(c).topic(h256(i.address(), h256::AlignRight)); uninstallWatch(m_balancesFilter); - m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); }); + m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); } void Main::onNameRegChange() @@ -644,6 +645,7 @@ void Main::writeSettings() s.setValue("url", ui->urlEdit->text()); s.setValue("privateChain", m_privateChain); s.setValue("verbosity", ui->verbosity->value()); + s.setValue("jitvm", ui->jitvm->isChecked()); bytes d = m_webThree->saveNodes(); if (d.size()) @@ -718,6 +720,7 @@ void Main::readSettings(bool _skipGeometry) m_privateChain = s.value("privateChain", "").toString(); ui->usePrivate->setChecked(m_privateChain.size()); ui->verbosity->setValue(s.value("verbosity", 1).toInt()); + ui->jitvm->setChecked(s.value("jitvm", true).toBool()); ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html on_urlEdit_returnPressed(); @@ -817,6 +820,12 @@ void Main::on_usePrivate_triggered() on_killBlockchain_triggered(); } +void Main::on_jitvm_triggered() +{ + bool jit = ui->jitvm->isChecked(); + VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); +} + void Main::on_urlEdit_returnPressed() { QString s = ui->urlEdit->text(); @@ -1162,8 +1171,11 @@ void Main::timerEvent(QTimerEvent*) m_qweb->poll(); for (auto const& i: m_handlers) - if (ethereum()->checkWatch(i.first)) - i.second(); + { + auto ls = ethereum()->checkWatch(i.first); + if (ls.size()) + i.second(ls); + } } string Main::renderDiff(dev::eth::StateDiff const& _d) const @@ -1265,7 +1277,7 @@ void Main::on_transactionQueue_currentItemChanged() auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " << toHex(receipt.rlp()) << "
"; - s << renderDiff(ethereum()->diff(i, -1)); + s << renderDiff(ethereum()->diff(i, 0)); // s << "Pre: " << fs.rootHash() << "
"; // s << "Post: " << ts.rootHash() << ""; } @@ -1802,8 +1814,6 @@ void Main::on_net_triggered() web3()->setClientVersion(n); if (ui->net->isChecked()) { - // TODO: alter network stuff? - //ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0 web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setNetworkPreferences(netPrefs()); ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index bb79e59ef..52a71102d 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -66,6 +66,8 @@ struct WorldState std::vector levels; }; +using WatchHandler = std::function; + class Main : public QMainWindow { Q_OBJECT @@ -156,6 +158,7 @@ private slots: void on_importKeyFile_triggered(); void on_post_clicked(); void on_newIdentity_triggered(); + void on_jitvm_triggered(); void refreshWhisper(); void refreshBlockChain(); @@ -194,8 +197,8 @@ private: dev::u256 value() const; dev::u256 gasPrice() const; - unsigned installWatch(dev::eth::LogFilter const& _tf, std::function const& _f); - unsigned installWatch(dev::h256 _tf, std::function const& _f); + unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f); + unsigned installWatch(dev::h256 _tf, WatchHandler const& _f); void uninstallWatch(unsigned _w); void keysChanged(); @@ -228,7 +231,7 @@ private: std::unique_ptr m_webThree; - std::map> m_handlers; + std::map m_handlers; unsigned m_nameRegFilter = (unsigned)-1; unsigned m_currenciesFilter = (unsigned)-1; unsigned m_balancesFilter = (unsigned)-1; diff --git a/eth/main.cpp b/eth/main.cpp index a0a605193..dfe020763 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -180,6 +180,12 @@ void sighandler(int) g_exit = true; } +enum class NodeMode +{ + PeerServer, + Full +}; + int main(int argc, char** argv) { unsigned short listenPort = 30303; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index f4803bd52..adcf70b61 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "SHA3.h" #include "FileSystem.h" #include "CryptoPP.h" @@ -139,7 +140,7 @@ h256 Nonce::get(bool _commit) static h256 s_seed; static string s_seedFile(getDataDir() + "/seed"); static mutex s_x; - lock_guard l(s_x); + Guard l(s_x); if (!s_seed) { static Nonce s_nonce; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index d73e3fa43..acd59184f 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -20,6 +20,7 @@ */ #include "CryptoPP.h" +#include using namespace std; using namespace dev; @@ -40,7 +41,7 @@ void Secp256k1::encrypt(Public const& _k, bytes& io_cipher) ciphertext.resize(e.CiphertextLength(plen)); { - lock_guard l(x_rng); + Guard l(x_rng); e.Encrypt(m_rng, io_cipher.data(), plen, ciphertext.data()); } @@ -65,7 +66,7 @@ void Secp256k1::decrypt(Secret const& _k, bytes& io_text) DecodingResult r; { - lock_guard l(x_rng); + Guard l(x_rng); r = d.Decrypt(m_rng, io_text.data(), clen, plain.data()); } @@ -99,7 +100,7 @@ Signature Secp256k1::sign(Secret const& _key, h256 const& _hash) ECP::Point rp; Integer r; { - lock_guard l(x_params); + Guard l(x_params); rp = m_params.ExponentiateBase(k); r = m_params.ConvertElementToInteger(rp); } @@ -149,7 +150,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Element x; { - lock_guard l(x_curve); + Guard l(x_curve); m_curve.DecodePoint(x, encodedpoint, 33); if (!m_curve.VerifyPoint(x)) return recovered; @@ -158,7 +159,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) // if (_signature[64] & 2) // { // r += m_q; -// lock_guard l(x_params); +// Guard l(x_params); // if (r >= m_params.GetMaxExponent()) // return recovered; // } @@ -171,7 +172,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Point p; byte recoveredbytes[65]; { - lock_guard l(x_curve); + Guard l(x_curve); // todo: make generator member p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); m_curve.EncodePoint(recoveredbytes, p, false); @@ -210,7 +211,7 @@ void Secp256k1::exportPublicKey(CryptoPP::DL_PublicKey_EC const& bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); { - lock_guard l(x_params); + Guard l(x_params); m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); } @@ -223,7 +224,7 @@ void Secp256k1::exponentToPublic(Integer const& _e, Public& o_p) CryptoPP::DL_PublicKey_EC pk; { - lock_guard l(x_params); + Guard l(x_params); pk.Initialize(m_params, m_params.ExponentiateBase(_e)); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index a57faf546..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(); } -void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const +LocalisedLogEntries Client::checkWatch(unsigned _watchId) +{ + Guard l(m_filterLock); + LocalisedLogEntries ret; + + try { + std::swap(ret, m_watches.at(_watchId).changes); + } catch (...) {} + + return ret; +} + +void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed) +{ + Guard l(m_filterLock); + for (pair& i: m_filters) + if ((unsigned)i.second.filter.latest() > m_bc.number()) + { + // acceptable number. + auto m = i.second.filter.matches(_receipt); + if (m.size()) + { + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1)); + io_changed.insert(i.first); + } + } +} + +void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) { // TODO: more precise check on whether the txs match. auto d = m_bc.info(_block); + auto br = m_bc.receipts(_block); - lock_guard l(m_filterLock); - for (pair const& i: m_filters) + Guard l(m_filterLock); + for (pair& i: m_filters) if ((unsigned)i.second.filter.latest() >= d.number && (unsigned)i.second.filter.earliest() <= d.number && i.second.filter.matches(d.logBloom)) - o_changed.insert(i.first); + // acceptable number & looks like block may contain a matching log entry. + for (TransactionReceipt const& tr: br.receipts) + { + auto m = i.second.filter.matches(tr); + if (m.size()) + { + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, (unsigned)d.number)); + io_changed.insert(i.first); + } + } } void Client::setForceMining(bool _enable) @@ -467,10 +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); @@ -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 efe076dab..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 {}; } @@ -125,9 +120,9 @@ template bytes abiIn(std::string _id, T const& ... _t) } template struct ABIDeserialiser {}; -template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret; io_t.cropped(0, N).populate(ret.ref()); return ret; } }; +template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; -template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } }; +template <> struct ABIDeserialiser { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template T abiOut(bytes const& _data) @@ -188,11 +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/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 377effe11..ecf5de292 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -77,766 +77,5 @@ private: std::function m_onFail; }; -// TODO: Move it to cpp file. Not done to make review easier. -inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) -{ - auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; - - if (m_jumpDests.empty()) - for (unsigned i = 0; i < _ext.code.size(); ++i) - if (_ext.code[i] == (byte)Instruction::JUMPDEST) - m_jumpDests.insert(i); - else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) - i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; - u256 nextPC = m_curPC + 1; - auto osteps = _steps; - for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1) - { - // INSTRUCTION... - Instruction inst = (Instruction)_ext.getCode(m_curPC); - - // FEES... - bigint runGas = c_stepGas; - bigint newTempSize = m_temp.size(); - bigint copySize = 0; - - auto onOperation = [&]() - { - if (_onOp) - _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); - }; - // should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird. - //m_onFail = std::function(onOperation); - - switch (inst) - { - case Instruction::STOP: - runGas = 0; - break; - - case Instruction::SUICIDE: - require(1); - runGas = 0; - break; - - case Instruction::SSTORE: - require(2); - if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) - runGas = c_sstoreSetGas; - else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) - { - runGas = 0; - _ext.sub.refunds += c_sstoreRefundGas; - } - else - runGas = c_sstoreResetGas; - break; - - case Instruction::SLOAD: - require(1); - runGas = c_sloadGas; - break; - - // These all operate on memory and therefore potentially expand it: - case Instruction::MSTORE: - require(2); - newTempSize = (bigint)m_stack.back() + 32; - break; - case Instruction::MSTORE8: - require(2); - newTempSize = (bigint)m_stack.back() + 1; - break; - case Instruction::MLOAD: - require(1); - newTempSize = (bigint)m_stack.back() + 32; - break; - case Instruction::RETURN: - require(2); - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); - break; - case Instruction::SHA3: - require(2); - runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); - break; - case Instruction::CALLDATACOPY: - require(3); - copySize = m_stack[m_stack.size() - 3]; - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); - break; - case Instruction::CODECOPY: - require(3); - copySize = m_stack[m_stack.size() - 3]; - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); - break; - case Instruction::EXTCODECOPY: - require(4); - copySize = m_stack[m_stack.size() - 4]; - newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]); - break; - - case Instruction::BALANCE: - require(1); - runGas = c_balanceGas; - break; - case Instruction::LOG0: - case Instruction::LOG1: - case Instruction::LOG2: - case Instruction::LOG3: - case Instruction::LOG4: - { - unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0; - require(n + 2); - runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2]; - newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]); - break; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - require(7); - runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1]; - newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5])); - break; - - case Instruction::CREATE: - { - require(3); - newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]); - runGas = c_createGas; - break; - } - case Instruction::EXP: - { - require(2); - auto expon = m_stack[m_stack.size() - 2]; - runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8)); - break; - } - - case Instruction::BLOCKHASH: - require(1); - break; - - case Instruction::PC: - case Instruction::MSIZE: - case Instruction::GAS: - case Instruction::JUMPDEST: - case Instruction::ADDRESS: - case Instruction::ORIGIN: - case Instruction::CALLER: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - case Instruction::PUSH1: - case Instruction::PUSH2: - case Instruction::PUSH3: - case Instruction::PUSH4: - case Instruction::PUSH5: - case Instruction::PUSH6: - case Instruction::PUSH7: - case Instruction::PUSH8: - case Instruction::PUSH9: - case Instruction::PUSH10: - case Instruction::PUSH11: - case Instruction::PUSH12: - case Instruction::PUSH13: - case Instruction::PUSH14: - case Instruction::PUSH15: - case Instruction::PUSH16: - case Instruction::PUSH17: - case Instruction::PUSH18: - case Instruction::PUSH19: - case Instruction::PUSH20: - case Instruction::PUSH21: - case Instruction::PUSH22: - case Instruction::PUSH23: - case Instruction::PUSH24: - case Instruction::PUSH25: - case Instruction::PUSH26: - case Instruction::PUSH27: - case Instruction::PUSH28: - case Instruction::PUSH29: - case Instruction::PUSH30: - case Instruction::PUSH31: - case Instruction::PUSH32: - break; - case Instruction::NOT: - case Instruction::ISZERO: - case Instruction::CALLDATALOAD: - case Instruction::EXTCODESIZE: - case Instruction::POP: - case Instruction::JUMP: - require(1); - break; - case Instruction::ADD: - case Instruction::MUL: - case Instruction::SUB: - case Instruction::DIV: - case Instruction::SDIV: - case Instruction::MOD: - case Instruction::SMOD: - case Instruction::LT: - case Instruction::GT: - case Instruction::SLT: - case Instruction::SGT: - case Instruction::EQ: - case Instruction::AND: - case Instruction::OR: - case Instruction::XOR: - case Instruction::BYTE: - case Instruction::JUMPI: - case Instruction::SIGNEXTEND: - require(2); - break; - case Instruction::ADDMOD: - case Instruction::MULMOD: - require(3); - break; - case Instruction::DUP1: - case Instruction::DUP2: - case Instruction::DUP3: - case Instruction::DUP4: - case Instruction::DUP5: - case Instruction::DUP6: - case Instruction::DUP7: - case Instruction::DUP8: - case Instruction::DUP9: - case Instruction::DUP10: - case Instruction::DUP11: - case Instruction::DUP12: - case Instruction::DUP13: - case Instruction::DUP14: - case Instruction::DUP15: - case Instruction::DUP16: - require(1 + (int)inst - (int)Instruction::DUP1); - break; - case Instruction::SWAP1: - case Instruction::SWAP2: - case Instruction::SWAP3: - case Instruction::SWAP4: - case Instruction::SWAP5: - case Instruction::SWAP6: - case Instruction::SWAP7: - case Instruction::SWAP8: - case Instruction::SWAP9: - case Instruction::SWAP10: - case Instruction::SWAP11: - case Instruction::SWAP12: - case Instruction::SWAP13: - case Instruction::SWAP14: - case Instruction::SWAP15: - case Instruction::SWAP16: - require((int)inst - (int)Instruction::SWAP1 + 2); - break; - default: - BOOST_THROW_EXCEPTION(BadInstruction()); - } - - newTempSize = (newTempSize + 31) / 32 * 32; - if (newTempSize > m_temp.size()) - runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; - runGas += c_copyGas * (copySize + 31) / 32; - - onOperation(); -// if (_onOp) -// _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); - - if (m_gas < runGas) - { - // Out of gas! - m_gas = 0; - BOOST_THROW_EXCEPTION(OutOfGas()); - } - - m_gas = (u256)((bigint)m_gas - runGas); - - if (newTempSize > m_temp.size()) - m_temp.resize((size_t)newTempSize); - - // EXECUTE... - switch (inst) - { - case Instruction::ADD: - //pops two items and pushes S[-1] + S[-2] mod 2^256. - m_stack[m_stack.size() - 2] += m_stack.back(); - m_stack.pop_back(); - break; - case Instruction::MUL: - //pops two items and pushes S[-1] * S[-2] mod 2^256. - m_stack[m_stack.size() - 2] *= m_stack.back(); - m_stack.pop_back(); - break; - case Instruction::SUB: - m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::DIV: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() / m_stack[m_stack.size() - 2] : 0; - m_stack.pop_back(); - break; - case Instruction::SDIV: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0; - m_stack.pop_back(); - break; - case Instruction::MOD: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() % m_stack[m_stack.size() - 2] : 0; - m_stack.pop_back(); - break; - case Instruction::SMOD: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0; - m_stack.pop_back(); - break; - case Instruction::EXP: - { - auto base = m_stack.back(); - auto expon = m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); - break; - } - case Instruction::NOT: - m_stack.back() = ~m_stack.back(); - break; - case Instruction::LT: - m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::GT: - m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::SLT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::SGT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::EQ: - m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::ISZERO: - m_stack.back() = m_stack.back() ? 0 : 1; - break; - case Instruction::AND: - m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::OR: - m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::XOR: - m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::BYTE: - m_stack[m_stack.size() - 2] = m_stack.back() < 32 ? (m_stack[m_stack.size() - 2] >> (unsigned)(8 * (31 - m_stack.back()))) & 0xff : 0; - m_stack.pop_back(); - break; - case Instruction::ADDMOD: - m_stack[m_stack.size() - 3] = u256((bigint(m_stack.back()) + bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::MULMOD: - m_stack[m_stack.size() - 3] = u256((bigint(m_stack.back()) * bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::SIGNEXTEND: - if (m_stack.back() < 31) - { - unsigned const testBit(m_stack.back() * 8 + 7); - u256& number = m_stack[m_stack.size() - 2]; - u256 mask = ((u256(1) << testBit) - 1); - if (boost::multiprecision::bit_test(number, testBit)) - number |= ~mask; - else - number &= mask; - } - m_stack.pop_back(); - break; - case Instruction::SHA3: - { - unsigned inOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned inSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - m_stack.push_back(sha3(bytesConstRef(m_temp.data() + inOff, inSize))); - break; - } - case Instruction::ADDRESS: - m_stack.push_back(fromAddress(_ext.myAddress)); - break; - case Instruction::ORIGIN: - m_stack.push_back(fromAddress(_ext.origin)); - break; - case Instruction::BALANCE: - { - m_stack.back() = _ext.balance(asAddress(m_stack.back())); - break; - } - case Instruction::CALLER: - m_stack.push_back(fromAddress(_ext.caller)); - break; - case Instruction::CALLVALUE: - m_stack.push_back(_ext.value); - break; - case Instruction::CALLDATALOAD: - { - if ((unsigned)m_stack.back() + (uint64_t)31 < _ext.data.size()) - m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back()); - else - { - h256 r; - for (uint64_t i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + (uint64_t)32, j = 0; i < e; ++i, ++j) - r[j] = i < _ext.data.size() ? _ext.data[i] : 0; - m_stack.back() = (u256)r; - } - break; - } - case Instruction::CALLDATASIZE: - m_stack.push_back(_ext.data.size()); - break; - case Instruction::CODESIZE: - m_stack.push_back(_ext.code.size()); - break; - case Instruction::EXTCODESIZE: - m_stack.back() = _ext.codeAt(asAddress(m_stack.back())).size(); - break; - case Instruction::CALLDATACOPY: - case Instruction::CODECOPY: - case Instruction::EXTCODECOPY: - { - Address a; - if (inst == Instruction::EXTCODECOPY) - { - a = asAddress(m_stack.back()); - m_stack.pop_back(); - } - unsigned offset = (unsigned)m_stack.back(); - m_stack.pop_back(); - u256 index = m_stack.back(); - m_stack.pop_back(); - unsigned size = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned sizeToBeCopied; - switch(inst) - { - case Instruction::CALLDATACOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.data.size() ? (u256)_ext.data.size() < index ? 0 : _ext.data.size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.data.data() + (unsigned)index, sizeToBeCopied); - break; - case Instruction::CODECOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.code.size() ? (u256)_ext.code.size() < index ? 0 : _ext.code.size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.code.data() + (unsigned)index, sizeToBeCopied); - break; - case Instruction::EXTCODECOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < index ? 0 : _ext.codeAt(a).size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.codeAt(a).data() + (unsigned)index, sizeToBeCopied); - break; - default: - // this is unreachable, but if someone introduces a bug in the future, he may get here. - assert(false); - BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("CALLDATACOPY, CODECOPY or EXTCODECOPY instruction requested.")); - break; - } - memset(m_temp.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied); - break; - } - case Instruction::GASPRICE: - m_stack.push_back(_ext.gasPrice); - break; - case Instruction::BLOCKHASH: - m_stack.back() = (u256)_ext.blockhash(m_stack.back()); - break; - case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); - break; - case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); - break; - case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); - break; - case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); - break; - case Instruction::GASLIMIT: - m_stack.push_back(1000000); - break; - case Instruction::PUSH1: - case Instruction::PUSH2: - case Instruction::PUSH3: - case Instruction::PUSH4: - case Instruction::PUSH5: - case Instruction::PUSH6: - case Instruction::PUSH7: - case Instruction::PUSH8: - case Instruction::PUSH9: - case Instruction::PUSH10: - case Instruction::PUSH11: - case Instruction::PUSH12: - case Instruction::PUSH13: - case Instruction::PUSH14: - case Instruction::PUSH15: - case Instruction::PUSH16: - case Instruction::PUSH17: - case Instruction::PUSH18: - case Instruction::PUSH19: - case Instruction::PUSH20: - case Instruction::PUSH21: - case Instruction::PUSH22: - case Instruction::PUSH23: - case Instruction::PUSH24: - case Instruction::PUSH25: - case Instruction::PUSH26: - case Instruction::PUSH27: - case Instruction::PUSH28: - case Instruction::PUSH29: - case Instruction::PUSH30: - case Instruction::PUSH31: - case Instruction::PUSH32: - { - int i = (int)inst - (int)Instruction::PUSH1 + 1; - nextPC = m_curPC + 1; - m_stack.push_back(0); - for (; i--; nextPC++) - m_stack.back() = (m_stack.back() << 8) | _ext.getCode(nextPC); - break; - } - case Instruction::POP: - m_stack.pop_back(); - break; - case Instruction::DUP1: - case Instruction::DUP2: - case Instruction::DUP3: - case Instruction::DUP4: - case Instruction::DUP5: - case Instruction::DUP6: - case Instruction::DUP7: - case Instruction::DUP8: - case Instruction::DUP9: - case Instruction::DUP10: - case Instruction::DUP11: - case Instruction::DUP12: - case Instruction::DUP13: - case Instruction::DUP14: - case Instruction::DUP15: - case Instruction::DUP16: - { - auto n = 1 + (int)inst - (int)Instruction::DUP1; - m_stack.push_back(m_stack[m_stack.size() - n]); - break; - } - case Instruction::SWAP1: - case Instruction::SWAP2: - case Instruction::SWAP3: - case Instruction::SWAP4: - case Instruction::SWAP5: - case Instruction::SWAP6: - case Instruction::SWAP7: - case Instruction::SWAP8: - case Instruction::SWAP9: - case Instruction::SWAP10: - case Instruction::SWAP11: - case Instruction::SWAP12: - case Instruction::SWAP13: - case Instruction::SWAP14: - case Instruction::SWAP15: - case Instruction::SWAP16: - { - unsigned n = (int)inst - (int)Instruction::SWAP1 + 2; - auto d = m_stack.back(); - m_stack.back() = m_stack[m_stack.size() - n]; - m_stack[m_stack.size() - n] = d; - break; - } - case Instruction::MLOAD: - { - m_stack.back() = (u256)*(h256 const*)(m_temp.data() + (unsigned)m_stack.back()); - break; - } - case Instruction::MSTORE: - { - *(h256*)&m_temp[(unsigned)m_stack.back()] = (h256)m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - m_stack.pop_back(); - break; - } - case Instruction::MSTORE8: - { - m_temp[(unsigned)m_stack.back()] = (byte)(m_stack[m_stack.size() - 2] & 0xff); - m_stack.pop_back(); - m_stack.pop_back(); - break; - } - case Instruction::SLOAD: - m_stack.back() = _ext.store(m_stack.back()); - break; - case Instruction::SSTORE: - _ext.setStore(m_stack.back(), m_stack[m_stack.size() - 2]); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::JUMP: - nextPC = m_stack.back(); - if (!m_jumpDests.count(nextPC)) - BOOST_THROW_EXCEPTION(BadJumpDestination()); - m_stack.pop_back(); - break; - case Instruction::JUMPI: - if (m_stack[m_stack.size() - 2]) - { - nextPC = m_stack.back(); - if (!m_jumpDests.count(nextPC)) - BOOST_THROW_EXCEPTION(BadJumpDestination()); - } - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::PC: - m_stack.push_back(m_curPC); - break; - case Instruction::MSIZE: - m_stack.push_back(m_temp.size()); - break; - case Instruction::GAS: - m_stack.push_back(m_gas); - break; - case Instruction::JUMPDEST: - break; -/* case Instruction::LOG0: - _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - break; - case Instruction::LOG1: - _ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3])); - break; - case Instruction::LOG2: - _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4])); - break; - case Instruction::LOG3: - _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5])); - break; - case Instruction::LOG4: - _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6])); - break;*/ - case Instruction::LOG0: - _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG1: - _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG2: - _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG3: - _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG4: - _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::CREATE: - { - u256 endowment = m_stack.back(); - m_stack.pop_back(); - unsigned initOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned initSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - - if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) - { - _ext.subBalance(endowment); - m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); - } - else - m_stack.push_back(0); - break; - } - case Instruction::CALL: - case Instruction::CALLCODE: - { - u256 gas = m_stack.back(); - m_stack.pop_back(); - Address receiveAddress = asAddress(m_stack.back()); - m_stack.pop_back(); - u256 value = m_stack.back(); - m_stack.pop_back(); - - unsigned inOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned inSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned outOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned outSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - - if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024) - { - _ext.subBalance(value); - m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress)); - } - else - m_stack.push_back(0); - - m_gas += gas; - break; - } - case Instruction::RETURN: - { - unsigned b = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned s = (unsigned)m_stack.back(); - m_stack.pop_back(); - - return bytesConstRef(m_temp.data() + b, s); - } - case Instruction::SUICIDE: - { - Address dest = asAddress(m_stack.back()); - _ext.suicide(dest); - // ...follow through to... - } - case Instruction::STOP: - return bytesConstRef(); - } - } - if (_steps == (uint64_t)-1) - BOOST_THROW_EXCEPTION(StepsDone()); - return bytesConstRef(); -} - } } diff --git a/libjsqrc/ethereumjs/.travis.yml b/libjsqrc/ethereumjs/.travis.yml index fafacbd5a..83b21d840 100644 --- a/libjsqrc/ethereumjs/.travis.yml +++ b/libjsqrc/ethereumjs/.travis.yml @@ -8,4 +8,6 @@ before_script: script: - "jshint *.js lib" after_script: - - npm run-script gulp + - npm run-script build + - npm test + diff --git a/libjsqrc/ethereumjs/README.md b/libjsqrc/ethereumjs/README.md index 865b62c6b..f18d382bd 100644 --- a/libjsqrc/ethereumjs/README.md +++ b/libjsqrc/ethereumjs/README.md @@ -50,13 +50,35 @@ web3.eth.coinbase.then(function(result){ For another example see `example/index.html`. +## Contribute! + +### Requirements + +* Node.js +* npm +* gulp (build) +* mocha (tests) + +```bash +sudo apt-get update +sudo apt-get install nodejs +sudo apt-get install npm +sudo apt-get install nodejs-legacy +``` + ## Building -* `gulp build` +```bash (gulp) +npm run-script build +``` ### Testing +```bash (mocha) +npm test +``` + **Please note this repo is in it's early stage.** If you'd like to run a WebSocket ethereum node check out @@ -76,4 +98,4 @@ ethereum -ws -loglevel=4 [dep-image]: https://david-dm.org/ethereum/ethereum.js.svg [dep-url]: https://david-dm.org/ethereum/ethereum.js [dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg -[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies \ No newline at end of file +[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js index 26de2c02e..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); }; }; @@ -166,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; }; }; @@ -277,6 +289,7 @@ module.exports = { methodSignature: methodSignature }; + },{}],2:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -441,8 +454,10 @@ var contract = function (address, desc) { transact: function (extra) { extra = extra || {}; extra.to = address; - extra.data = parsed; - return web3.eth.transact(extra).then(onSuccess); + return abi.methodSignature(desc, method.name).then(function (signature) { + extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed; + return web3.eth.transact(extra).then(onSuccess); + }); } }; }; diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map index bb29b435d..e60f94922 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js.map +++ b/libjsqrc/ethereumjs/dist/ethereum.js.map @@ -12,14 +12,14 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;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 var method = json[index];\n\n for (var i = 0; i < method.inputs.length; i++) {\n var found = false;\n for (var j = 0; j < inputTypes.length && !found; j++) {\n found = inputTypes[j](method.inputs[i].type, params[i]);\n }\n if (!found) {\n console.error('unsupported json type: ' + method.inputs[i].type);\n }\n bytes += found;\n }\n return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return -1;\n }\n\n var padding = calcPadding(type, expected);\n return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\n return name === type ? padding * 2 : -1;\n };\n };\n\n var formatInt = function (value) {\n return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n };\n\n var formatHash = function (value) {\n return \"0x\" + value;\n };\n\n var formatBool = function (value) {\n return value === '1' ? true : false;\n };\n\n var formatString = function (value) {\n return web3.toAscii(value);\n };\n\n return [\n { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n { padding: prefixedType('int', calcBitPadding), format: formatInt },\n { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n { padding: prefixedType('string', calcBytePadding), format: formatString },\n { padding: prefixedType('real', calcRealPadding), format: formatInt },\n { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n { padding: namedType('address', 20) },\n { padding: namedType('bool', 1), format: formatBool }\n ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n output = output.slice(2);\n\n var result = [];\n var method = json[index];\n for (var i = 0; i < method.outputs.length; i++) {\n var padding = -1;\n for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n padding = outputTypes[j].padding(method.outputs[i].type);\n }\n\n if (padding === -1) {\n // not found output parsing\n continue;\n }\n var res = output.slice(0, padding);\n var formatter = outputTypes[j - 1].format;\n result.push(formatter ? formatter(res) : (\"0x\" + res));\n output = output.slice(padding);\n }\n\n return result;\n};\n\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n return toAbiInput(json, method.name, params);\n };\n });\n\n return parser;\n};\n\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function (output) {\n return fromAbiOutput(json, method.name, output);\n };\n });\n\n return parser;\n};\n\nvar methodSignature = function (json, name) {\n var method = json[findMethodIndex(json, name)];\n var result = name + '(';\n var inputTypes = method.inputs.map(function (inp) {\n return inp.type;\n });\n result += inputTypes.join(',');\n result += ')';\n\n return web3.sha3(web3.fromAscii(result));\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\n};\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n return findIndex(json, function (method) {\n return method.name === methodName;\n });\n};\n\nvar padLeft = function (string, chars) {\n return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n var sizes = value.split('x');\n for (var padding = 0, i = 0; i < sizes; i++) {\n padding += (sizes[i] / 8);\n }\n return padding;\n};\n\nvar setupInputTypes = function () {\n \n 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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\n }\n };\n };\n });\n\n return contract;\n};\n\nmodule.exports = contract;\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar abi = require('./abi');\n\n// method signature length in bytes\nvar ETH_METHOD_SIGNATURE_LENGTH = 4;\n\nvar contract = function (address, desc) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n var contract = {};\n\n desc.forEach(function (method) {\n contract[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n var parsed = inputParser[method.name].apply(null, params);\n\n var onSuccess = function (result) {\n return outputParser[method.name](result);\n };\n\n return {\n call: function (extra) {\n extra = extra || {};\n extra.to = address;\n return abi.methodSignature(desc, method.name).then(function (signature) {\n extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n return web3.eth.call(extra).then(onSuccess);\n });\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n return abi.methodSignature(desc, method.name).then(function (signature) {\n extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n return web3.eth.transact(extra).then(onSuccess);\n });\n }\n };\n };\n });\n\n return contract;\n};\n\nmodule.exports = contract;\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httprpc.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpRpcProvider = function (host) {\n this.handlers = [];\n this.host = host;\n};\n\nfunction formatJsonRpcObject(object) {\n return {\n jsonrpc: '2.0',\n method: object.call,\n params: object.args,\n id: object._id\n };\n}\n\nfunction formatJsonRpcMessage(message) {\n var object = JSON.parse(message);\n\n return {\n _id: object.id,\n data: object.result,\n error: object.error\n };\n}\n\nHttpRpcProvider.prototype.sendRequest = function (payload, cb) {\n var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open(\"POST\", this.host, true);\n request.send(JSON.stringify(data));\n request.onreadystatechange = function () {\n if (request.readyState === 4 && cb) {\n cb(request);\n }\n };\n};\n\nHttpRpcProvider.prototype.send = function (payload) {\n var self = this;\n this.sendRequest(payload, function (request) {\n self.handlers.forEach(function (handler) {\n handler.call(self, formatJsonRpcMessage(request.responseText));\n });\n });\n};\n\nHttpRpcProvider.prototype.poll = function (payload, id) {\n var self = this;\n this.sendRequest(payload, function (request) {\n var parsed = JSON.parse(request.responseText);\n if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {\n return;\n }\n self.handlers.forEach(function (handler) {\n handler.call(self, {_event: payload.call, _id: id, data: parsed.result});\n });\n });\n};\n\nObject.defineProperty(HttpRpcProvider.prototype, \"onmessage\", {\n set: function (handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = HttpRpcProvider;\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nif (typeof(module) !== \"undefined\")\n module.exports = web3;\n", diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js index a0054b65e..1d909e464 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.min.js +++ b/libjsqrc/ethereumjs/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i++)o+=r[i]/8;return o},c=function(){var t=function(t,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),i(r,2*a)}},e=function(t,e,n){return function(r,o){return r!==t?!1:i(n?n(o):o,2*e)}},n=function(t){return t?"0x1":"0x0"};return[t("uint",a),t("int",a),t("hash",a),t("string",s),t("real",u),t("ureal",u),e("address",20),e("bool",1,n)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&ni;i++)o+=r[i]/8;return o},c=function(){var t=function(t,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return a>32?!1:(a=32,"string"===t?web3.fromAscii(r,a).substr(2):(r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),i(r,2*a)))}},e=function(t,e,n){return function(r,o){return r!==t?!1:(e=32,i(n?n(o):o,2*e))}},n=function(t){return t?"0x1":"0x0"};return[t("uint",a),t("int",a),t("hash",a),t("string",s),t("real",u),t("ureal",u),e("address",20),e("bool",1,n)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;s32?-1:(o=32,2*o)}},e=function(t,e){return function(n){return e=32,t===n?2*e:-1}},r=function(t){return t.length<=8?+parseInt(t,16):n(t)},o=function(t){return"0x"+t},i=function(t){return"1"===t?!0:!1},c=function(t){return web3.toAscii(t)};return[{padding:t("uint",a),format:r},{padding:t("int",a),format:r},{padding:t("hash",a),format:o},{padding:t("string",s),format:c},{padding:t("real",u),format:r},{padding:t("ureal",u),format:r},{padding:e("address",20)},{padding:e("bool",1),format:i}]},p=f(),d=function(t,e,n){var r=o(t,e);if(-1!==r){n=n.slice(2);for(var i=[],a=t[r],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&n 32) + return false; // not allowed to be so big. + padding = 32; // override as per the new ABI. + + if (prefix === "string") + return web3.fromAscii(value, padding).substr(2); if (typeof value === "number") value = value.toString(16); else if (typeof value === "string") @@ -110,6 +116,8 @@ var setupInputTypes = function () { return false; } + padding = 32; //override as per the new ABI. + return padLeft(formatter ? formatter(value) : value, padding * 2); }; }; @@ -165,12 +173,16 @@ var setupOutputTypes = function () { } var padding = calcPadding(type, expected); + if (padding > 32) + return -1; // not allowed to be so big. + padding = 32; // override as per the new ABI. return padding * 2; }; }; var namedType = function (name, padding) { return function (type) { + padding = 32; // override as per the new ABI. return name === type ? padding * 2 : -1; }; }; @@ -275,3 +287,4 @@ module.exports = { outputParser: outputParser, methodSignature: methodSignature }; + diff --git a/libjsqrc/ethereumjs/lib/contract.js b/libjsqrc/ethereumjs/lib/contract.js index 4cb202255..eb7fbf018 100644 --- a/libjsqrc/ethereumjs/lib/contract.js +++ b/libjsqrc/ethereumjs/lib/contract.js @@ -57,8 +57,10 @@ var contract = function (address, desc) { transact: function (extra) { extra = extra || {}; extra.to = address; - extra.data = parsed; - return web3.eth.transact(extra).then(onSuccess); + return abi.methodSignature(desc, method.name).then(function (signature) { + extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed; + return web3.eth.transact(extra).then(onSuccess); + }); } }; }; diff --git a/libjsqrc/ethereumjs/package.json b/libjsqrc/ethereumjs/package.json index fc34be487..b4f180d10 100644 --- a/libjsqrc/ethereumjs/package.json +++ b/libjsqrc/ethereumjs/package.json @@ -25,12 +25,14 @@ "jshint": ">=2.5.0", "uglifyify": "^2.6.0", "unreachable-branch-transform": "^0.1.0", - "vinyl-source-stream": "^1.0.0" + "vinyl-source-stream": "^1.0.0", + "mocha": ">=2.1.0" }, "scripts": { "build": "gulp", "watch": "gulp watch", - "lint": "gulp lint" + "lint": "gulp lint", + "test": "mocha" }, "repository": { "type": "git", diff --git a/libjsqrc/ethereumjs/test/abi.parsers.js b/libjsqrc/ethereumjs/test/abi.parsers.js new file mode 100644 index 000000000..06a77fb86 --- /dev/null +++ b/libjsqrc/ethereumjs/test/abi.parsers.js @@ -0,0 +1,37 @@ +var assert = require('assert'); +var abi = require('../lib/abi.js'); + +describe('abi', function() { + describe('inputParser', function() { + it('should parse ...', function() { + + var desc = [{ + "name": "multiply", + "inputs": [ + { + "name": "a", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "d", + "type": "uint256" + } + ] + }]; + + var iParser = abi.inputParser(desc); + assert.equal(iParser.multiply(1), "0x000000000000000000000000000000000000000000000000000000000000000001"); + + }); + }); + + + describe('outputParser', function() { + it('parse ...', function() { + + }); + }); +}); + diff --git a/libjsqrc/ethereumjs/test/db.methods.js b/libjsqrc/ethereumjs/test/db.methods.js new file mode 100644 index 000000000..b4abfc4d7 --- /dev/null +++ b/libjsqrc/ethereumjs/test/db.methods.js @@ -0,0 +1,18 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('db', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.db, 'put'); + u.methodExists(web3.db, 'get'); + u.methodExists(web3.db, 'putString'); + u.methodExists(web3.db, 'getString'); + }); + }); +}); + diff --git a/libjsqrc/ethereumjs/test/eth.methods.js b/libjsqrc/ethereumjs/test/eth.methods.js new file mode 100644 index 000000000..7190b27d2 --- /dev/null +++ b/libjsqrc/ethereumjs/test/eth.methods.js @@ -0,0 +1,42 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('eth', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.eth, 'balanceAt'); + u.methodExists(web3.eth, 'stateAt'); + u.methodExists(web3.eth, 'storageAt'); + u.methodExists(web3.eth, 'countAt'); + u.methodExists(web3.eth, 'codeAt'); + u.methodExists(web3.eth, 'transact'); + u.methodExists(web3.eth, 'call'); + u.methodExists(web3.eth, 'block'); + u.methodExists(web3.eth, 'transaction'); + u.methodExists(web3.eth, 'uncle'); + u.methodExists(web3.eth, 'compilers'); + u.methodExists(web3.eth, 'lll'); + u.methodExists(web3.eth, 'solidity'); + u.methodExists(web3.eth, 'serpent'); + u.methodExists(web3.eth, 'logs'); + }); + + it('should have all properties implemented', function () { + u.propertyExists(web3.eth, 'coinbase'); + u.propertyExists(web3.eth, 'listening'); + u.propertyExists(web3.eth, 'mining'); + u.propertyExists(web3.eth, 'gasPrice'); + u.propertyExists(web3.eth, 'account'); + u.propertyExists(web3.eth, 'accounts'); + u.propertyExists(web3.eth, 'peerCount'); + u.propertyExists(web3.eth, 'defaultBlock'); + u.propertyExists(web3.eth, 'number'); + }); + }); +}); + + diff --git a/libjsqrc/ethereumjs/test/mocha.opts b/libjsqrc/ethereumjs/test/mocha.opts new file mode 100644 index 000000000..b2db8d5a7 --- /dev/null +++ b/libjsqrc/ethereumjs/test/mocha.opts @@ -0,0 +1,2 @@ +--reporter Spec + diff --git a/libjsqrc/ethereumjs/test/shh.methods.js b/libjsqrc/ethereumjs/test/shh.methods.js new file mode 100644 index 000000000..08f573a3c --- /dev/null +++ b/libjsqrc/ethereumjs/test/shh.methods.js @@ -0,0 +1,19 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('shh', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.shh, 'post'); + u.methodExists(web3.shh, 'newIdentity'); + u.methodExists(web3.shh, 'haveIdentity'); + u.methodExists(web3.shh, 'newGroup'); + u.methodExists(web3.shh, 'addToGroup'); + }); + }); +}); + diff --git a/libjsqrc/ethereumjs/test/utils.js b/libjsqrc/ethereumjs/test/utils.js new file mode 100644 index 000000000..4c508da67 --- /dev/null +++ b/libjsqrc/ethereumjs/test/utils.js @@ -0,0 +1,15 @@ +var assert = require('assert'); + +var methodExists = function (object, method) { + assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented'); +}; + +var propertyExists = function (object, property) { + assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented'); +}; + +module.exports = { + methodExists: methodExists, + propertyExists: propertyExists +}; + diff --git a/libjsqrc/ethereumjs/test/web3.methods.js b/libjsqrc/ethereumjs/test/web3.methods.js new file mode 100644 index 000000000..a7e020978 --- /dev/null +++ b/libjsqrc/ethereumjs/test/web3.methods.js @@ -0,0 +1,18 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + it('should have all methods implemented', function() { + u.methodExists(web3, 'sha3'); + u.methodExists(web3, 'toAscii'); + u.methodExists(web3, 'fromAscii'); + u.methodExists(web3, 'toFixed'); + u.methodExists(web3, 'fromFixed'); + u.methodExists(web3, 'offset'); + }); +}); + diff --git a/libjsqrc/js.qrc b/libjsqrc/js.qrc index eee8f6652..896ab472f 100644 --- a/libjsqrc/js.qrc +++ b/libjsqrc/js.qrc @@ -1,7 +1,7 @@ - - - es6-promise-2.0.0.js - setup.js - ethereumjs/dist/ethereum.js - + + + es6-promise-2.0.0.js + setup.js + ethereumjs/dist/ethereum.js + diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index d1c3cd19b..4be6f228f 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -558,7 +558,7 @@ void Host::prunePeers() for (auto i: m_peers) if (!dc.count(i.first)) if (auto p = i.second.lock()) - if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. + if (chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. { ++agedPeers; if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 657986b36..49df0f703 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -85,7 +85,7 @@ private: _frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \ _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \ - _frame->evaluateJavaScript(contentsOfQResource(":/js/ethereum.js")); \ + _frame->evaluateJavaScript(contentsOfQResource(":/js/webthree.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \ } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index b76fc17e9..d401c38fc 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -51,6 +51,7 @@ private: std::string get(std::string const& _name, std::string const& _key) override; void put(std::string const& _name, std::string const& _key, std::string const& _value) override; + private: dev::WebThreeDirect& m_web3; leveldb::ReadOptions m_readOptions; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 565db9555..5003454f0 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -70,7 +70,7 @@ static Json::Value toJson(dev::eth::Transaction const& _t) return res; } -static Json::Value toJson(dev::eth::LogEntry const& _e) +static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; @@ -78,13 +78,14 @@ static Json::Value toJson(dev::eth::LogEntry const& _e) res["address"] = toJS(_e.address); for (auto const& t: _e.topics) res["topics"].append(toJS(t)); + res["number"] = _e.number; return res; } -static Json::Value toJson(dev::eth::LogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. +static Json::Value toJson(dev::eth::LocalisedLogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. { Json::Value res; - for (dev::eth::LogEntry const& e: _es) + for (dev::eth::LocalisedLogEntry const& e: _es) res.append(toJson(e)); return res; } @@ -328,9 +329,9 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) return ret; } -bool WebThreeStubServerBase::eth_changed(int const& _id) +Json::Value WebThreeStubServerBase::eth_changed(int const& _id) { - return client()->checkWatch(_id); + return toJson(client()->checkWatch(_id)); } std::string WebThreeStubServerBase::eth_codeAt(string const& _address) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 6868207a6..168ab288a 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -71,7 +71,7 @@ public: virtual Json::Value eth_blockByHash(std::string const& _hash); virtual Json::Value eth_blockByNumber(int const& _number); virtual std::string eth_call(Json::Value const& _json); - virtual bool eth_changed(int const& _id); + virtual Json::Value eth_changed(int const& _id); virtual std::string eth_codeAt(std::string const& _address); virtual std::string eth_coinbase(); virtual Json::Value eth_compilers(); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 779d8bec3..15c53e0fa 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -45,7 +45,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(new jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newFilterStringI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI); - this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_filterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_filterLogsI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI); this->bindAndAddMethod(new jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI); @@ -287,7 +287,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer MixClient::storageAt(Address _a, int _block) const return m_state.storage(_a); } -eth::LogEntries MixClient::logs(unsigned _watchId) const +eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const { (void)_watchId; - return LogEntries(); + return LocalisedLogEntries(); } -eth::LogEntries MixClient::logs(eth::LogFilter const& _filter) const +eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _filter) const { (void)_filter; - return LogEntries(); + return LocalisedLogEntries(); } unsigned MixClient::installWatch(eth::LogFilter const& _filter) @@ -208,13 +208,13 @@ void MixClient::uninstallWatch(unsigned _watchId) BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::uninstallWatch")); } -bool MixClient::peekWatch(unsigned _watchId) const +eth::LocalisedLogEntries MixClient::peekWatch(unsigned _watchId) const { (void)_watchId; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::peekWatch")); } -bool MixClient::checkWatch(unsigned _watchId) +eth::LocalisedLogEntries MixClient::checkWatch(unsigned _watchId) { (void)_watchId; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::checkWatch")); diff --git a/mix/MixClient.h b/mix/MixClient.h index 4cbaad6e8..b7ba7fbf3 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -82,13 +82,13 @@ public: u256 stateAt(Address _a, u256 _l, int _block) const override; bytes codeAt(Address _a, int _block) const override; std::map storageAt(Address _a, int _block) const override; - eth::LogEntries logs(unsigned _watchId) const override; - eth::LogEntries logs(eth::LogFilter const& _filter) const override; + eth::LocalisedLogEntries logs(unsigned _watchId) const override; + eth::LocalisedLogEntries logs(eth::LogFilter const& _filter) const override; unsigned installWatch(eth::LogFilter const& _filter) override; unsigned installWatch(h256 _filterId) override; void uninstallWatch(unsigned _watchId) override; - bool peekWatch(unsigned _watchId) const override; - bool checkWatch(unsigned _watchId) override; + eth::LocalisedLogEntries peekWatch(unsigned _watchId) const override; + eth::LocalisedLogEntries checkWatch(unsigned _watchId) override; h256 hashFromNumber(unsigned _number) const override; eth::BlockInfo blockInfo(h256 _hash) const override; eth::BlockDetails blockDetails(h256 _hash) const override; diff --git a/neth/main.cpp b/neth/main.cpp index 0b48edc11..1252b205b 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -292,6 +292,12 @@ int nc_window_streambuf::sync() vector form_dialog(vector _sfields, vector _lfields, vector _bfields, int _cols, int _rows, string _post_form); +enum class NodeMode +{ + PeerServer, + Full +}; + int main(int argc, char** argv) { unsigned short listenPort = 30303; diff --git a/standard.js b/standard.js new file mode 100644 index 000000000..74ebc74ad --- /dev/null +++ b/standard.js @@ -0,0 +1,61 @@ +var compile = function(name) { return web3.eth.solidity(env.contents("../../dapp-bin/" + name + "/" + name + ".sol")); }; +var create = function(code) { return web3.eth.transact({ 'code': code }); }; +var send = function(from, val, to) { return web3.eth.transact({ 'from': from, 'value': val, 'to': to }); }; +var initService = function(name, dep) { return dep.then(function(){ return compile(name).then(create); }); }; + +var addrConfig = compile("config").then(create); +var addrNameReg = initService("namereg", addrConfig); + +var abiNameReg = [{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]}]; +var regName = function(account, name) { return web3.contract(addrNameReg, abiNameReg).register(name).transact({'from': account, 'gas': 10000}); }; +/* +var coins = initService("coins", 1, nameReg); +var coin = initService("coin", 2, coins); +var approve = function(account, approvedAddress) { web3.eth.transact({ 'from': account, 'to': coin, 'gas': '10000', 'data': [ web3.fromAscii('approve'), approvedAddress ] }); }; +var exchange = initService("exchange", 3, coin); +var offer = function(account, haveCoin, haveVal, wantCoin, wantVal) { web3.eth.transact({ 'from': account, 'to': exchange, 'gas': '10000', 'data': [web3.fromAscii('new'), haveCoin, haveVal, wantCoin, wantVal] }); }; +*/ +addrConfig.then(function() { + env.note("config ready"); + web3.eth.accounts.then(function(accounts) + { + env.note("accounts ready"); + var funded = send(accounts[0], '100000000000000000000', accounts[1]); + funded.then(function(){ + env.note("second account funded"); + regName(accounts[1], 'Gav Would'); + }); + regName(accounts[0], 'Gav'); + // TODO: once we have the exchange. +// approve(accounts[0], exchange).then(function(){ offer(accounts[0], coin, '5000', '0', '5000000000000000000'); }); +// funded.then(function(){ approve(accounts[1], exchange); }); + + // TODO: once we have a new implementation of DNSReg. + // env.note('Register gav.eth...') + // eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] }); + }); +}); + +// TODO +/* +var nameRegJeff; + +env.note('Create NameRegJeff...') +eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; }); + +env.note('Register NameRegJeff...') +eth.transact({ 'to': config, 'data': ['4', nameRegJeff] }); + +var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00'; + +var dnsReg; +env.note('Create DnsReg...') +eth.transact({ 'code': dnsRegCode }, function(a) { dnsReg = a; }); + +env.note('DnsReg at address ' + dnsReg) + +env.note('Register DnsReg...') +eth.transact({ 'to': config, 'data': ['4', dnsReg] }); +*/ + +// env.load('/home/gav/Eth/cpp-ethereum/stdserv.js') diff --git a/third/MainWin.cpp b/third/MainWin.cpp index 894f1af0f..2e967e407 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -182,14 +182,14 @@ void Main::onKeysChanged() installBalancesWatch(); } -unsigned Main::installWatch(dev::eth::LogFilter const& _tf, std::function const& _f) +unsigned Main::installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; return ret; } -unsigned Main::installWatch(dev::h256 _tf, std::function const& _f) +unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; @@ -198,21 +198,21 @@ unsigned Main::installWatch(dev::h256 _tf, std::function const& _f) void Main::installWatches() { - installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)0), [=](){ installNameRegWatch(); }); - installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)1), [=](){ installCurrenciesWatch(); }); - installWatch(dev::eth::ChainChangedFilter, [=](){ onNewBlock(); }); + installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)0), [=](LocalisedLogEntries const&){ installNameRegWatch(); }); + installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)1), [=](LocalisedLogEntries const&){ installCurrenciesWatch(); }); + installWatch(dev::eth::ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); }); } void Main::installNameRegWatch() { ethereum()->uninstallWatch(m_nameRegFilter); - m_nameRegFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); }); + m_nameRegFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 0)), [=](LocalisedLogEntries const&){ onNameRegChange(); }); } void Main::installCurrenciesWatch() { ethereum()->uninstallWatch(m_currenciesFilter); - m_currenciesFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); }); + m_currenciesFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 1)), [=](LocalisedLogEntries const&){ onCurrenciesChange(); }); } void Main::installBalancesWatch() @@ -228,7 +228,7 @@ void Main::installBalancesWatch() tf.address(c).topic((u256)(u160)i.address()); ethereum()->uninstallWatch(m_balancesFilter); - m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); }); + m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); } void Main::onNameRegChange() @@ -536,8 +536,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); + } } void Main::ourAccountsRowsMoved() diff --git a/third/MainWin.h b/third/MainWin.h index 478fb6fb6..3b4acc3a8 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -50,6 +50,8 @@ class WhisperHost; class QQuickView; class WebThreeStubServer; +using WatchHandler = std::function; + class Main : public QMainWindow { Q_OBJECT @@ -95,8 +97,8 @@ private: void readSettings(bool _skipGeometry = false); void writeSettings(); - 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 onNewBlock(); void onNameRegChange(); @@ -124,7 +126,7 @@ private: QList m_myKeys; QList m_myIdentities; - std::map> m_handlers; + std::map m_handlers; unsigned m_nameRegFilter = (unsigned)-1; unsigned m_currenciesFilter = (unsigned)-1; unsigned m_balancesFilter = (unsigned)-1;