Ethereum  PoC-8
The C++ Implementation of Ethereum
VMFactory.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "VMFactory.h"
19 #include "EVMC.h"
20 #include "LegacyVM.h"
21 
22 #include <libaleth-interpreter/interpreter.h>
23 
24 #include <evmc/loader.h>
25 
26 namespace po = boost::program_options;
27 
28 namespace dev
29 {
30 namespace eth
31 {
32 namespace
33 {
34 auto g_kind = VMKind::Legacy;
35 
40 std::unique_ptr<EVMC> g_evmcDll;
41 
46 struct VMKindTableEntry
47 {
49  const char* name;
50 };
51 
56 VMKindTableEntry vmKindsTable[] = {
57  {VMKind::Interpreter, "interpreter"},
58  {VMKind::Legacy, "legacy"},
59 };
60 
61 void setVMKind(const std::string& _name)
62 {
63  for (auto& entry : vmKindsTable)
64  {
65  // Try to find a match in the table of VMs.
66  if (_name == entry.name)
67  {
68  g_kind = entry.kind;
69  return;
70  }
71  }
72 
73  // If no match for predefined VM names, try loading it as an EVMC VM DLL.
75 
76  // Release previous instance
77  g_evmcDll.reset();
78 
79  evmc_loader_error_code ec;
80  evmc_instance *instance = evmc_load_and_create(_name.c_str(), &ec);
81  assert(ec == EVMC_LOADER_SUCCESS || instance == nullptr);
82 
83  switch (ec)
84  {
85  case EVMC_LOADER_SUCCESS:
86  break;
87  case EVMC_LOADER_CANNOT_OPEN:
88  BOOST_THROW_EXCEPTION(
89  po::validation_error(po::validation_error::invalid_option_value, "vm", _name, 1));
90  case EVMC_LOADER_SYMBOL_NOT_FOUND:
91  BOOST_THROW_EXCEPTION(std::system_error(std::make_error_code(std::errc::invalid_seek),
92  "loading " + _name + " failed: EVMC create function not found"));
93  case EVMC_LOADER_ABI_VERSION_MISMATCH:
94  BOOST_THROW_EXCEPTION(std::system_error(std::make_error_code(std::errc::invalid_argument),
95  "loading " + _name + " failed: EVMC ABI version mismatch"));
96  default:
97  BOOST_THROW_EXCEPTION(
98  std::system_error(std::error_code(static_cast<int>(ec), std::generic_category()),
99  "loading " + _name + " failed"));
100  }
101 
102  g_evmcDll.reset(new EVMC{instance});
103 
104  cnote << "Loaded EVMC module: " << g_evmcDll->name() << " " << g_evmcDll->version() << " ("
105  << _name << ")";
106 }
107 } // namespace
108 
109 namespace
110 {
113 const char c_evmcPrefix[] = "evmc ";
114 
116 std::vector<std::pair<std::string, std::string>> s_evmcOptions;
117 
122 void parseEvmcOptions(const std::vector<std::string>& _opts)
123 {
124  for (auto& s : _opts)
125  {
126  auto separatorPos = s.find('=');
127  if (separatorPos == s.npos)
128  throw po::invalid_syntax{po::invalid_syntax::missing_parameter, c_evmcPrefix + s};
129  auto name = s.substr(0, separatorPos);
130  auto value = s.substr(separatorPos + 1);
131  s_evmcOptions.emplace_back(std::move(name), std::move(value));
132  }
133 }
134 } // namespace
135 
136 std::vector<std::pair<std::string, std::string>>& evmcOptions() noexcept
137 {
138  return s_evmcOptions;
139 };
140 
141 po::options_description vmProgramOptions(unsigned _lineLength)
142 {
143  // It must be a static object because boost expects const char*.
144  static const std::string description = [] {
145  std::string names;
146  for (auto& entry : vmKindsTable)
147  {
148  if (!names.empty())
149  names += ", ";
150  names += entry.name;
151  }
152 
153  return "Select VM implementation. Available options are: " + names + ".";
154  }();
155 
156  po::options_description opts("VM OPTIONS", _lineLength);
157  auto add = opts.add_options();
158 
159  add("vm",
160  po::value<std::string>()
161  ->value_name("<name>|<path>")
162  ->default_value("legacy")
163  ->notifier(setVMKind),
164  description.data());
165 
166  add(c_evmcPrefix,
167  po::value<std::vector<std::string>>()
168  ->multitoken()
169  ->value_name("<option>=<value>")
170  ->notifier(parseEvmcOptions),
171  "EVMC option\n");
172 
173  return opts;
174 }
175 
176 
178 {
179  return create(g_kind);
180 }
181 
183 {
184  static const auto default_delete = [](VMFace * _vm) noexcept { delete _vm; };
185  static const auto null_delete = [](VMFace*) noexcept {};
186 
187  switch (_kind)
188  {
189  case VMKind::Interpreter:
190  return {new EVMC{evmc_create_interpreter()}, default_delete};
191  case VMKind::DLL:
192  assert(g_evmcDll != nullptr);
193  // Return "fake" owning pointer to global EVMC DLL VM.
194  return {g_evmcDll.get(), null_delete};
195  case VMKind::Legacy:
196  default:
197  return {new LegacyVM, default_delete};
198  }
199 }
200 } // namespace eth
201 } // namespace dev
dev::eth::EVMC
The wrapper implementing the VMFace interface with a EVMC VM as a backend.
Definition: EVMC.h:17
EVMC.h
dev::eth::VMFactory::create
static VMPtr create()
Creates a VM instance of the global kind (controlled by the –vm command line option).
Definition: VMFactory.cpp:177
dev::eth::VMPtr
std::unique_ptr< VMFace, void(*)(VMFace *)> VMPtr
Definition: VMFactory.h:44
dev::eth::VMFace
EVM Virtual Machine interface.
Definition: VMFace.h:64
cnote
#define cnote
dev::eth::LegacyVM
Definition: LegacyVM.h:30
dev::eth::VMKind::Interpreter
@ Interpreter
dev::eth::VMKind::DLL
@ DLL
VMFactory.h
kind
VMKind kind
Definition: VMFactory.cpp:48
name
const char * name
Definition: VMFactory.cpp:49
dev::eth::VMKind::Legacy
@ Legacy
dev::eth::evmcOptions
std::vector< std::pair< std::string, std::string > > & evmcOptions() noexcept
Returns the EVMC options parsed from command line.
Definition: VMFactory.cpp:136
LegacyVM.h
dev::eth::VMKind
VMKind
Definition: VMFactory.h:28
dev
Definition: Address.cpp:21
dev::eth::vmProgramOptions
po::options_description vmProgramOptions(unsigned _lineLength)
Definition: VMFactory.cpp:141
dev::db::g_kind
auto g_kind
Definition: DBFactory.cpp:32