Browse Source

merge

cl-refactor
yann300 10 years ago
parent
commit
58b9088de5
  1. 2
      .gitignore
  2. 4
      .gitmodules
  3. 14
      CMakeLists.txt
  4. 4
      README.md
  5. 72
      alethzero/MainWin.cpp
  6. 50
      boost/process.hpp
  7. 200
      boost/process/child.hpp
  8. 41
      boost/process/config.hpp
  9. 209
      boost/process/context.hpp
  10. 406
      boost/process/detail/file_handle.hpp
  11. 187
      boost/process/detail/pipe.hpp
  12. 495
      boost/process/detail/posix_ops.hpp
  13. 176
      boost/process/detail/stream_info.hpp
  14. 231
      boost/process/detail/systembuf.hpp
  15. 355
      boost/process/detail/win32_ops.hpp
  16. 50
      boost/process/environment.hpp
  17. 583
      boost/process/operations.hpp
  18. 116
      boost/process/pistream.hpp
  19. 178
      boost/process/posix_child.hpp
  20. 118
      boost/process/posix_context.hpp
  21. 81
      boost/process/posix_operations.hpp
  22. 128
      boost/process/posix_status.hpp
  23. 117
      boost/process/postream.hpp
  24. 130
      boost/process/process.hpp
  25. 134
      boost/process/self.hpp
  26. 105
      boost/process/status.hpp
  27. 234
      boost/process/stream_behavior.hpp
  28. 128
      boost/process/win32_child.hpp
  29. 61
      boost/process/win32_context.hpp
  30. 77
      boost/process/win32_operations.hpp
  31. 2364
      doc/Doxyfile
  32. 15
      docker/Dockerfile
  33. 14
      eth/main.cpp
  34. 1
      evmjit
  35. 4
      exp/main.cpp
  36. 2
      libdevcore/Common.cpp
  37. 3
      libdevcore/Common.h
  38. 180
      libdevcore/CommonData.cpp
  39. 3
      libdevcore/CommonData.h
  40. 2
      libdevcore/CommonIO.cpp
  41. 52
      libdevcore/Diff.h
  42. 1
      libdevcore/vector_ref.h
  43. 3
      libethcore/BlockInfo.cpp
  44. 4
      libethcore/CommonEth.cpp
  45. 8
      libethcore/CommonEth.h
  46. 18
      libethereum/AccountDiff.cpp
  47. 55
      libethereum/AccountDiff.h
  48. 29
      libethereum/Client.cpp
  49. 34
      libethereum/Client.h
  50. 11
      libethereum/Executive.cpp
  51. 6
      libethereum/Executive.h
  52. 4
      libethereum/ExtVM.cpp
  53. 4
      libethereum/ExtVM.h
  54. 84
      libethereum/State.cpp
  55. 14
      libethereum/State.h
  56. 16
      libethereum/TransactionReceipt.cpp
  57. 3
      libethereum/TransactionReceipt.h
  58. 3
      libevm/CMakeLists.txt
  59. 3
      libevm/ExtVMFace.cpp
  60. 10
      libevm/ExtVMFace.h
  61. 32
      libevm/VM.h
  62. 10
      libevm/VMFactory.cpp
  63. 105
      libjsqrc/ethereum.js
  64. 2
      libp2p/Session.cpp
  65. 2
      libsolidity/ExpressionCompiler.cpp
  66. 1
      libsolidity/InterfaceHandler.cpp
  67. 22
      libsolidity/Token.h
  68. 5
      libweb3jsonrpc/WebThreeStubServer.cpp
  69. 1
      libweb3jsonrpc/WebThreeStubServer.h
  70. 16
      libweb3jsonrpc/abstractwebthreestubserver.h
  71. 2
      libweb3jsonrpc/spec.json
  72. 2
      mix/AssemblyDebuggerModel.cpp
  73. 3
      neth/main.cpp
  74. 53
      test/SolidityABIJSON.cpp
  75. 35
      test/SolidityEndToEndTest.cpp
  76. 10
      test/SolidityNameAndTypeResolution.cpp
  77. 2
      test/SolidityParser.cpp
  78. 19
      test/TestHelper.cpp
  79. 1
      test/TestHelper.h
  80. 22
      test/createRandomTest.cpp
  81. 5
      test/jsonrpc.cpp
  82. 2
      test/solidityExecutionFramework.h
  83. 205
      test/stInitCodeTestFiller.json
  84. 163
      test/stRefundTestFiller.json
  85. 102
      test/stSystemOperationsTestFiller.json
  86. 137
      test/stTransactionTestFiller.json
  87. 4
      test/state.cpp
  88. 2
      test/stateOriginal.cpp
  89. 26
      test/vm.cpp

2
.gitignore

@ -64,3 +64,5 @@ profile
DerivedData
project.pbxproj
evmjit

4
.gitmodules

@ -0,0 +1,4 @@
[submodule "evmjit"]
path = evmjit
url = https://github.com/ethereum/evmjit
branch = develop

14
CMakeLists.txt

@ -18,6 +18,7 @@ function(createDefaultCacheConfig)
set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)")
set(PARANOIA OFF CACHE BOOL "Additional run-time checks")
set(JSONRPC ON CACHE BOOL "Build with jsonprc. default on")
set(EVMJIT OFF CACHE BOOL "Build a just-in-time compiler for EVM code (requires LLVM)")
endfunction()
@ -38,6 +39,10 @@ function(configureProject)
message(FATAL_ERROR "VM tracing requires debug.")
endif ()
endif ()
if (EVMJIT)
add_definitions(-DETH_EVMJIT)
endif()
endfunction()
@ -84,7 +89,7 @@ cmake_policy(SET CMP0015 NEW)
createDefaultCacheConfig()
configureProject()
message("-- VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}; JSONRPC: ${JSONRPC}")
message("-- VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}; JSONRPC: ${JSONRPC}; EVMJIT: ${EVMJIT}")
# Default TARGET_PLATFORM to "linux".
@ -107,6 +112,13 @@ include(EthExecutableHelper)
createBuildInfo()
if (EVMJIT)
# Workaround for Ubuntu broken LLVM package
link_directories(/usr/lib/llvm-3.5/lib)
add_subdirectory(evmjit)
endif()
add_subdirectory(libdevcore)
add_subdirectory(libevmcore)
add_subdirectory(liblll)

4
README.md

@ -1,5 +1,9 @@
## Ethereum C++ Client.
[![Build
Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build
Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop
By Gav Wood, 2014.
[![Build

72
alethzero/MainWin.cpp

@ -106,6 +106,8 @@ static QString contentsOfQResource(std::string const& res)
}
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
Address c_newConfig = Address("d5f9d8d94886e70b06e474c3fb14fd43e2f23970");
Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1");
Main::Main(QWidget *parent) :
QMainWindow(parent),
@ -448,8 +450,29 @@ static Public stringToPublic(QString const& _a)
return Public();
}
static Address g_newNameReg;
QString Main::pretty(dev::Address _a) const
{
static std::map<Address, QString> s_memos;
if (!s_memos.count(_a))
{
if (!g_newNameReg)
g_newNameReg = abiOut<Address>(ethereum()->call(c_newConfig, abiIn(1, (u256)1)));
if (g_newNameReg)
{
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn(2, _a)))));
s_memos[_a] = s;
if (s.size())
return s;
}
}
else
if (s_memos[_a].size())
return s_memos[_a];
h256 n;
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
@ -469,19 +492,47 @@ QString Main::render(dev::Address _a) const
return QString::fromStdString(_a.abridged());
}
Address Main::fromString(QString const& _a) const
string32 fromString(std::string const& _s)
{
string32 ret;
for (unsigned i = 0; i < 32 && i <= _s.size(); ++i)
ret[i] = i < _s.size() ? _s[i] : 0;
return ret;
}
Address Main::fromString(QString const& _n) const
{
if (_a == "(Create Contract)")
if (_n == "(Create Contract)")
return Address();
string sn = _a.toStdString();
static std::map<QString, Address> s_memos;
if (!s_memos.count(_n))
{
if (!g_newNameReg)
g_newNameReg = abiOut<Address>(ethereum()->call(c_newConfig, abiIn(1, (u256)1)));
if (g_newNameReg)
{
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn(0, ::fromString(_n.toStdString()))));
s_memos[_n] = a;
if (a)
return a;
}
}
else
if (s_memos[_n])
return s_memos[_n];
string sn = _n.toStdString();
if (sn.size() > 32)
sn.resize(32);
h256 n;
memcpy(n.data(), sn.data(), sn.size());
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size())
if (_n.size())
{
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a);
@ -489,8 +540,9 @@ Address Main::fromString(QString const& _a) const
if (h256 a = ethereum()->stateAt(m_nameReg, n))
return right160(a);
}
if (_a.size() == 40)
return Address(fromHex(_a.toStdString()));
if (_n.size() == 40)
return Address(fromHex(_n.toStdString()));
else
return Address();
}
@ -1112,7 +1164,7 @@ string Main::renderDiff(dev::eth::StateDiff const& _d) const
s << "<hr/>";
dev::eth::AccountDiff const& ad = i.second;
s << "<code style=\"white-space: pre; font-weight: bold\">" << ad.lead() << " </code>" << " <b>" << render(i.first).toStdString() << "</b>";
s << "<code style=\"white-space: pre; font-weight: bold\">" << lead(ad.changeType()) << " </code>" << " <b>" << render(i.first).toStdString() << "</b>";
if (!ad.exist.to())
continue;
@ -1133,7 +1185,7 @@ string Main::renderDiff(dev::eth::StateDiff const& _d) const
s << " (" << ad.code.from().size() << " bytes)";
}
for (pair<u256, dev::eth::Diff<u256>> const& i: ad.storage)
for (pair<u256, dev::Diff<u256>> const& i: ad.storage)
{
s << "<br/><code style=\"white-space: pre\">";
if (!i.second.from())
@ -1350,7 +1402,7 @@ void Main::on_debugCurrent_triggered()
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
m_executiveState = ethereum()->state(txi + 1, h);
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, 0));
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = m_executiveState.pending()[txi];
m_executiveState = m_executiveState.fromPending(txi);
auto r = t.rlp();
@ -1803,7 +1855,7 @@ void Main::on_debug_clicked()
{
Secret s = i.secret();
m_executiveState = ethereum()->postState();
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, 0));
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s);

50
boost/process.hpp

@ -1,50 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process.hpp
*
* Convenience header that includes all other Boost.Process public header
* files. It is important to note that those headers that are specific to
* a given platform are only included if the library is being used in that
* same platform.
*/
#ifndef BOOST_PROCESS_HPP
#define BOOST_PROCESS_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <boost/process/posix_child.hpp>
# include <boost/process/posix_context.hpp>
# include <boost/process/posix_operations.hpp>
# include <boost/process/posix_status.hpp>
#elif defined(BOOST_WINDOWS_API)
# include <boost/process/win32_child.hpp>
# include <boost/process/win32_context.hpp>
# include <boost/process/win32_operations.hpp>
#else
# error "Unsupported platform."
#endif
#include <boost/process/child.hpp>
#include <boost/process/context.hpp>
#include <boost/process/environment.hpp>
#include <boost/process/operations.hpp>
#include <boost/process/pistream.hpp>
#include <boost/process/postream.hpp>
#include <boost/process/process.hpp>
#include <boost/process/self.hpp>
#include <boost/process/status.hpp>
#include <boost/process/stream_behavior.hpp>
#endif

200
boost/process/child.hpp

