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

Commit

Permalink
eth rpc support
Browse files Browse the repository at this point in the history
  • Loading branch information
winsvega committed May 23, 2018
1 parent 975fe5c commit 5515bfb
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 45 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
69 changes: 69 additions & 0 deletions libdevcore/JsonUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,72 @@ 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, possibleJsonType> const& _validationMap,
std::set<std::string> const& _ignoreFields)
{
// check for unexpected fiedls
for (auto const& field : _o)
{
if (!_validationMap.count(field.first) && !_ignoreFields.count(field.first))
{
std::string const comment = "Unexpected field '" + field.first + "' in config: " + _config;
std::cerr << comment << "\n";
BOOST_THROW_EXCEPTION(UnknownField() << errinfo_comment(comment));
}
}

// check field types with validation map
for (auto const vmap : _validationMap)
{
if (!_o.count(vmap.first))
{
std::string const comment = "Expected field '" + vmap.first + "' not found in config: " + _config;
std::cerr << comment << "\n";
BOOST_THROW_EXCEPTION(MissingField() << errinfo_comment(comment));
}

bool matched = false;
std::string sTypes;
for(auto const& type: vmap.second)
{
if (sTypes.size())
sTypes += ", or ";
sTypes += jsonTypeAsString(type);
if (_o.at(vmap.first).type() == type)
matched = true;
}
if (matched == false)
{
std::string const comment = "Field '" + vmap.first + "' expected to be " + sTypes +
", but set to " + jsonTypeAsString(_o.at(vmap.first).type()) + " in " + _config;
std::cerr << comment << "\n";
BOOST_THROW_EXCEPTION(WrongFieldType() << errinfo_comment(comment));
}
}
}

10 changes: 10 additions & 0 deletions libdevcore/JsonUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,14 @@ 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);

// Check json _o with validation map that reuires certain field of certain type to be present in json
typedef std::set<json_spirit::Value_type> possibleJsonType;
void requireJsonFields(json_spirit::mObject const& _o, std::string const& _config,
std::map<std::string, possibleJsonType> const& _validationMap,
std::set<std::string> const& _ignoreFields = {});

}
2 changes: 2 additions & 0 deletions libdevcore/TrieDB.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ class FatGenericTrieDB: private SpecificTrieDB<GenericTrieDB<_DB>, h256>

HashedIterator() {}
HashedIterator(FatGenericTrieDB const* _trie) : Super(_trie) {}
HashedIterator(FatGenericTrieDB const* _trie, bytesConstRef _hashedKey): Super(_trie, _hashedKey) {}

bytes key() const
{
Expand All @@ -490,6 +491,7 @@ class FatGenericTrieDB: private SpecificTrieDB<GenericTrieDB<_DB>, h256>

HashedIterator hashedBegin() const { return HashedIterator(this); }
HashedIterator hashedEnd() const { return HashedIterator(); }
HashedIterator hashedLowerBound(h256 const& _hashedKey) const { return HashedIterator(this, _hashedKey.ref()); }
};

