Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include validator manifests in published list: #2278

Merged
merged 1 commit into from
Nov 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/ripple/app/misc/ValidatorList.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ enum class ListDisposition
"expiration", and @c "validators" field. @c "expiration" contains the
Ripple timestamp (seconds since January 1st, 2000 (00:00 UTC)) for when
the list expires. @c "validators" contains an array of objects with a
@c "validation_public_key" field.
@c "validation_public_key" and optional @c "manifest" field.
@c "validation_public_key" should be the hex-encoded master public key.
@c "manifest" should be the base64-encoded validator manifest.

@li @c "manifest": Base64-encoded serialization of a manifest containing the
publisher's master and signing public keys.
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/app/misc/ValidatorSite.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ namespace ripple {
"expiration", and @c "validators" field. @c "expiration" contains the
Ripple timestamp (seconds since January 1st, 2000 (00:00 UTC)) for when
the list expires. @c "validators" contains an array of objects with a
@c "validation_public_key" field.
@c "validation_public_key" and optional @c "manifest" field.
@c "validation_public_key" should be the hex-encoded master public key.
@c "manifest" should be the base64-encoded validator manifest.

@li @c "manifest": Base64-encoded serialization of a manifest containing the
publisher's master and signing public keys.
Expand Down
26 changes: 26 additions & 0 deletions src/ripple/app/misc/impl/ValidatorList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ ValidatorList::applyList (
std::vector<PublicKey> oldList = publisherList;
publisherList.clear ();
publisherList.reserve (newList.size ());
std::vector<std::string> manifests;
for (auto const& val : newList)
{
if (val.isObject () &&
Expand All @@ -210,6 +211,9 @@ ValidatorList::applyList (
publisherList.push_back (
PublicKey(Slice{ ret.first.data (), ret.first.size() }));
}

if (val.isMember ("manifest") && val["manifest"].isString ())
manifests.push_back(val["manifest"].asString ());
}
}

Expand Down Expand Up @@ -254,6 +258,28 @@ ValidatorList::applyList (
"No validator keys included in valid list";
}

for (auto const& valManifest : manifests)
{
auto m = Manifest::make_Manifest (
beast::detail::base64_decode(valManifest));

if (! m || ! keyListings_.count (m->masterKey))
{
JLOG (j_.warn()) <<
"List for " << strHex(pubKey) <<
" contained untrusted validator manifest";
continue;
}

auto const result = validatorManifests_.applyManifest (std::move(*m));
if (result == ManifestDisposition::invalid)
{
JLOG (j_.warn()) <<
"List for " << strHex(pubKey) <<
" contained invalid validator manifest";
}
}

return ListDisposition::accepted;
}

Expand Down
70 changes: 53 additions & 17 deletions src/test/app/ValidatorList_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ namespace test {
class ValidatorList_test : public beast::unit_test::suite
{
private:
struct Validator
{
PublicKey masterPublic;
PublicKey signingPublic;
std::string manifest;
};

static
PublicKey
randomNode ()
Expand All @@ -49,6 +56,7 @@ class ValidatorList_test : public beast::unit_test::suite
return derivePublicKey (KeyType::ed25519, randomSecretKey());
}

static
std::string
makeManifestString (
PublicKey const& pk,
Expand All @@ -72,9 +80,22 @@ class ValidatorList_test : public beast::unit_test::suite
return std::string(static_cast<char const*> (s.data()), s.size());
}

static
Validator
randomValidator ()
{
auto const secret = randomSecretKey();
auto const masterPublic =
derivePublicKey(KeyType::ed25519, secret);
auto const signingKeys = randomKeyPair(KeyType::secp256k1);
return { masterPublic, signingKeys.first,
beast::detail::base64_encode(makeManifestString (
masterPublic, secret, signingKeys.first, signingKeys.second, 1)) };
}

std::string
makeList (
std::vector <PublicKey> const& validators,
std::vector <Validator> const& validators,
std::size_t sequence,
std::size_t expiration)
{
Expand All @@ -85,7 +106,8 @@ class ValidatorList_test : public beast::unit_test::suite

for (auto const& val : validators)
{
data += "{\"validation_public_key\":\"" + strHex(val) + "\"},";
data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) +
"\",\"manifest\":\"" + val.manifest + "\"},";
}

data.pop_back();
Expand Down Expand Up @@ -355,15 +377,15 @@ class ValidatorList_test : public beast::unit_test::suite
emptyLocalKey, emptyCfgKeys, cfgKeys1));

