Ethereum  PoC-8
The C++ Implementation of Ethereum
Account.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 */
22 #include "Account.h"
23 #include "SecureTrieDB.h"
24 #include "ValidationSchemes.h"
25 #include <libdevcore/JsonUtils.h>
26 #include <libdevcore/OverlayDB.h>
28 #include <libethcore/Precompiled.h>
29 
30 using namespace std;
31 using namespace dev;
32 using namespace dev::eth;
33 using namespace dev::eth::validation;
34 
35 namespace fs = boost::filesystem;
36 
37 void Account::setCode(bytes&& _code)
38 {
39  m_codeCache = std::move(_code);
40  m_hasNewCode = true;
41  m_codeHash = sha3(m_codeCache);
42 }
43 
44 u256 Account::originalStorageValue(u256 const& _key, OverlayDB const& _db) const
45 {
46  auto it = m_storageOriginal.find(_key);
47  if (it != m_storageOriginal.end())
48  return it->second;
49 
50  // Not in the original values cache - go to the DB.
51  SecureTrieDB<h256, OverlayDB> const memdb(const_cast<OverlayDB*>(&_db), m_storageRoot);
52  std::string const payload = memdb.at(_key);
53  auto const value = payload.size() ? RLP(payload).toInt<u256>() : 0;
54  m_storageOriginal[_key] = value;
55  return value;
56 }
57 
58 namespace js = json_spirit;
59 
60 namespace
61 {
62 
63 uint64_t toUnsigned(js::mValue const& _v)
64 {
65  switch (_v.type())
66  {
67  case js::int_type: return _v.get_uint64();
68  case js::str_type: return fromBigEndian<uint64_t>(fromHex(_v.get_str()));
69  default: return 0;
70  }
71 }
72 
73 PrecompiledContract createPrecompiledContract(js::mObject const& _precompiled)
74 {
75  auto n = _precompiled.at("name").get_str();
76  try
77  {
78  u256 startingBlock = 0;
79  if (_precompiled.count("startingBlock"))
80  startingBlock = u256(_precompiled.at("startingBlock").get_str());
81 
82  if (!_precompiled.count("linear"))
83  return PrecompiledContract(PrecompiledRegistrar::pricer(n), PrecompiledRegistrar::executor(n), startingBlock);
84 
85  auto const& l = _precompiled.at("linear").get_obj();
86  unsigned base = toUnsigned(l.at("base"));
87  unsigned word = toUnsigned(l.at("word"));
88  return PrecompiledContract(base, word, PrecompiledRegistrar::executor(n), startingBlock);
89  }
90  catch (PricerNotFound const&)
91  {
92  cwarn << "Couldn't create a precompiled contract account. Missing a pricer called:" << n;
93  throw;
94  }
95  catch (ExecutorNotFound const&)
96  {
97  // Oh dear - missing a plugin?
98  cwarn << "Couldn't create a precompiled contract account. Missing an executor called:" << n;
99  throw;
100  }
101 }
102 }
103 
104 // TODO move AccountMaskObj to libtesteth (it is used only in test logic)
105 AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _defaultNonce,
106  AccountMaskMap* o_mask, PrecompiledContractMap* o_precompiled, const fs::path& _configPath)
107 {
108  auto u256Safe = [](std::string const& s) -> u256 {
109  bigint ret(s);
110  if (ret >= bigint(1) << 256)
111  BOOST_THROW_EXCEPTION(
112  ValueTooLarge() << errinfo_comment("State value is equal or greater than 2**256"));
113  return (u256)ret;
114  };
115 
116  std::unordered_map<Address, Account> ret;
117 
118  js::mValue val;
119  json_spirit::read_string_or_throw(_json, val);
120 
121  for (auto const& account : val.get_obj())
122  {
123  Address a(fromHex(account.first));
124  auto const& accountMaskJson = account.second.get_obj();
125 
126  bool haveBalance = (accountMaskJson.count(c_wei) || accountMaskJson.count(c_finney) ||
127  accountMaskJson.count(c_balance));
128  bool haveNonce = accountMaskJson.count(c_nonce);
129  bool haveCode = accountMaskJson.count(c_code) || accountMaskJson.count(c_codeFromFile);
130  bool haveStorage = accountMaskJson.count(c_storage);
131  bool shouldNotExists = accountMaskJson.count(c_shouldnotexist);
132 
133  if (haveStorage || haveCode || haveNonce || haveBalance)
134  {
135  u256 balance = 0;
136  if (accountMaskJson.count(c_wei))
137  balance = u256Safe(accountMaskJson.at(c_wei).get_str());
138  else if (accountMaskJson.count(c_finney))
139  balance = u256Safe(accountMaskJson.at(c_finney).get_str()) * finney;
140  else if (accountMaskJson.count(c_balance))
141  balance = u256Safe(accountMaskJson.at(c_balance).get_str());
142 
143  u256 nonce =
144  haveNonce ? u256Safe(accountMaskJson.at(c_nonce).get_str()) : _defaultNonce;
145 
146  ret[a] = Account(nonce, balance);
147  auto codeIt = accountMaskJson.find(c_code);
148  if (codeIt != accountMaskJson.end())
149  {
150  auto& codeObj = codeIt->second;
151  if (codeObj.type() == json_spirit::str_type)
152  {
153  auto& codeStr = codeObj.get_str();
154  if (codeStr.find("0x") != 0 && !codeStr.empty())
155  cerr << "Error importing code of account " << a
156  << "! Code needs to be hex bytecode prefixed by \"0x\".";
157  else
158  ret[a].setCode(fromHex(codeStr));
159  }
160  else
161  cerr << "Error importing code of account " << a
162  << "! Code field needs to be a string";
163  }
164 
165  auto codePathIt = accountMaskJson.find(c_codeFromFile);
166  if (codePathIt != accountMaskJson.end())
167  {
168  auto& codePathObj = codePathIt->second;
169  if (codePathObj.type() == json_spirit::str_type)
170  {
171  fs::path codePath{codePathObj.get_str()};
172  if (codePath.is_relative()) // Append config dir if code file path is relative.
173  codePath = _configPath.parent_path() / codePath;
174  bytes code = contents(codePath);
175  if (code.empty())
176  cerr << "Error importing code of account " << a << "! Code file "
177  << codePath << " empty or does not exist.\n";
178  ret[a].setCode(std::move(code));
179  }
180  else
181  cerr << "Error importing code of account " << a
182  << "! Code file path must be a string\n";
183  }
184 
185  if (haveStorage)
186  for (pair<string, js::mValue> const& j : accountMaskJson.at(c_storage).get_obj())
187  ret[a].setStorage(u256(j.first), u256(j.second.get_str()));
188  }
189 
190  if (o_mask)
191  {
192  (*o_mask)[a] =
193  AccountMask(haveBalance, haveNonce, haveCode, haveStorage, shouldNotExists);
194  if (!haveStorage && !haveCode && !haveNonce && !haveBalance &&
195  shouldNotExists) // defined only shouldNotExists field
196  ret[a] = Account(0, 0);
197  }
198 
199  if (o_precompiled && accountMaskJson.count(c_precompiled))
200  {
201  js::mObject p = accountMaskJson.at(c_precompiled).get_obj();
202  o_precompiled->insert(make_pair(a, createPrecompiledContract(p)));
203  }
204  }
205 
206  return ret;
207 }
dev::eth::AccountMask
Definition: Account.h:229
dev::eth::validation::c_finney
string const c_finney
Definition: ValidationSchemes.cpp:36
dev::contents
bytes contents(boost::filesystem::path const &_file)
Definition: CommonIO.cpp:107
dev::eth::validation
Definition: ValidationSchemes.cpp:29
dev::eth::validation::c_codeFromFile
string const c_codeFromFile
A file containg a code as bytes.
Definition: ValidationSchemes.cpp:50
dev::eth::PrecompiledContract
Definition: ChainOperationParams.h:36
dev::sha3
bool sha3(bytesConstRef _input, bytesRef o_output) noexcept
Definition: SHA3.cpp:28
dev::eth::validation::c_wei
string const c_wei
Definition: ValidationSchemes.cpp:35
dev::eth::validation::c_storage
string const c_storage
Definition: ValidationSchemes.cpp:48
dev::eth::AccountMap
std::unordered_map< Address, Account > AccountMap
Definition: Account.h:267
dev::eth
Definition: BasicAuthority.h:32
dev::eth::AccountMaskMap
std::unordered_map< Address, AccountMask > AccountMaskMap
Definition: Account.h:268
dev::eth::validation::c_shouldnotexist
string const c_shouldnotexist
Definition: ValidationSchemes.cpp:51
ChainOperationParams.h
dev::FixedHash< 20 >
dev::eth::jsonToAccountMap
AccountMap jsonToAccountMap(std::string const &_json, u256 const &_defaultNonce=0, AccountMaskMap *o_mask=nullptr, PrecompiledContractMap *o_precompiled=nullptr, const boost::filesystem::path &_configPath={})
dev::eth::validation::c_nonce
string const c_nonce
Definition: ValidationSchemes.cpp:39
ValidationSchemes.h
dev::bytes
std::vector< byte > bytes
Definition: Common.h:72
dev::eth::validation::c_balance
string const c_balance
Definition: ValidationSchemes.cpp:34
JsonUtils.h
dev::eth::validation::c_precompiled
string const c_precompiled
Definition: ValidationSchemes.cpp:46
dev::OverlayDB
Definition: OverlayDB.h:34
SecureTrieDB.h
Precompiled.h
dev::bigint
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<> > bigint
Definition: Common.h:118
dev::SpecificTrieDB::at
std::string at(KeyType _k) const
Definition: TrieDB.h:329
OverlayDB.h
std
Definition: FixedHash.h:393
dev::u256
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u256
Definition: Common.h:121
dev::RLP::toInt
_T toInt(int _flags=Strict) const
Converts to int of type given; if isData(), decodes as big-endian bytestream.
Definition: RLP.h:257
dev
Definition: Address.cpp:21
dev::eth::validation::c_code
string const c_code
Definition: ValidationSchemes.cpp:47
cwarn
#define cwarn
Account.h
dev::RLP
Definition: RLP.h:48
dev::SpecificTrieDB
Definition: TrieDB.h:318
dev::fromHex
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:81
dev::eth::Account
Definition: Account.h:57
dev::errinfo_comment
boost::error_info< struct tag_comment, std::string > errinfo_comment
Definition: Assertions.h:69
dev::eth::PrecompiledContractMap
std::unordered_map< Address, PrecompiledContract > PrecompiledContractMap
Definition: Account.h:271