@ -1,200 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/child.hpp
*
* Includes the declaration of the child class.
*/
#ifndef BOOST_PROCESS_CHILD_HPP
#define BOOST_PROCESS_CHILD_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <sys/types.h>
# include <sys/wait.h>
# include <cerrno>
#elif defined(BOOST_WINDOWS_API)
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/process/process.hpp>
#include <boost/process/pistream.hpp>
#include <boost/process/postream.hpp>
#include <boost/process/status.hpp>
#include <boost/process/detail/file_handle.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/assert.hpp>
#include <vector>
namespace boost {
namespace process {
/**
* Generic implementation of the Child concept.
*
* The child class implements the Child concept in an operating system
* agnostic way.
*/
class child : public process
{
public:
/**
* Gets a reference to the child's standard input stream.
*
* Returns a reference to a postream object that represents the
* standard input communication channel with the child process.
*/
postream &get_stdin() const
{
BOOST_ASSERT(stdin_);
return *stdin_;
}
/**
* Gets a reference to the child's standard output stream.
*
* Returns a reference to a pistream object that represents the
* standard output communication channel with the child process.
*/
pistream &get_stdout() const
{
BOOST_ASSERT(stdout_);
return *stdout_;
}
/**
* Gets a reference to the child's standard error stream.
*
* Returns a reference to a pistream object that represents the
* standard error communication channel with the child process.
*/
pistream &get_stderr() const
{
BOOST_ASSERT(stderr_);
return *stderr_;
}
/**
* Blocks and waits for the child process to terminate.
*
* Returns a status object that represents the child process'
* finalization condition. The child process object ceases to be
* valid after this call.
*
* \remark Blocking remarks: This call blocks if the child
* process has not finalized execution and waits until
* it terminates.
*/
status wait()
{
#if defined(BOOST_POSIX_API)
int s;
if (::waitpid(get_id(), &s, 0) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::child::wait: waitpid(2) failed"));
return status(s);
#elif defined(BOOST_WINDOWS_API)
::WaitForSingleObject(process_handle_.get(), INFINITE);
DWORD code;
if (!::GetExitCodeProcess(process_handle_.get(), &code))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::child::wait: GetExitCodeProcess failed"));
return status(code);
#endif
}
/**
* Creates a new child object that represents the just spawned child
* process \a id.
*
* The \a fhstdin, \a fhstdout and \a fhstderr file handles represent
* the parent's handles used to communicate with the corresponding
* data streams. They needn't be valid but their availability must
* match the redirections configured by the launcher that spawned this
* process.
*
* The \a fhprocess handle represents a handle to the child process.
* It is only used on Windows as the implementation of wait() needs a
* process handle.
*/
child(id_type id, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr, detail::file_handle fhprocess = detail::file_handle())
: process(id)
#if defined(BOOST_WINDOWS_API)
, process_handle_(fhprocess.release(), ::CloseHandle)
#endif
{
if (fhstdin.valid())
stdin_.reset(new postream(fhstdin));
if (fhstdout.valid())
stdout_.reset(new pistream(fhstdout));
if (fhstderr.valid())
stderr_.reset(new pistream(fhstderr));
}
private:
/**
* The standard input stream attached to the child process.
*
* This postream object holds the communication channel with the
* child's process standard input. It is stored in a pointer because
* this field is only valid when the user requested to redirect this
* data stream.
*/
boost::shared_ptr<postream> stdin_;
/**
* The standard output stream attached to the child process.
*
* This postream object holds the communication channel with the
* child's process standard output. It is stored in a pointer because
* this field is only valid when the user requested to redirect this
* data stream.
*/
boost::shared_ptr<pistream> stdout_;
/**
* The standard error stream attached to the child process.
*
* This postream object holds the communication channel with the
* child's process standard error. It is stored in a pointer because
* this field is only valid when the user requested to redirect this
* data stream.
*/
boost::shared_ptr<pistream> stderr_;
#if defined(BOOST_WINDOWS_API)
/**
* Process handle owned by RAII object.
*/
boost::shared_ptr<void> process_handle_;
#endif
};
/**
* Collection of child objects.
*
* This convenience type represents a collection of child objects backed
* by a vector.
*/
typedef std::vector<child> children;
}
}
#endif

41
boost/process/config.hpp

@ -1,41 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/config.hpp
*
* Defines macros that are used by the library's code to determine the
* operating system it is running under and the features it supports.
*/
#ifndef BOOST_PROCESS_CONFIG_HPP
#define BOOST_PROCESS_CONFIG_HPP
#include <boost/config.hpp>
#include <boost/system/config.hpp>
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
# if !defined(BOOST_PROCESS_POSIX_PATH_MAX)
/**
* The macro BOOST_PROCESS_POSIX_PATH_MAX is set to a positive integer
* value which specifies the system's maximal supported path length.
* By default it is set to 259. You should set the macro to PATH_MAX
* which should be defined in limits.h provided by your operating system
* if you experience problems when instantiating a context. The
* constructor of basic_work_directory_context tries to find out
* dynamically the maximal supported path length but uses
* BOOST_PROCESS_POSIX_PATH_MAX if it fails.
*/
# define BOOST_PROCESS_POSIX_PATH_MAX 259
# endif
#endif
#endif

209
boost/process/context.hpp

@ -1,209 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/context.hpp
*
* Includes the declaration of the context class and several accessory
* base classes.
*/
#ifndef BOOST_PROCESS_CONTEXT_HPP
#define BOOST_PROCESS_CONTEXT_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <boost/scoped_array.hpp>
# include <cerrno>
# include <unistd.h>
#elif defined(BOOST_WINDOWS_API)
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/process/environment.hpp>
#include <boost/process/stream_behavior.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <boost/assert.hpp>
#include <string>
#include <vector>
namespace boost {
namespace process {
/**
* Base context class that defines the child's work directory.
*
* Base context class that defines the necessary fields to configure a
* child's work directory. This class is useless on its own because no
* function in the library will accept it as a valid Context
* implementation.
*/
template <class Path>
class basic_work_directory_context
{
public:
/**
* Constructs a new work directory context.
*
* Constructs a new work directory context making the work directory
* described by the new object point to the caller's current working
* directory.
*/
basic_work_directory_context()
{
#if defined(BOOST_POSIX_API)
errno = 0;
long size = ::pathconf(".", _PC_PATH_MAX);
if (size == -1 && errno)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: pathconf(2) failed"));
else if (size == -1)
size = BOOST_PROCESS_POSIX_PATH_MAX;
boost::scoped_array<char> cwd(new char[size]);
if (!::getcwd(cwd.get(), size))
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: getcwd(2) failed"));
work_directory = cwd.get();
#elif defined(BOOST_WINDOWS_API)
char cwd[MAX_PATH];
if (!::GetCurrentDirectoryA(sizeof(cwd), cwd))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: GetCurrentDirectory failed"));
work_directory = cwd;
#endif
BOOST_ASSERT(!work_directory.empty());
}
/**
* The process' initial work directory.
*
* The work directory is the directory in which the process starts
* execution.
*/
Path work_directory;
};
/**
* Base context class that defines the child's environment.
*
* Base context class that defines the necessary fields to configure a
* child's environment variables. This class is useless on its own
* because no function in the library will accept it as a valid Context
* implementation.
*/
class environment_context
{
public:
/**
* The process' environment.
*
* Contains the list of environment variables, alongside with their
* values, that will be passed to the spawned child process.
*/
boost::process::environment environment;
};
/**
* Process startup execution context.
*
* The context class groups all the parameters needed to configure a
* process' environment during its creation.
*/
template <class Path>
class basic_context : public basic_work_directory_context<Path>, public environment_context
{
public:
/**
* Child's stdin behavior.
*/
stream_behavior stdin_behavior;
/**
* Child's stdout behavior.
*/
stream_behavior stdout_behavior;
/**
* Child's stderr behavior.
*/
stream_behavior stderr_behavior;
};
typedef basic_context<std::string> context;
/**
* Represents a child process in a pipeline.
*
* This convenience class is a triplet that holds all the data required
* to spawn a new child process in a pipeline.
*/
template <class Executable, class Arguments, class Context>
class basic_pipeline_entry
{
public:
/**
* The executable to launch.
*/
Executable executable;
/**
* The set of arguments to pass to the executable.
*/
Arguments arguments;
/**
* The child's execution context.
*/
Context context;
/**
* The type of the Executable concept used in this template
* instantiation.
*/
typedef Executable executable_type;
/**
* The type of the Arguments concept used in this template
* instantiation.
*/
typedef Arguments arguments_type;
/**
* The type of the Context concept used in this template
* instantiation.
*/
typedef Context context_type;
/**
* Constructs a new pipeline_entry object.
*
* Given the executable, set of arguments and execution triplet,
* constructs a new pipeline_entry object that holds the three
* values.
*/
basic_pipeline_entry(const Executable &exe, const Arguments &args, const Context &ctx)
: executable(exe),
arguments(args),
context(ctx)
{
}
};
/**
* Default instantiation of basic_pipeline_entry.
*/
typedef basic_pipeline_entry<std::string, std::vector<std::string>, context> pipeline_entry;
}
}
#endif

406
boost/process/detail/file_handle.hpp

@ -1,406 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/detail/file_handle.hpp
*
* Includes the declaration of the file_handle class. This file is for
* internal usage only and must not be included by the library user.
*/
#ifndef BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP
#define BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <cerrno>
# include <unistd.h>
#elif defined(BOOST_WINDOWS_API)
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/assert.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
namespace process {
namespace detail {
/**
* Simple RAII model for system file handles.
*
* The \a file_handle class is a simple RAII model for native system file
* handles. This class wraps one of such handles grabbing its ownership,
* and automaticaly closes it upon destruction. It is basically used
* inside the library to avoid leaking open file handles, shall an
* unexpected execution trace occur.
*
* A \a file_handle object can be copied but doing so invalidates the
* source object. There can only be a single valid \a file_handle object
* for a given system file handle. This is similar to std::auto_ptr's
* semantics.
*
* This class also provides some convenience methods to issue special file
* operations under their respective platforms.
*/
class file_handle
{
public:
#if defined(BOOST_PROCESS_DOXYGEN)
/**
* Opaque name for the native handle type.
*
* Each operating system identifies file handles using a specific type.
* The \a handle_type type is used to transparently refer to file
* handles regarless of the operating system in which this class is
* used.
*
* If this class is used on a POSIX system, \a NativeSystemHandle is
* an integer type while it is a \a HANDLE on a Windows system.
*/
typedef NativeSystemHandle handle_type;
#elif defined(BOOST_POSIX_API)
typedef int handle_type;
#elif defined(BOOST_WINDOWS_API)
typedef HANDLE handle_type;
#endif
/**
* Constructs an invalid file handle.
*
* This constructor creates a new \a file_handle object that represents
* an invalid file handle. An invalid file handle can be copied but
* cannot be manipulated in any way (except checking for its validity).
*
* \see valid()
*/
file_handle()
: handle_(invalid_value())
{
}
/**
* Constructs a new file handle from a native file handle.
*
* This constructor creates a new \a file_handle object that takes
* ownership of the given \a h native file handle. The user must not
* close \a h on his own during the lifetime of the new object.
* Ownership can be reclaimed using release().
*
* \pre The native file handle must be valid; a close operation must
* succeed on it.
* \see release()
*/
file_handle(handle_type h)
: handle_(h)
{
BOOST_ASSERT(handle_ != invalid_value());
}
/**
* Copy constructor; invalidates the source handle.
*
* This copy constructor creates a new file handle from a given one.
* Ownership of the native file handle is transferred to the new
* object, effectively invalidating the source file handle. This
* avoids having two live \a file_handle objects referring to the
* same native file handle. The source file handle needs not be
* valid in the name of simplicity.
*
* \post The source file handle is invalid.
* \post The new file handle owns the source's native file handle.
*/
file_handle(const file_handle &fh)
: handle_(fh.handle_)
{
fh.handle_ = invalid_value();
}
/**
* Releases resources if the handle is valid.
*
* If the file handle is valid, the destructor closes it.
*
* \see valid()
*/
~file_handle()
{
if (valid())
close();
}
/**
* Assignment operator; invalidates the source handle.
*
* This assignment operator transfers ownership of the RHS file
* handle to the LHS one, effectively invalidating the source file
* handle. This avoids having two live \a file_handle objects
* referring to the same native file handle. The source file
* handle needs not be valid in the name of simplicity.
*
* \post The RHS file handle is invalid.
* \post The LHS file handle owns RHS' native file handle.
* \return A reference to the LHS file handle.
*/
file_handle &operator=(const file_handle &fh)
{
handle_ = fh.handle_;
fh.handle_ = invalid_value();
return *this;
}
/**
* Checks whether the file handle is valid or not.
*
* Returns a boolean indicating whether the file handle is valid or
* not. If the file handle is invalid, no other methods can be
* executed other than the destructor.
*
* \return true if the file handle is valid; false otherwise.
*/
bool valid() const
{
return handle_ != invalid_value();
}
/**
* Closes the file handle.
*
* Explicitly closes the file handle, which must be valid. Upon
* exit, the handle is not valid any more.
*
* \pre The file handle is valid.
* \post The file handle is invalid.
* \post The native file handle is closed.
*/
void close()
{
BOOST_ASSERT(valid());
#if defined(BOOST_POSIX_API)
::close(handle_);
#elif defined(BOOST_WINDOWS_API)
::CloseHandle(handle_);
#endif
handle_ = invalid_value();
}
/**
* Reclaims ownership of the native file handle.
*
* Explicitly reclaims ownership of the native file handle contained
* in the \a file_handle object, returning the native file handle.
* The caller is responsible of closing it later on.
*
* \pre The file handle is valid.
* \post The file handle is invalid.
* \return The native file handle.
*/
handle_type release()
{
BOOST_ASSERT(valid());
handle_type h = handle_;
handle_ = invalid_value();
return h;
}
/**
* Gets the native file handle.
*
* Returns the native file handle for the \a file_handle object.
* The caller can issue any operation on it except closing it.
* If closing is required, release() shall be used.
*
* \pre The file handle is valid.
* \post The file handle is valid.
* \return The native file handle.
*/
handle_type get() const
{
BOOST_ASSERT(valid());
return handle_;
}
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
/**
* Changes the native file handle to the given one.
*
* Given a new native file handle \a h, this operation assigns this
* handle to the current object, closing its old native file handle.
* In other words, it first calls dup2() to remap the old handle to
* the new one and then closes the old handle.
*
* If \a h is open, it is automatically closed by dup2().
*
* This operation is only available in POSIX systems.
*
* \pre The file handle is valid.
* \pre The native file handle \a h is valid; i.e., it must be
* closeable.
* \post The file handle's native file handle is \a h.
* \throw boost::system::system_error If the internal remapping
* operation fails.
*/
void posix_remap(handle_type h)
{
BOOST_ASSERT(valid());
if (::dup2(handle_, h) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: dup2(2) failed"));
if (::close(handle_) == -1)
{
::close(h);
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: close(2) failed"));
}
handle_ = h;
}
/**
* Duplicates an open native file handle.
*
* Given a native file handle \a h1, this routine duplicates it so
* that it ends up being identified by the native file handle \a h2
* and returns a new \a file_handle owning \a h2.
*
* This operation is only available in POSIX systems.
*
* \pre The native file handle \a h1 is open.
* \pre The native file handle \a h2 is valid (non-negative).
* \post The native file handle \a h1 is closed.
* \post The native file handle \a h2 is the same as the old \a h1
* from the operating system's point of view.
* \return A new \a file_handle object that owns \a h2.
* \throw boost::system::system_error If dup2() fails.
*/
static file_handle posix_dup(int h1, int h2)
{
if (::dup2(h1, h2) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_dup: dup2(2) failed"));
return file_handle(h2);
}
#endif
#if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN)
/**
* Duplicates the \a h native file handle.
*
* Given a native file handle \a h, this routine constructs a new
* \a file_handle object that owns a new duplicate of \a h. The
* duplicate's inheritable flag is set to the value of \a inheritable.
*
* This operation is only available in Windows systems.
*
* \pre The native file handle \a h is valid.
* \return A file handle owning a duplicate of \a h.
* \throw boost::system::system_error If DuplicateHandle() fails.
*/
static file_handle win32_dup(HANDLE h, bool inheritable)
{
HANDLE h2;
if (!::DuplicateHandle(::GetCurrentProcess(), h, ::GetCurrentProcess(), &h2, 0, inheritable ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_dup: DuplicateHandle failed"));
return file_handle(h2);
}
/**
* Creates a new duplicate of a standard file handle.
*
* Constructs a new \a file_handle object that owns a duplicate of a
* standard file handle. The \a d parameter specifies which standard
* file handle to duplicate and can be one of \a STD_INPUT_HANDLE,
* \a STD_OUTPUT_HANDLE or \a STD_ERROR_HANDLE. The duplicate's
* inheritable flag is set to the value of \a inheritable.
*
* This operation is only available in Windows systems.
*
* \pre \a d refers to one of the standard handles as described above.
* \return A file handle owning a duplicate of the standard handle
* referred to by \a d.
* \throw boost::system::system_error If GetStdHandle() or
* DuplicateHandle() fails.
*/
static file_handle win32_std(DWORD d, bool inheritable)
{
BOOST_ASSERT(d == STD_INPUT_HANDLE || d == STD_OUTPUT_HANDLE || d == STD_ERROR_HANDLE);
HANDLE h = ::GetStdHandle(d);
if (h == INVALID_HANDLE_VALUE)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_std: GetStdHandle failed"));
return win32_dup(h, inheritable);
}
/**
* Changes the file handle's inheritable flag.
*
* Changes the file handle's inheritable flag to \a i. It is not
* necessary for the file handle's flag to be different than \a i.
*
* This operation is only available in Windows systems.
*
* \pre The file handle is valid.
* \post The native file handle's inheritable flag is set to \a i.
* \throw boost::system::system_error If the property change fails.
*/
void win32_set_inheritable(bool i)
{
BOOST_ASSERT(valid());
if (!::SetHandleInformation(handle_, HANDLE_FLAG_INHERIT, i ? HANDLE_FLAG_INHERIT : 0))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_set_inheritable: SetHandleInformation failed"));
}
#endif
private:
/**
* Internal handle value.
*
* This variable holds the native handle value for the file handle
* hold by this object. It is interesting to note that this needs
* to be mutable because the copy constructor and the assignment
* operator invalidate the source object.
*/
mutable handle_type handle_;
/**
* Constant function representing an invalid handle value.
*
* Returns the platform-specific handle value that represents an
* invalid handle. This is a constant function rather than a regular
* constant because, in the latter case, we cannot define it under
* Windows due to the value being of a complex type.
*/
static handle_type invalid_value()
{
#if defined(BOOST_POSIX_API)
return -1;
#elif defined(BOOST_WINDOWS_API)
return INVALID_HANDLE_VALUE;
#endif
}
};
}
}
}
#endif

187
boost/process/detail/pipe.hpp

@ -1,187 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/detail/pipe.hpp
*
* Includes the declaration of the pipe class. This file is for
* internal usage only and must not be included by the library user.
*/
#ifndef BOOST_PROCESS_DETAIL_PIPE_HPP
#define BOOST_PROCESS_DETAIL_PIPE_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <unistd.h>
# include <cerrno>
#elif defined(BOOST_WINDOWS_API)
# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE)
# include <boost/lexical_cast.hpp>
# include <string>
# endif
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/process/detail/file_handle.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
namespace process {
namespace detail {
/**
* Simple RAII model for anonymous pipes.
*
* The pipe class is a simple RAII model for anonymous pipes. It
* provides a portable constructor that allocates a new %pipe and creates
* a pipe object that owns the two file handles associated to it: the
* read end and the write end.
*
* These handles can be retrieved for modification according to
* file_handle semantics. Optionally, their ownership can be transferred
* to external \a file_handle objects which comes handy when the two
* ends need to be used in different places (i.e. after a POSIX fork()
* system call).
*
* Pipes can be copied following the same semantics as file handles.
* In other words, copying a %pipe object invalidates the source one.
*
* \see file_handle
*/
class pipe
{
public:
/**
* Creates a new %pipe.
*
* The default pipe constructor allocates a new anonymous %pipe
* and assigns its ownership to the created pipe object. On Windows
* when the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE is defined
* a named pipe is created. This is required if asynchronous I/O
* should be used as asynchronous I/O is only supported by named
* pipes on Windows.
*
* \throw boost::system::system_error If the anonymous %pipe
* creation fails.
*/
pipe()
{
file_handle::handle_type hs[2];
#if defined(BOOST_POSIX_API)
if (::pipe(hs) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::pipe::pipe: pipe(2) failed"));
#elif defined(BOOST_WINDOWS_API)
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE)
static unsigned int nextid = 0;
std::string pipe = "\\\\.\\pipe\\boost_process_" + boost::lexical_cast<std::string>(::GetCurrentProcessId()) + "_" + boost::lexical_cast<std::string>(nextid++);
hs[0] = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa);
if (hs[0] == INVALID_HANDLE_VALUE)
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateNamedPipe failed"));
hs[1] = ::CreateFileA(pipe.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hs[1] == INVALID_HANDLE_VALUE)
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateFile failed"));
OVERLAPPED overlapped;
ZeroMemory(&overlapped, sizeof(overlapped));
overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
if (!overlapped.hEvent)
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateEvent failed"));
BOOL b = ::ConnectNamedPipe(hs[0], &overlapped);
if (!b)
{
if (::GetLastError() == ERROR_IO_PENDING)
{
if (::WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_FAILED)
{
::CloseHandle(overlapped.hEvent);
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: WaitForSingleObject failed"));
}
}
else if (::GetLastError() != ERROR_PIPE_CONNECTED)
{
::CloseHandle(overlapped.hEvent);
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: ConnectNamedPipe failed"));
}
}
::CloseHandle(overlapped.hEvent);
# else
if (!::CreatePipe(&hs[0], &hs[1], &sa, 0))
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreatePipe failed"));
# endif
#endif
read_end_ = file_handle(hs[0]);
write_end_ = file_handle(hs[1]);
}
/**
* Returns the %pipe's read end file handle.
*
* Obtains a reference to the %pipe's read end file handle. Care
* should be taken to not duplicate the returned object if ownership
* shall remain to the %pipe.
*
* Duplicating the returned object invalidates its corresponding file
* handle in the %pipe.
*
* \return A reference to the %pipe's read end file handle.
*/
file_handle &rend()
{
return read_end_;
}
/**
* Returns the %pipe's write end file handle.
*
* Obtains a reference to the %pipe's write end file handle. Care
* should be taken to not duplicate the returned object if ownership
* shall remain to the %pipe.
*
* Duplicating the returned object invalidates its corresponding file
* handle in the %pipe.
*
* \return A reference to the %pipe's write end file handle.
*/
file_handle &wend()
{
return write_end_;
}
private:
/**
* The %pipe's read end file handle.
*/
file_handle read_end_;
/**
* The %pipe's write end file handle.
*/
file_handle write_end_;
};
}
}
}
#endif

495
boost/process/detail/posix_ops.hpp

@ -1,495 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/detail/posix_ops.hpp
*
* Provides some convenience functions to start processes under POSIX
* operating systems.
*/
#ifndef BOOST_PROCESS_DETAIL_POSIX_OPS_HPP
#define BOOST_PROCESS_DETAIL_POSIX_OPS_HPP
#include <boost/process/environment.hpp>
#include <boost/process/detail/file_handle.hpp>
#include <boost/process/detail/pipe.hpp>
#include <boost/process/detail/stream_info.hpp>
#include <boost/scoped_array.hpp>
#include <boost/assert.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <map>
#include <utility>
#include <string>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
namespace boost {
namespace process {
namespace detail {
/**
* Converts the command line to an array of C strings.
*
* Converts the command line's list of arguments to the format expected
* by the \a argv parameter in the POSIX execve() system call.
*
* This operation is only available on POSIX systems.
*
* \return The first argument of the pair is an integer that indicates
* how many strings are stored in the second argument. The
* second argument is a NULL-terminated, dynamically allocated
* array of dynamically allocated strings holding the arguments
* to the executable. The caller is responsible of freeing them.
*/
template <class Arguments>
inline std::pair<std::size_t, char**> collection_to_posix_argv(const Arguments &args)
{
std::size_t nargs = args.size();
BOOST_ASSERT(nargs > 0);
char **argv = new char*[nargs + 1];
typename Arguments::size_type i = 0;
for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it)
{
argv[i] = new char[it->size() + 1];
std::strncpy(argv[i], it->c_str(), it->size() + 1);
++i;
}
argv[nargs] = 0;
return std::pair<std::size_t, char**>(nargs, argv);
}
/**
* Converts an environment to a char** table as used by execve().
*
* Converts the environment's contents to the format used by the
* execve() system call. The returned char** array is allocated
* in dynamic memory; the caller must free it when not used any
* more. Each entry is also allocated in dynamic memory and is a
* NULL-terminated string of the form var=value; these must also be
* released by the caller.
*
* \return A dynamically allocated char** array that represents
* the environment's content. Each array entry is a
* NULL-terminated string of the form var=value.
*/
inline char **environment_to_envp(const environment &env)
{
char **envp = new char*[env.size() + 1];
environment::size_type i = 0;
for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
{
std::string s = it->first + "=" + it->second;
envp[i] = new char[s.size() + 1];
std::strncpy(envp[i], s.c_str(), s.size() + 1);
++i;
}
envp[i] = 0;
return envp;
}
/**
* Holds a mapping between native file descriptors and their corresponding
* pipes to set up communication between the parent and the %child process.
*/
typedef std::map<int, stream_info> info_map;
/**
* Helper class to configure a POSIX %child.
*
* This helper class is used to hold all the attributes that configure a
* new POSIX %child process and to centralize all the actions needed to
* make them effective.
*
* All its fields are public for simplicity. It is only intended for
* internal use and it is heavily coupled with the Context
* implementations.
*/
struct posix_setup
{
/**
* The work directory.
*
* This string specifies the directory in which the %child process
* starts execution. It cannot be empty.
*/
std::string work_directory;
/**
* The chroot directory, if any.
*
* Specifies the directory in which the %child process is chrooted
* before execution. Empty if this feature is not desired.
*/
std::string chroot;
/**
* The user credentials.
*
* UID that specifies the user credentials to use to run the %child
* process. Defaults to the current UID.
*/
uid_t uid;
/**
* The effective user credentials.
*
* EUID that specifies the effective user credentials to use to run
* the %child process. Defaults to the current EUID.
*/
uid_t euid;
/**
* The group credentials.
*
* GID that specifies the group credentials to use to run the %child
* process. Defaults to the current GID.
*/
gid_t gid;
/**
* The effective group credentials.
*
* EGID that specifies the effective group credentials to use to run
* the %child process. Defaults to the current EGID.
*/
gid_t egid;
/**
* Creates a new properties set.
*
* Creates a new object that has sensible default values for all the
* properties.
*/
posix_setup()
: uid(::getuid()),
euid(::geteuid()),
gid(::getgid()),
egid(::getegid())
{
}
/**
* Sets up the execution environment.
*
* Modifies the current execution environment (that of the %child) so
* that the properties become effective.
*
* \throw boost::system::system_error If any error ocurred during
* environment configuration. The child process should abort
* execution if this happens because its start conditions
* cannot be met.
*/
void operator()() const
{
if (!chroot.empty() && ::chroot(chroot.c_str()) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chroot(2) failed"));
if (gid != ::getgid() && ::setgid(gid) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setgid(2) failed"));
if (egid != ::getegid() && ::setegid(egid) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setegid(2) failed"));
if (uid != ::getuid() && ::setuid(uid) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setuid(2) failed"));
if (euid != ::geteuid() && ::seteuid(euid) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: seteuid(2) failed"));
BOOST_ASSERT(!work_directory.empty());
if (::chdir(work_directory.c_str()) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chdir(2) failed"));
}
};
/**
* Configures child process' input streams.
*
* Sets up the current process' input streams to behave according to the
* information in the \a info map. \a closeflags is modified to reflect
* those descriptors that should not be closed because they where modified
* by the function.
*
* Modifies the current execution environment, so this should only be run
* on the child process after the fork(2) has happened.
*
* \throw boost::system::system_error If any error occurs during the
* configuration.
*/
inline void setup_input(info_map &info, bool *closeflags, int maxdescs)
{
for (info_map::iterator it = info.begin(); it != info.end(); ++it)
{
int d = it->first;
stream_info &si = it->second;
BOOST_ASSERT(d < maxdescs);
closeflags[d] = false;
switch (si.type_)
{
case stream_info::use_file:
{
int fd = ::open(si.file_.c_str(), O_RDONLY);
if (fd == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_input: open(2) of " + si.file_ + " failed"));
if (fd != d)
{
file_handle h(fd);
h.posix_remap(d);
h.release();
}
break;
}
case stream_info::use_handle:
{
if (si.handle_.get() != d)
si.handle_.posix_remap(d);
break;
}
case stream_info::use_pipe:
{
si.pipe_->wend().close();
if (d != si.pipe_->rend().get())
si.pipe_->rend().posix_remap(d);
break;
}
default:
{
BOOST_ASSERT(si.type_ == stream_info::inherit);
break;
}
}
}
}
/**
* Configures child process' output streams.
*
* Sets up the current process' output streams to behave according to the
* information in the \a info map. \a closeflags is modified to reflect
* those descriptors that should not be closed because they where
* modified by the function.
*
* Modifies the current execution environment, so this should only be run
* on the child process after the fork(2) has happened.
*
* \throw boost::system::system_error If any error occurs during the
* configuration.
*/
inline void setup_output(info_map &info, bool *closeflags, int maxdescs)
{
for (info_map::iterator it = info.begin(); it != info.end(); ++it)
{
int d = it->first;
stream_info &si = it->second;
BOOST_ASSERT(d < maxdescs);
closeflags[d] = false;
switch (si.type_)
{
case stream_info::redirect:
{
break;
}
case stream_info::use_file:
{
int fd = ::open(si.file_.c_str(), O_WRONLY);
if (fd == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_output: open(2) of " + si.file_ + " failed"));
if (fd != d)
{
file_handle h(fd);
h.posix_remap(d);
h.release();
}
break;
}
case stream_info::use_handle:
{
if (si.handle_.get() != d)
si.handle_.posix_remap(d);
break;
}
case stream_info::use_pipe:
{
si.pipe_->rend().close();
if (d != si.pipe_->wend().get())
si.pipe_->wend().posix_remap(d);
break;
}
default:
{
BOOST_ASSERT(si.type_ == stream_info::inherit);
break;
}
}
}
for (info_map::const_iterator it = info.begin(); it != info.end(); ++it)
{
int d = it->first;
const stream_info &si = it->second;
if (si.type_ == stream_info::redirect)
file_handle::posix_dup(si.desc_to_, d).release();
}
}
/**
* Starts a new child process in a POSIX operating system.
*
* This helper functions is provided to simplify the Context's task when
* it comes to starting up a new process in a POSIX operating system.
* The function hides all the details of the fork/exec pair of calls as
* well as all the setup of communication pipes and execution environment.
*
* \param exe The executable to spawn the child process.
* \param args The arguments for the executable.
* \param env The environment variables that the new child process
* receives.
* \param infoin A map describing all input file descriptors to be
* redirected.
* \param infoout A map describing all output file descriptors to be
* redirected.
* \param setup A helper object used to configure the child's execution
* environment.
* \return The new process' PID. The caller is responsible of creating
* an appropriate Child representation for it.
*/
template <class Executable, class Arguments>
inline pid_t posix_start(const Executable &exe, const Arguments &args, const environment &env, info_map &infoin, info_map &infoout, const posix_setup &setup)
{
pid_t pid = ::fork();
if (pid == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: fork(2) failed"));
else if (pid == 0)
{
#if defined(F_MAXFD)
int maxdescs = ::fcntl(-1, F_MAXFD, 0);
if (maxdescs == -1)
maxdescs = ::sysconf(_SC_OPEN_MAX);
#else
int maxdescs = ::sysconf(_SC_OPEN_MAX);
#endif
if (maxdescs == -1)
maxdescs = 1024;
try
{
boost::scoped_array<bool> closeflags(new bool[maxdescs]);
for (int i = 0; i < maxdescs; ++i)
closeflags[i] = true;
setup_input(infoin, closeflags.get(), maxdescs);
setup_output(infoout, closeflags.get(), maxdescs);
for (int i = 0; i < maxdescs; ++i)
{
if (closeflags[i])
::close(i);
}
setup();
}
catch (const boost::system::system_error &e)
{
::write(STDERR_FILENO, e.what(), std::strlen(e.what()));
::write(STDERR_FILENO, "\n", 1);
std::exit(EXIT_FAILURE);
}
std::pair<std::size_t, char**> argcv = collection_to_posix_argv(args);
char **envp = environment_to_envp(env);
::execve(exe.c_str(), argcv.second, envp);
boost::system::system_error e(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: execve(2) failed");
for (std::size_t i = 0; i < argcv.first; ++i)
delete[] argcv.second[i];
delete[] argcv.second;
for (std::size_t i = 0; i < env.size(); ++i)
delete[] envp[i];
delete[] envp;
::write(STDERR_FILENO, e.what(), std::strlen(e.what()));
::write(STDERR_FILENO, "\n", 1);
std::exit(EXIT_FAILURE);
}
BOOST_ASSERT(pid > 0);
for (info_map::iterator it = infoin.begin(); it != infoin.end(); ++it)
{
stream_info &si = it->second;
if (si.type_ == stream_info::use_pipe)
si.pipe_->rend().close();
}
for (info_map::iterator it = infoout.begin(); it != infoout.end(); ++it)
{
stream_info &si = it->second;
if (si.type_ == stream_info::use_pipe)
si.pipe_->wend().close();
}
return pid;
}
/**
* Locates a communication pipe and returns one of its endpoints.
*
* Given a \a info map, and a file descriptor \a desc, searches for its
* communicataion pipe in the map and returns one of its endpoints as
* indicated by the \a out flag. This is intended to be used by a
* parent process after a fork(2) call.
*
* \pre If the info map contains the given descriptor, it is configured
* to use a pipe.
* \post The info map does not contain the given descriptor.
* \return If the file descriptor is found in the map, returns the pipe's
* read end if out is true; otherwise its write end. If the
* descriptor is not found returns an invalid file handle.
*/
inline file_handle posix_info_locate_pipe(info_map &info, int desc, bool out)
{
file_handle fh;
info_map::iterator it = info.find(desc);
if (it != info.end())
{
stream_info &si = it->second;
if (si.type_ == stream_info::use_pipe)
{
fh = out ? si.pipe_->rend().release() : si.pipe_->wend().release();
BOOST_ASSERT(fh.valid());
}
info.erase(it);
}
return fh;
}
}
}
}
#endif

176
boost/process/detail/stream_info.hpp

@ -1,176 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/detail/stream_info.hpp
*
* Provides the definition of the stream_info structure.
*/
#ifndef BOOST_PROCESS_DETAIL_STREAM_INFO_HPP
#define BOOST_PROCESS_DETAIL_STREAM_INFO_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <unistd.h>
#elif defined(BOOST_WINDOWS_API)
#else
# error "Unsupported platform."
#endif
#include <boost/process/stream_behavior.hpp>
#include <boost/process/detail/file_handle.hpp>
#include <boost/process/detail/pipe.hpp>
#include <boost/optional.hpp>
#include <boost/assert.hpp>
#include <string>
namespace boost {
namespace process {
namespace detail {
/**
* Configuration data for a file descriptor.
*
* This convenience structure provides a compact way to pass information
* around on how to configure a file descriptor. It is a lower-level
* representation of stream_behavior, as it can hold the same information
* but in a way that can be used by the underlying operating system.
*/
struct stream_info
{
/**
* Supported stream types.
*/
enum type
{
/**
* Matches stream_behavior::close.
*/
close,
/**
* Matches stream_behavior::inherit.
*/
inherit,
/**
* Matches stream_behavior::redirect_to_stdout and
* stream_behavior::posix_redirect.
*/
redirect,
/**
* Matches stream_behavior::silence.
*/
use_file,
/**
* TODO: Matches nothing yet ...
*/
use_handle,
/**
* Matches stream_behavior::capture.
*/
use_pipe
};
/**
* Stream type.
*/
type type_;
/**
* Descriptor to use when stream type is set to \a redirect.
*/
int desc_to_;
/**
* File to use when stream type is set to \a use_file.
*/
std::string file_;
/**
* Handle to use when stream type is set to \a use_handle.
*/
file_handle handle_;
/**
* Pipe to use when stream type is set to \a use_pipe.
*/
boost::optional<pipe> pipe_;
/**
* Constructs a new stream_info object.
*/
stream_info(const stream_behavior &sb, bool out)
{
switch (sb.type_)
{
case stream_behavior::close:
{
type_ = close;
break;
}
case stream_behavior::inherit:
{
type_ = inherit;
break;
}
case stream_behavior::redirect_to_stdout:
{
type_ = redirect;
#if defined(BOOST_POSIX_API)
desc_to_ = STDOUT_FILENO;
#elif defined(BOOST_WINDOWS_API)
desc_to_ = 1;
#endif
break;
}
#if defined(BOOST_POSIX_API)
case stream_behavior::posix_redirect:
{
type_ = redirect;
desc_to_ = sb.desc_to_;
break;
}
#endif
case stream_behavior::silence:
{
type_ = use_file;
#if defined(BOOST_POSIX_API)
file_ = out ? "/dev/null" : "/dev/zero";
#elif defined(BOOST_WINDOWS_API)
file_ = "NUL";
#endif
break;
}
case stream_behavior::capture:
{
type_ = use_pipe;
pipe_ = pipe();
break;
}
default:
{
BOOST_ASSERT(false);
}
}
}
};
}
}
}
#endif

231
boost/process/detail/systembuf.hpp

@ -1,231 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/detail/systembuf.hpp
*
* Includes the declaration of the systembuf class. This file is for
* internal usage only and must not be included by the library user.
*/
#ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
#define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <sys/types.h>
# include <unistd.h>
#elif defined(BOOST_WINDOWS_API)
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/noncopyable.hpp>
#include <boost/scoped_array.hpp>
#include <boost/assert.hpp>
#include <streambuf>
#include <cstddef>
namespace boost {
namespace process {
class postream;
namespace detail {
/**
* std::streambuf implementation for system file handles.
*
* systembuf provides a std::streambuf implementation for system file
* handles. Contrarywise to file_handle, this class does \b not take
* ownership of the native file handle; this should be taken care of
* somewhere else.
*
* This class follows the expected semantics of a std::streambuf object.
* However, it is not copyable to avoid introducing inconsistences with
* the on-disk file and the in-memory buffers.
*/
class systembuf : public std::streambuf, public boost::noncopyable
{
friend class ::boost::process::postream;
public:
#if defined(BOOST_PROCESS_DOXYGEN)
/**
* Opaque name for the native handle type.
*/
typedef NativeHandleType handle_type;
#elif defined(BOOST_POSIX_API)
typedef int handle_type;
#elif defined(BOOST_WINDOWS_API)
typedef HANDLE handle_type;
#endif
/**
* Constructs a new systembuf for the given file handle.
*
* This constructor creates a new systembuf object that reads or
* writes data from/to the \a h native file handle. This handle
* is \b not owned by the created systembuf object; the code
* should take care of it externally.
*
* This class buffers input and output; the buffer size may be
* tuned through the \a bufsize parameter, which defaults to 8192
* bytes.
*
* \see pistream and postream
*/
explicit systembuf(handle_type h, std::size_t bufsize = 8192)
: handle_(h),
bufsize_(bufsize),
read_buf_(new char[bufsize]),
write_buf_(new char[bufsize])
{
#if defined(BOOST_POSIX_API)
BOOST_ASSERT(handle_ >= 0);
#elif defined(BOOST_WINDOWS_API)
BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE);
#endif
BOOST_ASSERT(bufsize_ > 0);
setp(write_buf_.get(), write_buf_.get() + bufsize_);
}
protected:
/**
* Reads new data from the native file handle.
*
* This operation is called by input methods when there is no more
* data in the input buffer. The function fills the buffer with new
* data, if available.
*
* \pre All input positions are exhausted (gptr() >= egptr()).
* \post The input buffer has new data, if available.
* \returns traits_type::eof() if a read error occurrs or there are
* no more data to be read. Otherwise returns
* traits_type::to_int_type(*gptr()).
*/
virtual int_type underflow()
{
BOOST_ASSERT(gptr() >= egptr());
bool ok;
#if defined(BOOST_POSIX_API)
ssize_t cnt = ::read(handle_, read_buf_.get(), bufsize_);
ok = (cnt != -1 && cnt != 0);
#elif defined(BOOST_WINDOWS_API)
DWORD cnt;
BOOL res = ::ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL);
ok = (res && cnt > 0);
#endif
if (!ok)
return traits_type::eof();
else
{
setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt);
return traits_type::to_int_type(*gptr());
}
}
/**
* Makes room in the write buffer for additional data.
*
* This operation is called by output methods when there is no more
* space in the output buffer to hold a new element. The function
* first flushes the buffer's contents to disk and then clears it to
* leave room for more characters. The given \a c character is
* stored at the beginning of the new space.
*
* \pre All output positions are exhausted (pptr() >= epptr()).
* \post The output buffer has more space if no errors occurred
* during the write to disk.
* \post *(pptr() - 1) is \a c.
* \returns traits_type::eof() if a write error occurrs. Otherwise
* returns traits_type::not_eof(c).
*/
virtual int_type overflow(int c)
{
BOOST_ASSERT(pptr() >= epptr());
if (sync() == -1)
return traits_type::eof();
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
traits_type::assign(*pptr(), c);
pbump(1);
}
return traits_type::not_eof(c);
}
/**
* Flushes the output buffer to disk.
*
* Synchronizes the systembuf buffers with the contents of the file
* associated to this object through the native file handle. The
* output buffer is flushed to disk and cleared to leave new room
* for more data.
*
* \returns 0 on success, -1 if an error occurred.
*/
virtual int sync()
{
#if defined(BOOST_POSIX_API)
ssize_t cnt = pptr() - pbase();
#elif defined(BOOST_WINDOWS_API)
long cnt = pptr() - pbase();
#endif
bool ok;
#if defined(BOOST_POSIX_API)
ok = ::write(handle_, pbase(), cnt) == cnt;
#elif defined(BOOST_WINDOWS_API)
DWORD rcnt;
BOOL res = ::WriteFile(handle_, pbase(), cnt, &rcnt, NULL);
ok = (res && static_cast<long>(rcnt) == cnt);
#endif
if (ok)
pbump(-cnt);
return ok ? 0 : -1;
}
private:
/**
* Native file handle used by the systembuf object.
*/
handle_type handle_;
/**
* Internal buffer size used during read and write operations.
*/
std::size_t bufsize_;
/**
* Internal buffer used during read operations.
*/
boost::scoped_array<char> read_buf_;
/**
* Internal buffer used during write operations.
*/
boost::scoped_array<char> write_buf_;
};
}
}
}
#endif

355
boost/process/detail/win32_ops.hpp

@ -1,355 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/detail/win32_ops.hpp
*
* Provides some convenience functions to start processes under
* Windows-compatible operating systems.
*/
#ifndef BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
#define BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
#include <boost/process/environment.hpp>
#include <boost/process/detail/file_handle.hpp>
#include <boost/process/detail/pipe.hpp>
#include <boost/process/detail/stream_info.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_array.hpp>
#include <boost/scoped_array.hpp>
#include <boost/assert.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <vector>
#include <string>
#include <cstddef>
#include <string.h>
#include <windows.h>
namespace boost {
namespace process {
namespace detail {
/**
* Converts the command line to a plain string. Converts the command line's
* list of arguments to the format expected by the \a lpCommandLine parameter
* in the CreateProcess() system call.
*
* This operation is only available on Windows systems.
*
* \return A dynamically allocated string holding the command line
* to be passed to the executable. It is returned in a
* shared_array object to ensure its release at some point.
*/
template <class Arguments>
inline boost::shared_array<char> collection_to_win32_cmdline(const Arguments &args)
{
typedef std::vector<std::string> arguments_t;
arguments_t args2;
typename Arguments::size_type i = 0;
std::size_t size = 0;
for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it)
{
std::string arg = *it;
std::string::size_type pos = 0;
while ( (pos = arg.find('"', pos)) != std::string::npos)
{
arg.replace(pos, 1, "\\\"");
pos += 2;
}
if (arg.find(' ') != std::string::npos)
arg = '\"' + arg + '\"';
if (i++ != args.size() - 1)
arg += ' ';
args2.push_back(arg);
size += arg.size() + 1;
}
boost::shared_array<char> cmdline(new char[size]);
cmdline.get()[0] = '\0';
for (arguments_t::size_type i = 0; i < args.size(); ++i)
#if defined(__CYGWIN__)
::strncat(cmdline.get(), args2[i].c_str(), args2[i].size());
#else
::strcat_s(cmdline.get(), size, args2[i].c_str());
#endif
return cmdline;
}
/**
* Converts an environment to a string used by CreateProcess().
*
* Converts the environment's contents to the format used by the
* CreateProcess() system call. The returned char* string is
* allocated in dynamic memory; the caller must free it when not
* used any more. This is enforced by the use of a shared pointer.
*
* \return A dynamically allocated char* string that represents
* the environment's content. This string is of the form
* var1=value1\\0var2=value2\\0\\0.
*/
inline boost::shared_array<char> environment_to_win32_strings(const environment &env)
{
boost::shared_array<char> envp;
if (env.empty())
{
envp.reset(new char[2]);
::ZeroMemory(envp.get(), 2);
}
else
{
std::string s;
for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
{
s += it->first + "=" + it->second;
s.push_back(0);
}
envp.reset(new char[s.size() + 1]);
#if defined(__CYGWIN__)
::memcpy(envp.get(), s.c_str(), s.size() + 1);
#else
::memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1);
#endif
}
return envp;
}
/**
* Helper class to configure a Win32 %child.
*
* This helper class is used to hold all the attributes that configure a
* new Win32 %child process.
*
* All its fields are public for simplicity. It is only intended for
* internal use and it is heavily coupled with the Context
* implementations.
*/
struct win32_setup
{
/**
* The work directory.
*
* This string specifies the directory in which the %child process
* starts execution. It cannot be empty.
*/
std::string work_directory;
/**
* The process startup properties.
*
* This Win32-specific object holds a list of properties that describe
* how the new process should be started. The \a STARTF_USESTDHANDLES
* flag should not be set in it because it is automatically configured
* by win32_start().
*/
STARTUPINFOA *startupinfo;
};
/**
* Starts a new child process in a Win32 operating system.
*
* This helper functions is provided to simplify the Context's task when
* it comes to starting up a new process in a Win32 operating system.
*
* \param exe The executable to spawn the child process.
* \param args The arguments for the executable.
* \param env The environment variables that the new child process
* receives.
* \param infoin Information that describes stdin's behavior.
* \param infoout Information that describes stdout's behavior.
* \param infoerr Information that describes stderr's behavior.
* \param setup A helper object holding extra child information.
* \return The new process' information as returned by the CreateProcess()
* system call. The caller is responsible of creating an
* appropriate Child representation for it.
* \pre \a setup.startupinfo_ cannot have the \a STARTF_USESTDHANDLES set
* in the \a dwFlags field.
*/
template <class Executable, class Arguments>
inline PROCESS_INFORMATION win32_start(const Executable &exe, const Arguments &args, const environment &env, stream_info &infoin, stream_info &infoout, stream_info &infoerr, const win32_setup &setup)
{
file_handle chin, chout, cherr;
BOOST_ASSERT(setup.startupinfo->cb >= sizeof(STARTUPINFOA));
BOOST_ASSERT(!(setup.startupinfo->dwFlags & STARTF_USESTDHANDLES));
boost::scoped_ptr<STARTUPINFOA> si(new STARTUPINFOA);
::CopyMemory(si.get(), setup.startupinfo, sizeof(*setup.startupinfo));
si->dwFlags |= STARTF_USESTDHANDLES;
switch (infoin.type_)
{
case stream_info::close:
{
break;
}
case stream_info::inherit:
{
chin = file_handle::win32_std(STD_INPUT_HANDLE, true);
break;
}
case stream_info::use_file:
{
HANDLE h = ::CreateFileA(infoin.file_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
chin = file_handle(h);
break;
}
case stream_info::use_handle:
{
chin = infoin.handle_;
chin.win32_set_inheritable(true);
break;
}
case stream_info::use_pipe:
{
infoin.pipe_->rend().win32_set_inheritable(true);
chin = infoin.pipe_->rend();
break;
}
default:
{
BOOST_ASSERT(false);
break;
}
}
si->hStdInput = chin.valid() ? chin.get() : INVALID_HANDLE_VALUE;
switch (infoout.type_)
{
case stream_info::close:
{
break;
}
case stream_info::inherit:
{
chout = file_handle::win32_std(STD_OUTPUT_HANDLE, true);
break;
}
case stream_info::use_file:
{
HANDLE h = ::CreateFileA(infoout.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
chout = file_handle(h);
break;
}
case stream_info::use_handle:
{
chout = infoout.handle_;
chout.win32_set_inheritable(true);
break;
}
case stream_info::use_pipe:
{
infoout.pipe_->wend().win32_set_inheritable(true);
chout = infoout.pipe_->wend();
break;
}
default:
{
BOOST_ASSERT(false);
break;
}
}
si->hStdOutput = chout.valid() ? chout.get() : INVALID_HANDLE_VALUE;
switch (infoerr.type_)
{
case stream_info::close:
{
break;
}
case stream_info::inherit:
{
cherr = file_handle::win32_std(STD_ERROR_HANDLE, true);
break;
}
case stream_info::redirect:
{
BOOST_ASSERT(infoerr.desc_to_ == 1);
BOOST_ASSERT(chout.valid());
cherr = file_handle::win32_dup(chout.get(), true);
break;
}
case stream_info::use_file:
{
HANDLE h = ::CreateFileA(infoerr.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
cherr = file_handle(h);
break;
}
case stream_info::use_handle:
{
cherr = infoerr.handle_;
cherr.win32_set_inheritable(true);
break;
}
case stream_info::use_pipe:
{
infoerr.pipe_->wend().win32_set_inheritable(true);
cherr = infoerr.pipe_->wend();
break;
}
default:
{
BOOST_ASSERT(false);
break;
}
}
si->hStdError = cherr.valid() ? cherr.get() : INVALID_HANDLE_VALUE;
PROCESS_INFORMATION pi;
::ZeroMemory(&pi, sizeof(pi));
boost::shared_array<char> cmdline = collection_to_win32_cmdline(args);
boost::scoped_array<char> executable(new char[exe.size() + 1]);
#if defined(__CYGWIN__)
::strcpy(executable.get(), exe.c_str());
#else
::strcpy_s(executable.get(), exe.size() + 1, exe.c_str());
#endif
boost::scoped_array<char> workdir(new char[setup.work_directory.size() + 1]);
#if defined(__CYGWIN__)
::strcpy(workdir.get(), setup.work_directory.c_str());
#else
::strcpy_s(workdir.get(), setup.work_directory.size() + 1, setup.work_directory.c_str());
#endif
boost::shared_array<char> envstrs = environment_to_win32_strings(env);
if (!::CreateProcessA(executable.get()[0] ? executable.get() : NULL, cmdline.get(), NULL, NULL, TRUE, CREATE_NO_WINDOW, envstrs.get(), workdir.get(), si.get(), &pi))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateProcess failed"));
return pi;
}
}
}
}
#endif

50
boost/process/environment.hpp

@ -1,50 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/environment.hpp
*
* Includes the declaration of the environment class.
*/
#ifndef BOOST_PROCESS_ENVIRONMENT_HPP
#define BOOST_PROCESS_ENVIRONMENT_HPP
#include <string>
#include <map>
namespace boost {
namespace process {
/**
* Representation of a process' environment variables.
*
* The environment is a map that stablishes an unidirectional
* association between variable names and their values and is
* represented by a string to string map.
*
* Variables may be defined to the empty string. Be aware that doing so
* is not portable: POSIX systems will treat such variables as being
* defined to the empty value, but Windows systems are not able to
* distinguish them from undefined variables.
*
* Neither POSIX nor Windows systems support a variable with no name.
*
* It is worthy to note that the environment is sorted alphabetically.
* This is provided for-free by the map container used to implement this
* type, and this behavior is required by Windows systems.
*/
typedef std::map<std::string, std::string> environment;
}
}
#endif

583
boost/process/operations.hpp

@ -1,583 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/operations.hpp
*
* Provides miscellaneous free functions.
*/
#ifndef BOOST_PROCESS_OPERATIONS_HPP
#define BOOST_PROCESS_OPERATIONS_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <boost/process/detail/posix_ops.hpp>
# include <stdlib.h>
# include <unistd.h>
# if defined(__CYGWIN__)
# include <boost/scoped_array.hpp>
# include <sys/cygwin.h>
# endif
#elif defined(BOOST_WINDOWS_API)
# include <boost/process/detail/win32_ops.hpp>
# include <boost/algorithm/string/predicate.hpp>
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/process/child.hpp>
#include <boost/process/stream_behavior.hpp>
#include <boost/process/status.hpp>
#include <boost/process/detail/file_handle.hpp>
#include <boost/process/detail/pipe.hpp>
#include <boost/process/detail/stream_info.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <boost/scoped_array.hpp>
#include <boost/assert.hpp>
#include <string>
#include <vector>
#include <stdexcept>
#include <cstddef>
namespace boost {
namespace process {
/**
* Locates the executable program \a file in all the directory components
* specified in \a path. If \a path is empty, the value of the PATH
* environment variable is used.
*
* The path variable is interpreted following the same conventions used
* to parse the PATH environment variable in the underlying platform.
*
* \throw boost::filesystem::filesystem_error If the file cannot be found
* in the path.
*/
inline std::string find_executable_in_path(const std::string &file, std::string path = "")
{
#if defined(BOOST_POSIX_API)
BOOST_ASSERT(file.find('/') == std::string::npos);
#elif defined(BOOST_WINDOWS_API)
BOOST_ASSERT(file.find_first_of("\\/") == std::string::npos);
#endif
std::string result;
#if defined(BOOST_POSIX_API)
if (path.empty())
{
const char *envpath = ::getenv("PATH");
// if (!envpath)
// boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: retrieving PATH failed", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory)));
path = envpath;
}
BOOST_ASSERT(!path.empty());
#if defined(__CYGWIN__)
if (!::cygwin_posix_path_list_p(path.c_str()))
{
int size = ::cygwin_win32_to_posix_path_list_buf_size(path.c_str());
boost::scoped_array<char> cygpath(new char[size]);
::cygwin_win32_to_posix_path_list(path.c_str(), cygpath.get());
path = cygpath.get();
}
#endif
std::string::size_type pos1 = 0, pos2;
do
{
pos2 = path.find(':', pos1);
std::string dir = (pos2 != std::string::npos) ? path.substr(pos1, pos2 - pos1) : path.substr(pos1);
std::string f = dir + (boost::algorithm::ends_with(dir, "/") ? "" : "/") + file;
if (!::access(f.c_str(), X_OK))
result = f;
pos1 = pos2 + 1;
} while (pos2 != std::string::npos && result.empty());
#elif defined(BOOST_WINDOWS_API)
const char *exts[] = { "", ".exe", ".com", ".bat", NULL };
const char **ext = exts;
while (*ext)
{
char buf[MAX_PATH];
char *dummy;
DWORD size = ::SearchPathA(path.empty() ? NULL : path.c_str(), file.c_str(), *ext, MAX_PATH, buf, &dummy);
BOOST_ASSERT(size < MAX_PATH);
if (size > 0)
{
result = buf;
break;
}
++ext;
}
#endif
// if (result.empty())
// boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: file not found", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory)));
return result;
}
/**
* Extracts the program name from a given executable.
*
* \return The program name. On Windows the program name
* is returned without a file extension.
*/
inline std::string executable_to_progname(const std::string &exe)
{
std::string::size_type begin = 0;
std::string::size_type end = std::string::npos;
#if defined(BOOST_POSIX_API)
std::string::size_type slash = exe.rfind('/');
#elif defined(BOOST_WINDOWS_API)
std::string::size_type slash = exe.find_last_of("/\\");
#endif
if (slash != std::string::npos)
begin = slash + 1;
#if defined(BOOST_WINDOWS_API)
if (exe.size() > 4 &&
(boost::algorithm::iends_with(exe, ".exe") || boost::algorithm::iends_with(exe, ".com") || boost::algorithm::iends_with(exe, ".bat")))
end = exe.size() - 4;
#endif
return exe.substr(begin, end - begin);
}
/**
* Starts a new child process.
*
* Launches a new process based on the binary image specified by the
* executable, the set of arguments to be passed to it and several
* parameters that describe the execution context.
*
* \remark Blocking remarks: This function may block if the device
* holding the executable blocks when loading the image. This might
* happen if, e.g., the binary is being loaded from a network share.
*
* \return A handle to the new child process.
*/
template <class Executable, class Arguments, class Context>
inline child launch(const Executable &exe, const Arguments &args, const Context &ctx)
{
detail::file_handle fhstdin, fhstdout, fhstderr;
BOOST_ASSERT(!args.empty());
BOOST_ASSERT(!ctx.work_directory.empty());
#if defined(BOOST_POSIX_API)
detail::info_map infoin, infoout;
if (ctx.stdin_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false);
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si));
}
if (ctx.stdout_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true);
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si));
}
if (ctx.stderr_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
}
detail::posix_setup s;
s.work_directory = ctx.work_directory;
child::id_type pid = detail::posix_start(exe, args, ctx.environment, infoin, infoout, s);
if (ctx.stdin_behavior.get_type() == stream_behavior::capture)
{
fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false);
BOOST_ASSERT(fhstdin.valid());
}
if (ctx.stdout_behavior.get_type() == stream_behavior::capture)
{
fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true);
BOOST_ASSERT(fhstdout.valid());
}
if (ctx.stderr_behavior.get_type() == stream_behavior::capture)
{
fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true);
BOOST_ASSERT(fhstderr.valid());
}
return child(pid, fhstdin, fhstdout, fhstderr);
#elif defined(BOOST_WINDOWS_API)
detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false);
if (behin.type_ == detail::stream_info::use_pipe)
fhstdin = behin.pipe_->wend();
detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true);
if (behout.type_ == detail::stream_info::use_pipe)
fhstdout = behout.pipe_->rend();
detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true);
if (beherr.type_ == detail::stream_info::use_pipe)
fhstderr = beherr.pipe_->rend();
STARTUPINFOA si;
::ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
detail::win32_setup s;
s.work_directory = ctx.work_directory;
s.startupinfo = &si;
PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s);
if (!::CloseHandle(pi.hThread))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch: CloseHandle failed"));
return child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, detail::file_handle(pi.hProcess));
#endif
}
/**
* Launches a shell-based command.
*
* Executes the given command through the default system shell. The
* command is subject to pattern expansion, redirection and pipelining.
* The shell is launched as described by the parameters in the execution
* context.
*
* This function behaves similarly to the system(3) system call. In a
* POSIX system, the command is fed to /bin/sh whereas under a Windows
* system, it is fed to cmd.exe. It is difficult to write portable
* commands as the first parameter, but this function comes in handy in
* multiple situations.
*/
template <class Context>
inline child launch_shell(const std::string &command, const Context &ctx)
{
std::string exe;
std::vector<std::string> args;
#if defined(BOOST_POSIX_API)
exe = "/bin/sh";
args.push_back("sh");
args.push_back("-c");
args.push_back(command);
#elif defined(BOOST_WINDOWS_API)
char sysdir[MAX_PATH];
UINT size = ::GetSystemDirectoryA(sysdir, sizeof(sysdir));
if (!size)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_shell: GetWindowsDirectory failed"));
BOOST_ASSERT(size < MAX_PATH);
exe = std::string(sysdir) + (sysdir[size - 1] != '\\' ? "\\cmd.exe" : "cmd.exe");
args.push_back("cmd");
args.push_back("/c");
args.push_back(command);
#endif
return launch(exe, args, ctx);
}
/**
* Launches a pipelined set of child processes.
*
* Given a collection of pipeline_entry objects describing how to launch
* a set of child processes, spawns them all and connects their inputs and
* outputs in a way that permits pipelined communication.
*
* \pre Let 1..N be the processes in the collection: the input behavior of
* the 2..N processes must be set to close_stream().
* \pre Let 1..N be the processes in the collection: the output behavior of
* the 1..N-1 processes must be set to close_stream().
* \remark Blocking remarks: This function may block if the device holding
* the executable of one of the entries blocks when loading the
* image. This might happen if, e.g., the binary is being loaded
* from a network share.
* \return A set of Child objects that represent all the processes spawned
* by this call. You should use wait_children() to wait for their
* termination.
*/
template <class Entries>
inline children launch_pipeline(const Entries &entries)
{
BOOST_ASSERT(entries.size() >= 2);
children cs;
detail::file_handle fhinvalid;
boost::scoped_array<detail::pipe> pipes(new detail::pipe[entries.size() - 1]);
#if defined(BOOST_POSIX_API)
{
typename Entries::size_type i = 0;
const typename Entries::value_type::context_type &ctx = entries[i].context;
detail::info_map infoin, infoout;
if (ctx.stdin_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false);
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si));
}
BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close);
detail::stream_info si2(close_stream(), true);
si2.type_ = detail::stream_info::use_handle;
si2.handle_ = pipes[i].wend().release();
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2));
if (ctx.stderr_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
}
detail::posix_setup s;
s.work_directory = ctx.work_directory;
pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s);
detail::file_handle fhstdin;
if (ctx.stdin_behavior.get_type() == stream_behavior::capture)
{
fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false);
BOOST_ASSERT(fhstdin.valid());
}
cs.push_back(child(pid, fhstdin, fhinvalid, fhinvalid));
}
for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i)
{
const typename Entries::value_type::context_type &ctx = entries[i].context;
detail::info_map infoin, infoout;
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
detail::stream_info si1(close_stream(), false);
si1.type_ = detail::stream_info::use_handle;
si1.handle_ = pipes[i - 1].rend().release();
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1));
BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close);
detail::stream_info si2(close_stream(), true);
si2.type_ = detail::stream_info::use_handle;
si2.handle_ = pipes[i].wend().release();
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2));
if (ctx.stderr_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
}
detail::posix_setup s;
s.work_directory = ctx.work_directory;
pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s);
cs.push_back(child(pid, fhinvalid, fhinvalid, fhinvalid));
}
{
typename Entries::size_type i = entries.size() - 1;
const typename Entries::value_type::context_type &ctx = entries[i].context;
detail::info_map infoin, infoout;
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
detail::stream_info si1(close_stream(), false);
si1.type_ = detail::stream_info::use_handle;
si1.handle_ = pipes[i - 1].rend().release();
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1));
if (ctx.stdout_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true);
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si));
}
if (ctx.stderr_behavior.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
}
detail::posix_setup s;
s.work_directory = ctx.work_directory;
pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s);
detail::file_handle fhstdout, fhstderr;
if (ctx.stdout_behavior.get_type() == stream_behavior::capture)
{
fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true);
BOOST_ASSERT(fhstdout.valid());
}
if (ctx.stderr_behavior.get_type() == stream_behavior::capture)
{
fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true);
BOOST_ASSERT(fhstderr.valid());
}
cs.push_back(child(pid, fhinvalid, fhstdout, fhstderr));
}
#elif defined(BOOST_WINDOWS_API)
STARTUPINFOA si;
detail::win32_setup s;
s.startupinfo = &si;
{
typename Entries::size_type i = 0;
const typename Entries::value_type::context_type &ctx = entries[i].context;
detail::stream_info sii = detail::stream_info(ctx.stdin_behavior, false);
detail::file_handle fhstdin;
if (sii.type_ == detail::stream_info::use_pipe)
fhstdin = sii.pipe_->wend();
BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close);
detail::stream_info sio(close_stream(), true);
sio.type_ = detail::stream_info::use_handle;
sio.handle_ = pipes[i].wend().release();
detail::stream_info sie(ctx.stderr_behavior, true);
s.work_directory = ctx.work_directory;
::ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s);
if (!::CloseHandle(pi.hThread))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed"));
cs.push_back(child(pi.dwProcessId, fhstdin, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess)));
}
for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i)
{
const typename Entries::value_type::context_type &ctx = entries[i].context;
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
detail::stream_info sii(close_stream(), false);
sii.type_ = detail::stream_info::use_handle;
sii.handle_ = pipes[i - 1].rend().release();
detail::stream_info sio(close_stream(), true);
sio.type_ = detail::stream_info::use_handle;
sio.handle_ = pipes[i].wend().release();
detail::stream_info sie(ctx.stderr_behavior, true);
s.work_directory = ctx.work_directory;
::ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s);
if (!::CloseHandle(pi.hThread))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed"));
cs.push_back(child(pi.dwProcessId, fhinvalid, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess)));
}
{
typename Entries::size_type i = entries.size() - 1;
const typename Entries::value_type::context_type &ctx = entries[i].context;
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
detail::stream_info sii(close_stream(), false);
sii.type_ = detail::stream_info::use_handle;
sii.handle_ = pipes[i - 1].rend().release();
detail::file_handle fhstdout, fhstderr;
detail::stream_info sio(ctx.stdout_behavior, true);
if (sio.type_ == detail::stream_info::use_pipe)
fhstdout = sio.pipe_->rend();
detail::stream_info sie(ctx.stderr_behavior, true);
if (sie.type_ == detail::stream_info::use_pipe)
fhstderr = sie.pipe_->rend();
s.work_directory = ctx.work_directory;
::ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s);
if (!::CloseHandle(pi.hThread))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed"));
cs.push_back(child(pi.dwProcessId, fhinvalid, fhstdout, fhstderr, detail::file_handle(pi.hProcess)));
}
#endif
return cs;
}
/**
* Waits for a collection of children to terminate.
*
* Given a collection of Child objects (such as std::vector<child> or
* the convenience children type), waits for the termination of all of
* them.
*
* \remark Blocking remarks: This call blocks if any of the children
* processes in the collection has not finalized execution and
* waits until it terminates.
*
* \return The exit status of the first process that returns an error
* code or, if all of them executed correctly, the exit status
* of the last process in the collection.
*/
template <class Children>
inline status wait_children(Children &cs)
{
BOOST_ASSERT(cs.size() >= 2);
typename Children::iterator it = cs.begin();
while (it != cs.end())
{
const status s = it->wait();
++it;
if (it == cs.end())
return s;
else if (!s.exited() || s.exit_status() != EXIT_SUCCESS)
{
while (it != cs.end())
{
it->wait();
++it;
}
return s;
}
}
BOOST_ASSERT(false);
return cs.begin()->wait();
}
}
}
#endif

