Skip to content

Commit

Permalink
Report additional fields in validation stream:
Browse files Browse the repository at this point in the history
The HardenedValidations amendment introduces additional fields
in validations:

- `sfValidatedHash`, if present, is the hash the of last ledger that
  the validator considers to be fully validated.
- `sfCookie`, if present, is a 64-bit cookie (the default
  implementation selects it randomly at startup but other
  implementations are possible), which can be used to improve the
  detection and classification of duplicate validations.
- `sfServerVersion`, if present, reports the version of the software
  that the validator is running. By surfacing this information,
  server operators gain additional insight about variety of software
  on the network.

If merged, this commit fixes #3797 by adding the fields to the
`validations` stream as shown below:

- `sfValidateHash` as `validated_hash`: a 256-bit hex string;
- `sfCookie` as `cookie`: a 64-bit integer as a string; and
- `sfServerVersion` as `server_version`: a 64-bit integer as
  a string.
  • Loading branch information
nbougalis authored and scottschurr committed Jul 23, 2021
1 parent 7bd5d51 commit dc6d5cd
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 16 deletions.
9 changes: 9 additions & 0 deletions src/ripple/app/misc/NetworkOPs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,15 @@ NetworkOPsImp::pubValidation(std::shared_ptr<STValidation> const& val)
jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
jvObj[jss::data] = strHex(val->getSerializer().slice());

if (auto version = (*val)[~sfServerVersion])
jvObj[jss::server_version] = std::to_string(*version);

if (auto cookie = (*val)[~sfCookie])
jvObj[jss::cookie] = std::to_string(*cookie);

if (auto hash = (*val)[~sfValidatedHash])
jvObj[jss::validated_hash] = strHex(*hash);

auto const masterKey =
app_.validatorManifests().getMasterKey(signerPublic);

Expand Down
3 changes: 3 additions & 0 deletions src/ripple/protocol/jss.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ JSS(complete_shards); // out: OverlayImpl, PeerImp
JSS(consensus); // out: NetworkOPs, LedgerConsensus
JSS(converge_time); // out: NetworkOPs
JSS(converge_time_s); // out: NetworkOPs
JSS(cookie); // out: NetworkOPs
JSS(count); // in: AccountTx*, ValidatorList
JSS(counters); // in/out: retrieve counters
JSS(currentShard); // out: NodeToShardStatus
Expand Down Expand Up @@ -498,6 +499,7 @@ JSS(server_domain); // out: NetworkOPs
JSS(server_state); // out: NetworkOPs
JSS(server_state_duration_us); // out: NetworkOPs
JSS(server_status); // out: NetworkOPs
JSS(server_version); // out: NetworkOPs
JSS(settle_delay); // out: AccountChannels
JSS(severity); // in: LogLevel
JSS(shards); // in/out: GetCounts, DownloadShard
Expand Down Expand Up @@ -587,6 +589,7 @@ JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*
JSS(validator_list_expires); // out: NetworkOps, ValidatorList
JSS(validator_list); // out: NetworkOps, ValidatorList
JSS(validators);
JSS(validated_hash); // out: NetworkOPs
JSS(validated_ledger); // out: NetworkOPs
JSS(validated_ledger_index); // out: SubmitTransaction
JSS(validated_ledgers); // out: NetworkOPs
Expand Down
76 changes: 60 additions & 16 deletions src/test/rpc/Subscribe_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,24 +365,68 @@ class Subscribe_test : public beast::unit_test::suite
}

{
// Accept a ledger
env.close();
// Lambda to check ledger validations from the stream.
auto validValidationFields = [&env, &valPublicKey](
Json::Value const& jv) {
if (jv[jss::type] != "validationReceived")
return false;

// Check stream update
using namespace std::chrono_literals;
if (jv[jss::validation_public_key].asString() != valPublicKey)
return false;

BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
return jv[jss::type] == "validationReceived" &&
jv[jss::validation_public_key].asString() == valPublicKey &&
jv[jss::ledger_hash] ==
to_string(env.closed()->info().hash) &&
jv[jss::ledger_index] ==
std::to_string(env.closed()->info().seq) &&
jv[jss::flags] ==
(vfFullyCanonicalSig | vfFullValidation) &&
jv[jss::full] == true && !jv.isMember(jss::load_fee) &&
jv[jss::signature] && jv[jss::signing_time];
}));
if (jv[jss::ledger_hash] !=
to_string(env.closed()->info().hash))
return false;

if (jv[jss::ledger_index] !=
std::to_string(env.closed()->info().seq))
return false;

if (jv[jss::flags] != (vfFullyCanonicalSig | vfFullValidation))
return false;

if (jv[jss::full] != true)
return false;

if (jv.isMember(jss::load_fee))
return false;

if (!jv.isMember(jss::signature))
return false;

if (!jv.isMember(jss::signing_time))
return false;

if (!jv.isMember(jss::cookie))
return false;

if (!jv.isMember(jss::validated_hash))
return false;

// Certain fields are only added on a flag ledger.
bool const isFlagLedger =
(env.closed()->info().seq + 1) % 256 == 0;

if (jv.isMember(jss::server_version) != isFlagLedger)
return false;

if (jv.isMember(jss::reserve_base) != isFlagLedger)
return false;

if (jv.isMember(jss::reserve_inc) != isFlagLedger)
return false;

return true;
};

// Check stream update. Look at enough stream entries so we see
// at least one flag ledger.
while (env.closed()->info().seq < 300)
{
env.close();
using namespace std::chrono_literals;
BEAST_EXPECT(wsc->findMsg(5s, validValidationFields));
}
}

// RPC unsubscribe
Expand Down

0 comments on commit dc6d5cd

Please sign in to comment.