Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
Merge pull request #5030 from ethereum/smallrpc
Browse files Browse the repository at this point in the history
explicit chainParams check
  • Loading branch information
winsvega authored Jun 15, 2018
2 parents a3f2afe + 5549af4 commit b859d94
Show file tree
Hide file tree
Showing 11 changed files with 446 additions and 201 deletions.
2 changes: 2 additions & 0 deletions libdevcore/Exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ DEV_SIMPLE_EXCEPTION(Overflow);
DEV_SIMPLE_EXCEPTION(FailedInvariant);
DEV_SIMPLE_EXCEPTION(ValueTooLarge);
DEV_SIMPLE_EXCEPTION(UnknownField);
DEV_SIMPLE_EXCEPTION(MissingField);
DEV_SIMPLE_EXCEPTION(WrongFieldType);
DEV_SIMPLE_EXCEPTION(InterfaceNotSupported);
DEV_SIMPLE_EXCEPTION(ExternalFunctionFailure);

Expand Down
85 changes: 83 additions & 2 deletions libdevcore/JsonUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/

#include <libdevcore/JsonUtils.h>
#include <json_spirit/JsonSpiritHeaders.h>
#include <libdevcore/JsonUtils.h>
#include <boost/algorithm/string/join.hpp>
#include <ostream>
#include <set>
#include <string>
#include <ostream>

void dev::validateFieldNames(json_spirit::mObject const& _obj, std::set<std::string> const& _allowedFields)
{
Expand All @@ -31,3 +32,83 @@ void dev::validateFieldNames(json_spirit::mObject const& _obj, std::set<std::str
BOOST_THROW_EXCEPTION(UnknownField() << errinfo_comment(comment));
}
}

std::string dev::jsonTypeAsString(json_spirit::Value_type _type)
{
switch (_type)
{
case json_spirit::obj_type:
return "json Object";
case json_spirit::array_type:
return "json Array";
case json_spirit::str_type:
return "json String";
case json_spirit::bool_type:
return "json Bool";
case json_spirit::int_type:
return "json Int";
case json_spirit::real_type:
return "json Real";
case json_spirit::null_type:
return "json Null";
default:
return "json n/a";
}
}

void dev::requireJsonFields(json_spirit::mObject const& _o, std::string const& _config,
std::map<std::string, JsonFieldOptions> const& _validationMap)
{
// check for unexpected fiedls
for (auto const& field : _o)
{
if (!_validationMap.count(field.first))
{
std::string const comment =
"Unexpected field '" + field.first + "' in config: " + _config;
std::cerr << comment << "\n"
<< json_spirit::write_string((json_spirit::mValue)_o, true) << "\n";
BOOST_THROW_EXCEPTION(UnknownField() << errinfo_comment(comment));
}
}

// check field types with validation map
for (auto const vmap : _validationMap)
{
auto const& expectedFieldName = vmap.first;
auto const& expectedFieldPresence = vmap.second.second;
// check that all required fields are in the object
if (!_o.count(expectedFieldName))
{
if (expectedFieldPresence == JsonFieldPresence::Required)
{
std::string const comment =
"Expected field '" + expectedFieldName + "' not found in config: " + _config;
std::cerr << comment << "\n"
<< json_spirit::write_string((json_spirit::mValue)_o, true) << "\n";
BOOST_THROW_EXCEPTION(MissingField() << errinfo_comment(comment));
}
else if (expectedFieldPresence == JsonFieldPresence::Optional)
continue;
}

// check that field type is one of allowed field types
auto const& expectedFieldTypes = vmap.second.first;
bool matched = expectedFieldTypes.count(_o.at(expectedFieldName).type());
if (matched == false)
{
std::vector<std::string> types;
for (auto const& type : expectedFieldTypes)
types.push_back(jsonTypeAsString(type));
std::string sTypes = boost::algorithm::join(types, " or ");

std::string const comment = "Field '" + expectedFieldName + "' is expected to be " +
sTypes + ", but is set to " +
jsonTypeAsString(_o.at(expectedFieldName).type()) + " in " +
_config;
std::cerr << comment << "\n"
<< json_spirit::write_string((json_spirit::mValue)_o, true) << "\n";
BOOST_THROW_EXCEPTION(WrongFieldType() << errinfo_comment(comment));
}
}
}
21 changes: 21 additions & 0 deletions libdevcore/JsonUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,25 @@ namespace dev
{
// Throws UnknownField() if _obj contains field names not listed in _allowedFields.
void validateFieldNames(json_spirit::mObject const& _obj, std::set<std::string> const& _allowedFields);

// Converts json value type to string
std::string jsonTypeAsString(json_spirit::Value_type _type);

enum class JsonFieldPresence
{
Required,
Optional
};
using JsonTypeSet = std::set<json_spirit::Value_type>;
using JsonFieldOptions = std::pair<JsonTypeSet, JsonFieldPresence>;
/// Check the json object with validation map that reuires certain field of certain type to be
/// present in json
/**
@param _o a json object to check
@param _configName a string with json object name. Will apper in error message.
@param _validationMap a map with json objects that would be checked. "objName" -> {js::str_type,
jsonField::Required}
*/
void requireJsonFields(json_spirit::mObject const& _o, std::string const& _configName,
std::map<std::string, JsonFieldOptions> const& _validationMap);
}
168 changes: 76 additions & 92 deletions libethereum/Account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
*/