116
boost/process/pistream.hpp

@ -1,116 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/pistream.hpp
*
* Includes the declaration of the pistream class.
*/
#ifndef BOOST_PROCESS_PISTREAM_HPP
#define BOOST_PROCESS_PISTREAM_HPP
#include <boost/process/detail/file_handle.hpp>
#include <boost/process/detail/systembuf.hpp>
#include <boost/noncopyable.hpp>
#include <istream>
namespace boost {
namespace process {
/**
* Child process' output stream.
*
* The pistream class represents an output communication channel with the
* child process. The child process writes data to this stream and the
* parent process can read it through the pistream object. In other
* words, from the child's point of view, the communication channel is an
* output one, but from the parent's point of view it is an input one;
* hence the confusing pistream name.
*
* pistream objects cannot be copied because they own the file handle
* they use to communicate with the child and because they buffer data
* that flows through the communication channel.
*
* A pistream object behaves as a std::istream stream in all senses.
* The class is only provided because it must provide a method to let
* the caller explicitly close the communication channel.
*
* \remark Blocking remarks: Functions that read data from this
* stream can block if the associated file handle blocks during
* the read. As this class is used to communicate with child
* processes through anonymous pipes, the most typical blocking
* condition happens when the child has no more data to send to
* the pipe's system buffer. When this happens, the buffer
* eventually empties and the system blocks until the writer
* generates some data.
*/
class pistream : public std::istream, public boost::noncopyable
{
public:
/**
* Creates a new process' output stream.
*
* Given a file handle, this constructor creates a new pistream
* object that owns the given file handle \a fh. Ownership of
* \a fh is transferred to the created pistream object.
*
* \pre \a fh is valid.
* \post \a fh is invalid.
* \post The new pistream object owns \a fh.
*/
explicit pistream(detail::file_handle &fh)
: std::istream(0),
handle_(fh),
systembuf_(handle_.get())
{
rdbuf(&systembuf_);
}
/**
* Returns the file handle managed by this stream.
*
* The file handle must not be copied. Copying invalidates
* the source file handle making the pistream unusable.
*/
detail::file_handle &handle()
{
return handle_;
}
/**
* Closes the file handle managed by this stream.
*
* Explicitly closes the file handle managed by this stream. This
* function can be used by the user to tell the child process it's
* not willing to receive more data.
*/
void close()
{
handle_.close();
}
private:
/**
* The file handle managed by this stream.
*/
detail::file_handle handle_;
/**
* The systembuf object used to manage this stream's data.
*/
detail::systembuf systembuf_;
};
}
}
#endif

