Browse Source

Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

cl-refactor
Gav Wood 10 years ago
parent
commit
455c8f298c
  1. 1
      eth/main.cpp
  2. 1
      ethminer/MinerAux.h
  3. 7
      evmjit/CMakeLists.txt
  4. 60
      libdevcore/concurrent_queue.h
  5. 4
      libethcore/EthashSealEngine.cpp
  6. 1
      libethcore/Miner.h
  7. 47
      libethereum/BlockChainSync.cpp
  8. 1
      libethereum/BlockChainSync.h
  9. 7
      libethereum/Client.cpp
  10. 2
      libethereum/Client.h
  11. 25
      libethereum/EthereumHost.cpp
  12. 2
      libethereum/EthereumHost.h
  13. 4
      libethereum/EthereumPeer.cpp
  14. 11
      libethereum/Executive.cpp
  15. 43
      libevm/SmartVM.cpp
  16. 23
      libp2p/Common.cpp
  17. 11
      libp2p/Common.h
  18. 68
      mix/ContractCallDataEncoder.cpp
  19. 4
      mix/ContractCallDataEncoder.h
  20. 13
      mix/QContractDefinition.cpp
  21. 3
      solc/docker_emscripten/Dockerfile
  22. 2
      test/fuzzTesting/CMakeLists.txt
  23. 37
      test/fuzzTesting/createRandomTest.cpp
  24. 150
      test/fuzzTesting/fuzzHelper.cpp
  25. 17
      test/fuzzTesting/fuzzHelper.h
  26. 34
      test/libdevcore/rlp.cpp

1
eth/main.cpp

@ -1700,6 +1700,7 @@ int main(int argc, char** argv)
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
// TODO: expose sealant interface.
c->setShouldPrecomputeDAG(m.shouldPrecompute());
c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU);
c->setAddress(beneficiary);
c->setNetworkId(networkId);

1
ethminer/MinerAux.h

@ -380,6 +380,7 @@ public:
};
MinerType minerType() const { return m_minerType; }
bool shouldPrecompute() const { return m_precompute; }
private:
void doInitDAG(unsigned _n)

7
evmjit/CMakeLists.txt

