mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 11:15:56 +00:00
Add validator token to config (RIPD-1386)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import base64, os, random, struct, sys
|
||||
import base64, binascii, json, os, random, struct, sys
|
||||
import ed25519
|
||||
import ecdsa
|
||||
import hashlib
|
||||
@@ -188,9 +188,14 @@ def perform_check(s, print=print):
|
||||
|
||||
def perform_sign(
|
||||
seq, validation_pk_human, validation_sk_human, master_sk_human, print=print):
|
||||
print('[validation_manifest]')
|
||||
print(wrap(get_signature(
|
||||
int(seq), validation_pk_human, validation_sk_human, master_sk_human)))
|
||||
manifest = get_signature(
|
||||
int(seq), validation_pk_human, validation_sk_human, master_sk_human)
|
||||
|
||||
print('[validator_token]')
|
||||
print(wrap(base64.b64encode(json.dumps({
|
||||
"validation_secret_key": binascii.b2a_hex(Base58.decode_version(validation_sk_human)[1]),
|
||||
"manifest": manifest},
|
||||
separators=(',', ':')))))
|
||||
|
||||
def perform_verify(
|
||||
seq, validation_pk_human, master_pk_human, signature, print=print):
|
||||
|
||||
@@ -104,9 +104,7 @@ n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
|
||||
[validation_seed]
|
||||
{validation_seed}
|
||||
#vaidation_public_key: {validation_public_key}
|
||||
#validation_public_key: {validation_public_key}
|
||||
|
||||
# Other rippled's trusting this validator need this key
|
||||
[validator_keys]
|
||||
@@ -119,8 +117,8 @@ n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
expire = 1
|
||||
auto_connect = 1
|
||||
|
||||
[validation_manifest]
|
||||
{validation_manifest}
|
||||
[validator_token]
|
||||
{validator_token}
|
||||
|
||||
[rpc_startup]
|
||||
{{ "command": "log_level", "severity": "debug" }}
|
||||
@@ -201,7 +199,7 @@ def sign_manifest(seq, validation_pk, master_secret):
|
||||
result = []
|
||||
for l in r.splitlines():
|
||||
l.strip()
|
||||
if not l or l == '[validation_manifest]':
|
||||
if not l or l == '[validator_token]':
|
||||
continue
|
||||
result.append(l)
|
||||
return '\n'.join(result)
|
||||
@@ -430,7 +428,7 @@ def new_config_ephemeral_key(
|
||||
if rm_dbs and os.path.exists(db_dir):
|
||||
shutil.rmtree(db_dir)
|
||||
os.makedirs(db_dir)
|
||||
# replace the validation_manifest section with `signed`
|
||||
# replace the validator_token section with `signed`
|
||||
bak = config_file + '.bak'
|
||||
if is_windows() and os.path.isfile(bak):
|
||||
os.remove(bak)
|
||||
@@ -440,7 +438,7 @@ def new_config_ephemeral_key(
|
||||
with open(config_file, 'w') as out:
|
||||
for l in src:
|
||||
sl = l.strip()
|
||||
if not in_manifest and sl == '[validation_manifest]':
|
||||
if not in_manifest and sl == '[validator_token]':
|
||||
in_manifest = True
|
||||
elif in_manifest:
|
||||
if sl.startswith('[') or sl.startswith('#'):
|
||||
@@ -539,7 +537,7 @@ def get_configs(manifest_seq):
|
||||
sibling_ip = '127.0.0.1'
|
||||
sibling_port = port_nums[sibling_index][1]
|
||||
d = {
|
||||
'validation_manifest': s,
|
||||
'validator_token': s,
|
||||
'all_validator_keys': all_validator_keys,
|
||||
'node_db_type': node_db_type,
|
||||
'node_db_path': node_db_path,
|
||||
|
||||
@@ -141,9 +141,13 @@ class test_Sign(TestCase):
|
||||
Sign.perform_sign(self.SEQUENCE, public, private, private, print=self.print)
|
||||
self.assertEquals(
|
||||
self.results,
|
||||
[[['[validation_manifest]'], {}],
|
||||
[['JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2dnZ2dnZ2\n'
|
||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkYwRAIgXyobHA8sDQxmDJNLE6HIaARlzvcd79/wT068\n'
|
||||
'e113gUkCIHkI540JQT2LHwAD7/y3wFE5X3lEXMfgZRkpLZTxkpticBJAzo5VrUEr0U47sHvu\n'
|
||||
'IjbrINLCTM6pAScA899G9kpMWexbXv1ceIbTP5JH1HyQmsZsROTeHR0irojvYgx7JLaiAA=='],
|
||||
[[['[validator_token]'], {}],
|
||||
[['eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiNmI2YjZiNmI2YjZiNmI2YjZiNmI2Yj\n'
|
||||
'ZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YiIsIm1hbmlm\n'
|
||||
'ZXN0IjoiSkFBQUFCZHhJZTJESUtVWmQ5akRqS2lra254bkRmV0NIa1NYWVpSZUZlbn\n'
|
||||
'ZzbW9WQ2RJdzZuTWhBbloyZG5aMmRuWjJkbloyZG5aMmRuWjJkbloyZG5aMmRuWjJk\n'
|
||||
'bloyZG5aMmRrWXdSQUlnWHlvYkhBOHNEUXhtREpOTEU2SElhQVJsenZjZDc5L3dUMD\n'
|
||||
'Y4ZTExM2dVa0NJSGtJNTQwSlFUMkxId0FENy95M3dGRTVYM2xFWE1mZ1pSa3BMWlR4\n'
|
||||
'a3B0aWNCSkF6bzVWclVFcjBVNDdzSHZ1SWpicklOTENUTTZwQVNjQTg5OUc5a3BNV2\n'
|
||||
'V4Ylh2MWNlSWJUUDVKSDFIeVFtc1pzUk9UZUhSMGlyb2p2WWd4N0pMYWlBQT09In0='],
|
||||
{}]])
|
||||
|
||||
@@ -8,7 +8,7 @@ Validators use two types of key pairs: *master keys* and *ephemeral
|
||||
keys*. Ephemeral keys are used to sign and verify validations. Master keys are
|
||||
used to sign and verify manifests that change ephemeral keys. The master secret
|
||||
key should be tightly controlled. The ephemeral secret key needs to be present
|
||||
in the config file.
|
||||
in the config file in the form of a token.
|
||||
|
||||
## Validator Keys
|
||||
|
||||
@@ -28,10 +28,9 @@ Sample output:
|
||||
paamfhAn5m1NM4UUu5mmvVaHQy8Fb65bkpbaNrvKwX3YMKdjzi2
|
||||
```
|
||||
|
||||
The first value is the master public key. Add the public key to the config
|
||||
for this validator. A one-word comment must be added after the key (for example
|
||||
*ThisServersName*). Any other rippled trusting the validator needs to add the
|
||||
master public key to its config. Only add keys received from trusted sources.
|
||||
The first value is the master public key. Any other rippled trusting the
|
||||
validator needs to add the master public key to its config. Only add keys
|
||||
received from trusted sources.
|
||||
|
||||
The second value is the corresponding master secret key. **DO NOT INSTALL THIS
|
||||
IN THE CONFIG**. The master secret key will be used to sign manifests that
|
||||
@@ -63,17 +62,6 @@ Sample output:
|
||||
}
|
||||
```
|
||||
|
||||
Add the `validation_seed` value (the ephemeral secret key) to this validator's
|
||||
config. It is recommended to add the ephemeral public key and the sequence
|
||||
number as a comment as well (sequence numbers are be explained below):
|
||||
|
||||
```
|
||||
[validation_seed]
|
||||
sh8bLqqkGBknGcsgRTrFMxcciwytm
|
||||
# validation_public_key: n9LtZ9haqYMbzJ92cDd3pu3Lko6uEznrXuYea3ehuhVcwDHF5coX
|
||||
# sequence number: 1
|
||||
```
|
||||
|
||||
A manifest is a signed message used to inform other servers of this validator's
|
||||
ephemeral public key. A manifest contains a sequence number, the new ephemeral
|
||||
public key, and it is signed with both the ephemeral and master secret keys.
|
||||
@@ -95,15 +83,18 @@ For example:
|
||||
Sample output:
|
||||
|
||||
```
|
||||
[validation_manifest]
|
||||
JAAAAAFxIe3t8rIb4Ba8JHI97CbwpxmTq0LhN/7ZAbsNaSwrbHaypHMhAzTuu07YGOvVvB3+
|
||||
aS0jhP+q0TVgTjGJKhx+yTY1Da3ddkYwRAIgDkmIt3dPNsfeCH3ApMZgpwqG4JwtIlKEymqK
|
||||
S7v+VqkCIFQXg20ZMpXXT86vmLdlmPspgeUN1scWsuFoPYUUJywycBJAl93+/bZbfZ4quTeM
|
||||
5y80/OSIcVoWPcHajwrAl68eiAW4MVFeJXvShXNfnT+XsxMjDh0VpOkhvyp971i1MgjBAA==
|
||||
```
|
||||
[validator_token]
|
||||
eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiN2VkMWM2ZDVmMTBhOGUyYWNmZWE0OW
|
||||
NkNzE5ZjhiZjZhMWI1Yjg2M2Q3N2QxMDE1MjVkNGQxOWU4ZWYwNjU1OSIsIm1hbmlm
|
||||
ZXN0IjoiSkFBQUFBRnhJZTNVZ3lXb3QwdFpSTFBNbDQ1dit5YkdPanJYNkE5c1JIcU
|
||||
lJWUlZSTZjREhuTWhBNlNqWWZnWnJsTHFXU2UrNzlWUkZnOWJEeVZKNDMvYmV6Zkxu
|
||||
dWkxVzhQdWRrWXdSQUlnY09KWmVpdmFaOW1abmM4Y1N4bUlOVGVYSUlKOE5oTXprRD
|
||||
lrWThseGRkc0NJRk1OU3k5Qmo4VHNQWlV4NzNwYUJ0RmxpaDZWOTlSRXNnU3V6Wlhr
|
||||
BXMHNWTVZXR09QUnY0Ylg2dDVmYi9haUtoNkZyRVdtYk5YeXpRNmI5TGhDQT09In0=
|
||||
```
|
||||
|
||||
Copy this to the config for this validator. Don't forget to update the comment
|
||||
noting the sequence number.
|
||||
Copy this to the config for this validator. It is recommended to add the
|
||||
sequence number as a comment as well.
|
||||
|
||||
## Revoking a key
|
||||
|
||||
|
||||
@@ -600,6 +600,15 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validator_token]
|
||||
#
|
||||
# This is an alternative to [validation_seed] that allows rippled to perform
|
||||
# validation without having to store the validator keys on the network
|
||||
# connected server. The field should contain a base64-encoded blob.
|
||||
# External tools are available for generating validator keys and tokens.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validators_file]
|
||||
#
|
||||
# Path or name of a file that contains the validation public keys of nodes
|
||||
@@ -634,6 +643,7 @@
|
||||
# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
|
||||
#
|
||||
#
|
||||
#
|
||||
# [path_search]
|
||||
# When searching for paths, the default search aggressiveness. This can take
|
||||
# exponentially more resources as the size is increased.
|
||||
|
||||
@@ -62,6 +62,11 @@ public:
|
||||
|
||||
virtual bool peerPosition (Pos_t const& position) = 0;
|
||||
|
||||
virtual PublicKey const& getValidationPublicKey () const = 0;
|
||||
|
||||
virtual void setValidationKeys (
|
||||
SecretKey const& valSecret, PublicKey const& valPublic) = 0;
|
||||
|
||||
virtual void startRound (
|
||||
LgrID_t const& prevLCLHash,
|
||||
std::shared_ptr<Ledger const> const& prevLedger,
|
||||
|
||||
@@ -73,8 +73,6 @@ LedgerConsensusImp<Traits>::LedgerConsensusImp (
|
||||
, ourID_ (calcNodeID (app.nodeIdentity().first))
|
||||
, state_ (State::open)
|
||||
, closeTime_ {}
|
||||
, valPublic_ (app_.config().VALIDATION_PUB)
|
||||
, valSecret_ (app_.config().VALIDATION_PRIV)
|
||||
, consensusFail_ (false)
|
||||
, roundTime_ (0)
|
||||
, closePercent_ (0)
|
||||
@@ -1780,6 +1778,20 @@ void LedgerConsensusImp<Traits>::addLoad(STValidation::ref val)
|
||||
val->setFieldU32(sfLoadFee, fee);
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
PublicKey const& LedgerConsensusImp<Traits>::getValidationPublicKey () const
|
||||
{
|
||||
return valPublic_;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void LedgerConsensusImp<Traits>::setValidationKeys (
|
||||
SecretKey const& valSecret, PublicKey const& valPublic)
|
||||
{
|
||||
valSecret_ = valSecret;
|
||||
valPublic_ = valPublic;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::shared_ptr <LedgerConsensus<RCLCxTraits>>
|
||||
make_LedgerConsensus (
|
||||
|
||||
@@ -354,6 +354,16 @@ private:
|
||||
// nodes that have bowed out of this consensus process
|
||||
hash_set<NodeID_t> deadNodes_;
|
||||
beast::Journal j_;
|
||||
|
||||
public:
|
||||
/** Returns validation public key */
|
||||
PublicKey const&
|
||||
getValidationPublicKey () const override;
|
||||
|
||||
/** Set validation private and public key pair. */
|
||||
void
|
||||
setValidationKeys (
|
||||
SecretKey const& valSecret, PublicKey const& valPublic) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
#include <ripple/overlay/Cluster.h>
|
||||
#include <ripple/overlay/make_Overlay.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/SecretKey.h>
|
||||
#include <ripple/protocol/STParsedJSON.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
@@ -1102,26 +1103,59 @@ bool ApplicationImp::setup()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validatorManifests_->load (
|
||||
getWalletDB (), "ValidatorManifests",
|
||||
config().section (SECTION_VALIDATION_MANIFEST).lines()))
|
||||
{
|
||||
JLOG(m_journal.fatal()) << "Invalid configured validator manifest.";
|
||||
return false;
|
||||
}
|
||||
PublicKey valPublic;
|
||||
SecretKey valSecret;
|
||||
std::string manifest;
|
||||
if (config().exists (SECTION_VALIDATOR_TOKEN))
|
||||
{
|
||||
if (auto const token = ValidatorToken::make_ValidatorToken (
|
||||
config().section (SECTION_VALIDATOR_TOKEN).lines ()))
|
||||
{
|
||||
valSecret = token->validationSecret;
|
||||
valPublic = derivePublicKey (KeyType::secp256k1, valSecret);
|
||||
manifest = std::move(token->manifest);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(m_journal.fatal()) <<
|
||||
"Invalid entry in validator token configuration.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (config().exists (SECTION_VALIDATION_SEED))
|
||||
{
|
||||
auto const seed = parseBase58<Seed>(
|
||||
config().section (SECTION_VALIDATION_SEED).lines ().front());
|
||||
if (!seed)
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid seed specified in [" SECTION_VALIDATION_SEED "]");
|
||||
valSecret = generateSecretKey (KeyType::secp256k1, *seed);
|
||||
valPublic = derivePublicKey (KeyType::secp256k1, valSecret);
|
||||
}
|
||||
|
||||
publisherManifests_->load (
|
||||
getWalletDB (), "PublisherManifests");
|
||||
if (!validatorManifests_->load (
|
||||
getWalletDB (), "ValidatorManifests", manifest))
|
||||
{
|
||||
JLOG(m_journal.fatal()) << "Invalid configured validator manifest.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup trusted validators
|
||||
if (!validators_->load (
|
||||
config_->VALIDATION_PUB,
|
||||
config().section (SECTION_VALIDATORS).values (),
|
||||
config().section (SECTION_VALIDATOR_LIST_KEYS).values ()))
|
||||
{
|
||||
JLOG(m_journal.fatal()) <<
|
||||
"Invalid entry in validator configuration.";
|
||||
return false;
|
||||
publisherManifests_->load (
|
||||
getWalletDB (), "PublisherManifests");
|
||||
|
||||
m_networkOPs->setValidationKeys (valSecret, valPublic);
|
||||
|
||||
// Setup trusted validators
|
||||
if (!validators_->load (
|
||||
valPublic,
|
||||
config().section (SECTION_VALIDATORS).values (),
|
||||
config().section (SECTION_VALIDATOR_LIST_KEYS).values ()))
|
||||
{
|
||||
JLOG(m_journal.fatal()) <<
|
||||
"Invalid entry in validator configuration.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validatorSites_->load (
|
||||
|
||||
@@ -57,6 +57,8 @@ class OrderBookDB;
|
||||
class Overlay;
|
||||
class PathRequests;
|
||||
class PendingSaves;
|
||||
class PublicKey;
|
||||
class SecretKey;
|
||||
class AccountIDCache;
|
||||
class STLedgerEntry;
|
||||
class TimeKeeper;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/app/main/NodeIdentity.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
@@ -32,14 +33,14 @@ std::pair<PublicKey, SecretKey>
|
||||
loadNodeIdentity (Application& app)
|
||||
{
|
||||
// If a seed is specified in the configuration file use that directly.
|
||||
if (!app.config().NODE_SEED.empty ())
|
||||
if (app.config().exists(SECTION_NODE_SEED))
|
||||
{
|
||||
auto const seed = parseBase58<Seed>(
|
||||
app.config().NODE_SEED);
|
||||
app.config().section(SECTION_NODE_SEED).lines().front());
|
||||
|
||||
if (!seed)
|
||||
Throw<std::runtime_error>(
|
||||
"NodeIdentity: Bad [node_seed] specified");
|
||||
"NodeIdentity: Bad [" SECTION_NODE_SEED "] specified");
|
||||
|
||||
auto secretKey =
|
||||
generateSecretKey (KeyType::secp256k1, *seed);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/SecretKey.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <string>
|
||||
@@ -54,8 +55,8 @@ namespace ripple {
|
||||
There are two stores of information within rippled related to manifests.
|
||||
An instance of ManifestCache stores, for each trusted validator, (a) its
|
||||
master public key, and (b) the most senior of all valid manifests it has
|
||||
seen for that validator, if any. On startup, the [validation_manifest]
|
||||
config entry (which is the manifest for this validator) is decoded and
|
||||
seen for that validator, if any. On startup, the [validator_token] config
|
||||
entry (which contains the manifest for this validator) is decoded and
|
||||
added to the manifest cache. Other manifests are added as "gossip" is
|
||||
received from rippled peers.
|
||||
|
||||
@@ -79,8 +80,6 @@ namespace ripple {
|
||||
|
||||
struct Manifest
|
||||
{
|
||||
static std::size_t constexpr textLength = 288;
|
||||
|
||||
std::string serialized;
|
||||
PublicKey masterKey;
|
||||
PublicKey signingKey;
|
||||
@@ -128,6 +127,22 @@ struct Manifest
|
||||
Blob getMasterSignature () const;
|
||||
};
|
||||
|
||||
struct ValidatorToken
|
||||
{
|
||||
std::string manifest;
|
||||
SecretKey validationSecret;
|
||||
|
||||
private:
|
||||
ValidatorToken(std::string const& m, SecretKey const& valSecret);
|
||||
|
||||
public:
|
||||
ValidatorToken(ValidatorToken const&) = delete;
|
||||
ValidatorToken(ValidatorToken&& other) = default;
|
||||
|
||||
static boost::optional<ValidatorToken>
|
||||
make_ValidatorToken(std::vector<std::string> const& tokenBlob);
|
||||
};
|
||||
|
||||
enum class ManifestDisposition
|
||||
{
|
||||
/// Manifest is valid
|
||||
@@ -230,7 +245,7 @@ public:
|
||||
*/
|
||||
bool load (
|
||||
DatabaseCon& dbCon, std::string const& dbTable,
|
||||
std::vector<std::string> const& configManifest);
|
||||
std::string const& configManifest);
|
||||
|
||||
/** Populate manifest cache with manifests in database.
|
||||
|
||||
|
||||
@@ -354,6 +354,15 @@ public:
|
||||
{
|
||||
mConsensus->setLastCloseTime(t);
|
||||
}
|
||||
PublicKey const& getValidationPublicKey () const override
|
||||
{
|
||||
return mLedgerConsensus->getValidationPublicKey ();
|
||||
}
|
||||
void setValidationKeys (
|
||||
SecretKey const& valSecret, PublicKey const& valPublic) override
|
||||
{
|
||||
mLedgerConsensus->setValidationKeys (valSecret, valPublic);
|
||||
}
|
||||
Json::Value getConsensusInfo () override;
|
||||
Json::Value getServerInfo (bool human, bool admin) override;
|
||||
void clearLedgerFetch () override;
|
||||
@@ -2043,35 +2052,11 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
||||
|
||||
if (admin)
|
||||
{
|
||||
if (app_.config().VALIDATION_PUB.size ())
|
||||
if (getValidationPublicKey().size ())
|
||||
{
|
||||
auto const& validation_manifest =
|
||||
app_.config().section (SECTION_VALIDATION_MANIFEST);
|
||||
|
||||
if (! validation_manifest.lines().empty())
|
||||
{
|
||||
std::string s;
|
||||
s.reserve (Manifest::textLength);
|
||||
for (auto const& line : validation_manifest.lines())
|
||||
s += beast::rfc2616::trim(line);
|
||||
if (auto mo = Manifest::make_Manifest (beast::detail::base64_decode(s)))
|
||||
{
|
||||
Json::Value valManifest = Json::objectValue;
|
||||
valManifest [jss::master_key] = toBase58 (
|
||||
TokenType::TOKEN_NODE_PUBLIC,
|
||||
mo->masterKey);
|
||||
valManifest [jss::signing_key] = toBase58 (
|
||||
TokenType::TOKEN_NODE_PUBLIC,
|
||||
mo->signingKey);
|
||||
valManifest [jss::seq] = Json::UInt (mo->sequence);
|
||||
|
||||
info[jss::validation_manifest] = valManifest;
|
||||
}
|
||||
}
|
||||
|
||||
info[jss::pubkey_validator] = toBase58 (
|
||||
TokenType::TOKEN_NODE_PUBLIC,
|
||||
app_.config().VALIDATION_PUB);
|
||||
app_.validators().localPublicKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -177,6 +177,9 @@ public:
|
||||
|
||||
// FIXME(NIKB): Remove the need for this function
|
||||
virtual void setLastCloseTime (NetClock::time_point t) = 0;
|
||||
virtual PublicKey const& getValidationPublicKey () const = 0;
|
||||
virtual void setValidationKeys (
|
||||
SecretKey const& valSecret, PublicKey const& valPublic) = 0;
|
||||
|
||||
virtual Json::Value getConsensusInfo () = 0;
|
||||
virtual Json::Value getServerInfo (bool human, bool admin) = 0;
|
||||
|
||||
@@ -280,6 +280,15 @@ public:
|
||||
trustedPublisher (
|
||||
PublicKey const& identity) const;
|
||||
|
||||
/** Returns local validator public key
|
||||
|
||||
@par Thread Safety
|
||||
|
||||
May be called concurrently
|
||||
*/
|
||||
PublicKey
|
||||
localPublicKey () const;
|
||||
|
||||
/** Invokes the callback once for every listed validation public key.
|
||||
|
||||
@note Undefined behavior results when calling ValidatorList members from
|
||||
|
||||
@@ -20,11 +20,15 @@
|
||||
#include <ripple/app/misc/Manifest.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/beast/rfc2616.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/json/json_reader.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/Sign.h>
|
||||
#include <beast/core/detail/base64.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ripple {
|
||||
@@ -139,6 +143,58 @@ Blob Manifest::getMasterSignature () const
|
||||
return st.getFieldVL (sfMasterSignature);
|
||||
}
|
||||
|
||||
ValidatorToken::ValidatorToken(std::string const& m, SecretKey const& valSecret)
|
||||
: manifest(m)
|
||||
, validationSecret(valSecret)
|
||||
{
|
||||
}
|
||||
|
||||
boost::optional<ValidatorToken>
|
||||
ValidatorToken::make_ValidatorToken(std::vector<std::string> const& tokenBlob)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string tokenStr;
|
||||
tokenStr.reserve (
|
||||
std::accumulate (tokenBlob.cbegin(), tokenBlob.cend(), std::size_t(0),
|
||||
[] (std::size_t init, std::string const& s)
|
||||
{
|
||||
return init + s.size();
|
||||
}));
|
||||
|
||||
for (auto const& line : tokenBlob)
|
||||
tokenStr += beast::rfc2616::trim(line);
|
||||
|
||||
tokenStr = beast::detail::base64_decode(tokenStr);
|
||||
|
||||
Json::Reader r;
|
||||
Json::Value token;
|
||||
if (! r.parse (tokenStr, token))
|
||||
return boost::none;
|
||||
|
||||
if (token.isMember("manifest") && token["manifest"].isString() &&
|
||||
token.isMember("validation_secret_key") &&
|
||||
token["validation_secret_key"].isString())
|
||||
{
|
||||
auto const ret = strUnHex (token["validation_secret_key"].asString());
|
||||
if (! ret.second || ! ret.first.size ())
|
||||
return boost::none;
|
||||
|
||||
return ValidatorToken(
|
||||
token["manifest"].asString(),
|
||||
SecretKey(Slice{ret.first.data(), ret.first.size()}));
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
PublicKey
|
||||
ManifestCache::getSigningKey (PublicKey const& pk) const
|
||||
{
|
||||
@@ -303,18 +359,14 @@ ManifestCache::load (
|
||||
bool
|
||||
ManifestCache::load (
|
||||
DatabaseCon& dbCon, std::string const& dbTable,
|
||||
std::vector<std::string> const& configManifest)
|
||||
std::string const& configManifest)
|
||||
{
|
||||
load (dbCon, dbTable);
|
||||
|
||||
if (! configManifest.empty())
|
||||
{
|
||||
std::string s;
|
||||
s.reserve (Manifest::textLength);
|
||||
for (auto const& line : configManifest)
|
||||
s += beast::rfc2616::trim(line);
|
||||
|
||||
auto mo = Manifest::make_Manifest (beast::detail::base64_decode(s));
|
||||
auto mo = Manifest::make_Manifest (
|
||||
beast::detail::base64_decode(configManifest));
|
||||
if (! mo)
|
||||
{
|
||||
JLOG (j_.error()) << "Malformed manifest in config";
|
||||
|
||||
@@ -365,6 +365,13 @@ ValidatorList::trustedPublisher (PublicKey const& identity) const
|
||||
return identity.size() && publisherLists_.count (identity);
|
||||
}
|
||||
|
||||
PublicKey
|
||||
ValidatorList::localPublicKey () const
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> read_lock{mutex_};
|
||||
return localPubKey_;
|
||||
}
|
||||
|
||||
bool
|
||||
ValidatorList::removePublisherList (PublicKey const& publisherKey)
|
||||
{
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
#include <ripple/basics/BasicConfig.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/protocol/SystemParameters.h> // VFALCO Breaks levelization
|
||||
#include <ripple/protocol/PublicKey.h> // NIKB Breaks levelization (TEMP)
|
||||
#include <ripple/protocol/SecretKey.h> // NIKB Breaks levelization (TEMP)
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
@@ -152,13 +150,8 @@ public:
|
||||
int PATH_SEARCH_MAX = 10;
|
||||
|
||||
// Validation
|
||||
PublicKey VALIDATION_PUB;
|
||||
SecretKey VALIDATION_PRIV;
|
||||
boost::optional<std::size_t> VALIDATION_QUORUM; // Minimum validations to consider ledger authoritative
|
||||
|
||||
// Node Identity
|
||||
std::string NODE_SEED;
|
||||
|
||||
std::uint64_t FEE_DEFAULT = 10;
|
||||
std::uint64_t FEE_ACCOUNT_RESERVE = 200*SYSTEM_CURRENCY_PARTS;
|
||||
std::uint64_t FEE_OWNER_RESERVE = 50*SYSTEM_CURRENCY_PARTS;
|
||||
|
||||
@@ -66,7 +66,7 @@ struct ConfigSection
|
||||
#define SECTION_VALIDATOR_LIST_KEYS "validator_list_keys"
|
||||
#define SECTION_VALIDATOR_LIST_SITES "validator_list_sites"
|
||||
#define SECTION_VALIDATORS "validators"
|
||||
#define SECTION_VALIDATION_MANIFEST "validation_manifest"
|
||||
#define SECTION_VALIDATOR_TOKEN "validator_token"
|
||||
#define SECTION_VETO_AMENDMENTS "veto_amendments"
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -358,22 +358,10 @@ void Config::loadFromString (std::string const& fileContents)
|
||||
if (getSingleSection (secConfig, SECTION_SSL_VERIFY, strTemp, j_))
|
||||
SSL_VERIFY = beast::lexicalCastThrow <bool> (strTemp);
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_VALIDATION_SEED, strTemp, j_))
|
||||
{
|
||||
auto const seed = parseBase58<Seed>(strTemp);
|
||||
if (!seed)
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid seed specified in [" SECTION_VALIDATION_SEED "]");
|
||||
VALIDATION_PRIV = generateSecretKey (KeyType::secp256k1, *seed);
|
||||
VALIDATION_PUB = derivePublicKey (KeyType::secp256k1, VALIDATION_PRIV);
|
||||
}
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_NODE_SEED, NODE_SEED, j_))
|
||||
{
|
||||
if (!parseBase58<Seed>(NODE_SEED))
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid seed specified in [" SECTION_NODE_SEED "]");
|
||||
}
|
||||
if (exists(SECTION_VALIDATION_SEED) && exists(SECTION_VALIDATOR_TOKEN))
|
||||
Throw<std::runtime_error> (
|
||||
"Cannot have both [" SECTION_VALIDATION_SEED "] "
|
||||
"and [" SECTION_VALIDATOR_TOKEN "] config sections");
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_NETWORK_QUORUM, strTemp, j_))
|
||||
NETWORK_QUORUM = beast::lexicalCastThrow <std::size_t> (strTemp);
|
||||
|
||||
@@ -1086,7 +1086,7 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMTransaction> const& m)
|
||||
flags |= SF_TRUSTED;
|
||||
}
|
||||
|
||||
if (! app_.config().VALIDATION_PUB.size())
|
||||
if (! app_.getOPs().getValidationPublicKey().size())
|
||||
{
|
||||
// For now, be paranoid and have each validator
|
||||
// check each transaction, regardless of source
|
||||
@@ -1248,8 +1248,8 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMProposeSet> const& m)
|
||||
return;
|
||||
}
|
||||
|
||||
if (app_.config().VALIDATION_PUB.size() &&
|
||||
publicKey == app_.config().VALIDATION_PUB)
|
||||
if (app_.getOPs().getValidationPublicKey().size() &&
|
||||
publicKey == app_.getOPs().getValidationPublicKey())
|
||||
{
|
||||
JLOG(p_journal_.trace()) << "Proposal: self";
|
||||
return;
|
||||
|
||||
@@ -442,7 +442,6 @@ JSS ( validated ); // out: NetworkOPs, RPCHelpers, AccountTx*
|
||||
JSS ( validated_ledger ); // out: NetworkOPs
|
||||
JSS ( validated_ledgers ); // out: NetworkOPs
|
||||
JSS ( validation_key ); // out: ValidationCreate, ValidationSeed
|
||||
JSS ( validation_manifest ); // out: NetworkOPs
|
||||
JSS ( validation_private_key ); // out: ValidationCreate
|
||||
JSS ( validation_public_key ); // out: ValidationCreate, ValidationSeed
|
||||
JSS ( validation_quorum ); // out: NetworkOPs
|
||||
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
PublicKey emptyLocalKey;
|
||||
std::vector<std::string> s1;
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> cfgManifest;
|
||||
std::string cfgManifest;
|
||||
for (auto const& man : inManifests)
|
||||
s1.push_back (toBase58(
|
||||
TokenType::TOKEN_NODE_PUBLIC, man->masterKey));
|
||||
@@ -259,7 +259,7 @@ public:
|
||||
}
|
||||
{
|
||||
// load config manifest
|
||||
std::vector<std::string> const badManifest ({"bad manifest"});
|
||||
std::string const badManifest = "bad manifest";
|
||||
|
||||
ManifestCache loaded;
|
||||
BEAST_EXPECT(! loaded.load (
|
||||
@@ -269,9 +269,8 @@ public:
|
||||
auto const pk = derivePublicKey(KeyType::ed25519, sk);
|
||||
auto const kp = randomKeyPair(KeyType::secp256k1);
|
||||
|
||||
std::vector<std::string> const cfgManifest ({
|
||||
makeManifestString (pk, sk, kp.first, kp.second, 0)
|
||||
});
|
||||
std::string const cfgManifest =
|
||||
makeManifestString (pk, sk, kp.first, kp.second, 0);
|
||||
|
||||
BEAST_EXPECT(loaded.load (
|
||||
dbCon, "ValidatorManifests", cfgManifest));
|
||||
@@ -367,6 +366,45 @@ public:
|
||||
BEAST_EXPECT(cache.getMasterKey(kp1.first) == kp1.first);
|
||||
}
|
||||
|
||||
void testValidatorToken()
|
||||
{
|
||||
testcase ("validator token");
|
||||
|
||||
{
|
||||
auto const valSecret = parseBase58<SecretKey>(
|
||||
TokenType::TOKEN_NODE_PRIVATE,
|
||||
"paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi");
|
||||
|
||||
// Format token string to test trim()
|
||||
std::vector<std::string> const tokenBlob = {
|
||||
" eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n",
|
||||
" \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl \n",
|
||||
"\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n",
|
||||
"\t hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t \t\n",
|
||||
"bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n",
|
||||
"hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n",
|
||||
"NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n",
|
||||
"VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n"
|
||||
};
|
||||
|
||||
auto const manifest =
|
||||
"JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/vCxHXXLplc2GnMhAkE1agqXxBwD"
|
||||
"wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+sAOkVB"
|
||||
"+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
|
||||
"gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFOr7C0kw"
|
||||
"2AiTzSCjIzditQ8=";
|
||||
|
||||
auto const token = ValidatorToken::make_ValidatorToken(tokenBlob);
|
||||
BEAST_EXPECT(token);
|
||||
BEAST_EXPECT(token->validationSecret == *valSecret);
|
||||
BEAST_EXPECT(token->manifest == manifest);
|
||||
}
|
||||
{
|
||||
std::vector<std::string> const badToken = { "bad token" };
|
||||
BEAST_EXPECT(! ValidatorToken::make_ValidatorToken(badToken));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -428,6 +466,7 @@ public:
|
||||
testLoadStore (cache);
|
||||
testGetSignature ();
|
||||
testGetKeys ();
|
||||
testValidatorToken ();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -142,9 +142,9 @@ private:
|
||||
auto const localMasterPublic = derivePublicKey(
|
||||
KeyType::ed25519, localMasterSecret);
|
||||
|
||||
auto cfgManifest = makeManifestString (
|
||||
localMasterPublic, localMasterSecret,
|
||||
localSigningPublic, localSigningSecret, 1);
|
||||
std::string const cfgManifest (makeManifestString (
|
||||
localMasterPublic, localMasterSecret,
|
||||
localSigningPublic, localSigningSecret, 1));
|
||||
|
||||
auto format = [](
|
||||
PublicKey const &publicKey,
|
||||
@@ -254,6 +254,7 @@ private:
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
*localSigningPublic, cfgKeys, emptyCfgPublishers));
|
||||
|
||||
BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
|
||||
BEAST_EXPECT(trustedKeys->listed (*localSigningPublic));
|
||||
for (auto const& n : configList)
|
||||
BEAST_EXPECT(trustedKeys->listed (n));
|
||||
@@ -268,6 +269,7 @@ private:
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
localSigningPublic, cfgKeys, emptyCfgPublishers));
|
||||
|
||||
BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
|
||||
BEAST_EXPECT(trustedKeys->listed (localSigningPublic));
|
||||
for (auto const& n : configList)
|
||||
BEAST_EXPECT(trustedKeys->listed (n));
|
||||
@@ -283,6 +285,7 @@ private:
|
||||
BEAST_EXPECT(trustedKeys->load (
|
||||
localSigningPublic, cfgKeys, emptyCfgPublishers));
|
||||
|
||||
BEAST_EXPECT(trustedKeys->localPublicKey() == localMasterPublic);
|
||||
BEAST_EXPECT(trustedKeys->listed (localSigningPublic));
|
||||
BEAST_EXPECT(trustedKeys->listed (localMasterPublic));
|
||||
for (auto const& n : configList)
|
||||
|
||||
@@ -474,6 +474,45 @@ port_wss_admin
|
||||
}
|
||||
}
|
||||
|
||||
void testValidatorKeys ()
|
||||
{
|
||||
testcase ("validator keys");
|
||||
|
||||
std::string const validationSeed = "spA4sh1qTvwq92X715tYyGQKmAKfa";
|
||||
|
||||
auto const token =
|
||||
"eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiOWVkNDVmODY2MjQxY2MxOGEyNzQ3Yj"
|
||||
"U0Mzg3YzA2MjU5MDc5NzJmNGU3MTkwMjMxZmFhOTM3NDU3ZmE5ZGFmNiIsIm1hbmlm"
|
||||
"ZXN0IjoiSkFBQUFBRnhJZTFGdHdtaW12R3RIMmlDY01KcUM5Z1ZGS2lsR2Z3MS92Q3"
|
||||
"hIWFhMcGxjMkduTWhBa0UxYWdxWHhCd0R3RGJJRDZPTVNZdU0wRkRBbHBBZ05rOFNL"
|
||||
"Rm43TU8yZmRrY3dSUUloQU9uZ3U5c0FLcVhZb3VKK2wyVjBXK3NBT2tWQitaUlM2UF"
|
||||
"NobEpBZlVzWGZBaUJzVkpHZXNhYWRPSmMvYUFab2tTMXZ5bUdtVnJsSFBLV1gzWXl3"
|
||||
"dTZpbjhIQVNRS1B1Z0JENjdrTWFSRkd2bXBBVEhsR0tKZHZERmxXUFl5NUFxRGVkRn"
|
||||
"Y1VEphMncwaTIxZXEzTVl5d0xWSlpuRk9yN0Mwa3cyQWlUelNDakl6ZGl0UTg9In0=";
|
||||
|
||||
{
|
||||
Config c;
|
||||
static boost::format configTemplate (R"rippleConfig(
|
||||
[validation_seed]
|
||||
%1%
|
||||
|
||||
[validator_token]
|
||||
%2%
|
||||
)rippleConfig");
|
||||
std::string error;
|
||||
auto const expectedError =
|
||||
"Cannot have both [validation_seed] "
|
||||
"and [validator_token] config sections";
|
||||
try {
|
||||
c.loadFromString (boost::str (
|
||||
configTemplate % validationSeed % token));
|
||||
} catch (std::runtime_error& e) {
|
||||
error = e.what();
|
||||
}
|
||||
BEAST_EXPECT(error == expectedError);
|
||||
}
|
||||
}
|
||||
|
||||
void testValidatorsFile ()
|
||||
{
|
||||
testcase ("validators_file");
|
||||
@@ -818,6 +857,7 @@ trustthesevalidators.gov
|
||||
{
|
||||
testLegacy ();
|
||||
testDbPath ();
|
||||
testValidatorKeys ();
|
||||
testValidatorsFile ();
|
||||
testSetup (false);
|
||||
testSetup (true);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <ripple/ledger/PaymentSandbox.h>
|
||||
#include <ripple/ledger/Sandbox.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -809,12 +810,9 @@ class GetAmendments_test
|
||||
setupConfigForUnitTests(*p);
|
||||
|
||||
// If the config has valid validation keys then we run as a validator.
|
||||
auto const seed = parseBase58<Seed>("shUwVw52ofnCUX5m7kPTKzJdr4HEH");
|
||||
if (!seed)
|
||||
Throw<std::runtime_error> ("Invalid seed specified");
|
||||
p->VALIDATION_PRIV = generateSecretKey (KeyType::secp256k1, *seed);
|
||||
p->VALIDATION_PUB =
|
||||
derivePublicKey (KeyType::secp256k1, p->VALIDATION_PRIV);
|
||||
p->section(SECTION_VALIDATION_SEED).append(
|
||||
std::vector<std::string>{"shUwVw52ofnCUX5m7kPTKzJdr4HEH"});
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <test/jtx/TestSuite.h>
|
||||
#include <ripple/overlay/Cluster.h>
|
||||
#include <ripple/overlay/ClusterNode.h>
|
||||
#include <ripple/protocol/SecretKey.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace tests {
|
||||
|
||||
@@ -29,18 +29,18 @@ namespace ripple {
|
||||
namespace test {
|
||||
|
||||
namespace validator {
|
||||
static auto const seed = "ss7t3J9dYentEFgKdPA3q6eyxtrLB";
|
||||
static auto const master_key =
|
||||
"nHUYwQk8AyQ8pW9p4SvrWC2hosvaoii9X54uGLDYGBtEFwWFHsJK";
|
||||
static auto const signing_key =
|
||||
"n9LHPLA36SBky1YjbaVEApQQ3s9XcpazCgfAG7jsqBb1ugDAosbm";
|
||||
// Format manifest string to test trim()
|
||||
static auto const manifest =
|
||||
" JAAAAAFxIe2cDLvm5IqpeGFlMTD98HCqv7+GE54anRD/zbvGNYtOsXMhAuUTyasIhvj2KPfN\n"
|
||||
" \tRbmmIBnqNUzidgkKb244eP794ZpMdkYwRAIgNVq8SYP7js0C/GAGMKVYXiCGUTIL7OKPSBLS \n"
|
||||
"\t7LTyrL4CIE+s4Tsn/FrrYj0nMEV1Mvf7PMRYCxtEERD3PG/etTJ3cBJAbwWWofHqg9IACoYV\n"
|
||||
"\t +n9ulZHSVRajo55EkZYw0XUXDw8zcI4gD58suOSLZTG/dXtZp17huIyHgxHbR2YeYjQpCw==\t \t";
|
||||
static auto sequence = 1;
|
||||
static auto const public_key =
|
||||
"nHBt9fsb4849WmZiCds4r5TXyBeQjqnH5kzPtqgMAQMgi39YZRPa";
|
||||
|
||||
static auto const token =
|
||||
"eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n"
|
||||
"QzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl\n"
|
||||
"c3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n"
|
||||
"hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\n"
|
||||
"bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n"
|
||||
"hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n"
|
||||
"NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n"
|
||||
"VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n";
|
||||
}
|
||||
|
||||
class ServerInfo_test : public beast::unit_test::suite
|
||||
@@ -52,18 +52,15 @@ public:
|
||||
{
|
||||
auto p = std::make_unique<Config>();
|
||||
boost::format toLoad(R"rippleConfig(
|
||||
[validation_manifest]
|
||||
[validator_token]
|
||||
%1%
|
||||
|
||||
[validation_seed]
|
||||
%2%
|
||||
|
||||
[validators]
|
||||
%3%
|
||||
%2%
|
||||
)rippleConfig");
|
||||
|
||||
p->loadFromString (boost::str (
|
||||
toLoad % validator::manifest % validator::seed % validator::master_key));
|
||||
toLoad % validator::token % validator::public_key));
|
||||
|
||||
setupConfigForUnitTests(*p);
|
||||
|
||||
@@ -88,15 +85,7 @@ public:
|
||||
BEAST_EXPECT(result[jss::status] == "success");
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::info));
|
||||
BEAST_EXPECT(result[jss::result][jss::info]
|
||||
[jss::pubkey_validator] == validator::signing_key);
|
||||
BEAST_EXPECT(result[jss::result][jss::info].isMember(
|
||||
jss::validation_manifest));
|
||||
BEAST_EXPECT(result[jss::result][jss::info][jss::validation_manifest]
|
||||
[jss::master_key] == validator::master_key);
|
||||
BEAST_EXPECT(result[jss::result][jss::info][jss::validation_manifest]
|
||||
[jss::signing_key] == validator::signing_key);
|
||||
BEAST_EXPECT(result[jss::result][jss::info][jss::validation_manifest]
|
||||
[jss::seq] == validator::sequence);
|
||||
[jss::pubkey_validator] == validator::public_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <test/jtx/WSClient.h>
|
||||
#include <test/jtx.h>
|
||||
@@ -313,26 +314,14 @@ public:
|
||||
|
||||
static
|
||||
std::unique_ptr<Config>
|
||||
makeValidatorConfig(
|
||||
std::string const& valPrivateKey, std::string const& valPublicKey)
|
||||
makeValidatorConfig(std::string const& seed)
|
||||
{
|
||||
auto p = std::make_unique<Config>();
|
||||
setupConfigForUnitTests(*p);
|
||||
|
||||
// If the config has valid validation keys then we run as a validator.
|
||||
auto const sk = parseBase58<SecretKey>(
|
||||
TOKEN_NODE_PRIVATE,
|
||||
valPrivateKey);
|
||||
if (!sk)
|
||||
Throw<std::runtime_error> ("Invalid validation private key");
|
||||
p->VALIDATION_PRIV = *sk;
|
||||
|
||||
auto const pk = parseBase58<PublicKey>(
|
||||
TOKEN_NODE_PUBLIC,
|
||||
valPublicKey);
|
||||
if (!pk)
|
||||
Throw<std::runtime_error> ("Invalid validation public key");
|
||||
p->VALIDATION_PUB = *pk;
|
||||
p->section(SECTION_VALIDATION_SEED).append(
|
||||
std::vector<std::string>{seed});
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -342,11 +331,10 @@ public:
|
||||
using namespace jtx;
|
||||
|
||||
// Public key must be derived from the private key
|
||||
const std::string valPrivateKey =
|
||||
"paEdUCVVCNnv4aYBepid9Xh3NaAr9xWRw2vh351piFJrxQwvExd";
|
||||
const std::string valPublicKey =
|
||||
"n9MvFGjgv1kYkm7bLbb2QUwSqgzrQkYMYHXtrzN8W28Jfp2mVihq";
|
||||
Env env(*this, makeValidatorConfig(valPrivateKey, valPublicKey));
|
||||
std::string const seed = "snpTg5uPtiRG2hE8HHCAF4NzdorKT";
|
||||
std::string const valPublicKey =
|
||||
"n9KCD2WU48u1WG3neBH6vRSinAxoTwrjLbjUAn6Xq6mCe5YrJv2V";
|
||||
Env env(*this, makeValidatorConfig(seed));
|
||||
auto wsc = makeWSClient(env.app().config());
|
||||
Json::Value stream;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user