#include "Account.h"
#include "ValidationSchemes.h"
#include <libdevcore/JsonUtils.h>
#include <libethcore/ChainOperationParams.h>
#include <libethcore/Precompiled.h>

using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::eth::validation;

namespace fs = boost::filesystem;

Expand All @@ -52,22 +54,22 @@ uint64_t toUnsigned(js::mValue const& _v)
}
}

PrecompiledContract createPrecompiledContract(js::mObject& _precompiled)
PrecompiledContract createPrecompiledContract(js::mObject const& _precompiled)
{
auto n = _precompiled["name"].get_str();
try
auto n = _precompiled.at("name").get_str();
try
{
u256 startingBlock = 0;
if (_precompiled.count("startingBlock"))
startingBlock = u256(_precompiled["startingBlock"].get_str());
startingBlock = u256(_precompiled.at("startingBlock").get_str());

if (!_precompiled.count("linear"))
if (!_precompiled.count("linear"))
return PrecompiledContract(PrecompiledRegistrar::pricer(n), PrecompiledRegistrar::executor(n), startingBlock);

auto l = _precompiled["linear"].get_obj();
unsigned base = toUnsigned(l["base"]);
unsigned word = toUnsigned(l["word"]);
return PrecompiledContract(base, word, PrecompiledRegistrar::executor(n), startingBlock);
auto const& l = _precompiled.at("linear").get_obj();
unsigned base = toUnsigned(l.at("base"));
unsigned word = toUnsigned(l.at("word"));
return PrecompiledContract(base, word, PrecompiledRegistrar::executor(n), startingBlock);
}
catch (PricerNotFound const&)
{
Expand All @@ -81,72 +83,53 @@ PrecompiledContract createPrecompiledContract(js::mObject& _precompiled)
throw;
}
}

}
namespace
{
string const c_wei = "wei";
string const c_finney = "finney";
string const c_balance = "balance";
string const c_nonce = "nonce";
string const c_code = "code";
string const c_codeFromFile = "codeFromFile"; ///< A file containg a code as bytes.
string const c_storage = "storage";
string const c_shouldnotexist = "shouldnotexist";
string const c_precompiled = "precompiled";
std::set<string> const c_knownAccountFields = {
c_wei, c_finney, c_balance, c_nonce, c_code, c_codeFromFile, c_storage, c_shouldnotexist,
c_code, c_precompiled
};
void validateAccountMapObj(js::mObject const& _o)
{
for (auto const& field: _o)
validateFieldNames(field.second.get_obj(), c_knownAccountFields);
}
}