template <class KeyType, class DB> using TrieDB = SpecificTrieDB<GenericTrieDB<DB>, KeyType>;
Expand Down
1 change: 1 addition & 0 deletions libethcore/ChainOperationParams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ EVMSchedule const& ChainOperationParams::scheduleForBlockNumber(u256 const& _blo

u256 ChainOperationParams::blockReward(EVMSchedule const& _schedule) const
{
return 0;
if (_schedule.blockRewardOverwrite)
return *_schedule.blockRewardOverwrite;
else
Expand Down
2 changes: 1 addition & 1 deletion libethcore/ChainOperationParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ struct ChainOperationParams

/// General chain params.
private:
u256 m_blockReward;
u256 m_blockReward = 5000000000000000000;
public:
EVMSchedule const& scheduleForBlockNumber(u256 const& _blockNumber) const;
u256 blockReward(EVMSchedule const& _schedule) const;
Expand Down
75 changes: 63 additions & 12 deletions libethereum/ChainParams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
* @date 2015
*/

#include "State.h"
#include "Account.h"
#include "GenesisInfo.h"
#include "ChainParams.h"
#include <json_spirit/JsonSpiritHeaders.h>
#include <libdevcore/Log.h>
Expand All @@ -27,9 +30,6 @@
#include <libethcore/SealEngine.h>
#include <libethcore/BlockHeader.h>
#include <libethcore/Precompiled.h>
#include "GenesisInfo.h"
#include "State.h"
#include "Account.h"
using namespace std;
using namespace dev;
using namespace eth;
Expand Down Expand Up @@ -90,6 +90,49 @@ set<string> const c_knownParamNames = {c_minGasLimit, c_maxGasLimit, c_gasLimitB
c_durationLimit, c_chainID, c_networkID, c_allowFutureBlocks};
} // anonymous namespace

void validateConfigJson(js::mObject const& _obj)
{
requireJsonFields(_obj, "ChainParams::loadConfig", {
{"sealEngine", {json_spirit::str_type} },
{"params", {json_spirit::obj_type} },
{"genesis", {json_spirit::obj_type} },
{"accounts", {json_spirit::obj_type} }
});

requireJsonFields(_obj.at("genesis").get_obj(), "ChainParams::loadConfig", {
{"author", {json_spirit::str_type} },
{"nonce", {json_spirit::str_type} },
{"author", {json_spirit::str_type} },
{"gasLimit", {json_spirit::str_type} },
{"timestamp", {json_spirit::str_type} },
{"difficulty", {json_spirit::str_type} },
{"extraData", {json_spirit::str_type} }
}, {"mixHash", "parentHash"});

js::mObject const& accounts = _obj.at("accounts").get_obj();
for (auto const& acc: accounts)
{
js::mObject const& account = acc.second.get_obj();
if (account.count("precompiled"))
{
requireJsonFields(account, "ChainParams::loadConfig", {
{"precompiled", {json_spirit::obj_type} }},
{"wei"}
);
}
else
{
if (account.count("wei"))
requireJsonFields(account, "ChainParams::loadConfig", {{"wei", {json_spirit::str_type}}});
else
{
requireJsonFields(account, "ChainParams::loadConfig",
{{"balance", {json_spirit::str_type}}}, {"code", "nonce", "storage"});
}
}
}
}

ChainParams ChainParams::loadConfig(
string const& _json, h256 const& _stateRoot, const boost::filesystem::path& _configPath) const
{
Expand All @@ -98,16 +141,23 @@ ChainParams ChainParams::loadConfig(
json_spirit::read_string_or_throw(_json, val);
js::mObject obj = val.get_obj();

validateFieldNames(obj, c_knownChainConfigFields);
validateConfigJson(obj);
validateFieldNames(obj, c_knownChainConfigFields);

// params
cp.sealEngineName = obj[c_sealEngine].get_str();
js::mObject params = obj[c_params].get_obj();
validateFieldNames(params, c_knownParamNames);

// Params that are not required and could be set to default value
if (params.count(c_accountStartNonce))
cp.accountStartNonce = u256(fromBigEndian<u256>(fromHex(params[c_accountStartNonce].get_str())));
if (params.count(c_maximumExtraDataSize)) //!!! this option does not affect actul extra data size check for some reason !!!
cp.maximumExtraDataSize = u256(fromBigEndian<u256>(fromHex(params[c_maximumExtraDataSize].get_str())));

cp.sealEngineName = obj[c_sealEngine].get_str();
// params
js::mObject params = obj[c_params].get_obj();
validateFieldNames(params, c_knownParamNames);
cp.accountStartNonce = u256(fromBigEndian<u256>(fromHex(params[c_accountStartNonce].get_str())));
cp.maximumExtraDataSize = u256(fromBigEndian<u256>(fromHex(params[c_maximumExtraDataSize].get_str())));
cp.tieBreakingGas = params.count(c_tieBreakingGas) ? params[c_tieBreakingGas].get_bool() : true;
cp.setBlockReward(u256(fromBigEndian<u256>(fromHex(params[c_blockReward].get_str()))));
if (params.count(c_blockReward))
cp.setBlockReward(u256(fromBigEndian<u256>(fromHex(params[c_blockReward].get_str()))));

auto setOptionalU256Parameter = [&params](u256 &_destination, string const& _name)
{
Expand Down Expand Up @@ -176,7 +226,8 @@ ChainParams ChainParams::loadGenesis(string const& _json, h256 const& _stateRoot

validateFieldNames(genesis, c_knownGenesisFields);

cp.parentHash = h256(genesis[c_parentHash].get_str());
if (genesis.count(c_parentHash))
cp.parentHash = h256(genesis[c_parentHash].get_str());
cp.author = genesis.count(c_coinbase) ? h160(genesis[c_coinbase].get_str()) : h160(genesis[c_author].get_str());
cp.difficulty = genesis.count(c_difficulty) ? u256(fromBigEndian<u256>(fromHex(genesis[c_difficulty].get_str()))) : 0;
cp.gasLimit = u256(fromBigEndian<u256>(fromHex(genesis[c_gasLimit].get_str())));
Expand Down
53 changes: 53 additions & 0 deletions libethereum/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ void State::commit(CommitBehaviour _commitBehaviour)
m_unchangedCacheEntries.clear();
}


unordered_map<Address, u256> State::addresses() const
{
#if ETH_FATDB
Expand All @@ -234,6 +235,58 @@ unordered_map<Address, u256> State::addresses() const
#endif
}

std::pair<State::AddressMap, h256> State::addresses(
h256 const& _beginHash, size_t _maxResults) const
{
AddressMap addresses;
h256 nextKey;

for (auto it = m_state.hashedLowerBound(_beginHash); it != m_state.hashedEnd(); ++it)
{
auto const address = Address(it.key());
auto const itCachedAddress = m_cache.find(address);

// skip if deleted in cache
if (itCachedAddress != m_cache.end() && itCachedAddress->second.isDirty() &&
!itCachedAddress->second.isAlive())
continue;

// break when _maxResults fetched
if (addresses.size() == _maxResults)
{
nextKey = h256((*it).first);
break;
}

h256 const hashedAddress((*it).first);
addresses[hashedAddress] = address;
}

// get addresses from cache with hash >= _beginHash (both new and old touched, we can't
// distinguish them) and order by hash
AddressMap cacheAddresses;
for (auto const& addressAndAccount : m_cache)
{
auto const& address = addressAndAccount.first;
auto const addressHash = sha3(address);
auto const& account = addressAndAccount.second;
if (account.isDirty() && account.isAlive() && addressHash >= _beginHash)
cacheAddresses.emplace(addressHash, address);
}

// merge addresses from DB and addresses from cache
addresses.insert(cacheAddresses.begin(), cacheAddresses.end());

// if some new accounts were created in cache we need to return fewer results
if (addresses.size() > _maxResults)
{
auto itEnd = std::next(addresses.begin(), _maxResults);
nextKey = itEnd->first;
addresses.erase(itEnd, addresses.end());
}
return {addresses, nextKey};
}

void State::setRoot(h256 const& _r)
{
m_cache.clear();
Expand Down
6 changes: 6 additions & 0 deletions libethereum/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ class State
RemoveEmptyAccounts
};

using AddressMap = std::map<h256, Address>;

/// Default constructor; creates with a blank database prepopulated with the genesis block.
explicit State(u256 const& _accountStartNonce): State(_accountStartNonce, OverlayDB(), BaseState::Empty) {}

Expand Down Expand Up @@ -207,6 +209,10 @@ class State
/// @throws InterfaceNotSupported if compiled without ETH_FATDB.
std::unordered_map<Address, u256> addresses() const;

/// @returns the map with maximum _maxResults elements containing hash->addresses and the next address hash.
/// This method faster then addresses() const;
std::pair<AddressMap, h256> addresses(h256 const& _begin, size_t _maxResults) const;

/// Execute a given transaction.
/// This will change the state accordingly.
std::pair<ExecutionResult, TransactionReceipt> execute(EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
Expand Down
37 changes: 37 additions & 0 deletions libweb3jsonrpc/Debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,43 @@ Json::Value Debug::debug_traceBlockByNumber(int _blockNumber, Json::Value const&
return ret;
}

Json::Value Debug::debug_accountRangeAt(
string const& _blockHashOrNumber, int _txIndex, string const& _addressHash, int _maxResults)
{
Json::Value ret(Json::objectValue);

if (_txIndex < 0)
throw jsonrpc::JsonRpcException("Negative index");
if (_maxResults <= 0)
throw jsonrpc::JsonRpcException("Nonpositive maxResults");

try
{
Block block = m_eth.block(blockHash(_blockHashOrNumber));
size_t const i = std::min(static_cast<size_t>(_txIndex), block.pending().size());
State state(State::Null);
// if(block.info().number() >= m_eth.chainParams().byzantiumForkBlock)
// state = block.state();
// else
createIntermediateState(state, block, i, m_eth.blockChain());
auto const addressMap = state.addresses(h256(_addressHash), _maxResults);

Json::Value addressList(Json::objectValue);
for (auto const& record: addressMap.first)
addressList[toString(record.first)] = toString(record.second);

ret["addressMap"] = addressList;
ret["nextKey"] = toString(addressMap.second);
}
catch (Exception const& _e)
{
cwarn << diagnostic_information(_e);
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS);
}

return ret;
}

Json::Value Debug::debug_storageRangeAt(string const& _blockHashOrNumber, int _txIndex, string const& _address, string const& _begin, int _maxResults)
{
Json::Value ret(Json::objectValue);
Expand Down
5 changes: 3 additions & 2 deletions libweb3jsonrpc/Debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ class Debug: public DebugFace
return RPCModules{RPCModule{"debug", "1.0"}};
}


virtual Json::Value debug_traceTransaction(std::string const& _txHash, Json::Value const& _json) override;
virtual Json::Value debug_accountRangeAt(std::string const& _blockHashOrNumber, int _txIndex,
std::string const& _addressHash, int _maxResults) override;
virtual Json::Value debug_traceTransaction(std::string const& _txHash, Json::Value const& _json) override;
virtual Json::Value debug_traceCall(Json::Value const& _call, std::string const& _blockNumber, Json::Value const& _options) override;
virtual Json::Value debug_traceBlockByNumber(int _blockNumber, Json::Value const& _json) override;
virtual Json::Value debug_traceBlockByHash(std::string const& _blockHash, Json::Value const& _json) override;
Expand Down
Loading

0 comments on commit 5515bfb

Please sign in to comment.