@ -25,8 +25,11 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT LLVM_DIR)
add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS)
link_directories(/usr/lib/llvm-3.7/lib)
else()
find_package(LLVM 3.7 REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
find_package(LLVM REQUIRED CONFIG)
if (${LLVM_VERSION} VERSION_LESS 3.7)
message(FATAL_ERROR "Incompatible LLVM version ${LLVM_VERSION}")
endif()
message(STATUS "Found LLVM ${LLVM_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen ipo)

60
libdevcore/concurrent_queue.h

@ -0,0 +1,60 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <utility>
#include <queue>
#include <condition_variable>
#include <mutex>
namespace dev
{
/// Concurrent queue.
/// You can push and pop elements to/from the queue. Pop will block until the queue is not empty.
/// The default backend (_QueueT) is std::queue. It can be changed to any type that has
/// proper push(), pop(), empty() and front() methods.
template<typename _T, typename _QueueT = std::queue<_T>>
class concurrent_queue
{
public:
template<typename _U>
void push(_U&& _elem)
{
{
std::lock_guard<decltype(x_mutex)> guard{x_mutex};
m_queue.push(std::forward<_U>(_elem));
}
m_cv.notify_one();
}
_T pop()
{
std::unique_lock<std::mutex> lock{x_mutex};
m_cv.wait(lock, [this]{ return !m_queue.empty(); });
auto item = std::move(m_queue.front());
m_queue.pop();
return item;
}
private:
_QueueT m_queue;
std::mutex x_mutex;
std::condition_variable m_cv;
};
}

4
libethcore/EthashSealEngine.cpp

@ -54,7 +54,9 @@ void EthashSealEngine::generateSeal(BlockInfo const& _bi)
m_farm.setWork(m_sealing);
m_farm.start(m_sealer);
m_farm.setWork(m_sealing); // TODO: take out one before or one after...
Ethash::ensurePrecomputed((unsigned)_bi.number());
bytes shouldPrecompute = option("precomputeDAG");
if (!shouldPrecompute.empty() && shouldPrecompute[0] == 1)
Ethash::ensurePrecomputed((unsigned)_bi.number());
}
void EthashSealEngine::onSealGenerated(std::function<void(bytes const&)> const& _f)

1
libethcore/Miner.h

@ -84,6 +84,7 @@ public:
m_farm(_ci.first),
m_index(_ci.second)
{}
virtual ~GenericMiner() {}
// API FOR THE FARM TO CALL IN WITH

47
libethereum/BlockChainSync.cpp

@ -300,7 +300,7 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP con
u256 totalDifficulty = _r[1].toInt<u256>();
if (totalDifficulty > _peer->m_totalDifficulty)
{
clog(NetMessageDetail) << "Received block with no known parent. Resyncing...";
clog(NetMessageDetail) << "Received block with no known parent. Peer needs syncing...";
resetSyncFor(_peer, h, totalDifficulty);
}
break;
@ -648,12 +648,10 @@ void PV60Sync::noteDoneBlocks(std::shared_ptr<EthereumPeer> _peer, bool _clemenc
clog(NetNote) << "Chain download failed. Aborted while incomplete.";
else
{
// Done our chain-get.
clog(NetWarn) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
clog(NetWarn) << downloadMan().remaining();
clog(NetWarn) << "WOULD BAN.";
// m_banned.insert(_peer->session()->id()); // We know who you are!
// _peer->disable("Peer sent hashes but was unable to provide the blocks.");
// This can happen when the leading peer aborts and the one that is selected instead does not have all the blocks.
// Just stop syncing to this peer. Sync will restart if there are no more peers to sync with.
clog(NetNote) << "Peer does not have required blocks";
resetNeedsSyncing(_peer);
}
resetSync();
downloadMan().reset();
@ -747,7 +745,7 @@ void PV60Sync::onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, h256s const&
RecursiveGuard l(x_sync);
if (isSyncing() && (m_state != SyncState::NewBlocks || isSyncing(_peer)))
{
clog(NetMessageSummary) << "Ignoring since we're already downloading.";
clog(NetMessageDetail) << "Ignoring new hashes since we're already downloading.";
return;
}
clog(NetMessageDetail) << "Not syncing and new block hash discovered: syncing without help.";
@ -838,7 +836,7 @@ void PV60Sync::onPeerAborting()
// Can't check invariants here since the peers is already removed from the list and the state is not updated yet.
if (m_syncer.expired() && m_state != SyncState::Idle)
{
clog(NetWarn) << "Syncing peer disconnected, restarting sync";
clog(NetNote) << "Syncing peer disconnected";
m_syncer.reset();
abortSync();
}
@ -969,11 +967,17 @@ void PV61Sync::completeSubchain(std::shared_ptr<EthereumPeer> _peer, unsigned _n
{
//Done chain-get
m_syncingNeededBlocks.clear();
// Add hashes to download skipping onces that are already downloaded
for (auto h = m_completeChainMap.rbegin(); h != m_completeChainMap.rend(); ++h)
m_syncingNeededBlocks.insert(m_syncingNeededBlocks.end(), h->second.hashes.begin(), h->second.hashes.end());
m_completeChainMap.clear();
m_knownHashes.clear();
m_syncingBlockNumber = 0;
if (!host().chain().isKnown(h->second.hashes.front()) && !host().chain().isKnown(h->second.hashes.back()))
{
if (host().bq().blockStatus(h->second.hashes.front()) == QueueStatus::Unknown || host().bq().blockStatus(h->second.hashes.back()) == QueueStatus::Unknown)
m_syncingNeededBlocks.insert(m_syncingNeededBlocks.end(), h->second.hashes.begin(), h->second.hashes.end());
else
for (h256 const& hash: h->second.hashes)
if (!host().chain().isKnown(hash) && host().bq().blockStatus(hash) == QueueStatus::Unknown)
m_syncingNeededBlocks.insert(m_syncingNeededBlocks.end(), hash);
}
transition(syncer, SyncState::Blocks);
}
else
@ -1007,6 +1011,7 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
{
// End of hash chain, add last chunk to download
m_readyChainMap.insert(make_pair(m_syncingBlockNumber, SubChain{ h256s{ _peer->m_latestHash }, _peer->m_latestHash }));
m_knownHashes.insert(_peer->m_latestHash);
m_hashScanComplete = true;
_peer->m_syncHashNumber = 0;
requestSubchain(_peer);
@ -1032,7 +1037,13 @@ void PV61Sync::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _h
if (isSyncing(_peer) && _peer->m_syncHashNumber == m_syncingBlockNumber)
{
// Got new subchain marker
assert(_hashes.size() == 1);
if (_hashes.size() != 1)
{
clog(NetWarn) << "Peer sent too many hashes";
_peer->disable("Too many hashes");
restartSync();
return;
}
m_knownHashes.insert(_hashes[0]);
m_readyChainMap.insert(make_pair(m_syncingBlockNumber, SubChain{ h256s{ _hashes[0] }, _hashes[0] }));
if ((m_readyChainMap.size() + m_downloadingChainMap.size() + m_completeChainMap.size()) * c_hashSubchainSize > _peer->m_expectedHashes)
@ -1186,6 +1197,14 @@ bool PV61Sync::isPV61Syncing() const
return m_syncingBlockNumber != 0;
}
void PV61Sync::completeSync()
{
m_completeChainMap.clear();
m_knownHashes.clear();
m_syncingBlockNumber = 0;
PV60Sync::completeSync();
}
bool PV61Sync::invariants() const
{
if (m_state == SyncState::Hashes)

1
libethereum/BlockChainSync.h

@ -292,6 +292,7 @@ public:
protected:
void restartSync() override;
void completeSync() override;
void requestSubchain(std::shared_ptr<EthereumPeer> _peer) override;
void syncHashes(std::shared_ptr<EthereumPeer> _peer) override;
void onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes) override;

7
libethereum/Client.cpp

@ -443,6 +443,13 @@ void Client::setForceMining(bool _enable)
startMining();
}
void Client::setShouldPrecomputeDAG(bool _precompute)
{
bytes trueBytes {1};
bytes falseBytes {0};
sealEngine()->setOption("precomputeDAG", _precompute ? trueBytes: falseBytes);
}
bool Client::isMining() const
{
return Ethash::isWorking(m_sealEngine.get());

2
libethereum/Client.h

@ -136,6 +136,8 @@ public:
bool turboMining() const { return m_turboMining; }
/// Enable/disable GPU mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); }
/// Enable/disable precomputing of the DAG for next epoch
void setShouldPrecomputeDAG(bool _precompute);
/// Check to see if we'd mine on an apparently bad chain.
bool mineOnBadChain() const { return m_mineOnBadChain; }

25
libethereum/EthereumHost.cpp

@ -84,7 +84,7 @@ bool EthereumHost::ensureInitialised()
void EthereumHost::reset()
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (m_sync)
m_sync->abortSync();
m_sync.reset();
@ -118,7 +118,7 @@ void EthereumHost::doWork()
if (m_syncStart)
{
DEV_GUARDED(x_sync)
DEV_RECURSIVE_GUARDED(x_sync)
if (!m_sync)
{
time_t now = std::chrono::system_clock::to_time_t(chrono::system_clock::now());
@ -288,46 +288,41 @@ BlockChainSync* EthereumHost::sync()
void EthereumHost::onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (sync())
sync()->onPeerStatus(_peer);
}
void EthereumHost::onPeerHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes)
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (sync())
sync()->onPeerHashes(_peer, _hashes);
}
void EthereumHost::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (sync())
sync()->onPeerBlocks(_peer, _r);
}
void EthereumHost::onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, h256s const& _hashes)
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (sync())
sync()->onPeerNewHashes(_peer, _hashes);
}
void EthereumHost::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (sync())
sync()->onPeerNewBlock(_peer, _r);
}
void EthereumHost::onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
{
if (_peer->isCriticalSyncing())
{
clog(EthereumHostTrace) << "Ignoring transaction from peer we are syncing with";
return;
}
unsigned itemCount = _r.itemCount();
clog(EthereumHostTrace) << "Transactions (" << dec << itemCount << "entries)";
m_tq.enqueue(_r, _peer->session()->id());
@ -335,7 +330,7 @@ void EthereumHost::onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP c
void EthereumHost::onPeerAborting()
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
try
{
if (m_sync)
@ -349,7 +344,7 @@ void EthereumHost::onPeerAborting()
bool EthereumHost::isSyncing() const
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (!m_sync)
return false;
return m_sync->isSyncing();
@ -357,7 +352,7 @@ bool EthereumHost::isSyncing() const
SyncStatus EthereumHost::status() const
{
Guard l(x_sync);
RecursiveGuard l(x_sync);
if (!m_sync)
return SyncStatus();
return m_sync->status();

2
libethereum/EthereumHost.h

@ -134,7 +134,7 @@ private:
bool m_newTransactions = false;
bool m_newBlocks = false;
mutable Mutex x_sync;
mutable RecursiveMutex x_sync;
mutable Mutex x_transactions;
DownloadMan m_man;
std::unique_ptr<BlockChainSync> m_sync;

4
libethereum/EthereumPeer.cpp

@ -145,7 +145,7 @@ void EthereumPeer::requestHashes(u256 _number, unsigned _count)
setAsking(Asking::Hashes);
RLPStream s;
prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << _count;
clog(NetMessageDetail) << "Requesting block hashes for numbers " << m_syncHashNumber << "-" << m_syncHashNumber + c_maxHashesAsk - 1;
clog(NetMessageDetail) << "Requesting block hashes for numbers " << m_syncHashNumber << "-" << m_syncHashNumber + _count - 1;
sealAndSend(s);
}
@ -298,7 +298,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
if (m_asking != Asking::Hashes)
{
clog(NetWarn) << "Peer giving us hashes when we didn't ask for them.";
clog(NetAllDetail) << "Peer giving us hashes when we didn't ask for them.";
break;
}
setIdle();

11
libethereum/Executive.cpp

@ -399,11 +399,14 @@ void Executive::finalize()
m_refunded = m_ext ? min((m_t.gas() - m_gas) / 2, m_ext->sub.refunds) : 0;
m_gas += m_refunded;
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice());
if (m_t)
{
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice());
u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice();
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned);
u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice();
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned);
}
// Suicides...
if (m_ext)

