Browse Source

Merge pull request #1408 from debris/1351_libtestutils

split #1351, libtestutils
cl-refactor
Gav Wood 10 years ago
parent
commit
4dd11a50c4
  1. 1
      CMakeLists.txt
  2. 100
      libtestutils/BlockChainLoader.cpp
  3. 52
      libtestutils/BlockChainLoader.h
  4. 34
      libtestutils/CMakeLists.txt
  5. 80
      libtestutils/Common.cpp
  6. 44
      libtestutils/Common.h
  7. 32
      libtestutils/FixedClient.cpp
  8. 59
      libtestutils/FixedClient.h
  9. 22
      libtestutils/FixedWebThreeServer.cpp
  10. 57
      libtestutils/FixedWebThreeServer.h
  11. 56
      libtestutils/StateLoader.cpp
  12. 45
      libtestutils/StateLoader.h
  13. 42
      libtestutils/TransientDirectory.cpp
  14. 50
      libtestutils/TransientDirectory.h

1
CMakeLists.txt

@ -194,6 +194,7 @@ add_subdirectory(libevm)
add_subdirectory(libethereum)
add_subdirectory(libwebthree)
add_subdirectory(libtestutils)
add_subdirectory(test)
if (NOT JUSTTESTS)

100
libtestutils/BlockChainLoader.cpp

@ -0,0 +1,100 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file BlockChainLoader.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "BlockChainLoader.h"
#include "StateLoader.h"
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::test;
using namespace dev::eth;
namespace dev
{
namespace test
{
dev::eth::BlockInfo toBlockInfo(Json::Value const& _json);
bytes toGenesisBlock(Json::Value const& _json);
}
}
dev::eth::BlockInfo dev::test::toBlockInfo(Json::Value const& _json)
{
RLPStream rlpStream;
auto size = _json.getMemberNames().size();
rlpStream.appendList(_json["hash"].empty() ? size : (size - 1));
rlpStream << fromHex(_json["parentHash"].asString());
rlpStream << fromHex(_json["uncleHash"].asString());
rlpStream << fromHex(_json["coinbase"].asString());
rlpStream << fromHex(_json["stateRoot"].asString());
rlpStream << fromHex(_json["transactionsTrie"].asString());
rlpStream << fromHex(_json["receiptTrie"].asString());
rlpStream << fromHex(_json["bloom"].asString());
rlpStream << bigint(_json["difficulty"].asString());
rlpStream << bigint(_json["number"].asString());
rlpStream << bigint(_json["gasLimit"].asString());
rlpStream << bigint(_json["gasUsed"].asString());
rlpStream << bigint(_json["timestamp"].asString());
rlpStream << fromHex(_json["extraData"].asString());
rlpStream << fromHex(_json["mixHash"].asString());
rlpStream << fromHex(_json["nonce"].asString());
BlockInfo result;
RLP rlp(rlpStream.out());
result.populateFromHeader(rlp, IgnoreNonce);
return result;
}
bytes dev::test::toGenesisBlock(Json::Value const& _json)
{
BlockInfo bi = toBlockInfo(_json);
RLPStream rlpStream;
bi.streamRLP(rlpStream, WithNonce);
RLPStream fullStream(3);
fullStream.appendRaw(rlpStream.out());
fullStream.appendRaw(RLPEmptyList);
fullStream.appendRaw(RLPEmptyList);
bi.verifyInternals(&fullStream.out());
return fullStream.out();
}
BlockChainLoader::BlockChainLoader(Json::Value const& _json)
{
// load pre state
StateLoader sl(_json["pre"]);
m_state = sl.state();
// load genesisBlock
m_bc.reset(new BlockChain(toGenesisBlock(_json["genesisBlockHeader"]), m_dir.path(), true));
// load blocks
for (auto const& block: _json["blocks"])
{
bytes rlp = fromHex(block["rlp"].asString());
m_bc->import(rlp, m_state.db());
}
// sync state
m_state.sync(*m_bc);
}

52
libtestutils/BlockChainLoader.h