// TODO move AccountMaskObj to libtesteth (it is used only in test logic)
AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _defaultNonce,
AccountMaskMap* o_mask, PrecompiledContractMap* o_precompiled, const fs::path& _configPath)
{
auto u256Safe = [](std::string const& s) -> u256 {
bigint ret(s);
if (ret >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State value is equal or greater than 2**256") );
return (u256)ret;
};

std::unordered_map<Address, Account> ret;

js::mValue val;
json_spirit::read_string_or_throw(_json, val);
js::mObject o = val.get_obj();
validateAccountMapObj(o);
for (auto const& account: o)
{
Address a(fromHex(account.first));
// FIXME: Do not copy every account object.
auto o = account.second.get_obj();

bool haveBalance = (o.count(c_wei) || o.count(c_finney) || o.count(c_balance));
bool haveNonce = o.count(c_nonce);
bool haveCode = o.count(c_code) || o.count(c_codeFromFile);
bool haveStorage = o.count(c_storage);
bool shouldNotExists = o.count(c_shouldnotexist);

if (haveStorage || haveCode || haveNonce || haveBalance)
{
u256 balance = 0;
if (o.count(c_wei))
balance = u256Safe(o[c_wei].get_str());
else if (o.count(c_finney))
balance = u256Safe(o[c_finney].get_str()) * finney;
else if (o.count(c_balance))
balance = u256Safe(o[c_balance].get_str());

u256 nonce = haveNonce ? u256Safe(o[c_nonce].get_str()) : _defaultNonce;
auto u256Safe = [](std::string const& s) -> u256 {
bigint ret(s);
if (ret >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(
ValueTooLarge() << errinfo_comment("State value is equal or greater than 2**256"));
return (u256)ret;
};

std::unordered_map<Address, Account> ret;

js::mValue val;
json_spirit::read_string_or_throw(_json, val);

for (auto const& account : val.get_obj())
{
Address a(fromHex(account.first));
auto const& accountMaskJson = account.second.get_obj();

bool haveBalance = (accountMaskJson.count(c_wei) || accountMaskJson.count(c_finney) ||
accountMaskJson.count(c_balance));
bool haveNonce = accountMaskJson.count(c_nonce);
bool haveCode = accountMaskJson.count(c_code) || accountMaskJson.count(c_codeFromFile);
bool haveStorage = accountMaskJson.count(c_storage);
bool shouldNotExists = accountMaskJson.count(c_shouldnotexist);

if (haveStorage || haveCode || haveNonce || haveBalance)
{
u256 balance = 0;
if (accountMaskJson.count(c_wei))
balance = u256Safe(accountMaskJson.at(c_wei).get_str());
else if (accountMaskJson.count(c_finney))
balance = u256Safe(accountMaskJson.at(c_finney).get_str()) * finney;
else if (accountMaskJson.count(c_balance))
balance = u256Safe(accountMaskJson.at(c_balance).get_str());

u256 nonce =
haveNonce ? u256Safe(accountMaskJson.at(c_nonce).get_str()) : _defaultNonce;

ret[a] = Account(nonce, balance);
auto codeIt = o.find(c_code);
if (codeIt != o.end())
auto codeIt = accountMaskJson.find(c_code);
if (codeIt != accountMaskJson.end())
{
auto& codeObj = codeIt->second;
if (codeObj.type() == json_spirit::str_type)
Expand All @@ -163,8 +146,8 @@ AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _def
<< "! Code field needs to be a string";
}

auto codePathIt = o.find(c_codeFromFile);
if (codePathIt != o.end())
auto codePathIt = accountMaskJson.find(c_codeFromFile);
if (codePathIt != accountMaskJson.end())
{
auto& codePathObj = codePathIt->second;
if (codePathObj.type() == json_spirit::str_type)
Expand All @@ -183,25 +166,26 @@ AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _def
<< "! Code file path must be a string\n";
}


if (haveStorage)
for (pair<string, js::mValue> const& j: o[c_storage].get_obj())
ret[a].setStorage(u256(j.first), u256(j.second.get_str()));
}

if (o_mask)
{
(*o_mask)[a] = AccountMask(haveBalance, haveNonce, haveCode, haveStorage, shouldNotExists);
if (!haveStorage && !haveCode && !haveNonce && !haveBalance && shouldNotExists) //defined only shouldNotExists field
ret[a] = Account(0, 0);
}

if (o_precompiled && o.count(c_precompiled))
{
js::mObject p = o[c_precompiled].get_obj();
o_precompiled->insert(make_pair(a, createPrecompiledContract(p)));
}
}

return ret;
if (haveStorage)
for (pair<string, js::mValue> const& j : accountMaskJson.at(c_storage).get_obj())
ret[a].setStorage(u256(j.first), u256(j.second.get_str()));
}

if (o_mask)
{
(*o_mask)[a] =
AccountMask(haveBalance, haveNonce, haveCode, haveStorage, shouldNotExists);
if (!haveStorage && !haveCode && !haveNonce && !haveBalance &&
shouldNotExists) // defined only shouldNotExists field
ret[a] = Account(0, 0);
}

if (o_precompiled && accountMaskJson.count(c_precompiled))
{
js::mObject p = accountMaskJson.at(c_precompiled).get_obj();
o_precompiled->insert(make_pair(a, createPrecompiledContract(p)));
}
}

return ret;
}
Loading

0 comments on commit b859d94

Please sign in to comment.