43
libevm/SmartVM.cpp

@ -21,9 +21,7 @@
#include "SmartVM.h"
#include <unordered_map>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <libdevcore/concurrent_queue.h>
#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/Guards.h>
@ -51,34 +49,26 @@ namespace
{
bytes code;
h256 codeHash;
static JitTask createStopSentinel() { return JitTask(); }
bool isStopSentinel()
{
assert((!code.empty() || !codeHash) && "'empty code => empty hash' invariand failed");
return code.empty();
}
};
class JitWorker
{
bool m_finished = false;
std::mutex x_mutex;
std::condition_variable m_cv;
std::thread m_worker;
std::queue<JitTask> m_queue;
bool pop(JitTask& o_task)
{
std::unique_lock<std::mutex> lock{x_mutex};
m_cv.wait(lock, [this]{ return m_finished || !m_queue.empty(); });
if (m_finished)
return false;
assert(!m_queue.empty());
o_task = std::move(m_queue.front());
m_queue.pop();
return true;
}
concurrent_queue<JitTask> m_queue;
void work()
{
clog(JitInfo) << "JIT worker started.";
JitTask task;
while (pop(task))
while (!(task = m_queue.pop()).isStopSentinel())
{
clog(JitInfo) << "Compilation... " << task.codeHash;
evmjit::JIT::compile(task.code.data(), task.code.size(), eth2jit(task.codeHash));
@ -93,18 +83,11 @@ namespace
~JitWorker()
{
DEV_GUARDED(x_mutex)
m_finished = true;
m_cv.notify_one();
push(JitTask::createStopSentinel());
m_worker.join();
}
void push(JitTask&& _task)
{
DEV_GUARDED(x_mutex)
m_queue.push(std::move(_task));
m_cv.notify_one();
}
void push(JitTask&& _task) { m_queue.push(std::move(_task)); }
};
}

23
libp2p/Common.cpp

@ -176,6 +176,29 @@ void NodeIPEndpoint::interpretRLP(RLP const& _r)
tcpPort = _r[2].toInt<uint16_t>();
}
void DeadlineOps::reap()
{
if (m_stopped)
return;
Guard l(x_timers);
std::vector<DeadlineOp>::iterator t = m_timers.begin();
while (t != m_timers.end())
if (t->expired())
{
t->wait();
t = m_timers.erase(t);
}
else
t++;
m_timers.emplace_back(m_io, m_reapIntervalMs, [this](boost::system::error_code const& ec)
{
if (!ec && !m_stopped)
reap();
});
}
namespace dev {
std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep)

