Ledger header RPC enhancements (RIPD-692):

This combines two enhancements to the ledger_data RPC
command and related commands.

The ledger_data RPC command will now return the ledger header
in the first query (the one with no marker specified).

Also, ledger_data and related commands will now provide the
ledger header in binary if binary output is specified.

Modified existing ledgerdata unit test to cover new functionality.
This commit is contained in:
Miguel Portilla
2016-11-21 14:31:05 -08:00
committed by Nik Bougalis
parent e00a6b0e5a
commit a7c4d682d2
6 changed files with 108 additions and 40 deletions

View File

@@ -288,7 +288,7 @@ Ledger::Ledger (Ledger const& prevLedger,
prevLedger.info_.closeTimeResolution,
getCloseAgree(prevLedger.info()), info_.seq);
if (stateMap_->get_version() == SHAMap::version{2})
if (stateMap_->is_v2())
{
info_.closeFlags |= sLCF_SHAMapV2;
}

View File

@@ -80,6 +80,21 @@ void fillJson(Object& json, bool closed, LedgerInfo const& info, bool bFull)
}
}
template <class Object>
void fillJsonBinary(Object& json, bool closed, LedgerInfo const& info)
{
if (! closed)
json[jss::closed] = false;
else
{
json[jss::closed] = true;
Serializer s;
addRaw (info, s);
json[jss::ledger_data] = strHex (s.peekData ());
}
}
template <class Object>
void fillJsonTx (Object& json, LedgerFill const& fill)
{
@@ -164,7 +179,10 @@ void fillJson (Object& json, LedgerFill const& fill)
// TODO: what happens if bBinary and bExtracted are both set?
// Is there a way to report this back?
auto bFull = isFull(fill);
fillJson(json, !fill.ledger.open(), fill.ledger.info(), bFull);
if (isBinary(fill))
fillJsonBinary(json, !fill.ledger.open(), fill.ledger.info());
else
fillJson(json, !fill.ledger.open(), fill.ledger.info(), bFull);
if (bFull || fill.options & LedgerFill::dumpTxrp)
fillJsonTx(json, fill);

View File

@@ -393,7 +393,7 @@ AmendmentTableImpl::doValidation (
}
}
if (!amendments.empty())
if (! amendments.empty())
std::sort (amendments.begin (), amendments.end ());
return amendments;
@@ -402,26 +402,8 @@ AmendmentTableImpl::doValidation (
std::vector <uint256>
AmendmentTableImpl::getDesired ()
{
// Get the list of amendments we support and do not
// veto
std::vector <uint256> amendments;
amendments.reserve (amendmentMap_.size());
{
std::lock_guard <std::mutex> sl (mutex_);
for (auto const& e : amendmentMap_)
{
if (e.second.supported && ! e.second.vetoed)
{
amendments.push_back (e.first);
}
}
}
if (!amendments.empty())
std::sort (amendments.begin (), amendments.end ());
return amendments;
// Get the list of amendments we support and do not veto
return doValidation({});
}
std::map <uint256, std::uint32_t>

View File

@@ -48,15 +48,16 @@ Json::Value doLedgerData (RPC::Context& context)
if (!lpLedger)
return jvResult;
boost::optional<ReadView::key_type> key = ReadView::key_type();
if (params.isMember (jss::marker))
bool const isMarker = params.isMember (jss::marker);
ReadView::key_type key = ReadView::key_type();
if (isMarker)
{
Json::Value const& jMarker = params[jss::marker];
if (! (jMarker.isString () && key->SetHex (jMarker.asString ())))
if (! (jMarker.isString () && key.SetHex (jMarker.asString ())))
return RPC::expected_field_error (jss::marker, "valid");
}
bool isBinary = params[jss::binary].asBool();
bool const isBinary = params[jss::binary].asBool();
int limit = -1;
if (params.isMember (jss::limit))
@@ -75,10 +76,18 @@ Json::Value doLedgerData (RPC::Context& context)
jvResult[jss::ledger_hash] = to_string (lpLedger->info().hash);
jvResult[jss::ledger_index] = lpLedger->info().seq;
if (! isMarker)
{
// Return base ledger data on first query
jvResult[jss::ledger] = getJson (
LedgerFill (*lpLedger, isBinary ?
LedgerFill::Options::binary : 0));
}
Json::Value& nodes = jvResult[jss::state];
auto e = lpLedger->sles.end();
for (auto i = lpLedger->sles.upper_bound(*key); i != e; ++i)
for (auto i = lpLedger->sles.upper_bound(key); i != e; ++i)
{
auto sle = lpLedger->read(keylet::unchecked((*i)->key()));
if (limit-- <= 0)

View File

@@ -43,7 +43,6 @@ class SHAMapV2_test : public beast::unit_test::suite
auto ledger =
std::make_shared<Ledger>(create_genesis, config,
amendments_v, env.app().family());
BEAST_EXPECT(! getSHAMapV2 (ledger->info()));
BEAST_EXPECT(ledger->stateMap().get_version() == SHAMap::version{1});

View File

@@ -17,6 +17,7 @@
*/
//==============================================================================
#include <ripple/basics/StringUtilities.h>
#include <ripple/protocol/JsonFields.h>
#include <ripple/test/jtx.h>
@@ -80,7 +81,8 @@ public:
Json::Value jvParams;
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
auto const jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto const jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT(
jrr[jss::ledger_current_index].isIntegral() &&
jrr[jss::ledger_current_index].asInt() > 0 );
@@ -91,7 +93,8 @@ public:
for (auto delta = -1; delta <= 1; delta++)
{
jvParams[jss::limit] = max_limit + delta;
auto const jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto const jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT(
checkArraySize( jrr[jss::state],
(delta > 0 && !as_admin) ? max_limit : max_limit + delta ));
@@ -121,7 +124,8 @@ public:
Json::Value jvParams;
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = true;
auto const jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto const jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT(
jrr[jss::ledger_current_index].isIntegral() &&
jrr[jss::ledger_current_index].asInt() > 0);
@@ -144,7 +148,8 @@ public:
// bad limit
Json::Value jvParams;
jvParams[jss::limit] = "0"; // NOT an integer
auto const jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto const jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not integer.");
@@ -154,7 +159,8 @@ public:
// invalid marker
Json::Value jvParams;
jvParams[jss::marker] = "NOT_A_MARKER";
auto const jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto const jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid.");
@@ -164,7 +170,8 @@ public:
// invalid marker - not a string
Json::Value jvParams;
jvParams[jss::marker] = 1;
auto const jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto const jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid.");
@@ -174,7 +181,8 @@ public:
// ask for a bad ledger index
Json::Value jvParams;
jvParams[jss::ledger_index] = 10u;
auto const jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto const jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
@@ -204,23 +212,75 @@ public:
Json::Value jvParams;
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
auto jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
auto jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
auto const total_count = jrr[jss::state].size();
// now make request with a limit and loop until we get all
jvParams[jss::limit] = 5;
jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
BEAST_EXPECT( checkMarker(jrr) );
auto running_total = jrr[jss::state].size();
while ( jrr.isMember(jss::marker) )
{
jvParams[jss::marker] = jrr[jss::marker];
jrr = env.rpc ( "json", "ledger_data", jvParams.toStyledString() ) [jss::result];
jrr = env.rpc ( "json", "ledger_data",
boost::lexical_cast<std::string>(jvParams)) [jss::result];
running_total += jrr[jss::state].size();
}
BEAST_EXPECT( running_total == total_count );
}
void testLedgerHeader()
{
using namespace test::jtx;
Env env { *this };
env.fund(XRP(100000), "alice");
env.close();
// Ledger header should be present in the first query
{
// Closed ledger with non binary form
Json::Value jvParams;
jvParams[jss::ledger_index] = "closed";
auto jrr = env.rpc("json", "ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_hash] ==
to_string(env.closed()->info().hash));
}
{
// Closed ledger with binary form
Json::Value jvParams;
jvParams[jss::ledger_index] = "closed";
jvParams[jss::binary] = true;
auto jrr = env.rpc("json", "ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
{
auto data = strUnHex(
jrr[jss::ledger][jss::ledger_data].asString());
if (BEAST_EXPECT(data.second))
{
Serializer s(data.first.data(), data.first.size());
std::uint32_t seq = 0;
BEAST_EXPECT(s.getInteger<std::uint32_t>(seq, 0));
BEAST_EXPECT(seq == 3);
}
}
}
{
// Current ledger with binary form
Json::Value jvParams;
jvParams[jss::binary] = true;
auto jrr = env.rpc("json", "ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(! jrr[jss::ledger].isMember(jss::ledger_data));
}
}
void run()
{
testCurrentLedgerToLimits(true);
@@ -228,8 +288,8 @@ public:
testCurrentLedgerBinary();
testBadInput();
testMarkerFollow();
testLedgerHeader();
}
};
BEAST_DEFINE_TESTSUITE(LedgerData,app,ripple);