178
boost/process/posix_child.hpp

@ -1,178 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/posix_child.hpp
*
* Includes the declaration of the posix_child class.
*/
#ifndef BOOST_PROCESS_POSIX_CHILD_HPP
#define BOOST_PROCESS_POSIX_CHILD_HPP
#include <boost/process/child.hpp>
#include <boost/process/pistream.hpp>
#include <boost/process/postream.hpp>
#include <boost/process/detail/pipe.hpp>
#include <boost/process/detail/posix_ops.hpp>
#include <boost/process/detail/stream_info.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/assert.hpp>
#include <map>
#include <unistd.h>
namespace boost {
namespace process {
/**
* POSIX implementation of the Child concept.
*
* The posix_child class implements the Child concept in a POSIX
* operating system.
*
* A POSIX child differs from a regular child (represented by a
* child object) in that it supports more than three communication
* channels with its parent. These channels are identified by regular
* file descriptors (integers).
*
* This class is built on top of the generic child so as to allow its
* trivial adoption. When a program is changed to use the POSIX-specific
* context (posix_context), it will most certainly need to migrate its
* use of the child class to posix_child. Doing so is only a matter of
* redefining the appropriate object and later using the required extra
* features: there should be no need to modify the existing code (e.g.
* method calls) in any other way.
*/
class posix_child : public child
{
public:
/**
* Gets a reference to the child's input stream \a desc.
*
* Returns a reference to a postream object that represents one of
* the multiple input communication channels with the child process.
* The channel is identified by \a desc as seen from the child's
* point of view. The parent can use the returned stream to send
* data to the child.
*
* Giving this function the STDIN_FILENO constant (defined in
* unistd.h) is a synonym for the get_stdin() call inherited from
* child.
*/
postream &get_input(int desc) const
{
if (desc == STDIN_FILENO)
return posix_child::get_stdin();
else
{
input_map_t::const_iterator it = input_map_.find(desc);
BOOST_ASSERT(it != input_map_.end());
return *it->second;
}
}
/**
* Gets a reference to the child's output stream \a desc.
*
* Returns a reference to a pistream object that represents one of
* the multiple output communication channels with the child process.
* The channel is identified by \a desc as seen from the child's
* point of view. The parent can use the returned stream to retrieve
* data from the child.
*
* Giving this function the STDOUT_FILENO or STDERR_FILENO constants
* (both defined in unistd.h) are synonyms for the get_stdout() and
* get_stderr() calls inherited from child, respectively.
*/
pistream &get_output(int desc) const
{
if (desc == STDOUT_FILENO)
return posix_child::get_stdout();
else if (desc == STDERR_FILENO)
return posix_child::get_stderr();
else
{
output_map_t::const_iterator it = output_map_.find(desc);
BOOST_ASSERT(it != output_map_.end());
return *it->second;
}
}
/**
* Constructs a new POSIX child object representing a just
* spawned child process.
*
* Creates a new child object that represents the just spawned process
* \a id.
*
* The \a infoin and \a infoout maps contain the pipes used to handle
* the redirections of the child process; at the moment, no other
* stream_info types are supported. If the launcher was asked to
* redirect any of the three standard flows, their pipes must be
* present in these maps.
*/
posix_child(id_type id, detail::info_map &infoin, detail::info_map &infoout)
: child(id,
detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false),
detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true),
detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true))
{
for (detail::info_map::iterator it = infoin.begin(); it != infoin.end(); ++it)
{
detail::stream_info &si = it->second;
if (si.type_ == detail::stream_info::use_pipe)
{
BOOST_ASSERT(si.pipe_->wend().valid());
boost::shared_ptr<postream> st(new postream(si.pipe_->wend()));
input_map_.insert(input_map_t::value_type(it->first, st));
}
}
for (detail::info_map::iterator it = infoout.begin(); it != infoout.end(); ++it)
{
detail::stream_info &si = it->second;
if (si.type_ == detail::stream_info::use_pipe)
{
BOOST_ASSERT(si.pipe_->rend().valid());
boost::shared_ptr<pistream> st(new pistream(si.pipe_->rend()));
output_map_.insert(output_map_t::value_type(it->first, st));
}
}
}
private:
/**
* Maps child's file descriptors to postream objects.
*/
typedef std::map<int, boost::shared_ptr<postream> > input_map_t;
/**
* Contains all relationships between child's input file
* descriptors and their corresponding postream objects.
*/
input_map_t input_map_;
/**
* Maps child's file descriptors to pistream objects.
*/
typedef std::map<int, boost::shared_ptr<pistream> > output_map_t;
/**
* Contains all relationships between child's output file
* descriptors and their corresponding pistream objects.
*/
output_map_t output_map_;
};
}
}
#endif