11
libp2p/Common.h

@ -235,16 +235,15 @@ class DeadlineOps
};
public:
DeadlineOps(ba::io_service& _io, unsigned _reapIntervalMs = 100): m_io(_io), m_reapIntervalMs(_reapIntervalMs), m_stopped({false}) { reap(); }
DeadlineOps(ba::io_service& _io, unsigned _reapIntervalMs = 100): m_io(_io), m_reapIntervalMs(_reapIntervalMs), m_stopped(false) { reap(); }
~DeadlineOps() { stop(); }
void schedule(unsigned _msInFuture, std::function<void(boost::system::error_code const&)> const& _f) { if (m_stopped) return; DEV_GUARDED(x_timers) m_timers.emplace_back(m_io, _msInFuture, _f); }
void schedule(unsigned _msInFuture, std::function<void(boost::system::error_code const&)> const& _f) { if (m_stopped) return; DEV_GUARDED(x_timers) m_timers.emplace_back(m_io, _msInFuture, _f); }
void stop() { m_stopped = true; DEV_GUARDED(x_timers) m_timers.clear(); }
protected:
void reap() { Guard l(x_timers); auto t = m_timers.begin(); while (t != m_timers.end()) if (t->expired()) { t->wait(); m_timers.erase(t); } else t++; m_timers.emplace_back(m_io, m_reapIntervalMs, [this](boost::system::error_code const& ec){ if (!ec) reap(); }); }
void reap();
private:
ba::io_service& m_io;
unsigned m_reapIntervalMs;