auto constexpr listSize = 20;
std::vector<PublicKey> list1;
std::vector<Validator> list1;
list1.reserve (listSize);
while (list1.size () < listSize)
list1.push_back (randomNode());
list1.push_back (randomValidator());

std::vector<PublicKey> list2;
std::vector<Validator> list2;
list2.reserve (listSize);
while (list2.size () < listSize)
list2.push_back (randomNode());
list2.push_back (randomValidator());

// do not apply expired list
auto const version = 1;
Expand All @@ -387,7 +409,10 @@ class ValidatorList_test : public beast::unit_test::suite
manifest1, blob1, sig1, version));

for (auto const& val : list1)
BEAST_EXPECT(trustedKeys->listed (val));
{
BEAST_EXPECT(trustedKeys->listed (val.masterPublic));
BEAST_EXPECT(trustedKeys->listed (val.signingPublic));
}

// do not use list from untrusted publisher
auto const untrustedManifest = beast::detail::base64_encode(
Expand Down Expand Up @@ -415,10 +440,16 @@ class ValidatorList_test : public beast::unit_test::suite
manifest1, blob2, sig2, version));

for (auto const& val : list1)
BEAST_EXPECT(! trustedKeys->listed (val));
{
BEAST_EXPECT(! trustedKeys->listed (val.masterPublic));
BEAST_EXPECT(! trustedKeys->listed (val.signingPublic));
}

for (auto const& val : list2)
BEAST_EXPECT(trustedKeys->listed (val));
{
BEAST_EXPECT(trustedKeys->listed (val.masterPublic));
BEAST_EXPECT(trustedKeys->listed (val.signingPublic));
}

// do not re-apply lists with past or current sequence numbers
BEAST_EXPECT(ListDisposition::stale ==
Expand Down Expand Up @@ -471,7 +502,10 @@ class ValidatorList_test : public beast::unit_test::suite

BEAST_EXPECT(! trustedKeys->trustedPublisher(publisherPublic));
for (auto const& val : list1)
BEAST_EXPECT(! trustedKeys->listed (val));
{
BEAST_EXPECT(! trustedKeys->listed (val.masterPublic));
BEAST_EXPECT(! trustedKeys->listed (val.signingPublic));
}
}

void
Expand Down Expand Up @@ -723,8 +757,8 @@ class ValidatorList_test : public beast::unit_test::suite
BEAST_EXPECT(trustedKeys->load (
emptyLocalKey, emptyCfgKeys, cfgKeys));

std::vector<PublicKey> list ({randomNode()});
hash_set<PublicKey> activeValidators ({ list[0] });
std::vector<Validator> list ({randomValidator()});
hash_set<PublicKey> activeValidators ({ list[0].masterPublic });

// do not apply expired list
auto const version = 1;
Expand All @@ -740,11 +774,13 @@ class ValidatorList_test : public beast::unit_test::suite
manifest, blob, sig, version));

trustedKeys->onConsensusStart (activeValidators);
BEAST_EXPECT(trustedKeys->trusted (list[0]));
BEAST_EXPECT(trustedKeys->trusted (list[0].masterPublic));
BEAST_EXPECT(trustedKeys->trusted (list[0].signingPublic));