118
boost/process/posix_context.hpp

@ -1,118 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/posix_context.hpp
*
* Includes the declaration of the posix_context class.
*/
#ifndef BOOST_PROCESS_POSIX_CONTEXT_HPP
#define BOOST_PROCESS_POSIX_CONTEXT_HPP
#include <boost/process/context.hpp>
#include <boost/process/stream_behavior.hpp>
#include <map>
#include <string>
#include <unistd.h>
namespace boost {
namespace process {
/**
* Holds a mapping between native file descriptors and their corresponding
* pipes to set up communication between the parent and the %child process.
*/
typedef std::map<int, stream_behavior> behavior_map;
template <class Path>
class posix_basic_context : public basic_work_directory_context<Path>, public environment_context
{
public:
/**
* Constructs a new POSIX-specific context.
*
* Constructs a new context. It is configured as follows:
* * All communcation channels with the child process are closed.
* * There are no channel mergings.
* * The initial work directory of the child processes is set to the
* current working directory.
* * The environment variables table is empty.
* * The credentials are the same as those of the current process.
*/
posix_basic_context()
: uid(::getuid()),
euid(::geteuid()),
gid(::getgid()),
egid(::getegid())
{
}
/**
* List of input streams that will be redirected.
*/
behavior_map input_behavior;
/**
* List of output streams that will be redirected.
*/
behavior_map output_behavior;
/**
* The user credentials.
*
* UID that specifies the user credentials to use to run the %child
* process. Defaults to the current UID.
*/
uid_t uid;
/**
* The effective user credentials.
*
* EUID that specifies the effective user credentials to use to run
* the %child process. Defaults to the current EUID.
*/
uid_t euid;
/**
* The group credentials.
*
* GID that specifies the group credentials to use to run the %child
* process. Defaults to the current GID.
*/
gid_t gid;
/**
* The effective group credentials.
*
* EGID that specifies the effective group credentials to use to run
* the %child process. Defaults to the current EGID.
*/
gid_t egid;
/**
* The chroot directory, if any.
*
* Specifies the directory in which the %child process is chrooted
* before execution. Empty if this feature is not desired.
*/
Path chroot;
};
/**
* Default instantiation of posix_basic_context.
*/
typedef posix_basic_context<std::string> posix_context;
}
}
#endif

81
boost/process/posix_operations.hpp

@ -1,81 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/posix_operations.hpp
*
* Provides miscellaneous free functions specific to POSIX operating
* systems.
*/
#ifndef BOOST_PROCESS_POSIX_OPERATIONS_HPP
#define BOOST_PROCESS_POSIX_OPERATIONS_HPP
#include <boost/process/posix_child.hpp>
#include <boost/process/posix_context.hpp>
#include <boost/process/stream_behavior.hpp>
#include <boost/process/detail/stream_info.hpp>
#include <boost/process/detail/posix_ops.hpp>
#include <sys/types.h>
namespace boost {
namespace process {
/**
* Starts a new child process.
*
* Given an executable and the set of arguments passed to it, starts
* a new process with all the parameters configured in the context.
* The context can be reused afterwards to launch other different
* processes.
*
* \return A handle to the new child process.
*/
template <class Executable, class Arguments, class Posix_Context>
inline posix_child posix_launch(const Executable &exe, const Arguments &args, const Posix_Context &ctx)
{
detail::info_map input_info;
for (behavior_map::const_iterator it = ctx.input_behavior.begin(); it != ctx.input_behavior.end(); ++it)
{
if (it->second.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(it->second, false);
input_info.insert(detail::info_map::value_type(it->first, si));
}
}
detail::info_map output_info;
for (behavior_map::const_iterator it = ctx.output_behavior.begin(); it != ctx.output_behavior.end(); ++it)
{
if (it->second.get_type() != stream_behavior::close)
{
detail::stream_info si = detail::stream_info(it->second, true);
output_info.insert(detail::info_map::value_type(it->first, si));
}
}
detail::posix_setup s;
s.work_directory = ctx.work_directory;
s.uid = ctx.uid;
s.euid = ctx.euid;
s.gid = ctx.gid;
s.egid = ctx.egid;
s.chroot = ctx.chroot;
pid_t pid = detail::posix_start(exe, args, ctx.environment, input_info, output_info, s);
return posix_child(pid, input_info, output_info);
}
}
}
#endif

128
boost/process/posix_status.hpp

@ -1,128 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/posix_status.hpp
*
* Includes the declaration of the posix_status class.
*/
#ifndef BOOST_PROCESS_POSIX_STATUS_HPP
#define BOOST_PROCESS_POSIX_STATUS_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <sys/wait.h>
#elif defined(BOOST_WINDOWS_API)
#else
# error "Unsupported platform."
#endif
#include <boost/process/status.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace process {
/**
* Status returned by a finalized %child process on a POSIX system.
*
* This class represents the %status returned by a child process after it
* has terminated. It contains some methods not available in the status
* class that provide information only available in POSIX systems.
*/
class posix_status : public status
{
public:
/**
* Creates a posix_status object from an existing status object.
*
* Creates a new status object representing the exit status of a
* child process. The construction is done based on an existing
* status object which already contains all the available
* information: this class only provides controlled access to it.
*/
posix_status(const status &s)
: status(s)
{
}
/**
* Returns whether the process exited due to an external
* signal.
*/
bool signaled() const
{
return WIFSIGNALED(flags_);
}
/**
* If signaled, returns the terminating signal code.
*
* If the process was signaled, returns the terminating signal code.
*
* \pre signaled() is true.
*/
int term_signal() const
{
BOOST_ASSERT(signaled());
return WTERMSIG(flags_);
}
/**
* If signaled, returns whether the process dumped core.
*
* If the process was signaled, returns whether the process
* produced a core dump.
*
* \pre signaled() is true.
*/
bool dumped_core() const
{
BOOST_ASSERT(signaled());
#ifdef WCOREDUMP
return WCOREDUMP(flags_);
#else
return false;
#endif
}
/**
* Returns whether the process was stopped by an external
* signal.
*/
bool stopped() const
{
return WIFSTOPPED(flags_);
}
/**
* If stopped, returns the stop signal code.
*
* If the process was stopped, returns the stop signal code.
*
* \pre stopped() is true.
*/
int stop_signal() const
{
BOOST_ASSERT(stopped());
return WSTOPSIG(flags_);
}
};
}
}
#endif

117
boost/process/postream.hpp

@ -1,117 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/postream.hpp
*
* Includes the declaration of the postream class.
*/
#ifndef BOOST_PROCESS_POSTREAM_HPP
#define BOOST_PROCESS_POSTREAM_HPP
#include <boost/process/detail/file_handle.hpp>
#include <boost/process/detail/systembuf.hpp>
#include <boost/noncopyable.hpp>
#include <ostream>
namespace boost {
namespace process {
/**
* Child process' input stream.
*
* The postream class represents an input communication channel with the
* child process. The child process reads data from this stream and the
* parent process can write to it through the postream object. In other
* words, from the child's point of view, the communication channel is an
* input one, but from the parent's point of view it is an output one;
* hence the confusing postream name.
*
* postream objects cannot be copied because they own the file handle
* they use to communicate with the child and because they buffer data
* that flows through the communication channel.
*
* A postream object behaves as a std::ostream stream in all senses.
* The class is only provided because it must provide a method to let
* the caller explicitly close the communication channel.
*
* \remark Blocking remarks: Functions that write data to this
* stream can block if the associated file handle blocks during
* the write. As this class is used to communicate with child
* processes through anonymous pipes, the most typical blocking
* condition happens when the child is not processing the data
* in the pipe's system buffer. When this happens, the buffer
* eventually fills up and the system blocks until the reader
* consumes some data, leaving some new room.
*/
class postream : public std::ostream, public boost::noncopyable
{
public:
/**
* Creates a new process' input stream.
*
* Given a file handle, this constructor creates a new postream
* object that owns the given file handle \a fh. Ownership of
* \a fh is transferred to the created postream object.
*
* \pre \a fh is valid.
* \post \a fh is invalid.
* \post The new postream object owns \a fh.
*/
explicit postream(detail::file_handle &fh)
: std::ostream(0),
handle_(fh),
systembuf_(handle_.get())
{
rdbuf(&systembuf_);
}
/**
* Returns the file handle managed by this stream.
*
* The file handle must not be copied. Copying invalidates
* the source file handle making the postream unusable.
*/
detail::file_handle &handle()
{
return handle_;
}
/**
* Closes the file handle managed by this stream.
*
* Explicitly closes the file handle managed by this stream. This
* function can be used by the user to tell the child process there
* is no more data to send.
*/
void close()
{
systembuf_.sync();
handle_.close();
}
private:
/**
* The file handle managed by this stream.
*/
detail::file_handle handle_;
/**
* The systembuf object used to manage this stream's data.
*/
detail::systembuf systembuf_;
};
}
}
#endif

130
boost/process/process.hpp

@ -1,130 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/process.hpp
*
* Includes the declaration of the process class.
*/
#ifndef BOOST_PROCESS_PROCESS_HPP
#define BOOST_PROCESS_PROCESS_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <cerrno>
# include <signal.h>
#elif defined(BOOST_WINDOWS_API)
# include <cstdlib>
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
namespace process {
/**
* Generic implementation of the Process concept.
*
* The process class implements the Process concept in an operating system
* agnostic way.
*/
class process
{
public:
#if defined(BOOST_PROCESS_DOXYGEN)
/**
* Opaque name for the native process' identifier type.
*
* Each operating system identifies processes using a specific type.
* The \a id_type type is used to transparently refer to a process
* regardless of the operating system in which this class is used.
*
* This type is guaranteed to be an integral type on all supported
* platforms.
*/
typedef NativeProcessId id_type;
#elif defined(BOOST_POSIX_API)
typedef pid_t id_type;
#elif defined(BOOST_WINDOWS_API)
typedef DWORD id_type;
#endif
/**
* Constructs a new process object.
*
* Creates a new process object that represents a running process
* within the system.
*/
process(id_type id)
: id_(id)
{
}
/**
* Returns the process' identifier.
*/
id_type get_id() const
{
return id_;
}
/**
* Terminates the process execution.
*
* Forces the termination of the process execution. Some platforms
* allow processes to ignore some external termination notifications
* or to capture them for a proper exit cleanup. You can set the
* \a force flag to true in them to force their termination regardless
* of any exit handler.
*
* After this call, accessing this object can be dangerous because the
* process identifier may have been reused by a different process. It
* might still be valid, though, if the process has refused to die.
*
* \throw boost::system::system_error If the system call used to
* terminate the process fails.
*/
void terminate(bool force = false) const
{
#if defined(BOOST_POSIX_API)
if (::kill(id_, force ? SIGKILL : SIGTERM) == -1)
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::process::terminate: kill(2) failed"));
#elif defined(BOOST_WINDOWS_API)
HANDLE h = ::OpenProcess(PROCESS_TERMINATE, FALSE, id_);
if (h == NULL)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: OpenProcess failed"));
if (!::TerminateProcess(h, EXIT_FAILURE))
{
::CloseHandle(h);
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: TerminateProcess failed"));
}
if (!::CloseHandle(h))
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: CloseHandle failed"));
#endif
}
private:
/**
* The process' identifier.
*/
id_type id_;
};
}
}
#endif

134
boost/process/self.hpp

@ -1,134 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/self.hpp
*
* Includes the declaration of the self class.
*/
#ifndef BOOST_PROCESS_SELF_HPP
#define BOOST_PROCESS_SELF_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <unistd.h>
#elif defined(BOOST_WINDOWS_API)
# include <windows.h>
#else
# error "Unsupported platform."
#endif
#include <boost/process/process.hpp>
#include <boost/process/environment.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <boost/noncopyable.hpp>
#include <string>
#if defined(BOOST_POSIX_API)
extern "C"
{
extern char **environ;
}
#endif
namespace boost {
namespace process {
/**
* Generic implementation of the Process concept.
*
* The self singleton provides access to the current process.
*/
class self : public process, boost::noncopyable
{
public:
/**
* Returns the self instance representing the caller's process.
*/
static self &get_instance()
{
static self *instance = 0;
if (!instance)
instance = new self;
return *instance;
}
/**
* Returns the current environment.
*
* Returns the current process' environment variables. Modifying the
* returned object has no effect on the current environment.
*/
static environment get_environment()
{
environment e;
#if defined(BOOST_POSIX_API)
char **env = ::environ;
while (*env)
{
std::string s = *env;
std::string::size_type pos = s.find('=');
e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1)));
++env;
}
#elif defined(BOOST_WINDOWS_API)
#ifdef GetEnvironmentStrings
#undef GetEnvironmentStrings
#endif
char *environ = ::GetEnvironmentStrings();
if (!environ)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::self::get_environment: GetEnvironmentStrings failed"));
try
{
char *env = environ;
while (*env)
{
std::string s = env;
std::string::size_type pos = s.find('=');
e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1)));
env += s.size() + 1;
}
}
catch (...)
{
::FreeEnvironmentStringsA(environ);
throw;
}
::FreeEnvironmentStringsA(environ);
#endif
return e;
}
private:
/**
* Constructs a new self object.
*
* Creates a new self object that represents the current process.
*/
self() :
#if defined(BOOST_POSIX_API)
process(::getpid())
#elif defined(BOOST_WINDOWS_API)
process(::GetCurrentProcessId())
#endif
{
}
};
}
}
#endif

105
boost/process/status.hpp

@ -1,105 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/status.hpp
*
* Includes the declaration of the status class.
*/
#ifndef BOOST_PROCESS_STATUS_HPP
#define BOOST_PROCESS_STATUS_HPP
#include <boost/process/config.hpp>
#if defined(BOOST_POSIX_API)
# include <sys/wait.h>
#elif defined(BOOST_WINDOWS_API)
#else
# error "Unsupported platform."
#endif
#include <boost/assert.hpp>
namespace boost {
namespace process {
class child;
/**
* Status returned by a finalized %child process.
*
* This class represents the %status returned by a child process after it
* has terminated. It only provides that information available under all
* supported platforms.
*
* \see posix_status
*/
class status
{
friend class child;
public:
/**
* Returns whether the process exited gracefully or not.
*/
bool exited() const
{
#if defined(BOOST_POSIX_API)
return WIFEXITED(flags_);
#elif defined(BOOST_WINDOWS_API)
return true;
#endif
}
/**
* If exited, returns the exit code.
*
* If the process exited, returns the exit code it returned.
*
* \pre exited() is true.
*/
int exit_status() const
{
BOOST_ASSERT(exited());
#if defined(BOOST_POSIX_API)
return WEXITSTATUS(flags_);
#elif defined(BOOST_WINDOWS_API)
return flags_;
#endif
}
protected:
/**
* Creates a status object based on exit information.
*
* Creates a new status object representing the exit status of a
* child process.
*
* \param flags In a POSIX system this parameter contains the
* flags returned by the ::waitpid() call. In a
* Windows system it contains the exit code only.
*/
status(int flags)
: flags_(flags)
{
}
/**
* OS-specific codification of exit status.
*/
int flags_;
};
}
}
#endif

234
boost/process/stream_behavior.hpp

@ -1,234 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/stream_behavior.hpp
*
* Includes the declaration of the stream_behavior class and associated
* free functions.
*/
#ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP
#define BOOST_PROCESS_STREAM_BEHAVIOR_HPP
#include <boost/process/config.hpp>
namespace boost {
namespace process {
namespace detail {
struct stream_info;
}
/**
* Describes the possible states for a communication stream.
*/
class stream_behavior
{
public:
friend struct detail::stream_info;
friend stream_behavior capture_stream();
friend stream_behavior close_stream();
friend stream_behavior inherit_stream();
friend stream_behavior redirect_stream_to_stdout();
friend stream_behavior silence_stream();
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
friend stream_behavior posix_redirect_stream(int to);
#endif
/**
* Describes the possible states for a communication stream.
*/
enum type
{
/**
* The child's stream is connected to the parent by using an
* anonymous pipe so that they can send and receive data to/from
* each other.
*/
capture,
/**
* The child's stream is closed upon startup so that it will not
* have any access to it.
*/
close,
/**
* The child's stream is connected to the same stream used by the
* parent. In other words, the corresponding parent's stream is
* inherited.
*/
inherit,
/**
* The child's stream is connected to child's standard output.
* This is typically used when configuring the standard error
* stream.
*/
redirect_to_stdout,
/**
* The child's stream is redirected to a null device so that its
* input is always zero or its output is lost, depending on
* whether the stream is an input or an output one. It is
* important to notice that this is different from close because
* the child is still able to write data. If we closed, e.g.
* stdout, the child might not work at all!
*/
silence,
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
/**
* The child redirects the stream's output to the provided file
* descriptor. This is a generalization of the portable
* redirect_to_stdout behavior.
*/
posix_redirect
#endif
};
/**
* Constructs a new stream behavior of type close.
*
* The public constructor creates a new stream behavior that defaults
* to the close behavior. In general, you will want to use the
* available free functions to construct a stream behavior (including
* the close one).
*/
stream_behavior()
: type_(stream_behavior::close)
{
}
/**
* Returns this stream's behavior type.
*/
type get_type() const
{
return type_;
}
private:
/**
* Constructs a new stream behavior of type \a t.
*
* Constructs a new stream behavior of type \a t. It is the
* responsibility of the caller to fill in any other attributes
* required by the specified type, if any.
*/
stream_behavior(type t)
: type_(t)
{
}
/**
* This stream's behavior type.
*/
type type_;
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
/**
* File descriptor the stream is redirected to.
*/
int desc_to_;
#endif
};
/**
* Creates a new stream_behavior of type stream_behavior::capture.
*
* Creates a new stream_behavior of type stream_behavior::capture,
* meaning that the child's stream is connected to the parent by using an
* anonymous pipe so that they can send and receive data to/from each
* other.
*/
inline stream_behavior capture_stream()
{
return stream_behavior(stream_behavior::capture);
}
/**
* Creates a new stream_behavior of type stream_behavior::close.
*
* Creates a new stream_behavior of type stream_behavior::close,
* meaning that the child's stream is closed upon startup so that it
* will not have any access to it.
*/
inline stream_behavior close_stream()
{
return stream_behavior(stream_behavior::close);
}
/**
* Creates a new stream_behavior of type stream_behavior::inherit.
*
* Creates a new stream_behavior of type stream_behavior::inherit,
* meaning that the child's stream is connected to the same stream used
* by the parent. In other words, the corresponding parent's stream is
* inherited.
*/
inline stream_behavior inherit_stream()
{
return stream_behavior(stream_behavior::inherit);
}
/**
* Creates a new stream_behavior of type
* stream_behavior::redirect_to_stdout.
*
* Creates a new stream_behavior of type
* stream_behavior::redirect_to_stdout, meaning that the child's stream is
* connected to child's standard output. This is typically used when
* configuring the standard error stream.
*/
inline stream_behavior redirect_stream_to_stdout()
{
return stream_behavior(stream_behavior::redirect_to_stdout);
}
/**
* Creates a new stream_behavior of type stream_behavior::silence.
*
* Creates a new stream_behavior of type stream_behavior::silence,
* meaning that the child's stream is redirected to a null device so that
* its input is always zero or its output is lost, depending on whether
* the stream is an input or an output one. It is important to notice
* that this is different from close because the child is still able to
* write data. If we closed, e.g. stdout, the child might not work at
* all!
*/
inline stream_behavior silence_stream()
{
return stream_behavior(stream_behavior::silence);
}
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
/**
* Creates a new stream_behavior of type stream_behavior::posix_redirect.
*
* Creates a new stream_behavior of type stream_behavior::posix_redirect,
* meaning that the child's stream is redirected to the \a to child's
* file descriptor. This is a generalization of the portable
* redirect_stream_to_stdout() behavior.
*/
inline stream_behavior posix_redirect_stream(int to)
{
stream_behavior sb(stream_behavior::posix_redirect);
sb.desc_to_ = to;
return sb;
}
#endif
}
}
#endif