68
mix/ContractCallDataEncoder.cpp

@ -237,6 +237,48 @@ QString ContractCallDataEncoder::toChar(dev::bytes const& _b)
return str;
}
QJsonValue ContractCallDataEncoder::decodeArrayContent(SolidityType const& _type, bytes const& _value, int& pos)
{
if (_type.baseType->array)
{
QJsonArray sub = decodeArray(*_type.baseType, _value, pos);
if (_type.baseType->dynamicSize)
pos = pos + 32;
return sub;
}
else
{
bytesConstRef value(_value.data() + pos, 32);
bytes rawParam(32);
value.populate(&rawParam);
QVariant i = decode(*_type.baseType, rawParam);
pos = pos + 32;
return i.toString();
}
}
QJsonArray ContractCallDataEncoder::decodeArray(SolidityType const& _type, bytes const& _value, int& pos)
{
QJsonArray array;
bytesConstRef value(&_value);
int count = 0;
if (!_type.dynamicSize)
count = _type.count;
else
{
bytesConstRef value(_value.data() + pos, 32); // offset
bytes rawParam(32);
value.populate(&rawParam);
bigint offset = decodeInt(rawParam);
pos = static_cast<int>(offset) + 32;
value = bytesConstRef(_value.data() + static_cast<int>(offset), 32); // offset
value.populate(&rawParam);
count = static_cast<int>(decodeInt(rawParam));
}
for (int k = 0; k < count; ++k)
array.append(decodeArrayContent(_type, _value, pos));
return array;
}
QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& _value)
{
@ -268,17 +310,31 @@ QString ContractCallDataEncoder::decode(QVariableDeclaration* const& _param, byt
QStringList ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const& _returnParameters, bytes _value)
{
bytesConstRef value(&_value);
bytes rawParam(32);
bytes _v = _value;
QStringList r;
int readPosition = 0;
for (int k = 0; k <_returnParameters.length(); k++)
{
value.populate(&rawParam);
value = value.cropped(32);
QVariableDeclaration* dec = static_cast<QVariableDeclaration*>(_returnParameters.at(k));
SolidityType const& type = dec->type()->type();
r.append(decode(type, rawParam).toString());
if (type.array)
{
QJsonArray array = decodeArray(type, _v, readPosition);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(array.toVariantList());
r.append(jsonDoc.toJson(QJsonDocument::Compact));
if (type.dynamicSize)
readPosition++;
else
readPosition = type.count;
}
else
{
bytesConstRef value(_value.data() + (readPosition * 32), 32);
bytes rawParam(32);
value.populate(&rawParam);
r.append(decode(type, rawParam).toString());
readPosition++;
}
}
return r;
}

4
mix/ContractCallDataEncoder.h

@ -60,6 +60,10 @@ public:
dev::bytes encodeBytes(QString const& _str);
/// Decode bytes from ABI
dev::bytes decodeBytes(dev::bytes const& _rawValue);
/// Decode array
QJsonArray decodeArray(SolidityType const& _type, bytes const& _value, int& pos);
/// Decode array items
QJsonValue decodeArrayContent(SolidityType const& _type, bytes const& _value, int& pos);
private:
unsigned encodeSingleItem(QString const& _data, SolidityType const& _type, bytes& _dest);

13
mix/QContractDefinition.cpp

@ -39,19 +39,8 @@ QContractDefinition::QContractDefinition(QObject* _parent, dev::solidity::Contra
else
m_constructor = new QFunctionDefinition(parent);
std::vector<std::string> found;
for (auto const& f: _contract->getDefinedFunctions())
{
m_functions.append(new QFunctionDefinition(parent, f));
found.push_back(f->getName());
}
for (auto const& it: _contract->getInterfaceFunctions())
{
if (std::find(found.begin(), found.end(), it.second->getDeclaration().getName()) == found.end())
m_functions.append(new QFunctionDefinition(parent, it.second));
}
m_functions.append(new QFunctionDefinition(parent, it.second));
for (auto const& it: _contract->getEvents())
m_events.append(new QFunctionDefinition(parent, it));

3
solc/docker_emscripten/Dockerfile

@ -66,6 +66,5 @@ RUN emcmake cmake -DETH_STATIC=1 -DSOLIDITY=ON -DGUI=0 -DCMAKE_CXX_COMPILER=/hom
RUN emmake make -j 6 soljson
WORKDIR /home/user/cpp-ethereum/solc
# somehow it does not work to pipe out both files
#ENTRYPOINT tar -c soljson.js soljson.js.mem | base64
ENTRYPOINT cat soljson.js

2
test/fuzzTesting/CMakeLists.txt

@ -8,7 +8,7 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp" "../libethereum/blockchain.cpp")
add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp" "../libethereum/blockchain.cpp" "../libdevcore/rlp.cpp")
add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp")
add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp")

37
test/fuzzTesting/createRandomTest.cpp

@ -34,6 +34,7 @@ extern std::string const c_testExampleStateTest;
extern std::string const c_testExampleTransactionTest;
extern std::string const c_testExampleVMTest;
extern std::string const c_testExampleBlockchainTest;
extern std::string const c_testExampleRLPTest;
//Main Test functinos
void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> _doTests, std::string const& _testString, bool _debug = false);
@ -62,7 +63,8 @@ int main(int argc, char *argv[])
if (arg == "-t" && i + 1 < argc)
{
testSuite = argv[i + 1];
if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests" && testSuite != "VMTests")
if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests"
&& testSuite != "VMTests" && testSuite != "RLPTests")
testSuite = "";
}
else
@ -139,6 +141,14 @@ int main(int argc, char *argv[])
else
fillRandomTest(dev::test::doVMTests, (filltest) ? testFillString : c_testExampleVMTest, filldebug);
}
else
if (testSuite == "RLPTests")
{
if (checktest)
return checkRandomTest(dev::test::doRlpTests, testmValue, debug);
else
fillRandomTest(dev::test::doRlpTests, (filltest) ? testFillString : c_testExampleRLPTest, filldebug);
}
}
return 0;
@ -239,12 +249,23 @@ void parseTestWithTypes(std::string& _test)
std::size_t pos = _test.find(types.at(i));
while (pos != std::string::npos)
{
if (types.at(i) == "[RLP]")
{
std::string debug;
int randomDepth = 1 + dev::test::RandomCode::randomUniInt() % 10;
_test.replace(pos, 5, dev::test::RandomCode::rndRLPSequence(randomDepth, debug));
cnote << debug;
}
else
if (types.at(i) == "[CODE]")
_test.replace(pos, 6, "0x"+dev::test::RandomCode::generate(10, options));
else
if (types.at(i) == "[HEX]")
_test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex());
else
if (types.at(i) == "[HEX32]")
_test.replace(pos, 7, dev::test::RandomCode::randomUniIntHex(std::numeric_limits<uint32_t>::max()));
else
if (types.at(i) == "[GASLIMIT]")
_test.replace(pos, 10, dev::test::RandomCode::randomUniIntHex(dev::u256("3000000000")));
else
@ -276,7 +297,7 @@ void parseTestWithTypes(std::string& _test)
std::vector<std::string> getTypes()
{
return {"[CODE]", "[HEX]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]", "[GASLIMIT]"};
return {"[RLP]", "[CODE]", "[HEX]", "[HEX32]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]", "[GASLIMIT]"};
}
std::string const c_testExampleTransactionTest = R"(
@ -305,7 +326,7 @@ std::string const c_testExampleStateTest = R"(
"currentCoinbase" : "[HASH20]",
"currentDifficulty" : "[HEX]",
"currentGasLimit" : "[GASLIMIT]",
"currentNumber" : "[HEX]",
"currentNumber" : "[HEX32]",
"currentTimestamp" : "[HEX]",
"previousHash" : "[HASH32]"
},
@ -335,7 +356,7 @@ std::string const c_testExampleStateTest = R"(
"transaction" : {
"data" : "[CODE]",
"gasLimit" : "[HEX]",
"gasPrice" : "[V]",
"gasPrice" : "[HEX32]",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
@ -377,6 +398,14 @@ std::string const c_testExampleVMTest = R"(
}
)";
std::string const c_testExampleRLPTest = R"(
{
"randomRLPTest" : {
"out" : "[RLP]"
}
}
)";
std::string const c_testExampleBlockchainTest = R"(
{
"randomBlockTest" : {

150
test/fuzzTesting/fuzzHelper.cpp

@ -42,11 +42,157 @@ boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist)
boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist);
boostUInt64Generator RandomCode::randUInt64Gen = boostUInt64Generator(gen, uInt64Dist);
std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
int RandomCode::recursiveRLP(std::string& _result, int _depth, std::string& _debug)
{
bool genValidRlp = true;
int bugProbability = randUniIntGen() % 100;
if (bugProbability < 80)
genValidRlp = false;
if (_depth > 1)
{
//create rlp blocks
int size = 1 + randUniIntGen() % 4;
for (auto i = 0; i < size; i++)
{
std::string blockstr;
std::string blockDebug;
recursiveRLP(blockstr, _depth - 1, blockDebug);
_result += blockstr;
_debug += blockDebug;
}
//make rlp header
int length = _result.size() / 2;
std::string header;
int rtype = 0;
int rnd = randUniIntGen() % 100;
if (rnd < 10)
{
//make header as array
if (length <= 55)
{
header = toCompactHex(128 + length);
rtype = 1;
}
else
{
std::string hexlength = toCompactHex(length);
header = toCompactHex(183 + hexlength.size() / 2) + hexlength;
rtype = 2;
}
}
else
{
//make header as list
if (length <= 55)
{
header = toCompactHex(192 + length);
rtype = 3;
}
else
{
std::string hexlength = toCompactHex(length, HexPrefix::DontAdd, 1);
header = toCompactHex(247 + hexlength.size() / 2) + hexlength;
rtype = 4;
}
}
_result = header + _result;
_debug = "[" + header + "(" + toString(length) + "){" + toString(rtype) + "}]" + _debug;
return _result.size() / 2;
}
if (_depth == 1)
{
bool genbug = false;
bool genbug2 = false;
int bugProbability = randUniIntGen() % 100;
if (bugProbability < 50 && !genValidRlp)
genbug = true;
bugProbability = randUniIntGen() % 100; //more randomness
if (bugProbability < 50 && !genValidRlp)
genbug2 = true;
std::string emptyZeros = genValidRlp ? "" : genbug ? "00" : "";
std::string emptyZeros2 = genValidRlp ? "" : genbug2 ? "00" : "";
int rnd = randUniIntGen() % 5;
switch (rnd)
{
case 0:
{
//single byte [0x00, 0x7f]
std::string rlp = emptyZeros + toCompactHex(genbug ? randUniIntGen() % 255 : randUniIntGen() % 128, HexPrefix::DontAdd, 1);
_result.insert(0, rlp);
_debug.insert(0, "[" + rlp + "]");
return 1;
}
case 1:
{
//string 0-55 [0x80, 0xb7] + string
int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
std::string hex = rndByteSequence(len);
if (len == 1)
if (genValidRlp && fromHex(hex)[0] < 128)
hex = toCompactHex((u64)128);
_result.insert(0, toCompactHex(128 + len) + emptyZeros + hex);
_debug.insert(0, "[" + toCompactHex(128 + len) + "(" + toString(len) + ")]" + emptyZeros + hex);
return len + 1;
}
case 2:
{
//string more 55 [0xb8, 0xbf] + length + string
int len = randUniIntGen() % 100;
if (len < 56 && genValidRlp)
len = 56;
std::string hex = rndByteSequence(len);
std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
std::string rlpblock = toCompactHex(183 + hexlen.size() / 2) + hexlen + emptyZeros + hex;
_debug.insert(0, "[" + toCompactHex(183 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){2}]" + emptyZeros + hex);
_result.insert(0, rlpblock);
return rlpblock.size() / 2;
}
case 3:
{
//list 0-55 [0xc0, 0xf7] + data
int len = genbug ? randUniIntGen() % 255 : randUniIntGen() % 55;
std::string hex = emptyZeros + rndByteSequence(len);
_result.insert(0, toCompactHex(192 + len) + hex);
_debug.insert(0, "[" + toCompactHex(192 + len) + "(" + toString(len) + "){3}]" + hex);
return len + 1;
}
case 4:
{
//list more 55 [0xf8, 0xff] + length + data
int len = randUniIntGen() % 100;
if (len < 56 && genValidRlp)
len = 56;
std::string hexlen = emptyZeros2 + toCompactHex(len, HexPrefix::DontAdd, 1);
std::string rlpblock = toCompactHex(247 + hexlen.size() / 2) + hexlen + emptyZeros + rndByteSequence(len);
_debug.insert(0, "[" + toCompactHex(247 + hexlen.size() / 2) + hexlen + "(" + toString(len) + "){4}]" + emptyZeros + rndByteSequence(len));
_result.insert(0, rlpblock);
return rlpblock.size() / 2;
}
}
}
return 0;
}
std::string RandomCode::rndRLPSequence(int _depth, std::string& _debug)
{
refreshSeed();
std::string hash;
_length = (_sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length;
_depth = std::min(std::max(1, _depth), 7); //limit depth to avoid overkill
recursiveRLP(hash, _depth, _debug);
return hash;
}
std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType)
{
refreshSeed();
std::string hash = "";
_length = (_sizeType == SizeStrictness::Strict) ? std::max(0, _length) : randomUniInt() % _length;
for (auto i = 0; i < _length; i++)
{
uint8_t byte = randOpCodeGen();

17
test/fuzzTesting/fuzzHelper.h

@ -66,6 +66,12 @@ enum class SizeStrictness
Random
};
struct RlpDebug
{
std::string rlp;
int insertions;
};
class RandomCode
{
public:
@ -75,6 +81,16 @@ public:
/// Generate random byte string of a given length
static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict);
/// Generate random rlp byte sequence of a given depth (e.g [[[]],[]]). max depth level = 20.
/// The _debug string contains returned rlp string with analysed sections
/// [] - length section/ or single byte rlp encoding
/// () - decimal representation of length
/// {1} - Array
/// {2} - Array more than 55
/// {3} - List
/// {4} - List more than 55
static std::string rndRLPSequence(int _depth, std::string& _debug);
/// Generate random int64
static std::string randomUniIntHex(u256 _maxVal = 0);
static int randomUniInt();
@ -83,6 +99,7 @@ private:
static std::string fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options);
static std::string getPushCode(int _value);
static std::string getPushCode(std::string const& _hex);
static int recursiveRLP(std::string& _result, int _depth, std::string& _debug);
static void refreshSeed();
static boost::random::mt19937 gen; ///< Random generator