@ -0,0 +1,52 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file BlockChainLoader.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <string>
#include <json/json.h>
#include <libethereum/BlockChain.h>
#include <libethereum/State.h>
#include "TransientDirectory.h"
namespace dev
{
namespace test
{
/**
* @brief Should be used to load test blockchain from json file
* Loads the blockchain from json, creates temporary directory to store it, removes the directory on dealloc
*/
class BlockChainLoader
{
public:
BlockChainLoader(Json::Value const& _json);
eth::BlockChain const& bc() const { return *m_bc; }
eth::State const& state() const { return m_state; }
private:
TransientDirectory m_dir;
std::auto_ptr<eth::BlockChain> m_bc;
eth::State m_state;
};
}
}

34
libtestutils/CMakeLists.txt

@ -0,0 +1,34 @@
cmake_policy(SET CMP0015 NEW)
# this policy was introduced in cmake 3.0
# remove if, once 3.0 will be used on unix
if (${CMAKE_MAJOR_VERSION} GREATER 2)
# old policy do not use MACOSX_RPATH
cmake_policy(SET CMP0042 OLD)
endif()
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE testutils)
file(GLOB HEADERS "*.h")
if (ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} web3jsonrpc)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

80
libtestutils/Common.cpp

@ -0,0 +1,80 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <random>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/FileSystem.h>
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::test;
std::string dev::test::getTestPath()
{
string testPath;
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
if (ptestPath == NULL)
{
ctest << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
return testPath;
}
int dev::test::randomNumber()
{
static std::mt19937 randomGenerator(time(0));
randomGenerator.seed(std::random_device()());
return std::uniform_int_distribution<int>(1)(randomGenerator);
}
Json::Value dev::test::loadJsonFromFile(std::string const& _path)
{
Json::Reader reader;
Json::Value result;
string s = asString(dev::contents(_path));
if (!s.length())
ctest << "Contents of " + _path + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?";
else
ctest << "FIXTURE: loaded test from file: " << _path;
reader.parse(s, result);
return result;
}
std::string dev::test::toTestFilePath(std::string const& _filename)
{
return getTestPath() + "/" + _filename + ".json";
}
std::string dev::test::getRandomPath()
{
std::stringstream stream;
stream << getDataDir() << "/EthereumTests/" << randomNumber();
return stream.str();
}

44
libtestutils/Common.h

@ -0,0 +1,44 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <string>
#include <json/json.h>
#include <libdevcore/Log.h>
namespace dev
{
namespace test
{
struct TestChannel: public LogChannel { static const char* name() { return "TEST"; } };
#define ctest dev::LogOutputStream<dev::test::TestChannel, true>()
std::string getTestPath();
int randomNumber();
Json::Value loadJsonFromFile(std::string const& _path);
std::string toTestFilePath(std::string const& _filename);
std::string getRandomPath();
}
}

32
libtestutils/FixedClient.cpp

@ -0,0 +1,32 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedClient.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "FixedClient.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
eth::State FixedClient::asOf(h256 const& _h) const
{
ReadGuard l(x_stateDB);
return State(m_state.db(), bc(), _h);
}

59
libtestutils/FixedClient.h

@ -0,0 +1,59 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedClient.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <libethereum/ClientBase.h>
#include <libethereum/BlockChain.h>
#include <libethereum/State.h>
namespace dev
{
namespace test
{
/**
* @brief mvp implementation of ClientBase
* Doesn't support mining interface
*/
class FixedClient: public dev::eth::ClientBase
{
public:
FixedClient(eth::BlockChain const& _bc, eth::State _state) : m_bc(_bc), m_state(_state) {}
virtual ~FixedClient() {}
// stub
virtual void flushTransactions() override {}
virtual eth::BlockChain const& bc() const override { return m_bc; }
using ClientBase::asOf;
virtual eth::State asOf(h256 const& _h) const override;
virtual eth::State preMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual eth::State postMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual void prepareForTransaction() override {}
private:
eth::BlockChain const& m_bc;
eth::State m_state;
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
};
}
}

22
libtestutils/FixedWebThreeServer.cpp

@ -0,0 +1,22 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedWebThreeStubServer.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "FixedWebThreeServer.h"

57
libtestutils/FixedWebThreeServer.h

@ -0,0 +1,57 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedWebThreeStubServer.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <libdevcore/Exceptions.h>
#include <libweb3jsonrpc/WebThreeStubServerBase.h>
/**
* @brief dummy JSON-RPC api implementation
* Should be used for test purposes only
* Supports eth && db interfaces
* Doesn't support shh && net interfaces
*/
class FixedWebThreeServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace
{
public:
FixedWebThreeServer(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client): WebThreeStubServerBase(_conn, _accounts), m_client(_client) {};
private:
dev::eth::Interface* client() override { return m_client; }
std::shared_ptr<dev::shh::Interface> face() override { BOOST_THROW_EXCEPTION(dev::InterfaceNotSupported("dev::shh::Interface")); }
dev::WebThreeNetworkFace* network() override { BOOST_THROW_EXCEPTION(dev::InterfaceNotSupported("dev::WebThreeNetworkFace")); }
dev::WebThreeStubDatabaseFace* db() override { return this; }
std::string get(std::string const& _name, std::string const& _key) override
{
std::string k(_name + "/" + _key);
return m_db[k];
}
void put(std::string const& _name, std::string const& _key, std::string const& _value) override
{
std::string k(_name + "/" + _key);
m_db[k] = _value;
}
private:
dev::eth::Interface* m_client;
std::map<std::string, std::string> m_db;
};

56
libtestutils/StateLoader.cpp

@ -0,0 +1,56 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file StateLoader.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "StateLoader.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
StateLoader::StateLoader(Json::Value const& _json) : m_state(Address(), OverlayDB(), BaseState::Empty)
{
for (string const& name: _json.getMemberNames())
{
Json::Value o = _json[name];
Address address = Address(name);
bytes code = fromHex(o["code"].asString().substr(2));
if (code.size())
{
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::ContractConception);
m_state.m_cache[address].setCode(code);
}
else
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::NormalCreation);
for (string const& j: o["storage"].getMemberNames())
m_state.setStorage(address, u256(j), u256(o["storage"][j].asString()));
for (auto i = 0; i < u256(o["nonce"].asString()); ++i)
m_state.noteSending(address);
m_state.ensureCached(address, false, false);
}
m_state.commit();
}