128
boost/process/win32_child.hpp

@ -1,128 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/win32_child.hpp
*
* Includes the declaration of the win32_child class.
*/
#ifndef BOOST_PROCESS_WIN32_CHILD_HPP
#define BOOST_PROCESS_WIN32_CHILD_HPP
#include <boost/process/child.hpp>
#include <boost/process/detail/file_handle.hpp>
#include <windows.h>
namespace boost {
namespace process {
/**
* Windows implementation of the Child concept.
*
* The win32_child class implements the Child concept in a Windows
* operating system.
*
* A Windows child differs from a regular %child (represented by a
* child object) in that it holds additional information about a process.
* Aside from the standard handle, it also includes a handle to the
* process' main thread, together with identifiers to both entities.
*
* This class is built on top of the generic child so as to allow its
* trivial adoption. When a program is changed to use the
* Windows-specific context (win32_context), it will most certainly need
* to migrate its use of the child class to win32_child. Doing so is only
* a matter of redefining the appropriate object and later using the
* required extra features: there should be no need to modify the existing
* code (e.g. method calls) in any other way.
*/
class win32_child : public child
{
public:
/**
* Constructs a new Windows child object representing a just
* spawned %child process.
*
* Creates a new %child object that represents the process described by
* the \a pi structure.
*
* The \a fhstdin, \a fhstdout and \a fhstderr parameters hold the
* communication streams used to interact with the %child process if
* the launcher configured redirections. See the parent class'
* constructor for more details on these.
*
* \see child
*/
win32_child(const PROCESS_INFORMATION &pi, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr)
: child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, pi.hProcess),
process_information_(pi),
thread_handle_(process_information_.hThread)
{
}
/**
* Returns the process handle.
*
* Returns a process-specific handle that can be used to access the
* process. This is the value of the \a hProcess field in the
* PROCESS_INFORMATION structure returned by CreateProcess().
*
* \see get_id()
*/
HANDLE get_handle() const
{
return process_information_.hProcess;
}
/**
* Returns the primary thread's handle.
*
* Returns a handle to the primary thread of the new process. This is
* the value of the \a hThread field in the PROCESS_INFORMATION
* structure returned by CreateProcess().
*
* \see get_primary_thread_id()
*/
HANDLE get_primary_thread_handle() const
{
return process_information_.hThread;
}
/**
* Returns the primary thread's identifier.
*
* Returns a system-wide value that identifies the process's primary
* thread. This is the value of the \a dwThreadId field in the
* PROCESS_INFORMATION structure returned by CreateProcess().
*
* \see get_primary_thread_handle()
*/
DWORD get_primary_thread_id() const
{
return process_information_.dwThreadId;
}
private:
/**
* Windows-specific process information.
*/
PROCESS_INFORMATION process_information_;
/**
* Thread handle owned by RAII object.
*/
detail::file_handle thread_handle_;
};
}
}
#endif

61
boost/process/win32_context.hpp

@ -1,61 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/win_32context.hpp
*
* Includes the declaration of the win32_context class.
*/
#ifndef BOOST_PROCESS_WIN32_CONTEXT_HPP
#define BOOST_PROCESS_WIN32_CONTEXT_HPP
#include <boost/process/context.hpp>
#include <string>
#include <windows.h>
namespace boost {
namespace process {
/**
* Generic implementation of the Context concept.
*
* The context class implements the Context concept in an operating
* system agnostic way; it allows spawning new child processes using
* a single and common interface across different systems.
*/
template <class String>
class win32_basic_context : public basic_context<String>
{
public:
/**
* Initializes the Win32-specific process startup information with NULL.
*/
win32_basic_context()
: startupinfo(NULL)
{
}
/**
* Win32-specific process startup information.
*/
STARTUPINFOA *startupinfo;
};
/**
* Default instantiation of win32_basic_context.
*/
typedef win32_basic_context<std::string> win32_context;
}
}
#endif

77
boost/process/win32_operations.hpp

@ -1,77 +0,0 @@
//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/win32_operations.hpp
*
* Provides miscellaneous free functions specific to Windows operating
* systems.
*/
#ifndef BOOST_PROCESS_WIN32_OPERATIONS_HPP
#define BOOST_PROCESS_WIN32_OPERATIONS_HPP
#include <boost/process/win32_child.hpp>
#include <boost/process/detail/file_handle.hpp>
#include <boost/process/detail/stream_info.hpp>
#include <boost/process/detail/win32_ops.hpp>
#include <windows.h>
namespace boost {
namespace process {
/**
* Starts a new child process.
*
* Given an executable and the set of arguments passed to it, starts
* a new process with all the parameters configured in the context.
* The context can be reused afterwards to launch other different
* processes.
*
* \return A handle to the new child process.
*/
template <class Executable, class Arguments, class Win32_Context>
inline win32_child win32_launch(const Executable &exe, const Arguments &args, const Win32_Context &ctx)
{
detail::file_handle fhstdin, fhstdout, fhstderr;
detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false);
if (behin.type_ == detail::stream_info::use_pipe)
fhstdin = behin.pipe_->wend();
detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true);
if (behout.type_ == detail::stream_info::use_pipe)
fhstdout = behout.pipe_->rend();
detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true);
if (beherr.type_ == detail::stream_info::use_pipe)
fhstderr = beherr.pipe_->rend();
detail::win32_setup s;
s.work_directory = ctx.work_directory;
STARTUPINFOA si;
if (!ctx.startupinfo)
{
::ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
s.startupinfo = &si;
}
else
s.startupinfo = ctx.startupinfo;
PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s);
return win32_child(pi, fhstdin, fhstdout, fhstderr);
}
}
}
#endif

2364
doc/Doxyfile

File diff suppressed because it is too large

15
docker/Dockerfile

@ -7,6 +7,7 @@ RUN apt-get upgrade -y
# Ethereum dependencies
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 )
RUN apt-get install -qy libncurses5-dev
@ -14,15 +15,11 @@ RUN apt-get install -qy libncurses5-dev
# Qt-based GUI
# RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev
# Cryptopp
RUN git clone --depth=1 https://github.com/mmoss/cryptopp.git
RUN cd cryptopp && scons --shared --prefix=/usr
# JSONRPC (version 0.2.1, see https://github.com/ethereum/cpp-ethereum/issues/453 )
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
RUN git clone --depth=1 --branch=0.2.1 https://github.com/cinemast/libjson-rpc-cpp.git
RUN mkdir -p libjson-rpc-cpp/build
RUN cd libjson-rpc-cpp/build && cmake .. && make && make install
# Ethereum PPA
RUN apt-get install -qy software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum
RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev
# Build Ethereum (HEADLESS)
RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum

14
eth/main.cpp

@ -89,6 +89,7 @@ void interactiveHelp()
<< " importConfig <path> Import the config (.RLP) from the path provided." <<endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl
<< " dumpreceipt <block> <index> Dumps a transation receipt." << endl
<< " exit Exits the application." << endl;
}
@ -606,6 +607,17 @@ int main(int argc, char** argv)
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
}
else if (c && cmd == "dumpreceipt")
{
unsigned block;
unsigned index;
iss >> block >> index;
dev::eth::TransactionReceipt r = c->blockChain().receipts(c->blockChain().numberHash(block)).receipts[index];
auto rb = r.rlp();
cout << "RLP: " << RLP(rb) << endl;
cout << "Hex: " << toHex(rb) << endl;
cout << r << endl;
}
else if (c && cmd == "dumptrace")
{
unsigned block;
@ -619,7 +631,7 @@ int main(int argc, char** argv)
dev::eth::State state =c->state(index + 1,c->blockChain().numberHash(block));
if (index < state.pending().size())
{
Executive e(state, 0);
Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();

1
evmjit

@ -0,0 +1 @@
Subproject commit 66d5a2b5cdf1361dcf0205b191dd12be090ed224

4
exp/main.cpp

@ -21,13 +21,13 @@
*/
#include <functional>
#include <libethereum/AccountDiff.h>
#include <libdevcore/RangeMask.h>
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h>
#include <libdevcore/CommonIO.h>
#include <libp2p/All.h>
#include <libdevcore/RangeMask.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/All.h>
#include <liblll/All.h>
@ -91,7 +91,7 @@ int main()
Transaction t(0, 10000, 10000, c, bytes(), 0, u.secret());
cnote << "Transaction: " << t;
cnote << s.balance(c);
s.execute(t.rlp());
s.execute(LastHashes(), t.rlp());
cnote << "State after transaction: " << s;
cnote << before.diff(s);
}

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.7.13";
char const* Version = "0.8.0";
}

3
libdevcore/Common.h

@ -74,6 +74,9 @@ using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>;
// Fixed-length string types.
using string32 = std::array<char, 32>;
// Null/Invalid values for convenience.
static const u256 Invalid256 = ~(u256)0;
static const bytes NullBytes;

180
libdevcore/CommonData.cpp

@ -123,180 +123,10 @@ bytes dev::asNibbles(std::string const& _s)
return ret;
}
#if 0
/* Following code is copyright 2012-2014 Luke Dashjr
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details.
*/
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#include <cstring>
static const int8_t b58digits_map[] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
{
size_t binsz = *binszp;
const unsigned char *b58u = (void*)b58;
unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
unsigned zerocount = 0;
if (!b58sz)
b58sz = strlen(b58);
memset(outi, 0, outisz * sizeof(*outi));
// Leading zeros, just count
for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i)
++zerocount;
for ( ; i < b58sz; ++i)
{
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits_map[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
}
for (; j < outisz; ++j)
{
*(binu++) = (outi[j] >> 0x18) & 0xff;
*(binu++) = (outi[j] >> 0x10) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff;
*(binu++) = (outi[j] >> 0) & 0xff;
}
// Count canonical base58 byte count
binu = bin;
for (i = 0; i < binsz; ++i)
{
if (binu[i])
break;
--*binszp;
}
*binszp += zerocount;
return true;
}
static
bool my_dblsha256(void *hash, const void *data, size_t datasz)
std::string dev::toString(string32 const& _s)
{
uint8_t buf[0x20];
return b58_sha256_impl(buf, data, datasz) && b58_sha256_impl(hash, buf, sizeof(buf));
}
int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz)
{
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4)
return -4;
if (!my_dblsha256(buf, bin, binsz - 4))
return -2;
if (memcmp(&binc[binsz - 4], buf, 4))
return -1;
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
{} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1')
return -3;
return binc[0];
}
static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
const uint8_t *bin = data;
int carry;
size_t i, j, high, zcount = 0;
size_t size;
while (zcount < binsz && !bin[zcount])
++zcount;
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t buf[size];
memset(buf, 0, size);
for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
{
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
{
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
}
}
for (j = 0; j < size && !buf[j]; ++j);
if (*b58sz <= zcount + size - j)
{
*b58sz = zcount + size - j + 1;
return false;
}
if (zcount)
memset(b58, '1', zcount);
for (i = zcount; j < size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
return true;
std::string ret;
for (unsigned i = 0; i < 32 && _s[i]; ++i)
ret.push_back(_s[i]);
return ret;
}
#endif

3
libdevcore/CommonData.h

@ -236,4 +236,7 @@ inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b)
return ret += _b;
}
/// Make normal string from fixed-length string.
std::string toString(string32 const& _s);
}

2
libdevcore/CommonIO.cpp

@ -65,6 +65,8 @@ bytes dev::contents(std::string const& _file)
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
if (length == 0) // return early, MSVC does not like reading 0 bytes
return {};
is.seekg (0, is.beg);
bytes ret(length);
is.read((char*)ret.data(), length);

52
libdevcore/Diff.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 Diff.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
namespace dev
{
enum class ExistDiff
{
Same,
New,
Dead
};
template <class T>
class Diff
{
public:
Diff() {}
Diff(T _from, T _to): m_from(_from), m_to(_to) {}
T const& from() const { return m_from; }
T const& to() const { return m_to; }
explicit operator bool() const { return m_from != m_to; }
private:
T m_from;
T m_to;
};
}

1
libdevcore/vector_ref.h

@ -41,6 +41,7 @@ public:
void retarget(_T const* _d, size_t _s) { m_data = _d; m_count = _s; }
void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); }
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
_T* begin() { return m_data; }
_T* end() { return m_data + m_count; }

3
libethcore/BlockInfo.cpp

@ -22,6 +22,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libethcore/CommonEth.h>
#include "ProofOfWork.h"
#include "Exceptions.h"
#include "BlockInfo.h"
@ -190,7 +191,7 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
if (!parentHash)
return c_genesisDifficulty;
else
return timestamp >= _parent.timestamp + 5 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10));
return timestamp >= _parent.timestamp + (c_protocolVersion == 49 ? 5 : 8) ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10));
}
void BlockInfo::verifyParent(BlockInfo const& _parent) const

4
libethcore/CommonEth.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 50;
const unsigned c_protocolVersion = 49;
const unsigned c_databaseVersion = 5;
static const vector<pair<u256, string>> g_units =
@ -48,7 +48,7 @@ static const vector<pair<u256, string>> g_units =
{((u256(1000000000) * 1000000000) * 1000000000) * 1000, "Tether"},
{(u256(1000000000) * 1000000000) * 1000000000, "Gether"},
{(u256(1000000000) * 1000000000) * 1000000, "Mether"},
{(u256(1000000000) * 1000000000) * 1000, "Kether"},
{(u256(1000000000) * 1000000000) * 1000, "grand"},
{u256(1000000000) * 1000000000, "ether"},
{u256(1000000000) * 1000000, "finney"},
{u256(1000000000) * 1000, "szabo"},

8
libethcore/CommonEth.h

@ -48,7 +48,7 @@ std::vector<std::pair<u256, std::string>> const& units();
using LogBloom = h512;
// The various denominations; here for ease of use where needed within code.
static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
/*static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Vether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Dether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Nether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
@ -59,13 +59,13 @@ static const u256 Pether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000
static const u256 Tether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Gether = (u256(1000000000) * 1000000000) * 1000000000;
static const u256 Mether = (u256(1000000000) * 1000000000) * 1000000;
static const u256 Kether = (u256(1000000000) * 1000000000) * 1000;
static const u256 grand = (u256(1000000000) * 1000000000) * 1000;*/
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
static const u256 Gwei = u256(1000000000);
/*static const u256 Gwei = u256(1000000000);
static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);
static const u256 Kwei = u256(1000);*/
static const u256 wei = u256(1);
}

18
libethereum/AccountDiff.cpp

@ -33,11 +33,19 @@ AccountChange AccountDiff::changeType() const
return exist ? exist.from() ? AccountChange::Deletion : AccountChange::Creation : (bn && sc) ? AccountChange::All : bn ? AccountChange::Intrinsic: sc ? AccountChange::CodeStorage : AccountChange::None;
}
char const* AccountDiff::lead() const
char const* dev::eth::lead(AccountChange _c)
{
bool bn = (balance || nonce);
bool sc = (!storage.empty() || code);
return exist ? exist.from() ? "XXX" : "+++" : (bn && sc) ? "***" : bn ? " * " : sc ? "* *" : " ";
switch (_c)
{
case AccountChange::None: return " ";
case AccountChange::Creation: return "+++";
case AccountChange::Deletion: return "XXX";
case AccountChange::Intrinsic: return " * ";
case AccountChange::CodeStorage: return "* *";
case AccountChange::All: return "***";
}
assert(false);
return "";
}
namespace dev {
@ -77,7 +85,7 @@ std::ostream& operator<<(std::ostream& _out, dev::eth::StateDiff const& _s)
dev::eth::AccountDiff d;
_out << d;
for (auto const& i: _s.accounts)
_out << i.second.lead() << " " << i.first << ": " << i.second << endl;
_out << lead(i.second.changeType()) << " " << i.first << ": " << i.second << endl;
return _out;
}

55
libethereum/AccountDiff.h

@ -22,6 +22,7 @@
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/Diff.h>
#include <libethcore/CommonEth.h>
namespace dev
@ -29,47 +30,55 @@ namespace dev
namespace eth
{
enum class ExistDiff { Same, New, Dead };
template <class T>
class Diff
/// Type of change that an account can have from state to state.
enum class AccountChange
{
public:
Diff() {}
Diff(T _from, T _to): m_from(_from), m_to(_to) {}
T const& from() const { return m_from; }
T const& to() const { return m_to; }
explicit operator bool() const { return m_from != m_to; }
private:
T m_from;
T m_to;
None, ///< Nothing changed at all.
Creation, ///< Account came into existance.
Deletion, ///< Account was deleted.
Intrinsic, ///< Account was already in existance and some internal aspect of the account altered such as balance, nonce or storage.
CodeStorage, ///< Account was already in existance and the code of the account changed.
All ///< Account was already in existance and all aspects of the account changed.
};
enum class AccountChange { None, Creation, Deletion, Intrinsic, CodeStorage, All };
/// @returns a three-character code that expresses the type of change.
char const* lead(AccountChange _c);
/**
* @brief Stores the difference between two accounts (typically the same account at two times).
*
* In order to determine what about an account has altered, this struct can be used to specify
* alterations. Use changed() and changeType() to determine what, if anything, is different.
*
* Five members are accessible: to determine the nature of the changes.
*/
struct AccountDiff
{
/// @returns true if the account has changed at all.
inline bool changed() const { return storage.size() || code || nonce || balance || exist; }
char const* lead() const;
/// @returns a three-character code that expresses the change.
AccountChange changeType() const;
Diff<bool> exist;
Diff<u256> balance;
Diff<u256> nonce;
std::map<u256, Diff<u256>> storage;
Diff<bytes> code;
Diff<bool> exist; ///< The account's existance; was it created/deleted or not?
Diff<u256> balance; ///< The account's balance; did it alter?
Diff<u256> nonce; ///< The account's nonce; did it alter?
std::map<u256, Diff<u256>> storage; ///< The account's storage addresses; each has its own Diff.
Diff<bytes> code; ///< The account's code; in general this should only have changed if exist also changed.
};
/**
* @brief Stores the difference between two states; this is just their encumbent accounts.
*/
struct StateDiff
{
std::map<Address, AccountDiff> accounts;
std::map<Address, AccountDiff> accounts; ///< The state's account changes; each has its own AccountDiff.
};
}
/// Simple stream output for the StateDiff.
std::ostream& operator<<(std::ostream& _out, dev::eth::StateDiff const& _s);
/// Simple stream output for the AccountDiff.
std::ostream& operator<<(std::ostream& _out, dev::eth::AccountDiff const& _s);
}

29
libethereum/Client.cpp

@ -27,6 +27,7 @@
#include <libdevcore/Log.h>
#include <libp2p/Host.h>
#include "Defaults.h"
#include "Executive.h"
#include "EthereumHost.h"
using namespace std;
using namespace dev;
@ -343,7 +344,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
n = temp.transactionsFrom(toAddress(_secret));
}
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
u256 gasUsed = temp.execute(t.rlp(), &out, false);
u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false);
(void)gasUsed; // TODO: do something with gasused which it returns.
}
catch (...)
@ -353,6 +354,30 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
return out;
}
bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice)
{
try
{
State temp;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
{
ReadGuard l(x_stateDB);
temp = m_postMine;
}
Executive e(temp, LastHashes(), 0);
if (!e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address()))
{
e.go();
return e.out().toBytes();
}
}
catch (...)
{
// TODO: Some sort of notification of failure.
}
return bytes();
}
Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
startWorking();
@ -442,7 +467,7 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ";
h512s newPendingBlooms = m_postMine.sync(m_tq);
h512s newPendingBlooms = m_postMine.sync(m_bc, m_tq);
if (newPendingBlooms.size())
{
for (auto i: newPendingBlooms)

34
libethereum/Client.h

@ -25,6 +25,8 @@
#include <mutex>
#include <list>
#include <atomic>
#include <string>
#include <array>
#include <boost/utility.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
@ -105,6 +107,35 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-"
#define cworkin dev::LogOutputStream<dev::eth::WorkInChannel, true>()
#define cworkout dev::LogOutputStream<dev::eth::WorkOutChannel, true>()
template <class T> struct ABISerialiser {};
template <unsigned N> struct ABISerialiser<FixedHash<N>> { static bytes serialise(FixedHash<N> const& _t) { return _t.asBytes(); } };
template <> struct ABISerialiser<u256> { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } };
template <> struct ABISerialiser<u160> { static bytes serialise(u160 const& _t) { return h160(_t).asBytes(); } };
template <> struct ABISerialiser<string32> { static bytes serialise(string32 const& _t) { return bytesConstRef((byte const*)_t.data(), 32).toBytes(); } };
inline bytes abiInAux() { return {}; }
template <class T, class ... U> bytes abiInAux(T const& _t, U const& ... _u)
{
return ABISerialiser<T>::serialise(_t) + abiInAux(_u ...);
}
template <class ... T> bytes abiIn(byte _id, T const& ... _t)
{
return bytes(1, _id) + abiInAux(_t ...);
}
template <class T> struct ABIDeserialiser {};
template <unsigned N> struct ABIDeserialiser<FixedHash<N>> { static FixedHash<N> deserialise(bytesConstRef& io_t) { FixedHash<N> ret; io_t.cropped(0, N).populate(ret.ref()); return ret; } };
template <> struct ABIDeserialiser<u256> { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian<u256>(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } };
template <> struct ABIDeserialiser<u160> { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian<u160>(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } };
template <> struct ABIDeserialiser<string32> { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref<char>(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } };
template <class T> T abiOut(bytes const& _data)
{
bytesConstRef o(&_data);
return ABIDeserialiser<T>::deserialise(o);
}
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@ -135,6 +166,9 @@ public:
/// Makes the given call. Nothing is recorded into the state.
virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
/// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH.
virtual bytes call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether);
// Informational stuff
// [NEW API]