34
test/libdevcore/rlp.cpp

@ -30,8 +30,8 @@
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <algorithm>
#include "../JsonSpiritHeaders.h"
#include "../TestHelper.h"
#include "test/JsonSpiritHeaders.h"
#include "test/TestHelper.h"
using namespace std;
using namespace dev;
@ -72,8 +72,6 @@ namespace dev
bytes payloadToDecode = fromHex(o["out"].get_str());
RLP payload(payloadToDecode);
ostringstream() << payload;
if (payload.isEmpty())
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Decoded Empty RLP!"));
o["in"] = "VALID";
}
catch (Exception const& _e)
@ -129,6 +127,8 @@ namespace dev
{
bytes payloadToDecode = fromHex(o["out"].get_str());
RLP payload(payloadToDecode);
//attempt to read all the contents of RLP
ostringstream() << payload;
if (rlpType == RlpType::Test)
@ -144,6 +144,10 @@ namespace dev
cnote << "rlp exception: " << _e.what();
was_exception = true;
}
catch (...)
{
was_exception = true;
}
//Expect exception as input is INVALID
if (rlpType == RlpType::Invalid && was_exception)
@ -238,6 +242,28 @@ namespace dev
BOOST_AUTO_TEST_SUITE(RlpTests)
BOOST_AUTO_TEST_CASE(EmptyArrayList)
{
try
{
bytes payloadToDecode = fromHex("80");
RLP payload(payloadToDecode);
ostringstream() << payload;
payloadToDecode = fromHex("с0");
RLP payload2(payloadToDecode);
ostringstream() << payload2;
}
catch (Exception const& _e)
{
TBOOST_ERROR("Failed test with Exception: " << _e.what());
}
catch (exception const& _e)
{
TBOOST_ERROR("Failed test with Exception: " << _e.what());
}
}
BOOST_AUTO_TEST_CASE(invalidRLPtest)
{
dev::test::executeTests("invalidRLPTest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);

Loading…
Cancel
Save