env.timeKeeper().set(expiration);
trustedKeys->onConsensusStart (activeValidators);
BEAST_EXPECT(! trustedKeys->trusted (list[0]));
BEAST_EXPECT(! trustedKeys->trusted (list[0].masterPublic));
BEAST_EXPECT(! trustedKeys->trusted (list[0].signingPublic));
}
{
// Test 1-9 configured validators
Expand Down Expand Up @@ -814,13 +850,13 @@ class ValidatorList_test : public beast::unit_test::suite

hash_set<PublicKey> activeValidators;

std::vector<PublicKey> valKeys;
std::vector<Validator> valKeys;
valKeys.reserve(n);

while (valKeys.size () != n)
{
valKeys.push_back (randomNode());
activeValidators.emplace (valKeys.back());
valKeys.push_back (randomValidator());
activeValidators.emplace (valKeys.back().masterPublic);
}

auto addPublishedList = [this, &env, &trustedKeys, &valKeys]()
Expand Down
48 changes: 39 additions & 9 deletions src/test/app/ValidatorSite_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
namespace ripple {
namespace test {

struct Validator
{
PublicKey masterPublic;
PublicKey signingPublic;
std::string manifest;
};

class http_sync_server
{
using endpoint_type = boost::asio::ip::tcp::endpoint;
Expand All @@ -57,7 +64,7 @@ class http_sync_server
int sequence,
std::size_t expiration,
int version,
std::vector <PublicKey> const& validators)
std::vector <Validator> const& validators)
: sock_(ios)
, acceptor_(ios)
{
Expand All @@ -68,7 +75,8 @@ class http_sync_server

for (auto const& val : validators)
{
data += "{\"validation_public_key\":\"" + strHex (val) + "\"},";
data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) +
"\",\"manifest\":\"" + val.manifest + "\"},";
}
data.pop_back();
data += "]}";
Expand Down Expand Up @@ -202,6 +210,7 @@ class ValidatorSite_test : public beast::unit_test::suite
return derivePublicKey (KeyType::secp256k1, randomSecretKey());
}

static
std::string
makeManifestString (
PublicKey const& pk,
Expand All @@ -226,6 +235,18 @@ class ValidatorSite_test : public beast::unit_test::suite
static_cast<char const*> (s.data()), s.size()));
}

static
Validator
randomValidator ()
{
auto const secret = randomSecretKey();
auto const masterPublic =
derivePublicKey(KeyType::ed25519, secret);
auto const signingKeys = randomKeyPair(KeyType::secp256k1);
return { masterPublic, signingKeys.first, makeManifestString (
masterPublic, secret, signingKeys.first, signingKeys.second, 1) };
}

void
testConfigLoad ()
{
Expand Down Expand Up @@ -306,15 +327,15 @@ class ValidatorSite_test : public beast::unit_test::suite
emptyLocalKey, emptyCfgKeys, cfgPublishers));

auto constexpr listSize = 20;
std::vector<PublicKey> list1;
std::vector<Validator> list1;
list1.reserve (listSize);
while (list1.size () < listSize)
list1.push_back (randomNode());
list1.push_back (randomValidator());

std::vector<PublicKey> list2;
std::vector<Validator> list2;
list2.reserve (listSize);
while (list2.size () < listSize)
list2.push_back (randomNode());
list2.push_back (randomValidator());

std::uint16_t constexpr port1 = 7475;
std::uint16_t constexpr port2 = 7476;
Expand Down Expand Up @@ -351,7 +372,10 @@ class ValidatorSite_test : public beast::unit_test::suite
sites->join();

for (auto const& val : list1)
BEAST_EXPECT(trustedKeys.listed (val));
{
BEAST_EXPECT(trustedKeys.listed (val.masterPublic));
BEAST_EXPECT(trustedKeys.listed (val.signingPublic));
}
}
{
// fetch multiple sites
Expand All @@ -367,10 +391,16 @@ class ValidatorSite_test : public beast::unit_test::suite
sites->join();

for (auto const& val : list1)
BEAST_EXPECT(trustedKeys.listed (val));
{
BEAST_EXPECT(trustedKeys.listed (val.masterPublic));
BEAST_EXPECT(trustedKeys.listed (val.signingPublic));
}

for (auto const& val : list2)
BEAST_EXPECT(trustedKeys.listed (val));
{
BEAST_EXPECT(trustedKeys.listed (val.masterPublic));
BEAST_EXPECT(trustedKeys.listed (val.signingPublic));
}
}
}

Expand Down