11
libethereum/Executive.cpp

@ -26,12 +26,19 @@
#include "State.h"
#include "ExtVM.h"
#include "Precompiled.h"
#include "BlockChain.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
#define ETH_VMTRACE 1
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
m_s(_s),
m_lastHashes(_s.getLastHashes(_bc)),
m_depth(_level)
{}
u256 Executive::gasUsed() const
{
return m_t.gas() - m_endGas;
@ -120,7 +127,7 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen
{
m_vm = VMFactory::create(_gas);
bytes const& c = m_s.code(_codeAddress);
m_ext = make_shared<ExtVM>(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth);
}
else
m_endGas = _gas;
@ -140,7 +147,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init.
m_vm = VMFactory::create(_gas);
m_ext = make_shared<ExtVM>(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
return _init.empty();
}

6
libethereum/Executive.h

@ -31,6 +31,7 @@ namespace eth
{
class State;
class BlockChain;
class ExtVM;
struct Manifest;
@ -49,7 +50,9 @@ class Executive
{
public:
/// Basic constructor.
Executive(State& _s, unsigned _level): m_s(_s), m_depth(_level) {}
Executive(State& _s, LastHashes const& _lh, unsigned _level): m_s(_s), m_lastHashes(_lh), m_depth(_level) {}
/// Basic constructor.
Executive(State& _s, BlockChain const& _bc, unsigned _level);
/// Basic destructor.
~Executive() = default;
@ -99,6 +102,7 @@ public:
private:
State& m_s; ///< The state to which this operation/transaction is applied.
LastHashes m_lastHashes;
std::shared_ptr<ExtVM> m_ext; ///< The VM externality object for the VM execution or null if no VM is required.
std::unique_ptr<VMFace> m_vm; ///< The VM object or null if no VM is required.
bytes m_precompiledOut; ///< Used for the output when there is no VM for a contract (i.e. precompiled).

4
libethereum/ExtVM.cpp

@ -28,7 +28,7 @@ using namespace dev::eth;
bool ExtVM::call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp, Address _myAddressOverride, Address _codeAddressOverride)
{
Executive e(m_s, depth + 1);
Executive e(m_s, lastHashes, depth + 1);
if (!e.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, io_gas, origin))
{
e.go(_onOp);
@ -45,7 +45,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
Executive e(m_s, depth + 1);
Executive e(m_s, lastHashes, depth + 1);
if (!e.create(myAddress, _endowment, gasPrice, io_gas, _code, origin))
{
e.go(_onOp);

4
libethereum/ExtVM.h

@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache)
ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache)
{
m_s.ensureCached(_myAddress, true, true);
}

84
libethereum/State.cpp

@ -114,7 +114,7 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
m_ourAddress = bi.coinbaseAddress;
sync(_bc, bi.parentHash, bip);
enact(&b);
enact(&b, _bc);
}
State::State(State const& _s):
@ -319,7 +319,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{
auto b = _bc.block(*it);
enact(&b);
enact(&b, _bc);
cleanup(true);
}
}
@ -348,7 +348,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
sync(_bc, _bi.parentHash);
resetCurrent();
m_previousBlock = biParent;
return enact(_block, &_bc);
return enact(_block, _bc);
}
map<Address, u256> State::addresses() const
@ -412,12 +412,14 @@ bool State::cull(TransactionQueue& _tq) const
return ret;
}
h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
// TRANSACTIONS
h512s ret;
auto ts = _tq.transactions();
auto lh = getLastHashes(_bc);
for (int goodTxs = 1; goodTxs;)
{
goodTxs = 0;
@ -429,7 +431,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
uncommitToMine();
// boost::timer t;
execute(i.second);
execute(lh, i.second);
ret.push_back(m_receipts.back().bloom());
_tq.noteGood(i);
++goodTxs;
@ -467,7 +469,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
return ret;
}
u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
{
// m_currentBlock is assumed to be prepopulated and reset.
@ -496,6 +498,8 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
LastHashes lh = getLastHashes(_bc);
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
for (auto const& tr: RLP(_block)[1])
@ -504,26 +508,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
k << i;
transactionsTrie.insert(&k.out(), tr.data());
// cnote << m_state.root() << m_state;
// cnote << *this;
execute(tr.data());
execute(lh, tr.data());
RLPStream receiptrlp;
m_receipts.back().streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
/*
if (tr[1].toHash<h256>() != m_state.root())
{
// Invalid state root
cnote << m_state.root() << "\n" << m_state;
cnote << *this;
cnote << "INVALID: " << tr[1].toHash<h256>();
BOOST_THROW_EXCEPTION(InvalidTransactionStateRoot());
}
if (tr[2].toInt<u256>() != gasUsed())
BOOST_THROW_EXCEPTION(InvalidTransactionGasUsed());
*/
++i;
}
@ -535,7 +524,20 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
if (receiptsTrie.root() != m_currentBlock.receiptsRoot)
{
cwarn << "Bad receipts state root!";
cwarn << "Bad receipts state root.";
cwarn << "Block:" << toHex(_block);
cwarn << "Block RLP:" << RLP(_block);
cwarn << "Want: " << receiptsTrie.root() << ", got: " << m_currentBlock.receiptsRoot;
for (unsigned j = 0; j < i; ++j)
{
RLPStream k;
k << j;
auto b = asBytes(receiptsTrie.at(&k.out()));
cwarn << j << ": ";
cwarn << "RLP: " << RLP(b);
cwarn << "Hex: " << toHex(b);
cwarn << TransactionReceipt(&b);
}
BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
}
@ -551,7 +553,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
// Check uncles & apply their rewards to state.
set<h256> nonces = { m_currentBlock.nonce };
Addresses rewarded;
set<h256> knownUncles = _bc ? _bc->allUnclesFrom(m_currentBlock.parentHash) : set<h256>();
set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
for (auto const& i: RLP(_block)[2])
{
if (knownUncles.count(sha3(i.data())))
@ -560,13 +562,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
BlockInfo uncle = BlockInfo::fromHeader(i.data());
if (nonces.count(uncle.nonce))
BOOST_THROW_EXCEPTION(DuplicateUncleNonce());
if (_bc)
{
BlockInfo uncleParent(_bc->block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6)
BOOST_THROW_EXCEPTION(UncleTooOld());
uncle.verifyParent(uncleParent);
}
BlockInfo uncleParent(_bc.block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
BOOST_THROW_EXCEPTION(UncleTooOld());
uncle.verifyParent(uncleParent);
nonces.insert(uncle.nonce);
tdIncrease += uncle.difficulty;
@ -648,7 +648,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
cnote << "PARANOIA root:" << s.rootHash();
// s.m_currentBlock.populate(&block.out(), false);
// s.m_currentBlock.verifyInternals(&block.out());
s.enact(&block.out(), &_bc, false); // don't check nonce for this since we haven't mined it yet.
s.enact(&block.out(), _bc, false); // don't check nonce for this since we haven't mined it yet.
s.cleanup(false);
return true;
}
@ -993,9 +993,21 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
LastHashes State::getLastHashes(BlockChain const& _bc) const
{
LastHashes ret;
ret.resize(256);
if (c_protocolVersion > 49)
{
unsigned n = (unsigned)m_previousBlock.number;
for (unsigned i = 0; i < 256; ++i)
ret[i] = _bc.numberHash(std::max<unsigned>(n, i) - i);
}
return ret;
}
u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, bool _commit)
{
#ifndef ETH_RELEASE
commit(); // get an updated hash
@ -1008,7 +1020,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
auto h = rootHash();
#endif
Executive e(*this, 0);
Executive e(*this, _lh, 0);
e.setup(_rlp);
u256 startGasUsed = gasUsed();
@ -1017,7 +1029,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp());
#endif
#if ETH_TRACE
#if ETH_VMTRACE
e.go(e.simpleTrace());
#else
e.go();

14
libethereum/State.h

@ -143,14 +143,18 @@ public:
/// @returns a list of bloom filters 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(TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
h512s 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;
LastHashes getLastHashes(BlockChain const& _bc) const;
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
u256 execute(bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(&_rlp, o_output, _commit); }
u256 execute(bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), &_rlp, o_output, _commit); }
u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), _rlp, o_output, _commit); }
u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); }
u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }
@ -268,9 +272,9 @@ private:
/// Retrieve all information about a given address into a cache.
void ensureCached(std::map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const;
/// Execute the given block, assuming it corresponds to m_currentBlock. If _bc is passed, it will be used to check the uncles.
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
u256 enact(bytesConstRef _block, BlockChain const* _bc = nullptr, bool _checkNonce = true);
u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true);
/// Finalise the block, applying the earned rewards.
void applyRewards(Addresses const& _uncleAddresses);

16
libethereum/TransactionReceipt.cpp

@ -49,3 +49,19 @@ void TransactionReceipt::streamRLP(RLPStream& _s) const
for (LogEntry const& l: m_log)
l.streamRLP(_s);
}
std::ostream& dev::operator<<(std::ostream& _out, TransactionReceipt const& _r)
{
_out << "Root: " << _r.stateRoot() << std::endl;
_out << "Gas used: " << _r.gasUsed() << std::endl;
_out << "Logs: " << _r.log().size() << " entries:" << std::endl;
for (LogEntry const& i: _r.log())
{
_out << "Address " << i.address << ". Topics:" << std::endl;
for (auto const& j: i.topics)
_out << " " << j << std::endl;
_out << " Data: " << toHex(i.data) << std::endl;
}
_out << "Bloom: " << _r.bloom() << std::endl;
return _out;
}

3
libethereum/TransactionReceipt.h

@ -58,4 +58,7 @@ private:
using TransactionReceipts = std::vector<TransactionReceipt>;
}
std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r);
}

3
libevm/CMakeLists.txt

@ -30,6 +30,9 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)
if (EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit-cpp)
endif()
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

3
libevm/ExtVMFace.cpp

@ -25,7 +25,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth):
ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth):
myAddress(_myAddress),
caller(_caller),
origin(_origin),
@ -33,6 +33,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256
gasPrice(_gasPrice),
data(_data),
code(_code),
lastHashes(_lh),
previousBlock(_previousBlock),
currentBlock(_currentBlock),
depth(_depth)

10
libevm/ExtVMFace.h

@ -93,6 +93,8 @@ struct SubState
class ExtVMFace;
class VM;
using LastHashes = std::vector<h256>;
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, VM*, ExtVMFace const*)>;
/**
@ -105,7 +107,7 @@ public:
ExtVMFace() = default;
/// Full constructor.
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth);
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth);
virtual ~ExtVMFace() = default;
@ -145,6 +147,9 @@ public:
/// Revert any changes made (by any of the other calls).
virtual void revert() {}
/// Hash of a block if within the last 256 blocks, or h256() otherwise.
h256 prevhash(u256 _number) { return _number < currentBlock.number && _number > (std::max<u256>(257, currentBlock.number) - 257) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } // TODO: CHECK!!!
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; }
@ -155,7 +160,8 @@ public:
u256 gasPrice; ///< Price of gas (that we already paid).
bytesConstRef data; ///< Current input data.
bytes code; ///< Current code that is executing.
BlockInfo previousBlock; ///< The previous block's information.
LastHashes lastHashes; ///< Most recent 256 blocks' hashes.
BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE
BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth = 0; ///< Depth of the present call.

32
libevm/VM.h

@ -83,29 +83,9 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; };
if (m_jumpDests.empty())
{
std::set<u256> implicit;
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)
{
int in = _ext.code[i] - (unsigned)Instruction::PUSH1 + 1;
u256 p = 0;
for (i++; in--; i++)
p = (p << 8) | _ext.getCode(i);
if ((_ext.getCode(i) == (byte)Instruction::JUMP || _ext.getCode(i) == (byte)Instruction::JUMPI) && !(_ext.getCode(p) == (byte)Instruction::JUMP || _ext.getCode(p) == (byte)Instruction::JUMPI))
if (p >= _ext.code.size())
m_jumpDests.insert(p);
else
implicit.insert(p);
else {}
i--;
}
for (unsigned i = 0; i < _ext.code.size(); i += instructionInfo((Instruction)_ext.getCode(i)).additional + 1)
if (implicit.count(i))
m_jumpDests.insert(i);
}
u256 nextPC = m_curPC + 1;
auto osteps = _steps;
@ -198,7 +178,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
require(1);
runGas = c_balanceGas;
break;
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
@ -240,6 +219,11 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
break;
}
case Instruction::PREVHASH:
if (c_protocolVersion > 49)
require(1);
break;
case Instruction::PC:
case Instruction::MSIZE:
case Instruction::GAS:
@ -251,7 +235,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
case Instruction::CALLDATASIZE:
case Instruction::CODESIZE:
case Instruction::GASPRICE:
case Instruction::PREVHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
@ -581,7 +564,10 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
m_stack.push_back(_ext.gasPrice);
break;
case Instruction::PREVHASH:
m_stack.push_back(_ext.previousBlock.hash);
if (c_protocolVersion > 49)
m_stack.back() = (u256)_ext.prevhash(m_stack.back());
else
m_stack.push_back(_ext.previousBlock.hash);
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);

10
libevm/VMFactory.cpp

@ -18,6 +18,10 @@
#include "VMFactory.h"
#include "VM.h"
#if ETH_EVMJIT
#include <evmjit/libevmjit-cpp/JitVM.h>
#endif
namespace dev
{
namespace eth
@ -34,8 +38,12 @@ void VMFactory::setKind(VMKind _kind)
std::unique_ptr<VMFace> VMFactory::create(u256 _gas)
{
asserts(g_kind == VMKind::Interpreter && "Only interpreter supported for now");
#if ETH_EVMJIT
return std::unique_ptr<VMFace>(g_kind == VMKind::JIT ? (VMFace*)new JitVM(_gas) : new VM(_gas));
#else
asserts(g_kind == VMKind::Interpreter && "JIT disabled in build configuration");
return std::unique_ptr<VMFace>(new VM(_gas));
#endif
}
}

105
libjsqrc/ethereum.js

@ -18,9 +18,19 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ
/** @file abi.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Gav Wood <g@ethdev.com>
* @date 2014
*/
// TODO: make these be actually accurate instead of falling back onto JS's doubles.
var hexToDec = function (hex) {
return parseInt(hex, 16).toString();
};
var decToHex = function (dec) {
return parseInt(dec).toString(16);
};
var findIndex = function (array, callback) {
var end = false;
var i = 0;
@ -36,8 +46,8 @@ var findMethodIndex = function (json, methodName) {
});
};
var padLeft = function (number, n) {
return (new Array(n * 2 - number.toString().length + 1)).join("0") + number;
var padLeft = function (string, chars) {
return Array(chars - string.length + 1).join("0") + string;
};
var setupInputTypes = function () {
@ -49,7 +59,13 @@ var setupInputTypes = function () {
}
var padding = parseInt(type.slice(expected.length)) / 8;
return padLeft(value, padding);
if (typeof value === "number")
value = value.toString(16);
else if (value.indexOf('0x') === 0)
value = value.substr(2);
else
value = (+value).toString(16);
return padLeft(value, padding * 2);
};
};
@ -59,17 +75,18 @@ var setupInputTypes = function () {
return false;
}
return padLeft(formatter ? value : formatter(value), padding);
return padLeft(formatter ? formatter(value) : value, padding * 2);
};
};
var formatBool = function (value) {
return value ? '1' : '0';
return value ? '0x1' : '0x0';
};
return [
prefixedType('uint'),
prefixedType('int'),
prefixedType('hash'),
namedType('address', 20),
namedType('bool', 1, formatBool),
];
@ -85,16 +102,13 @@ var toAbiInput = function (json, methodName, params) {
return;
}
// it needs to be checked in WebThreeStubServer
// something wrong might be with this additional zero
bytes = bytes + index + 'x' + '0';
bytes = "0x" + padLeft(index.toString(16), 2);
var method = json[index];
for (var i = 0; i < method.inputs.length; i++) {
var found = false;
for (var j = 0; j < inputTypes.length && !found; j++) {
var val = parseInt(params[i]).toString(16);
found = inputTypes[j](method.inputs[i].type, val);
found = inputTypes[j](method.inputs[i].type, params[i]);
}
if (!found) {
console.error('unsupported json type: ' + method.inputs[i].type);
@ -119,12 +133,16 @@ var setupOutputTypes = function () {
var namedType = function (name, padding) {
return function (type) {
return name === type ? padding * 2: -1;
return name === type ? padding * 2 : -1;
};
};
var formatInt = function (value) {
return parseInt(value, 16);
return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);
};
var formatHash = function (value) {
return "0x" + value;
};
var formatBool = function (value) {
@ -134,6 +152,7 @@ var setupOutputTypes = function () {
return [
{ padding: prefixedType('uint'), format: formatInt },
{ padding: prefixedType('int'), format: formatInt },
{ padding: prefixedType('hash'), format: formatHash },
{ padding: namedType('address', 20) },
{ padding: namedType('bool', 1), format: formatBool }
];
@ -164,7 +183,7 @@ var fromAbiOutput = function (json, methodName, output) {
}
var res = output.slice(0, padding);
var formatter = outputTypes[j - 1].format;
result.push(formatter ? formatter(res): res);
result.push(formatter ? formatter(res) : ("0x" + res));
output = output.slice(padding);
}
@ -484,6 +503,7 @@ module.exports = HttpRpcProvider;
* Jeffrey Wilcke <jeff@ethdev.com>
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* Gav Wood <g@ethdev.com>
* @date 2014
*/
@ -526,6 +546,12 @@ function flattenPromise (obj) {
return Promise.resolve(obj);
}
var web3Methods = function () {
return [
{ name: 'sha3', call: 'web3_sha3' }
];
};
var ethMethods = function () {
var blockCall = function (args) {
return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
@ -670,19 +696,20 @@ var setupProperties = function (obj, properties) {
});
};
// TODO: import from a dependency, don't duplicate.
var hexToDec = function (hex) {
return parseInt(hex, 16).toString();
};
var decToHex = function (dec) {
return parseInt(dec).toString(16);
};
var web3 = {
_callbacks: {},
_events: {},
providers: {},
toHex: function(str) {
var hex = "";
for(var i = 0; i < str.length; i++) {
var n = str.charCodeAt(i).toString(16);
hex += n.length < 2 ? '0' + n : n;
}
return hex;
},
toAscii: function(hex) {
// Find termination
@ -702,10 +729,6 @@ var web3 = {
return str;
},
toDecimal: function (val) {
return parseInt(val, 16);
},
fromAscii: function(str, pad) {
pad = pad === undefined ? 32 : pad;
var hex = this.toHex(str);
@ -714,6 +737,33 @@ var web3 = {
return "0x" + hex;
},
toDecimal: function (val) {
return hexToDec(val.substring(2));
},
fromDecimal: function (val) {
return "0x" + decToHex(val);
},
toEth: function(str) {
var val = typeof str === "string" ? str.indexOf('0x') == 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];
while (val > 3000 && unit < units.length - 1)
{
val /= 1000;
unit++;
}
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
while (true) {
var o = s;
s = s.replace(/(\d)(\d\d\d[\.\,])/, function($0, $1, $2) { return $1 + ',' + $2; });
if (o == s)
break;
}
return s + ' ' + units[unit];
},
eth: {
prototype: Object(), // jshint ignore:line
watch: function (params) {
@ -759,6 +809,7 @@ var web3 = {
}
};
setupMethods(web3, web3Methods());
setupMethods(web3.eth, ethMethods());
setupProperties(web3.eth, ethProperties());
setupMethods(web3.db, dbMethods());
@ -1065,4 +1116,4 @@ module.exports = web3;
},{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/main":5,"./lib/qt":6,"./lib/websocket":7}]},{},[])
//# sourceMappingURL=ethereum.js.map
//# sourceMappingURL=ethereum.js.map

2
libp2p/Session.cpp

@ -195,7 +195,7 @@ bool Session::interpret(RLP const& _r)
// "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments"
stringstream capslog;
for (auto cap: caps)
capslog << "(" << hex << cap.first << "," << hex << cap.second << ")";
capslog << "(" << cap.first << "," << dec << cap.second << ")";
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort;

2
libsolidity/ExpressionCompiler.cpp

@ -62,6 +62,8 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
m_currentLValue.retrieveValue(_assignment, true);
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
if (m_currentLValue.storesReferenceOnStack())
m_context << eth::Instruction::SWAP1;
}
m_currentLValue.storeValue(_assignment);
m_currentLValue.reset();

1
libsolidity/InterfaceHandler.cpp

@ -56,6 +56,7 @@ std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinitio
};
method["name"] = f->getName();
method["constant"] = f->isDeclaredConst();
method["inputs"] = populateParameters(f->getParameters());
method["outputs"] = populateParameters(f->getReturnParameters());
methods.append(method);

22
libsolidity/Token.h

@ -107,9 +107,9 @@ namespace solidity
T(COMMA, ",", 1) \
T(OR, "||", 4) \
T(AND, "&&", 5) \
T(BIT_OR, "|", 6) \
T(BIT_XOR, "^", 7) \
T(BIT_AND, "&", 8) \
T(BIT_OR, "|", 8) \
T(BIT_XOR, "^", 9) \
T(BIT_AND, "&", 10) \
T(SHL, "<<", 11) \
T(SAR, ">>", 11) \
T(SHR, ">>>", 11) \
@ -122,13 +122,13 @@ namespace solidity
/* Compare operators sorted by precedence. */ \
/* IsCompareOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \
T(EQ, "==", 9) \
T(NE, "!=", 9) \
T(LT, "<", 10) \
T(GT, ">", 10) \
T(LTE, "<=", 10) \
T(GTE, ">=", 10) \
K(IN, "in", 10) \
T(EQ, "==", 6) \
T(NE, "!=", 6) \
T(LT, "<", 7) \
T(GT, ">", 7) \
T(LTE, "<=", 7) \
T(GTE, ">=", 7) \
K(IN, "in", 7) \
\
/* Unary operators. */ \
/* IsUnaryOp() relies on this block of enum values */ \
@ -142,7 +142,7 @@ namespace solidity
/* Keywords */ \
K(BREAK, "break", 0) \
K(CASE, "case", 0) \
K(CONST, "const", 0) \
K(CONST, "constant", 0) \
K(CONTINUE, "continue", 0) \
K(CONTRACT, "contract", 0) \
K(DEFAULT, "default", 0) \

5
libweb3jsonrpc/WebThreeStubServer.cpp

@ -244,6 +244,11 @@ std::shared_ptr<dev::shh::Interface> WebThreeStubServer::face() const
return m_web3.whisper();
}
std::string WebThreeStubServer::web3_sha3(std::string const& _param1)
{
return toJS(sha3(jsToBytes(_param1)));
}
Json::Value WebThreeStubServer::eth_accounts()
{
Json::Value ret(Json::arrayValue);

1
libweb3jsonrpc/WebThreeStubServer.h

@ -64,6 +64,7 @@ class WebThreeStubServer: public AbstractWebThreeStubServer
public:
WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
virtual std::string web3_sha3(std::string const& _param1);
virtual Json::Value eth_accounts();
virtual std::string eth_balanceAt(std::string const& _address);
virtual Json::Value eth_blockByHash(std::string const& _hash);

16
libweb3jsonrpc/abstractwebthreestubserver.h

@ -12,6 +12,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
public:
AbstractWebThreeStubServer(jsonrpc::AbstractServerConnector &conn) : jsonrpc::AbstractServer<AbstractWebThreeStubServer>(conn)
{
this->bindAndAddMethod(new jsonrpc::Procedure("web3_sha3", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::web3_sha3I);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_setCoinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("eth_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_listeningI);
@ -61,9 +62,12 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(new jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI);
}
inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response)
{
response = this->web3_sha3(request[0u].asString());
}
inline virtual void eth_coinbaseI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_coinbase();
}
inline virtual void eth_setCoinbaseI(const Json::Value &request, Json::Value &response)
@ -72,7 +76,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_listeningI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_listening();
}
inline virtual void eth_setListeningI(const Json::Value &request, Json::Value &response)
@ -81,7 +84,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_miningI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_mining();
}
inline virtual void eth_setMiningI(const Json::Value &request, Json::Value &response)
@ -90,22 +92,18 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_gasPriceI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_gasPrice();
}
inline virtual void eth_accountsI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_accounts();
}
inline virtual void eth_peerCountI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_peerCount();
}
inline virtual void eth_defaultBlockI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_defaultBlock();
}
inline virtual void eth_setDefaultBlockI(const Json::Value &request, Json::Value &response)
@ -114,7 +112,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_numberI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_number();
}
inline virtual void eth_balanceAtI(const Json::Value &request, Json::Value &response)
@ -171,7 +168,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_compilersI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->eth_compilers();
}
inline virtual void eth_lllI(const Json::Value &request, Json::Value &response)
@ -232,7 +228,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void shh_newIdentityI(const Json::Value &request, Json::Value &response)
{
(void)request;
response = this->shh_newIdentity();
}
inline virtual void shh_haveIdentityI(const Json::Value &request, Json::Value &response)
@ -259,6 +254,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
response = this->shh_changed(request[0u].asInt());
}
virtual std::string web3_sha3(const std::string& param1) = 0;
virtual std::string eth_coinbase() = 0;
virtual bool eth_setCoinbase(const std::string& param1) = 0;
virtual bool eth_listening() = 0;