45
libtestutils/StateLoader.h

@ -0,0 +1,45 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file StateLoader.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <json/json.h>
#include <libethereum/State.h>
namespace dev
{
namespace test
{
/**
* @brief Friend of State, loads State from given JSON object
*/
class StateLoader
{
public:
StateLoader(Json::Value const& _json);
eth::State const& state() const { return m_state; }
private:
eth::State m_state;
};
}
}

42
libtestutils/TransientDirectory.cpp

@ -0,0 +1,42 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TransientDirectory.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <boost/filesystem.hpp>
#include <libdevcore/Exceptions.h>
#include "TransientDirectory.h"
using namespace std;
using namespace dev;
using namespace dev::test;
TransientDirectory::TransientDirectory(std::string const& _path) : m_path(_path)
{
// we never ever want to delete a directory (including all its contents) that we did not create ourselves.
if (boost::filesystem::exists(m_path))
BOOST_THROW_EXCEPTION(FileError());
boost::filesystem::create_directories(m_path);
}
TransientDirectory::~TransientDirectory()
{
boost::filesystem::remove_all(m_path);
}

50
libtestutils/TransientDirectory.h

@ -0,0 +1,50 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TransientDirectory.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <string>
#include "Common.h"
namespace dev
{
namespace test
{
/**
* @brief temporary directory implementation
* It creates temporary directory in the given path. On dealloc it removes the directory
* @throws if the given path already exists, throws an exception
*/
class TransientDirectory
{
public:
TransientDirectory(std::string const& _path = getRandomPath());
~TransientDirectory();
std::string const& path() const { return m_path; }
private:
std::string m_path;
};
}
}
Loading…
Cancel
Save