2
libweb3jsonrpc/spec.json

@ -1,4 +1,6 @@
[
{ "name": "web3_sha3", "params": [""], "order": [], "returns" : "" },
{ "name": "eth_coinbase", "params": [], "order": [], "returns" : "" },
{ "name": "eth_setCoinbase", "params": [""], "order": [], "returns" : true },
{ "name": "eth_listening", "params": [], "order": [], "returns" : false },

2
mix/AssemblyDebuggerModel.cpp

@ -39,7 +39,7 @@ AssemblyDebuggerModel::AssemblyDebuggerModel():
{
m_baseState.addBalance(m_userAccount.address(), 10000000 * ether);
m_executiveState = m_baseState;
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, 0));
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, LastHashes(), 0));
}
DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction)

3
neth/main.cpp

@ -415,6 +415,7 @@ int main(int argc, char** argv)
if (!(mainwin = initscr()))
{
cerr << "Error initialising ncurses.";
delete [] str;
return -1;
}
@ -1023,7 +1024,7 @@ void print_in_middle(WINDOW *win, int starty, int startx, int width, string str,
length = str.length();
temp = (width - length) / 2;
x = startx + (int)temp;
x = x + (int)temp;
wattron(win, color);
mvwprintw(win, y, x, "%s", str.c_str());
wattroff(win, color);

53
test/SolidityABIJSON.cpp

@ -76,6 +76,7 @@ BOOST_AUTO_TEST_CASE(basic_test)
char const* interface = R"([
{
"name": "f",
"constant": false,
"inputs": [
{
"name": "a",
@ -114,6 +115,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods)
char const* interface = R"([
{
"name": "f",
"constant": false,
"inputs": [
{
"name": "a",
@ -129,6 +131,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods)
},
{
"name": "g",
"constant": false,
"inputs": [
{
"name": "b",
@ -156,6 +159,7 @@ BOOST_AUTO_TEST_CASE(multiple_params)
char const* interface = R"([
{
"name": "f",
"constant": false,
"inputs": [
{
"name": "a",
@ -189,6 +193,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order)
char const* interface = R"([
{
"name": "c",
"constant": false,
"inputs": [
{
"name": "b",
@ -204,6 +209,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order)
},
{
"name": "f",
"constant": false,
"inputs": [
{
"name": "a",
@ -222,6 +228,53 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order)
checkInterface(sourceCode, interface);
}
BOOST_AUTO_TEST_CASE(const_function)
{
char const* sourceCode = "contract test {\n"
" function foo(uint a, uint b) returns(uint d) { return a + b; }\n"
" function boo(uint32 a) constant returns(uint b) { return a * 4; }\n"
"}\n";
char const* interface = R"([
{
"name": "boo",
"constant": true,
"inputs": [{
"name": "a",
"type": "uint32"
}],
"outputs": [
{
"name": "b",
"type": "uint256"
}
]
},
{
"name": "foo",
"constant": false,
"inputs": [
{
"name": "a",
"type": "uint256"
},
{
"name": "b",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
checkInterface(sourceCode, interface);
}
BOOST_AUTO_TEST_SUITE_END()
}

35
test/SolidityEndToEndTest.cpp

@ -504,6 +504,41 @@ BOOST_AUTO_TEST_CASE(state_smoke_test)
BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3)));
}
BOOST_AUTO_TEST_CASE(compound_assign)
{
char const* sourceCode = "contract test {\n"
" uint value1;\n"
" uint value2;\n"
" function f(uint x, uint y) returns (uint w) {\n"
" uint value3 = y;"
" value1 += x;\n"
" value3 *= x;"
" value2 *= value3 + value1;\n"
" return value2 += 7;"
" }\n"
"}\n";
compileAndRun(sourceCode);
u256 value1;
u256 value2;
auto f = [&](u256 const& _x, u256 const& _y) -> u256
{
u256 value3 = _y;
value1 += _x;
value3 *= _x;
value2 *= value3 + value1;
return value2 += 7;
};
testSolidityAgainstCpp(0, f, u256(0), u256(6));
testSolidityAgainstCpp(0, f, u256(1), u256(3));
testSolidityAgainstCpp(0, f, u256(2), u256(25));
testSolidityAgainstCpp(0, f, u256(3), u256(69));
testSolidityAgainstCpp(0, f, u256(4), u256(84));
testSolidityAgainstCpp(0, f, u256(5), u256(2));
testSolidityAgainstCpp(0, f, u256(6), u256(51));
testSolidityAgainstCpp(0, f, u256(7), u256(48));
}
BOOST_AUTO_TEST_CASE(simple_mapping)
{
char const* sourceCode = "contract test {\n"

10
test/SolidityNameAndTypeResolution.cpp

@ -311,6 +311,16 @@ BOOST_AUTO_TEST_CASE(forward_function_reference)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
{
char const* text = "contract First {\n"
" function fun() returns (bool ret) {\n"
" return 1 & 2 == 8 & 9 && 1 ^ 2 < 4 | 6;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_SUITE_END()
}

2
test/SolidityParser.cpp

@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(empty_function)
{
char const* text = "contract test {\n"
" uint256 stateVar;\n"
" function functionName(hash160 arg1, address addr) const\n"
" function functionName(hash160 arg1, address addr) constant\n"
" returns (int id)\n"
" { }\n"
"}\n";

19
test/TestHelper.cpp

@ -26,6 +26,7 @@
#include <boost/filesystem/path.hpp>
#include <libethereum/Client.h>
#include <liblll/Compiler.h>
#include <libevm/VMFactory.h>
using namespace std;
using namespace dev::eth;
@ -330,7 +331,7 @@ void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore,
}
}
BOOST_CHECK_EQUAL(_resultStore.size(), _expectedStore.size());
for (auto&& resultStorePair : _resultStore)
for (auto&& resultStorePair: _resultStore)
{
if (!_expectedStore.count(resultStorePair.first))
BOOST_ERROR(_expectedAddr << ": unexpected store key " << resultStorePair.first);
@ -472,4 +473,20 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
}
}
void processCommandLineOptions()
{
auto argc = boost::unit_test::framework::master_test_suite().argc;
auto argv = boost::unit_test::framework::master_test_suite().argv;
for (auto i = 0; i < argc; ++i)
{
if (std::string(argv[i]) == "--jit")
{
eth::VMFactory::setKind(eth::VMKind::JIT);
break;
}
}
}
} } // namespaces

1
test/TestHelper.h

@ -76,6 +76,7 @@ void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs);
void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests);
std::string getTestPath();
void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests);
void processCommandLineOptions();
template<typename mapType>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)

22
test/createRandomTest.cpp

@ -1,18 +1,18 @@
/*
This file is part of cpp-ethereum.
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 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.
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/>.
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 createRandomTest.cpp
* @author Christoph Jentzsch <jentzsch.simulationsoftware@gmail.com>

5
test/jsonrpc.cpp

@ -19,6 +19,9 @@
* @date 2014
*/
// @debris disabled as tests fail with:
// unknown location(0): fatal error in "jsonrpc_setMining": std::exception: Exception -32003 : Client connector error: : libcurl error: 28
// /home/gav/Eth/cpp-ethereum/test/jsonrpc.cpp(169): last checkpoint
#if ETH_JSONRPC && 0
#include <boost/test/unit_test.hpp>
@ -29,7 +32,7 @@
#include <libwebthree/WebThree.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <libweb3jsonrpc/CorsHttpServer.h>
#include <json/json.h>
//#include <json/json.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#include <set>

2
test/solidityExecutionFramework.h

@ -117,7 +117,7 @@ private:
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0)
{
m_state.addBalance(m_sender, _value); // just in case
eth::Executive executive(m_state, 0);
eth::Executive executive(m_state, eth::LastHashes(), 0);
eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
: eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
bytes transactionRLP = t.rlp();

205
test/stInitCodeTestFiller.json

@ -92,6 +92,36 @@
"value" : "1"
}
},
"StackUnderFlowContractCreation" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x6000f1",
"gasLimit" : "1000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "",
"value" : "0"
}
},
"TransactionSuicideInitCode" : {
"env" : {
@ -262,11 +292,11 @@
}
},
"CallTheContractToCreateContractWithInitCode" : {
"CallContractToCreateContractWhichWouldCreateContractInInitCode" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
@ -274,14 +304,15 @@
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "10000",
"balance": "1",
"nonce": 0,
"code": "{[[ 2 ]](ADDRESS)(CODECOPY 0 0 32)(CREATE 0 0 32)}",
"//": "{[[0]] 12 (CREATE 0 64 32)}",
"code": "{(MSTORE 0 0x600c600055602060406000f0)(CREATE 0 20 12)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
@ -291,12 +322,172 @@
"transaction" :
{
"data" : "0x00",
"gasLimit" : "10000",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1"
"value" : "0"
}
},
"CallContractToCreateContractWhichWouldCreateContractIfCalled" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 500 (SLOAD 0) 1 0 0 0 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"CallContractToCreateContractOOG" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "0",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 0 0 0 0 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"CallContractToCreateContractAndCallItOOG" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 1 0 0 0 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
},
"CallContractToCreateContractNoCash" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000",
"nonce": 0,
"//": "(CREATE 0 64 32)",
"//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}",
"code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1001 11 21)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "0x00",
"gasLimit" : "20000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0"
}
}
}

163
test/stRefundTestFiller.json

@ -141,5 +141,168 @@
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund50_1" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 }",
"storage" : {
"0x01" : "0x01",
"0x02" : "0x01",
"0x03" : "0x01",
"0x04" : "0x01",
"0x05" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund50_2" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 10 ]] 1 [[ 11 ]] 1 [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 }",
"storage" : {
"0x01" : "0x01",
"0x02" : "0x01",
"0x03" : "0x01",
"0x04" : "0x01",
"0x05" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund500" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ @@1 @@2 [[ 10 ]] (EXP 2 0xff) [[ 11 ]] (BALANCE (ADDRESS)) [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 [[ 6 ]] 0 }",
"storage" : {
"0x01" : "0x01",
"0x02" : "0x01",
"0x03" : "0x01",
"0x04" : "0x01",
"0x05" : "0x01",
"0x06" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund600" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ @@1 @@2 [[ 10 ]] (EXP 2 0xffff) [[ 11 ]] (BALANCE (ADDRESS)) [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 [[ 6 ]] 0 }",
"storage" : {
"0x01" : "0x01",
"0x02" : "0x01",
"0x03" : "0x01",
"0x04" : "0x01",
"0x05" : "0x01",
"0x06" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
}
}

102
test/stSystemOperationsTestFiller.json

@ -1410,5 +1410,107 @@
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"callValue": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[0]] (CALLVALUE) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"currentAccountBalance": {
"env": {
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber": "0",
"currentGasLimit": "10000000",
"currentDifficulty": "256",
"currentTimestamp": 1,
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre": {
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "{ [[0]] (balance (address)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "",
"storage": {}
}
},
"transaction": {
"nonce": "0",
"gasPrice": "1",
"gasLimit": "10000000",
"to": "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value": "100000",
"secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data": ""
}
},
"callerAccountBalance": {
"env": {
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber": "0",
"currentGasLimit": "10000000",
"currentDifficulty": "256",
"currentTimestamp": 1,
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre": {
"095e7baea6a6c7c4c2dfeb977efac326af552d87": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "{ [[0]] (balance (caller)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "1000000000000000000",
"nonce": 0,
"code": "",
"storage": {}
}
},
"transaction": {
"nonce": "0",
"gasPrice": "1",
"gasLimit": "10000000",
"to": "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value": "100000",
"secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data": ""
}
}
}

137
test/stTransactionTestFiller.json

@ -187,5 +187,140 @@
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "502"
}
}
},
"ContractStoreClearsSuccess" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "10000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "7000",
"code" : "",
"nonce" : "0",
"storage" : {
}
},
"d2571607e241ecf590ed94b12d87c94babe36db6" : {
"balance" : "0",
"code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 0)}",
"nonce" : "0",
"storage" : {
"0x" : "0x0c",
"0x01" : "0x0c",
"0x02" : "0x0c",
"0x03" : "0x0c",
"0x04" : "0x0c",
"0x05" : "0x0c",
"0x06" : "0x0c",
"0x07" : "0x0c",
"0x08" : "0x0c",
"0x09" : "0x0c"
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "600",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
"value" : "10"
}
},
"ContractStoreClearsOOG" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "10000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "7000",
"code" : "",
"nonce" : "0",
"storage" : {
}
},
"d2571607e241ecf590ed94b12d87c94babe36db6" : {
"balance" : "0",
"code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 12)}",
"nonce" : "0",
"storage" : {
"0x" : "0x0c",
"0x01" : "0x0c",
"0x02" : "0x0c",
"0x03" : "0x0c",
"0x04" : "0x0c",
"0x05" : "0x0c",
"0x06" : "0x0c",
"0x07" : "0x0c",
"0x08" : "0x0c",
"0x09" : "0x0c"
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "600",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
"value" : "10"
}
},
"TransactionTooManyRlpElements" : {
"env" : {
"currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "10000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "600",
"gasLimit" : "1600",
"gasPrice" : "1",
"gasPrice" : "12",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d9",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "d2571607e241ecf590ed94b12d87c94babe36db6",
"value" : "10"
}
},
}

4
test/state.cpp

@ -43,6 +43,8 @@ namespace dev { namespace test {
void doStateTests(json_spirit::mValue& v, bool _fillin)
{
processCommandLineOptions();
for (auto& i: v.get_obj())
{
cerr << i.first << endl;
@ -60,7 +62,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
try
{
theState.execute(tx, &output);
theState.execute(LastHashes(), tx, &output);
}
catch (Exception const& _e)
{

2
test/stateOriginal.cpp

@ -69,7 +69,7 @@ int stateTest()
assert(t.sender() == myMiner.address());
tx = t.rlp();
}
s.execute(tx);
s.execute(bc, tx);
cout << s;

26
test/vm.cpp

@ -20,6 +20,7 @@
* vm test functions.
*/
#include <chrono>
#include <boost/filesystem.hpp>
#include <libethereum/Executive.h>
#include <libevm/VMFactory.h>
@ -32,7 +33,7 @@ using namespace dev::eth;
using namespace dev::test;
FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix.
ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {}
ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, LastHashes(), _depth) {}
h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&)
{
@ -308,6 +309,8 @@ namespace dev { namespace test {
void doVMTests(json_spirit::mValue& v, bool _fillin)
{
processCommandLineOptions();
for (auto& i: v.get_obj())
{
cnote << i.first;
@ -317,7 +320,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
BOOST_REQUIRE(o.count("pre") > 0);
BOOST_REQUIRE(o.count("exec") > 0);
dev::test::FakeExtVM fev;
FakeExtVM fev;
fev.importEnv(o["env"].get_obj());
fev.importState(o["pre"].get_obj());
@ -332,12 +335,12 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
}
bytes output;
auto vm = eth::VMFactory::create(fev.gas);
u256 gas;
bool vmExceptionOccured = false;
auto startTime = std::chrono::high_resolution_clock::now();
try
{
auto vm = eth::VMFactory::create(fev.gas);
output = vm->go(fev, fev.simpleTrace()).toBytes();
gas = vm->gas();
}
@ -357,6 +360,21 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
BOOST_ERROR("Failed VM Test with Exception: " << _e.what());
}
auto endTime = std::chrono::high_resolution_clock::now();
auto argc = boost::unit_test::framework::master_test_suite().argc;
auto argv = boost::unit_test::framework::master_test_suite().argv;
for (auto i = 0; i < argc; ++i)
{
if (std::string(argv[i]) == "--show-times")
{
auto testDuration = endTime - startTime;
cnote << "Execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(testDuration).count()
<< " ms";
break;
}
}
// delete null entries in storage for the sake of comparison
for (auto &a: fev.addresses)

Loading…
Cancel
Save