diff --git a/AccountTx_8cpp_source.html b/AccountTx_8cpp_source.html index 8f22872aa2..1b32cf7dbd 100644 --- a/AccountTx_8cpp_source.html +++ b/AccountTx_8cpp_source.html @@ -567,7 +567,7 @@ $(function() {
beast::Journal::debug
Stream debug() const
Definition: Journal.h:317
ripple::Application::config
virtual Config & config()=0
ripple::Application::getRelationalDatabase
virtual RelationalDatabase & getRelationalDatabase()=0
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
ripple::LedgerMaster::getCloseTimeBySeq
std::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
Definition: LedgerMaster.cpp:1611
ripple::LedgerMaster::isValidated
bool isValidated(ReadView const &ledger)
Definition: LedgerMaster.cpp:512
ripple::LedgerMaster::getHashBySeq
uint256 getHashBySeq(std::uint32_t index)
Get a ledger's hash by sequence number using the cache.
Definition: LedgerMaster.cpp:1641
diff --git a/Application_8cpp_source.html b/Application_8cpp_source.html index 2ecae520c7..c79ddd619e 100644 --- a/Application_8cpp_source.html +++ b/Application_8cpp_source.html @@ -1438,835 +1438,836 @@ $(function() {
1360 if (!validators_->load(
1361 localSigningKey,
1362 config().section(SECTION_VALIDATORS).values(),
-
1363 config().section(SECTION_VALIDATOR_LIST_KEYS).values()))
-
1364 {
-
1365 JLOG(m_journal.fatal())
-
1366 << "Invalid entry in validator configuration.";
-
1367 return false;
-
1368 }
-
1369 }
-
1370
-
1371 if (!validatorSites_->load(
-
1372 config().section(SECTION_VALIDATOR_LIST_SITES).values()))
-
1373 {
-
1374 JLOG(m_journal.fatal())
-
1375 << "Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES << "]";
-
1376 return false;
-
1377 }
-
1378
-
1379 // Tell the AmendmentTable who the trusted validators are.
-
1380 m_amendmentTable->trustChanged(validators_->getQuorumKeys().second);
-
1381
-
1382 //----------------------------------------------------------------------
-
1383 //
-
1384 // Server
-
1385 //
-
1386 //----------------------------------------------------------------------
-
1387
-
1388 // VFALCO NOTE Unfortunately, in stand-alone mode some code still
-
1389 // foolishly calls overlay(). When this is fixed we can
-
1390 // move the instantiation inside a conditional:
-
1391 //
-
1392 // if (!config_.standalone())
-
1393 overlay_ = make_Overlay(
-
1394 *this,
-
1395 setup_Overlay(*config_),
-
1396 *serverHandler_,
-
1397 *m_resourceManager,
-
1398 *m_resolver,
-
1399 get_io_service(),
-
1400 *config_,
-
1401 m_collectorManager->collector());
-
1402 add(*overlay_); // add to PropertyStream
-
1403
-
1404 // start first consensus round
-
1405 if (!m_networkOPs->beginConsensus(
-
1406 m_ledgerMaster->getClosedLedger()->info().hash))
-
1407 {
-
1408 JLOG(m_journal.fatal()) << "Unable to start consensus";
-
1409 return false;
-
1410 }
-
1411
-
1412 {
-
1413 try
-
1414 {
-
1415 auto setup = setup_ServerHandler(
-
1416 *config_, beast::logstream{m_journal.error()});
-
1417 setup.makeContexts();
-
1418 serverHandler_->setup(setup, m_journal);
-
1419 }
-
1420 catch (std::exception const& e)
-
1421 {
-
1422 if (auto stream = m_journal.fatal())
-
1423 {
-
1424 stream << "Unable to setup server handler";
-
1425 if (std::strlen(e.what()) > 0)
-
1426 stream << ": " << e.what();
-
1427 }
-
1428 return false;
-
1429 }
-
1430 }
-
1431
-
1432 // Begin connecting to network.
-
1433 if (!config_->standalone())
-
1434 {
-
1435 // Should this message be here, conceptually? In theory this sort
-
1436 // of message, if displayed, should be displayed from PeerFinder.
-
1437 if (config_->PEER_PRIVATE && config_->IPS_FIXED.empty())
-
1438 {
-
1439 JLOG(m_journal.warn())
-
1440 << "No outbound peer connections will be made";
-
1441 }
-
1442
-
1443 // VFALCO NOTE the state timer resets the deadlock detector.
-
1444 //
-
1445 m_networkOPs->setStateTimer();
-
1446 }
-
1447 else
-
1448 {
-
1449 JLOG(m_journal.warn()) << "Running in standalone mode";
-
1450
-
1451 m_networkOPs->setStandAlone();
-
1452 }
-
1453
-
1454 if (config_->canSign())
-
1455 {
-
1456 JLOG(m_journal.warn()) << "*** The server is configured to allow the "
-
1457 "'sign' and 'sign_for'";
-
1458 JLOG(m_journal.warn()) << "*** commands. These commands have security "
-
1459 "implications and have";
-
1460 JLOG(m_journal.warn()) << "*** been deprecated. They will be removed "
-
1461 "in a future release of";
-
1462 JLOG(m_journal.warn()) << "*** rippled.";
-
1463 JLOG(m_journal.warn()) << "*** If you do not use them to sign "
-
1464 "transactions please edit your";
-
1465 JLOG(m_journal.warn())
-
1466 << "*** configuration file and remove the [enable_signing] stanza.";
-
1467 JLOG(m_journal.warn()) << "*** If you do use them to sign transactions "
-
1468 "please migrate to a";
-
1469 JLOG(m_journal.warn())
-
1470 << "*** standalone signing solution as soon as possible.";
-
1471 }
-
1472
-
1473 //
-
1474 // Execute start up rpc commands.
-
1475 //
-
1476 for (auto cmd : config_->section(SECTION_RPC_STARTUP).lines())
-
1477 {
-
1478 Json::Reader jrReader;
-
1479 Json::Value jvCommand;
-
1480
-
1481 if (!jrReader.parse(cmd, jvCommand))
-
1482 {
-
1483 JLOG(m_journal.fatal()) << "Couldn't parse entry in ["
-
1484 << SECTION_RPC_STARTUP << "]: '" << cmd;
-
1485 }
-
1486
-
1487 if (!config_->quiet())
-
1488 {
-
1489 JLOG(m_journal.fatal())
-
1490 << "Startup RPC: " << jvCommand << std::endl;
-
1491 }
-
1492
-
1493 Resource::Charge loadType = Resource::feeReferenceRPC;
-
1494 Resource::Consumer c;
-
1495 RPC::JsonContext context{
-
1496 {journal("RPCHandler"),
-
1497 *this,
-
1498 loadType,
-
1499 getOPs(),
-
1500 getLedgerMaster(),
-
1501 c,
-
1502 Role::ADMIN,
-
1503 {},
+
1363 config().section(SECTION_VALIDATOR_LIST_KEYS).values(),
+
1364 config().VALIDATOR_LIST_THRESHOLD))
+
1365 {
+
1366 JLOG(m_journal.fatal())
+
1367 << "Invalid entry in validator configuration.";
+
1368 return false;
+
1369 }
+
1370 }
+
1371
+
1372 if (!validatorSites_->load(
+
1373 config().section(SECTION_VALIDATOR_LIST_SITES).values()))
+
1374 {
+
1375 JLOG(m_journal.fatal())
+
1376 << "Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES << "]";
+
1377 return false;
+
1378 }
+
1379
+
1380 // Tell the AmendmentTable who the trusted validators are.
+
1381 m_amendmentTable->trustChanged(validators_->getQuorumKeys().second);
+
1382
+
1383 //----------------------------------------------------------------------
+
1384 //
+
1385 // Server
+
1386 //
+
1387 //----------------------------------------------------------------------
+
1388
+
1389 // VFALCO NOTE Unfortunately, in stand-alone mode some code still
+
1390 // foolishly calls overlay(). When this is fixed we can
+
1391 // move the instantiation inside a conditional:
+
1392 //
+
1393 // if (!config_.standalone())
+
1394 overlay_ = make_Overlay(
+
1395 *this,
+
1396 setup_Overlay(*config_),
+
1397 *serverHandler_,
+
1398 *m_resourceManager,
+
1399 *m_resolver,
+
1400 get_io_service(),
+
1401 *config_,
+
1402 m_collectorManager->collector());
+
1403 add(*overlay_); // add to PropertyStream
+
1404
+
1405 // start first consensus round
+
1406 if (!m_networkOPs->beginConsensus(
+
1407 m_ledgerMaster->getClosedLedger()->info().hash))
+
1408 {
+
1409 JLOG(m_journal.fatal()) << "Unable to start consensus";
+
1410 return false;
+
1411 }
+
1412
+
1413 {
+
1414 try
+
1415 {
+
1416 auto setup = setup_ServerHandler(
+
1417 *config_, beast::logstream{m_journal.error()});
+
1418 setup.makeContexts();
+
1419 serverHandler_->setup(setup, m_journal);
+
1420 }
+
1421 catch (std::exception const& e)
+
1422 {
+
1423 if (auto stream = m_journal.fatal())
+
1424 {
+
1425 stream << "Unable to setup server handler";
+
1426 if (std::strlen(e.what()) > 0)
+
1427 stream << ": " << e.what();
+
1428 }
+
1429 return false;
+
1430 }
+
1431 }
+
1432
+
1433 // Begin connecting to network.
+
1434 if (!config_->standalone())
+
1435 {
+
1436 // Should this message be here, conceptually? In theory this sort
+
1437 // of message, if displayed, should be displayed from PeerFinder.
+
1438 if (config_->PEER_PRIVATE && config_->IPS_FIXED.empty())
+
1439 {
+
1440 JLOG(m_journal.warn())
+
1441 << "No outbound peer connections will be made";
+
1442 }
+
1443
+
1444 // VFALCO NOTE the state timer resets the deadlock detector.
+
1445 //
+
1446 m_networkOPs->setStateTimer();
+
1447 }
+
1448 else
+
1449 {
+
1450 JLOG(m_journal.warn()) << "Running in standalone mode";
+
1451
+
1452 m_networkOPs->setStandAlone();
+
1453 }
+
1454
+
1455 if (config_->canSign())
+
1456 {
+
1457 JLOG(m_journal.warn()) << "*** The server is configured to allow the "
+
1458 "'sign' and 'sign_for'";
+
1459 JLOG(m_journal.warn()) << "*** commands. These commands have security "
+
1460 "implications and have";
+
1461 JLOG(m_journal.warn()) << "*** been deprecated. They will be removed "
+
1462 "in a future release of";
+
1463 JLOG(m_journal.warn()) << "*** rippled.";
+
1464 JLOG(m_journal.warn()) << "*** If you do not use them to sign "
+
1465 "transactions please edit your";
+
1466 JLOG(m_journal.warn())
+
1467 << "*** configuration file and remove the [enable_signing] stanza.";
+
1468 JLOG(m_journal.warn()) << "*** If you do use them to sign transactions "
+
1469 "please migrate to a";
+
1470 JLOG(m_journal.warn())
+
1471 << "*** standalone signing solution as soon as possible.";
+
1472 }
+
1473
+
1474 //
+
1475 // Execute start up rpc commands.
+
1476 //
+
1477 for (auto cmd : config_->section(SECTION_RPC_STARTUP).lines())
+
1478 {
+
1479 Json::Reader jrReader;
+
1480 Json::Value jvCommand;
+
1481
+
1482 if (!jrReader.parse(cmd, jvCommand))
+
1483 {
+
1484 JLOG(m_journal.fatal()) << "Couldn't parse entry in ["
+
1485 << SECTION_RPC_STARTUP << "]: '" << cmd;
+
1486 }
+
1487
+
1488 if (!config_->quiet())
+
1489 {
+
1490 JLOG(m_journal.fatal())
+
1491 << "Startup RPC: " << jvCommand << std::endl;
+
1492 }
+
1493
+
1494 Resource::Charge loadType = Resource::feeReferenceRPC;
+
1495 Resource::Consumer c;
+
1496 RPC::JsonContext context{
+
1497 {journal("RPCHandler"),
+
1498 *this,
+
1499 loadType,
+
1500 getOPs(),
+
1501 getLedgerMaster(),
+
1502 c,
+
1503 Role::ADMIN,
1504 {},
-
1505 RPC::apiMaximumSupportedVersion},
-
1506 jvCommand};
-
1507
-
1508 Json::Value jvResult;
-
1509 RPC::doCommand(context, jvResult);
-
1510
-
1511 if (!config_->quiet())
-
1512 {
-
1513 JLOG(m_journal.fatal()) << "Result: " << jvResult << std::endl;
-
1514 }
-
1515 }
-
1516
-
1517 validatorSites_->start();
-
1518
-
1519 return true;
-
1520}
-
1521
-
1522void
-
1523ApplicationImp::start(bool withTimers)
-
1524{
-
1525 JLOG(m_journal.info()) << "Application starting. Version is "
-
1526 << BuildInfo::getVersionString();
-
1527
-
1528 if (withTimers)
-
1529 {
-
1530 setSweepTimer();
-
1531 setEntropyTimer();
-
1532 }
-
1533
-
1534 m_io_latency_sampler.start();
-
1535 m_resolver->start();
-
1536 m_loadManager->start();
-
1537 m_shaMapStore->start();
-
1538 if (overlay_)
-
1539 overlay_->start();
-
1540 grpcServer_->start();
-
1541 ledgerCleaner_->start();
-
1542 perfLog_->start();
-
1543}
-
1544
-
1545void
-
1546ApplicationImp::run()
-
1547{
-
1548 if (!config_->standalone())
-
1549 {
-
1550 // VFALCO NOTE This seems unnecessary. If we properly refactor the load
-
1551 // manager then the deadlock detector can just always be
-
1552 // "armed"
-
1553 //
-
1554 getLoadManager().activateDeadlockDetector();
-
1555 }
-
1556
-
1557 {
-
1558 std::unique_lock<std::mutex> lk{stoppingMutex_};
-
1559 stoppingCondition_.wait(lk, [this] { return isTimeToStop.load(); });
-
1560 }
-
1561
-
1562 JLOG(m_journal.debug()) << "Application stopping";
-
1563
-
1564 m_io_latency_sampler.cancel_async();
-
1565
-
1566 // VFALCO Enormous hack, we have to force the probe to cancel
-
1567 // before we stop the io_service queue or else it never
-
1568 // unblocks in its destructor. The fix is to make all
-
1569 // io_objects gracefully handle exit so that we can
-
1570 // naturally return from io_service::run() instead of
-
1571 // forcing a call to io_service::stop()
-
1572 m_io_latency_sampler.cancel();
-
1573
-
1574 m_resolver->stop_async();
-
1575
-
1576 // NIKB This is a hack - we need to wait for the resolver to
-
1577 // stop. before we stop the io_server_queue or weird
-
1578 // things will happen.
-
1579 m_resolver->stop();
-
1580
-
1581 {
-
1582 boost::system::error_code ec;
-
1583 sweepTimer_.cancel(ec);
-
1584 if (ec)
-
1585 {
-
1586 JLOG(m_journal.error())
-
1587 << "Application: sweepTimer cancel error: " << ec.message();
-
1588 }
-
1589
-
1590 ec.clear();
-
1591 entropyTimer_.cancel(ec);
-
1592 if (ec)
-
1593 {
-
1594 JLOG(m_journal.error())
-
1595 << "Application: entropyTimer cancel error: " << ec.message();
-
1596 }
-
1597 }
-
1598
-
1599 // Make sure that any waitHandlers pending in our timers are done
-
1600 // before we declare ourselves stopped.
-
1601 using namespace std::chrono_literals;
-
1602
-
1603 waitHandlerCounter_.join("Application", 1s, m_journal);
-
1604
-
1605 mValidations.flush();
-
1606
-
1607 validatorSites_->stop();
-
1608
-
1609 // TODO Store manifests in manifests.sqlite instead of wallet.db
-
1610 validatorManifests_->save(
-
1611 getWalletDB(), "ValidatorManifests", [this](PublicKey const& pubKey) {
-
1612 return validators().listed(pubKey);
-
1613 });
-
1614
-
1615 publisherManifests_->save(
-
1616 getWalletDB(), "PublisherManifests", [this](PublicKey const& pubKey) {
-
1617 return validators().trustedPublisher(pubKey);
-
1618 });
-
1619
-
1620 // The order of these stop calls is delicate.
-
1621 // Re-ordering them risks undefined behavior.
-
1622 m_loadManager->stop();
-
1623 m_shaMapStore->stop();
-
1624 m_jobQueue->stop();
-
1625 if (overlay_)
-
1626 overlay_->stop();
-
1627 grpcServer_->stop();
-
1628 m_networkOPs->stop();
-
1629 serverHandler_->stop();
-
1630 m_ledgerReplayer->stop();
-
1631 m_inboundTransactions->stop();
-
1632 m_inboundLedgers->stop();
-
1633 ledgerCleaner_->stop();
-
1634 m_nodeStore->stop();
-
1635 perfLog_->stop();
-
1636
-
1637 JLOG(m_journal.info()) << "Done.";
-
1638}
-
1639
-
1640void
-
1641ApplicationImp::signalStop(std::string msg)
-
1642{
-
1643 if (!isTimeToStop.exchange(true))
-
1644 {
-
1645 if (msg.empty())
-
1646 JLOG(m_journal.warn()) << "Server stopping";
-
1647 else
-
1648 JLOG(m_journal.warn()) << "Server stopping: " << msg;
-
1649
-
1650 stoppingCondition_.notify_all();
-
1651 }
-
1652}
-
1653
-
1654bool
-
1655ApplicationImp::checkSigs() const
-
1656{
-
1657 return checkSigs_;
-
1658}
-
1659
-
1660void
-
1661ApplicationImp::checkSigs(bool check)
-
1662{
-
1663 checkSigs_ = check;
-
1664}
-
1665
-
1666bool
-
1667ApplicationImp::isStopping() const
-
1668{
-
1669 return isTimeToStop.load();
-
1670}
-
1671
-
1672int
-
1673ApplicationImp::fdRequired() const
-
1674{
-
1675 // Standard handles, config file, misc I/O etc:
-
1676 int needed = 128;
-
1677
-
1678 // 2x the configured peer limit for peer connections:
-
1679 if (overlay_)
-
1680 needed += 2 * overlay_->limit();
-
1681
-
1682 // the number of fds needed by the backend (internally
-
1683 // doubled if online delete is enabled).
-
1684 needed += std::max(5, m_shaMapStore->fdRequired());
-
1685
-
1686 // One fd per incoming connection a port can accept, or
-
1687 // if no limit is set, assume it'll handle 256 clients.
-
1688 for (auto const& p : serverHandler_->setup().ports)
-
1689 needed += std::max(256, p.limit);
-
1690
-
1691 // The minimum number of file descriptors we need is 1024:
-
1692 return std::max(1024, needed);
-
1693}
-
1694
-
1695//------------------------------------------------------------------------------
-
1696
-
1697void
-
1698ApplicationImp::startGenesisLedger()
-
1699{
-
1700 std::vector<uint256> const initialAmendments =
-
1701 (config_->START_UP == Config::FRESH) ? m_amendmentTable->getDesired()
-
1702 : std::vector<uint256>{};
-
1703
-
1704 std::shared_ptr<Ledger> const genesis = std::make_shared<Ledger>(
-
1705 create_genesis, *config_, initialAmendments, nodeFamily_);
-
1706 m_ledgerMaster->storeLedger(genesis);
-
1707
-
1708 auto const next =
-
1709 std::make_shared<Ledger>(*genesis, timeKeeper().closeTime());
-
1710 next->updateSkipList();
-
1711 XRPL_ASSERT(
-
1712 next->info().seq < XRP_LEDGER_EARLIEST_FEES ||
-
1713 next->read(keylet::fees()),
-
1714 "ripple::ApplicationImp::startGenesisLedger : valid ledger fees");
-
1715 next->setImmutable();
-
1716 openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger"));
-
1717 m_ledgerMaster->storeLedger(next);
-
1718 m_ledgerMaster->switchLCL(next);
-
1719}
-
1720
-
1721std::shared_ptr<Ledger>
-
1722ApplicationImp::getLastFullLedger()
-
1723{
-
1724 auto j = journal("Ledger");
-
1725
-
1726 try
-
1727 {
-
1728 auto const [ledger, seq, hash] = getLatestLedger(*this);
-
1729
-
1730 if (!ledger)
-
1731 return ledger;
-
1732
-
1733 XRPL_ASSERT(
-
1734 ledger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
-
1735 ledger->read(keylet::fees()),
-
1736 "ripple::ApplicationImp::getLastFullLedger : valid ledger fees");
-
1737 ledger->setImmutable();
-
1738
-
1739 if (getLedgerMaster().haveLedger(seq))
-
1740 ledger->setValidated();
-
1741
-
1742 if (ledger->info().hash == hash)
-
1743 {
-
1744 JLOG(j.trace()) << "Loaded ledger: " << hash;
-
1745 return ledger;
-
1746 }
-
1747
-
1748 if (auto stream = j.error())
-
1749 {
-
1750 stream << "Failed on ledger";
-
1751 Json::Value p;
-
1752 addJson(p, {*ledger, nullptr, LedgerFill::full});
-
1753 stream << p;
-
1754 }
-
1755
-
1756 return {};
-
1757 }
-
1758 catch (SHAMapMissingNode const& mn)
-
1759 {
-
1760 JLOG(j.warn()) << "Ledger in database: " << mn.what();
-
1761 return {};
-
1762 }
-
1763}
-
1764
-
1765std::shared_ptr<Ledger>
-
1766ApplicationImp::loadLedgerFromFile(std::string const& name)
-
1767{
-
1768 try
-
1769 {
-
1770 std::ifstream ledgerFile(name, std::ios::in);
-
1771
-
1772 if (!ledgerFile)
-
1773 {
-
1774 JLOG(m_journal.fatal()) << "Unable to open file '" << name << "'";
-
1775 return nullptr;
-
1776 }
-
1777
-
1778 Json::Reader reader;
-
1779 Json::Value jLedger;
-
1780
-
1781 if (!reader.parse(ledgerFile, jLedger))
-
1782 {
-
1783 JLOG(m_journal.fatal()) << "Unable to parse ledger JSON";
-
1784 return nullptr;
-
1785 }
-
1786
-
1787 std::reference_wrapper<Json::Value> ledger(jLedger);
-
1788
-
1789 // accept a wrapped ledger
-
1790 if (ledger.get().isMember("result"))
-
1791 ledger = ledger.get()["result"];
-
1792
-
1793 if (ledger.get().isMember("ledger"))
-
1794 ledger = ledger.get()["ledger"];
-
1795
-
1796 std::uint32_t seq = 1;
-
1797 auto closeTime = timeKeeper().closeTime();
-
1798 using namespace std::chrono_literals;
-
1799 auto closeTimeResolution = 30s;
-
1800 bool closeTimeEstimated = false;
-
1801 std::uint64_t totalDrops = 0;
-
1802
-
1803 if (ledger.get().isMember("accountState"))
-
1804 {
-
1805 if (ledger.get().isMember(jss::ledger_index))
-
1806 {
-
1807 seq = ledger.get()[jss::ledger_index].asUInt();
-
1808 }
-
1809
-
1810 if (ledger.get().isMember("close_time"))
-
1811 {
-
1812 using tp = NetClock::time_point;
-
1813 using d = tp::duration;
-
1814 closeTime = tp{d{ledger.get()["close_time"].asUInt()}};
-
1815 }
-
1816 if (ledger.get().isMember("close_time_resolution"))
-
1817 {
-
1818 using namespace std::chrono;
-
1819 closeTimeResolution =
-
1820 seconds{ledger.get()["close_time_resolution"].asUInt()};
-
1821 }
-
1822 if (ledger.get().isMember("close_time_estimated"))
-
1823 {
-
1824 closeTimeEstimated =
-
1825 ledger.get()["close_time_estimated"].asBool();
-
1826 }
-
1827 if (ledger.get().isMember("total_coins"))
-
1828 {
-
1829 totalDrops = beast::lexicalCastThrow<std::uint64_t>(
-
1830 ledger.get()["total_coins"].asString());
-
1831 }
-
1832
-
1833 ledger = ledger.get()["accountState"];
-
1834 }
-
1835
-
1836 if (!ledger.get().isArrayOrNull())
-
1837 {
-
1838 JLOG(m_journal.fatal()) << "State nodes must be an array";
-
1839 return nullptr;
-
1840 }
-
1841
-
1842 auto loadLedger =
-
1843 std::make_shared<Ledger>(seq, closeTime, *config_, nodeFamily_);
-
1844 loadLedger->setTotalDrops(totalDrops);
-
1845
-
1846 for (Json::UInt index = 0; index < ledger.get().size(); ++index)
-
1847 {
-
1848 Json::Value& entry = ledger.get()[index];
-
1849
-
1850 if (!entry.isObjectOrNull())
-
1851 {
-
1852 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
-
1853 return nullptr;
-
1854 }
-
1855
-
1856 uint256 uIndex;
-
1857
-
1858 if (!uIndex.parseHex(entry[jss::index].asString()))
-
1859 {
-
1860 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
-
1861 return nullptr;
-
1862 }
-
1863
-
1864 entry.removeMember(jss::index);
-
1865
-
1866 STParsedJSONObject stp("sle", ledger.get()[index]);
-
1867
-
1868 if (!stp.object || uIndex.isZero())
-
1869 {
-
1870 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
-
1871 return nullptr;
-
1872 }
-
1873
-
1874 // VFALCO TODO This is the only place that
-
1875 // constructor is used, try to remove it
-
1876 STLedgerEntry sle(*stp.object, uIndex);
-
1877
-
1878 if (!loadLedger->addSLE(sle))
-
1879 {
-
1880 JLOG(m_journal.fatal())
-
1881 << "Couldn't add serialized ledger: " << uIndex;
-
1882 return nullptr;
-
1883 }
-
1884 }
-
1885
-
1886 loadLedger->stateMap().flushDirty(hotACCOUNT_NODE);
-
1887
-
1888 XRPL_ASSERT(
-
1889 loadLedger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
-
1890 loadLedger->read(keylet::fees()),
-
1891 "ripple::ApplicationImp::loadLedgerFromFile : valid ledger fees");
-
1892 loadLedger->setAccepted(
-
1893 closeTime, closeTimeResolution, !closeTimeEstimated);
-
1894
-
1895 return loadLedger;
-
1896 }
-
1897 catch (std::exception const& x)
-
1898 {
-
1899 JLOG(m_journal.fatal()) << "Ledger contains invalid data: " << x.what();
-
1900 return nullptr;
-
1901 }
-
1902}
-
1903
-
1904bool
-
1905ApplicationImp::loadOldLedger(
-
1906 std::string const& ledgerID,
-
1907 bool replay,
-
1908 bool isFileName,
-
1909 std::optional<uint256> trapTxID)
-
1910{
-
1911 try
-
1912 {
-
1913 std::shared_ptr<Ledger const> loadLedger, replayLedger;
-
1914
-
1915 if (isFileName)
-
1916 {
-
1917 if (!ledgerID.empty())
-
1918 loadLedger = loadLedgerFromFile(ledgerID);
-
1919 }
-
1920 else if (ledgerID.length() == 64)
-
1921 {
-
1922 uint256 hash;
-
1923
-
1924 if (hash.parseHex(ledgerID))
-
1925 {
-
1926 loadLedger = loadByHash(hash, *this);
-
1927
-
1928 if (!loadLedger)
-
1929 {
-
1930 // Try to build the ledger from the back end
-
1931 auto il = std::make_shared<InboundLedger>(
-
1932 *this,
-
1933 hash,
-
1934 0,
-
1935 InboundLedger::Reason::GENERIC,
-
1936 stopwatch(),
-
1937 make_DummyPeerSet(*this));
-
1938 if (il->checkLocal())
-
1939 loadLedger = il->getLedger();
-
1940 }
-
1941 }
-
1942 }
-
1943 else if (ledgerID.empty() || boost::iequals(ledgerID, "latest"))
-
1944 {
-
1945 loadLedger = getLastFullLedger();
-
1946 }
-
1947 else
-
1948 {
-
1949 // assume by sequence
-
1950 std::uint32_t index;
-
1951
-
1952 if (beast::lexicalCastChecked(index, ledgerID))
-
1953 loadLedger = loadByIndex(index, *this);
-
1954 }
-
1955
-
1956 if (!loadLedger)
-
1957 return false;
-
1958
-
1959 if (replay)
-
1960 {
-
1961 // Replay a ledger close with same prior ledger and transactions
-
1962
-
1963 // this ledger holds the transactions we want to replay
-
1964 replayLedger = loadLedger;
-
1965
-
1966 JLOG(m_journal.info()) << "Loading parent ledger";
-
1967
-
1968 loadLedger = loadByHash(replayLedger->info().parentHash, *this);
-
1969 if (!loadLedger)
-
1970 {
-
1971 JLOG(m_journal.info())
-
1972 << "Loading parent ledger from node store";
-
1973
-
1974 // Try to build the ledger from the back end
-
1975 auto il = std::make_shared<InboundLedger>(
-
1976 *this,
-
1977 replayLedger->info().parentHash,
-
1978 0,
-
1979 InboundLedger::Reason::GENERIC,
-
1980 stopwatch(),
-
1981 make_DummyPeerSet(*this));
-
1982
-
1983 if (il->checkLocal())
-
1984 loadLedger = il->getLedger();
-
1985
-
1986 if (!loadLedger)
-
1987 {
-
1988 JLOG(m_journal.fatal()) << "Replay ledger missing/damaged";
-
1989 UNREACHABLE(
-
1990 "ripple::ApplicationImp::loadOldLedger : replay ledger "
-
1991 "missing/damaged");
-
1992 return false;
-
1993 }
-
1994 }
-
1995 }
-
1996 using namespace std::chrono_literals;
-
1997 using namespace date;
-
1998 static constexpr NetClock::time_point ledgerWarnTimePoint{
-
1999 sys_days{January / 1 / 2018} - sys_days{January / 1 / 2000}};
-
2000 if (loadLedger->info().closeTime < ledgerWarnTimePoint)
-
2001 {
-
2002 JLOG(m_journal.fatal())
-
2003 << "\n\n*** WARNING ***\n"
-
2004 "You are replaying a ledger from before "
-
2005 << to_string(ledgerWarnTimePoint)
-
2006 << " UTC.\n"
-
2007 "This replay will not handle your ledger as it was "
-
2008 "originally "
-
2009 "handled.\nConsider running an earlier version of rippled "
-
2010 "to "
-
2011 "get the older rules.\n*** CONTINUING ***\n";
-
2012 }
-
2013
-
2014 JLOG(m_journal.info()) << "Loading ledger " << loadLedger->info().hash
-
2015 << " seq:" << loadLedger->info().seq;
-
2016
-
2017 if (loadLedger->info().accountHash.isZero())
-
2018 {
-
2019 JLOG(m_journal.fatal()) << "Ledger is empty.";
-
2020 UNREACHABLE(
-
2021 "ripple::ApplicationImp::loadOldLedger : ledger is empty");
-
2022 return false;
-
2023 }
-
2024
-
2025 if (!loadLedger->walkLedger(journal("Ledger"), true))
-
2026 {
-
2027 JLOG(m_journal.fatal()) << "Ledger is missing nodes.";
-
2028 UNREACHABLE(
-
2029 "ripple::ApplicationImp::loadOldLedger : ledger is missing "
-
2030 "nodes");
-
2031 return false;
-
2032 }
-
2033
-
2034 if (!loadLedger->assertSensible(journal("Ledger")))
-
2035 {
-
2036 JLOG(m_journal.fatal()) << "Ledger is not sensible.";
-
2037 UNREACHABLE(
-
2038 "ripple::ApplicationImp::loadOldLedger : ledger is not "
-
2039 "sensible");
-
2040 return false;
-
2041 }
-
2042
-
2043 m_ledgerMaster->setLedgerRangePresent(
-
2044 loadLedger->info().seq, loadLedger->info().seq);
-
2045
-
2046 m_ledgerMaster->switchLCL(loadLedger);
-
2047 loadLedger->setValidated();
-
2048 m_ledgerMaster->setFullLedger(loadLedger, true, false);
-
2049 openLedger_.emplace(
-
2050 loadLedger, cachedSLEs_, logs_->journal("OpenLedger"));
-
2051
-
2052 if (replay)
-
2053 {
-
2054 // inject transaction(s) from the replayLedger into our open ledger
-
2055 // and build replay structure
-
2056 auto replayData =
-
2057 std::make_unique<LedgerReplay>(loadLedger, replayLedger);
-
2058
-
2059 for (auto const& [_, tx] : replayData->orderedTxns())
-
2060 {
-
2061 (void)_;
-
2062 auto txID = tx->getTransactionID();
-
2063 if (trapTxID == txID)
-
2064 {
-
2065 trapTxID_ = txID;
-
2066 JLOG(m_journal.debug()) << "Trap transaction set: " << txID;
-
2067 }
-
2068
-
2069 auto s = std::make_shared<Serializer>();
-
2070 tx->add(*s);
-
2071
-
2072 forceValidity(getHashRouter(), txID, Validity::SigGoodOnly);
-
2073
-
2074 openLedger_->modify(
-
2075 [&txID, &s](OpenView& view, beast::Journal j) {
-
2076 view.rawTxInsert(txID, std::move(s), nullptr);
-
2077 return true;
-
2078 });
-
2079 }
-
2080
-
2081 m_ledgerMaster->takeReplay(std::move(replayData));
-
2082
-
2083 if (trapTxID && !trapTxID_)
-
2084 {
-
2085 JLOG(m_journal.fatal())
-
2086 << "Ledger " << replayLedger->info().seq
-
2087 << " does not contain the transaction hash " << *trapTxID;
-
2088 return false;
-
2089 }
-
2090 }
-
2091 }
-
2092 catch (SHAMapMissingNode const& mn)
-
2093 {
-
2094 JLOG(m_journal.fatal())
-
2095 << "While loading specified ledger: " << mn.what();
-
2096 return false;
-
2097 }
-
2098 catch (boost::bad_lexical_cast&)
-
2099 {
-
2100 JLOG(m_journal.fatal())
-
2101 << "Ledger specified '" << ledgerID << "' is not valid";
-
2102 return false;
-
2103 }
-
2104
-
2105 return true;
-
2106}
-
2107
-
2108bool
-
2109ApplicationImp::serverOkay(std::string& reason)
-
2110{
-
2111 if (!config().ELB_SUPPORT)
-
2112 return true;
-
2113
-
2114 if (isStopping())
-
2115 {
-
2116 reason = "Server is shutting down";
-
2117 return false;
-
2118 }
-
2119
-
2120 if (getOPs().isNeedNetworkLedger())
-
2121 {
-
2122 reason = "Not synchronized with network yet";
-
2123 return false;
-
2124 }
-
2125
-
2126 if (getOPs().isAmendmentBlocked())
-
2127 {
-
2128 reason = "Server version too old";
-
2129 return false;
-
2130 }
-
2131
-
2132 if (getOPs().isUNLBlocked())
-
2133 {
-
2134 reason = "No valid validator list available";
-
2135 return false;
-
2136 }
-
2137
-
2138 if (getOPs().getOperatingMode() < OperatingMode::SYNCING)
-
2139 {
-
2140 reason = "Not synchronized with network";
-
2141 return false;
-
2142 }
-
2143
-
2144 if (!getLedgerMaster().isCaughtUp(reason))
-
2145 return false;
-
2146
-
2147 if (getFeeTrack().isLoadedLocal())
-
2148 {
-
2149 reason = "Too much load";
-
2150 return false;
-
2151 }
-
2152
-
2153 return true;
-
2154}
-
2155
-
2156beast::Journal
-
2157ApplicationImp::journal(std::string const& name)
-
2158{
-
2159 return logs_->journal(name);
-
2160}
-
2161
-
2162void
-
2163ApplicationImp::setMaxDisallowedLedger()
-
2164{
-
2165 auto seq = getRelationalDatabase().getMaxLedgerSeq();
-
2166 if (seq)
-
2167 maxDisallowedLedger_ = *seq;
-
2168
-
2169 JLOG(m_journal.trace())
-
2170 << "Max persisted ledger is " << maxDisallowedLedger_;
-
2171}
-
2172
-
2173//------------------------------------------------------------------------------
-
2174
-
2175Application::Application() : beast::PropertyStream::Source("app")
-
2176{
-
2177}
-
2178
-
2179//------------------------------------------------------------------------------
-
2180
-
2181std::unique_ptr<Application>
-
2182make_Application(
-
2183 std::unique_ptr<Config> config,
-
2184 std::unique_ptr<Logs> logs,
-
2185 std::unique_ptr<TimeKeeper> timeKeeper)
-
2186{
-
2187 return std::make_unique<ApplicationImp>(
-
2188 std::move(config), std::move(logs), std::move(timeKeeper));
-
2189}
-
2190
-
2191} // namespace ripple
+
1505 {},
+
1506 RPC::apiMaximumSupportedVersion},
+
1507 jvCommand};
+
1508
+
1509 Json::Value jvResult;
+
1510 RPC::doCommand(context, jvResult);
+
1511
+
1512 if (!config_->quiet())
+
1513 {
+
1514 JLOG(m_journal.fatal()) << "Result: " << jvResult << std::endl;
+
1515 }
+
1516 }
+
1517
+
1518 validatorSites_->start();
+
1519
+
1520 return true;
+
1521}
+
1522
+
1523void
+
1524ApplicationImp::start(bool withTimers)
+
1525{
+
1526 JLOG(m_journal.info()) << "Application starting. Version is "
+
1527 << BuildInfo::getVersionString();
+
1528
+
1529 if (withTimers)
+
1530 {
+
1531 setSweepTimer();
+
1532 setEntropyTimer();
+
1533 }
+
1534
+
1535 m_io_latency_sampler.start();
+
1536 m_resolver->start();
+
1537 m_loadManager->start();
+
1538 m_shaMapStore->start();
+
1539 if (overlay_)
+
1540 overlay_->start();
+
1541 grpcServer_->start();
+
1542 ledgerCleaner_->start();
+
1543 perfLog_->start();
+
1544}
+
1545
+
1546void
+
1547ApplicationImp::run()
+
1548{
+
1549 if (!config_->standalone())
+
1550 {
+
1551 // VFALCO NOTE This seems unnecessary. If we properly refactor the load
+
1552 // manager then the deadlock detector can just always be
+
1553 // "armed"
+
1554 //
+
1555 getLoadManager().activateDeadlockDetector();
+
1556 }
+
1557
+
1558 {
+
1559 std::unique_lock<std::mutex> lk{stoppingMutex_};
+
1560 stoppingCondition_.wait(lk, [this] { return isTimeToStop.load(); });
+
1561 }
+
1562
+
1563 JLOG(m_journal.debug()) << "Application stopping";
+
1564
+
1565 m_io_latency_sampler.cancel_async();
+
1566
+
1567 // VFALCO Enormous hack, we have to force the probe to cancel
+
1568 // before we stop the io_service queue or else it never
+
1569 // unblocks in its destructor. The fix is to make all
+
1570 // io_objects gracefully handle exit so that we can
+
1571 // naturally return from io_service::run() instead of
+
1572 // forcing a call to io_service::stop()
+
1573 m_io_latency_sampler.cancel();
+
1574
+
1575 m_resolver->stop_async();
+
1576
+
1577 // NIKB This is a hack - we need to wait for the resolver to
+
1578 // stop. before we stop the io_server_queue or weird
+
1579 // things will happen.
+
1580 m_resolver->stop();
+
1581
+
1582 {
+
1583 boost::system::error_code ec;
+
1584 sweepTimer_.cancel(ec);
+
1585 if (ec)
+
1586 {
+
1587 JLOG(m_journal.error())
+
1588 << "Application: sweepTimer cancel error: " << ec.message();
+
1589 }
+
1590
+
1591 ec.clear();
+
1592 entropyTimer_.cancel(ec);
+
1593 if (ec)
+
1594 {
+
1595 JLOG(m_journal.error())
+
1596 << "Application: entropyTimer cancel error: " << ec.message();
+
1597 }
+
1598 }
+
1599
+
1600 // Make sure that any waitHandlers pending in our timers are done
+
1601 // before we declare ourselves stopped.
+
1602 using namespace std::chrono_literals;
+
1603
+
1604 waitHandlerCounter_.join("Application", 1s, m_journal);
+
1605
+
1606 mValidations.flush();
+
1607
+
1608 validatorSites_->stop();
+
1609
+
1610 // TODO Store manifests in manifests.sqlite instead of wallet.db
+
1611 validatorManifests_->save(
+
1612 getWalletDB(), "ValidatorManifests", [this](PublicKey const& pubKey) {
+
1613 return validators().listed(pubKey);
+
1614 });
+
1615
+
1616 publisherManifests_->save(
+
1617 getWalletDB(), "PublisherManifests", [this](PublicKey const& pubKey) {
+
1618 return validators().trustedPublisher(pubKey);
+
1619 });
+
1620
+
1621 // The order of these stop calls is delicate.
+
1622 // Re-ordering them risks undefined behavior.
+
1623 m_loadManager->stop();
+
1624 m_shaMapStore->stop();
+
1625 m_jobQueue->stop();
+
1626 if (overlay_)
+
1627 overlay_->stop();
+
1628 grpcServer_->stop();
+
1629 m_networkOPs->stop();
+
1630 serverHandler_->stop();
+
1631 m_ledgerReplayer->stop();
+
1632 m_inboundTransactions->stop();
+
1633 m_inboundLedgers->stop();
+
1634 ledgerCleaner_->stop();
+
1635 m_nodeStore->stop();
+
1636 perfLog_->stop();
+
1637
+
1638 JLOG(m_journal.info()) << "Done.";
+
1639}
+
1640
+
1641void
+
1642ApplicationImp::signalStop(std::string msg)
+
1643{
+
1644 if (!isTimeToStop.exchange(true))
+
1645 {
+
1646 if (msg.empty())
+
1647 JLOG(m_journal.warn()) << "Server stopping";
+
1648 else
+
1649 JLOG(m_journal.warn()) << "Server stopping: " << msg;
+
1650
+
1651 stoppingCondition_.notify_all();
+
1652 }
+
1653}
+
1654
+
1655bool
+
1656ApplicationImp::checkSigs() const
+
1657{
+
1658 return checkSigs_;
+
1659}
+
1660
+
1661void
+
1662ApplicationImp::checkSigs(bool check)
+
1663{
+
1664 checkSigs_ = check;
+
1665}
+
1666
+
1667bool
+
1668ApplicationImp::isStopping() const
+
1669{
+
1670 return isTimeToStop.load();
+
1671}
+
1672
+
1673int
+
1674ApplicationImp::fdRequired() const
+
1675{
+
1676 // Standard handles, config file, misc I/O etc:
+
1677 int needed = 128;
+
1678
+
1679 // 2x the configured peer limit for peer connections:
+
1680 if (overlay_)
+
1681 needed += 2 * overlay_->limit();
+
1682
+
1683 // the number of fds needed by the backend (internally
+
1684 // doubled if online delete is enabled).
+
1685 needed += std::max(5, m_shaMapStore->fdRequired());
+
1686
+
1687 // One fd per incoming connection a port can accept, or
+
1688 // if no limit is set, assume it'll handle 256 clients.
+
1689 for (auto const& p : serverHandler_->setup().ports)
+
1690 needed += std::max(256, p.limit);
+
1691
+
1692 // The minimum number of file descriptors we need is 1024:
+
1693 return std::max(1024, needed);
+
1694}
+
1695
+
1696//------------------------------------------------------------------------------
+
1697
+
1698void
+
1699ApplicationImp::startGenesisLedger()
+
1700{
+
1701 std::vector<uint256> const initialAmendments =
+
1702 (config_->START_UP == Config::FRESH) ? m_amendmentTable->getDesired()
+
1703 : std::vector<uint256>{};
+
1704
+
1705 std::shared_ptr<Ledger> const genesis = std::make_shared<Ledger>(
+
1706 create_genesis, *config_, initialAmendments, nodeFamily_);
+
1707 m_ledgerMaster->storeLedger(genesis);
+
1708
+
1709 auto const next =
+
1710 std::make_shared<Ledger>(*genesis, timeKeeper().closeTime());
+
1711 next->updateSkipList();
+
1712 XRPL_ASSERT(
+
1713 next->info().seq < XRP_LEDGER_EARLIEST_FEES ||
+
1714 next->read(keylet::fees()),
+
1715 "ripple::ApplicationImp::startGenesisLedger : valid ledger fees");
+
1716 next->setImmutable();
+
1717 openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger"));
+
1718 m_ledgerMaster->storeLedger(next);
+
1719 m_ledgerMaster->switchLCL(next);
+
1720}
+
1721
+
1722std::shared_ptr<Ledger>
+
1723ApplicationImp::getLastFullLedger()
+
1724{
+
1725 auto j = journal("Ledger");
+
1726
+
1727 try
+
1728 {
+
1729 auto const [ledger, seq, hash] = getLatestLedger(*this);
+
1730
+
1731 if (!ledger)
+
1732 return ledger;
+
1733
+
1734 XRPL_ASSERT(
+
1735 ledger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
+
1736 ledger->read(keylet::fees()),
+
1737 "ripple::ApplicationImp::getLastFullLedger : valid ledger fees");
+
1738 ledger->setImmutable();
+
1739
+
1740 if (getLedgerMaster().haveLedger(seq))
+
1741 ledger->setValidated();
+
1742
+
1743 if (ledger->info().hash == hash)
+
1744 {
+
1745 JLOG(j.trace()) << "Loaded ledger: " << hash;
+
1746 return ledger;
+
1747 }
+
1748
+
1749 if (auto stream = j.error())
+
1750 {
+
1751 stream << "Failed on ledger";
+
1752 Json::Value p;
+
1753 addJson(p, {*ledger, nullptr, LedgerFill::full});
+
1754 stream << p;
+
1755 }
+
1756
+
1757 return {};
+
1758 }
+
1759 catch (SHAMapMissingNode const& mn)
+
1760 {
+
1761 JLOG(j.warn()) << "Ledger in database: " << mn.what();
+
1762 return {};
+
1763 }
+
1764}
+
1765
+
1766std::shared_ptr<Ledger>
+
1767ApplicationImp::loadLedgerFromFile(std::string const& name)
+
1768{
+
1769 try
+
1770 {
+
1771 std::ifstream ledgerFile(name, std::ios::in);
+
1772
+
1773 if (!ledgerFile)
+
1774 {
+
1775 JLOG(m_journal.fatal()) << "Unable to open file '" << name << "'";
+
1776 return nullptr;
+
1777 }
+
1778
+
1779 Json::Reader reader;
+
1780 Json::Value jLedger;
+
1781
+
1782 if (!reader.parse(ledgerFile, jLedger))
+
1783 {
+
1784 JLOG(m_journal.fatal()) << "Unable to parse ledger JSON";
+
1785 return nullptr;
+
1786 }
+
1787
+
1788 std::reference_wrapper<Json::Value> ledger(jLedger);
+
1789
+
1790 // accept a wrapped ledger
+
1791 if (ledger.get().isMember("result"))
+
1792 ledger = ledger.get()["result"];
+
1793
+
1794 if (ledger.get().isMember("ledger"))
+
1795 ledger = ledger.get()["ledger"];
+
1796
+
1797 std::uint32_t seq = 1;
+
1798 auto closeTime = timeKeeper().closeTime();
+
1799 using namespace std::chrono_literals;
+
1800 auto closeTimeResolution = 30s;
+
1801 bool closeTimeEstimated = false;
+
1802 std::uint64_t totalDrops = 0;
+
1803
+
1804 if (ledger.get().isMember("accountState"))
+
1805 {
+
1806 if (ledger.get().isMember(jss::ledger_index))
+
1807 {
+
1808 seq = ledger.get()[jss::ledger_index].asUInt();
+
1809 }
+
1810
+
1811 if (ledger.get().isMember("close_time"))
+
1812 {
+
1813 using tp = NetClock::time_point;
+
1814 using d = tp::duration;
+
1815 closeTime = tp{d{ledger.get()["close_time"].asUInt()}};
+
1816 }
+
1817 if (ledger.get().isMember("close_time_resolution"))
+
1818 {
+
1819 using namespace std::chrono;
+
1820 closeTimeResolution =
+
1821 seconds{ledger.get()["close_time_resolution"].asUInt()};
+
1822 }
+
1823 if (ledger.get().isMember("close_time_estimated"))
+
1824 {
+
1825 closeTimeEstimated =
+
1826 ledger.get()["close_time_estimated"].asBool();
+
1827 }
+
1828 if (ledger.get().isMember("total_coins"))
+
1829 {
+
1830 totalDrops = beast::lexicalCastThrow<std::uint64_t>(
+
1831 ledger.get()["total_coins"].asString());
+
1832 }
+
1833
+
1834 ledger = ledger.get()["accountState"];
+
1835 }
+
1836
+
1837 if (!ledger.get().isArrayOrNull())
+
1838 {
+
1839 JLOG(m_journal.fatal()) << "State nodes must be an array";
+
1840 return nullptr;
+
1841 }
+
1842
+
1843 auto loadLedger =
+
1844 std::make_shared<Ledger>(seq, closeTime, *config_, nodeFamily_);
+
1845 loadLedger->setTotalDrops(totalDrops);
+
1846
+
1847 for (Json::UInt index = 0; index < ledger.get().size(); ++index)
+
1848 {
+
1849 Json::Value& entry = ledger.get()[index];
+
1850
+
1851 if (!entry.isObjectOrNull())
+
1852 {
+
1853 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
+
1854 return nullptr;
+
1855 }
+
1856
+
1857 uint256 uIndex;
+
1858
+
1859 if (!uIndex.parseHex(entry[jss::index].asString()))
+
1860 {
+
1861 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
+
1862 return nullptr;
+
1863 }
+
1864
+
1865 entry.removeMember(jss::index);
+
1866
+
1867 STParsedJSONObject stp("sle", ledger.get()[index]);
+
1868
+
1869 if (!stp.object || uIndex.isZero())
+
1870 {
+
1871 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
+
1872 return nullptr;
+
1873 }
+
1874
+
1875 // VFALCO TODO This is the only place that
+
1876 // constructor is used, try to remove it
+
1877 STLedgerEntry sle(*stp.object, uIndex);
+
1878
+
1879 if (!loadLedger->addSLE(sle))
+
1880 {
+
1881 JLOG(m_journal.fatal())
+
1882 << "Couldn't add serialized ledger: " << uIndex;
+
1883 return nullptr;
+
1884 }
+
1885 }
+
1886
+
1887 loadLedger->stateMap().flushDirty(hotACCOUNT_NODE);
+
1888
+
1889 XRPL_ASSERT(
+
1890 loadLedger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
+
1891 loadLedger->read(keylet::fees()),
+
1892 "ripple::ApplicationImp::loadLedgerFromFile : valid ledger fees");
+
1893 loadLedger->setAccepted(
+
1894 closeTime, closeTimeResolution, !closeTimeEstimated);
+
1895
+
1896 return loadLedger;
+
1897 }
+
1898 catch (std::exception const& x)
+
1899 {
+
1900 JLOG(m_journal.fatal()) << "Ledger contains invalid data: " << x.what();
+
1901 return nullptr;
+
1902 }
+
1903}
+
1904
+
1905bool
+
1906ApplicationImp::loadOldLedger(
+
1907 std::string const& ledgerID,
+
1908 bool replay,
+
1909 bool isFileName,
+
1910 std::optional<uint256> trapTxID)
+
1911{
+
1912 try
+
1913 {
+
1914 std::shared_ptr<Ledger const> loadLedger, replayLedger;
+
1915
+
1916 if (isFileName)
+
1917 {
+
1918 if (!ledgerID.empty())
+
1919 loadLedger = loadLedgerFromFile(ledgerID);
+
1920 }
+
1921 else if (ledgerID.length() == 64)
+
1922 {
+
1923 uint256 hash;
+
1924
+
1925 if (hash.parseHex(ledgerID))
+
1926 {
+
1927 loadLedger = loadByHash(hash, *this);
+
1928
+
1929 if (!loadLedger)
+
1930 {
+
1931 // Try to build the ledger from the back end
+
1932 auto il = std::make_shared<InboundLedger>(
+
1933 *this,
+
1934 hash,
+
1935 0,
+
1936 InboundLedger::Reason::GENERIC,
+
1937 stopwatch(),
+
1938 make_DummyPeerSet(*this));
+
1939 if (il->checkLocal())
+
1940 loadLedger = il->getLedger();
+
1941 }
+
1942 }
+
1943 }
+
1944 else if (ledgerID.empty() || boost::iequals(ledgerID, "latest"))
+
1945 {
+
1946 loadLedger = getLastFullLedger();
+
1947 }
+
1948 else
+
1949 {
+
1950 // assume by sequence
+
1951 std::uint32_t index;
+
1952
+
1953 if (beast::lexicalCastChecked(index, ledgerID))
+
1954 loadLedger = loadByIndex(index, *this);
+
1955 }
+
1956
+
1957 if (!loadLedger)
+
1958 return false;
+
1959
+
1960 if (replay)
+
1961 {
+
1962 // Replay a ledger close with same prior ledger and transactions
+
1963
+
1964 // this ledger holds the transactions we want to replay
+
1965 replayLedger = loadLedger;
+
1966
+
1967 JLOG(m_journal.info()) << "Loading parent ledger";
+
1968
+
1969 loadLedger = loadByHash(replayLedger->info().parentHash, *this);
+
1970 if (!loadLedger)
+
1971 {
+
1972 JLOG(m_journal.info())
+
1973 << "Loading parent ledger from node store";
+
1974
+
1975 // Try to build the ledger from the back end
+
1976 auto il = std::make_shared<InboundLedger>(
+
1977 *this,
+
1978 replayLedger->info().parentHash,
+
1979 0,
+
1980 InboundLedger::Reason::GENERIC,
+
1981 stopwatch(),
+
1982 make_DummyPeerSet(*this));
+
1983
+
1984 if (il->checkLocal())
+
1985 loadLedger = il->getLedger();
+
1986
+
1987 if (!loadLedger)
+
1988 {
+
1989 JLOG(m_journal.fatal()) << "Replay ledger missing/damaged";
+
1990 UNREACHABLE(
+
1991 "ripple::ApplicationImp::loadOldLedger : replay ledger "
+
1992 "missing/damaged");
+
1993 return false;
+
1994 }
+
1995 }
+
1996 }
+
1997 using namespace std::chrono_literals;
+
1998 using namespace date;
+
1999 static constexpr NetClock::time_point ledgerWarnTimePoint{
+
2000 sys_days{January / 1 / 2018} - sys_days{January / 1 / 2000}};
+
2001 if (loadLedger->info().closeTime < ledgerWarnTimePoint)
+
2002 {
+
2003 JLOG(m_journal.fatal())
+
2004 << "\n\n*** WARNING ***\n"
+
2005 "You are replaying a ledger from before "
+
2006 << to_string(ledgerWarnTimePoint)
+
2007 << " UTC.\n"
+
2008 "This replay will not handle your ledger as it was "
+
2009 "originally "
+
2010 "handled.\nConsider running an earlier version of rippled "
+
2011 "to "
+
2012 "get the older rules.\n*** CONTINUING ***\n";
+
2013 }
+
2014
+
2015 JLOG(m_journal.info()) << "Loading ledger " << loadLedger->info().hash
+
2016 << " seq:" << loadLedger->info().seq;
+
2017
+
2018 if (loadLedger->info().accountHash.isZero())
+
2019 {
+
2020 JLOG(m_journal.fatal()) << "Ledger is empty.";
+
2021 UNREACHABLE(
+
2022 "ripple::ApplicationImp::loadOldLedger : ledger is empty");
+
2023 return false;
+
2024 }
+
2025
+
2026 if (!loadLedger->walkLedger(journal("Ledger"), true))
+
2027 {
+
2028 JLOG(m_journal.fatal()) << "Ledger is missing nodes.";
+
2029 UNREACHABLE(
+
2030 "ripple::ApplicationImp::loadOldLedger : ledger is missing "
+
2031 "nodes");
+
2032 return false;
+
2033 }
+
2034
+
2035 if (!loadLedger->assertSensible(journal("Ledger")))
+
2036 {
+
2037 JLOG(m_journal.fatal()) << "Ledger is not sensible.";
+
2038 UNREACHABLE(
+
2039 "ripple::ApplicationImp::loadOldLedger : ledger is not "
+
2040 "sensible");
+
2041 return false;
+
2042 }
+
2043
+
2044 m_ledgerMaster->setLedgerRangePresent(
+
2045 loadLedger->info().seq, loadLedger->info().seq);
+
2046
+
2047 m_ledgerMaster->switchLCL(loadLedger);
+
2048 loadLedger->setValidated();
+
2049 m_ledgerMaster->setFullLedger(loadLedger, true, false);
+
2050 openLedger_.emplace(
+
2051 loadLedger, cachedSLEs_, logs_->journal("OpenLedger"));
+
2052
+
2053 if (replay)
+
2054 {
+
2055 // inject transaction(s) from the replayLedger into our open ledger
+
2056 // and build replay structure
+
2057 auto replayData =
+
2058 std::make_unique<LedgerReplay>(loadLedger, replayLedger);
+
2059
+
2060 for (auto const& [_, tx] : replayData->orderedTxns())
+
2061 {
+
2062 (void)_;
+
2063 auto txID = tx->getTransactionID();
+
2064 if (trapTxID == txID)
+
2065 {
+
2066 trapTxID_ = txID;
+
2067 JLOG(m_journal.debug()) << "Trap transaction set: " << txID;
+
2068 }
+
2069
+
2070 auto s = std::make_shared<Serializer>();
+
2071 tx->add(*s);
+
2072
+
2073 forceValidity(getHashRouter(), txID, Validity::SigGoodOnly);
+
2074
+
2075 openLedger_->modify(
+
2076 [&txID, &s](OpenView& view, beast::Journal j) {
+
2077 view.rawTxInsert(txID, std::move(s), nullptr);
+
2078 return true;
+
2079 });
+
2080 }
+
2081
+
2082 m_ledgerMaster->takeReplay(std::move(replayData));
+
2083
+
2084 if (trapTxID && !trapTxID_)
+
2085 {
+
2086 JLOG(m_journal.fatal())
+
2087 << "Ledger " << replayLedger->info().seq
+
2088 << " does not contain the transaction hash " << *trapTxID;
+
2089 return false;
+
2090 }
+
2091 }
+
2092 }
+
2093 catch (SHAMapMissingNode const& mn)
+
2094 {
+
2095 JLOG(m_journal.fatal())
+
2096 << "While loading specified ledger: " << mn.what();
+
2097 return false;
+
2098 }
+
2099 catch (boost::bad_lexical_cast&)
+
2100 {
+
2101 JLOG(m_journal.fatal())
+
2102 << "Ledger specified '" << ledgerID << "' is not valid";
+
2103 return false;
+
2104 }
+
2105
+
2106 return true;
+
2107}
+
2108
+
2109bool
+
2110ApplicationImp::serverOkay(std::string& reason)
+
2111{
+
2112 if (!config().ELB_SUPPORT)
+
2113 return true;
+
2114
+
2115 if (isStopping())
+
2116 {
+
2117 reason = "Server is shutting down";
+
2118 return false;
+
2119 }
+
2120
+
2121 if (getOPs().isNeedNetworkLedger())
+
2122 {
+
2123 reason = "Not synchronized with network yet";
+
2124 return false;
+
2125 }
+
2126
+
2127 if (getOPs().isAmendmentBlocked())
+
2128 {
+
2129 reason = "Server version too old";
+
2130 return false;
+
2131 }
+
2132
+
2133 if (getOPs().isUNLBlocked())
+
2134 {
+
2135 reason = "No valid validator list available";
+
2136 return false;
+
2137 }
+
2138
+
2139 if (getOPs().getOperatingMode() < OperatingMode::SYNCING)
+
2140 {
+
2141 reason = "Not synchronized with network";
+
2142 return false;
+
2143 }
+
2144
+
2145 if (!getLedgerMaster().isCaughtUp(reason))
+
2146 return false;
+
2147
+
2148 if (getFeeTrack().isLoadedLocal())
+
2149 {
+
2150 reason = "Too much load";
+
2151 return false;
+
2152 }
+
2153
+
2154 return true;
+
2155}
+
2156
+
2157beast::Journal
+
2158ApplicationImp::journal(std::string const& name)
+
2159{
+
2160 return logs_->journal(name);
+
2161}
+
2162
+
2163void
+
2164ApplicationImp::setMaxDisallowedLedger()
+
2165{
+
2166 auto seq = getRelationalDatabase().getMaxLedgerSeq();
+
2167 if (seq)
+
2168 maxDisallowedLedger_ = *seq;
+
2169
+
2170 JLOG(m_journal.trace())
+
2171 << "Max persisted ledger is " << maxDisallowedLedger_;
+
2172}
+
2173
+
2174//------------------------------------------------------------------------------
+
2175
+
2176Application::Application() : beast::PropertyStream::Source("app")
+
2177{
+
2178}
+
2179
+
2180//------------------------------------------------------------------------------
+
2181
+
2182std::unique_ptr<Application>
+
2183make_Application(
+
2184 std::unique_ptr<Config> config,
+
2185 std::unique_ptr<Logs> logs,
+
2186 std::unique_ptr<TimeKeeper> timeKeeper)
+
2187{
+
2188 return std::make_unique<ApplicationImp>(
+
2189 std::move(config), std::move(logs), std::move(timeKeeper));
+
2190}
+
2191
+
2192} // namespace ripple
std::atomic
std::ifstream
std::string
@@ -2312,7 +2313,7 @@ $(function() {
ripple::ApplicationImp::getServerHandler
virtual ServerHandler & getServerHandler() override
Definition: Application.cpp:587
ripple::ApplicationImp::cluster_
std::unique_ptr< Cluster > cluster_
Definition: Application.cpp:201
ripple::ApplicationImp::config
Config & config() override
Definition: Application.cpp:532
-
ripple::ApplicationImp::signalStop
void signalStop(std::string msg="") override
Definition: Application.cpp:1641
+
ripple::ApplicationImp::signalStop
void signalStop(std::string msg="") override
Definition: Application.cpp:1642
ripple::ApplicationImp::validators_
std::unique_ptr< ValidatorList > validators_
Definition: Application.cpp:205
ripple::ApplicationImp::instanceCookie_
std::uint64_t const instanceCookie_
Definition: Application.cpp:166
ripple::ApplicationImp::getHashRouter
HashRouter & getHashRouter() override
Definition: Application.cpp:724
@@ -2328,7 +2329,7 @@ $(function() {
ripple::ApplicationImp::getAmendmentTable
AmendmentTable & getAmendmentTable() override
Definition: Application.cpp:712
ripple::ApplicationImp::m_io_latency_sampler
io_latency_sampler m_io_latency_sampler
Definition: Application.cpp:235
ripple::ApplicationImp::numberOfThreads
static std::size_t numberOfThreads(Config const &config)
Definition: Application.cpp:242
-
ripple::ApplicationImp::isStopping
bool isStopping() const override
Definition: Application.cpp:1667
+
ripple::ApplicationImp::isStopping
bool isStopping() const override
Definition: Application.cpp:1668
ripple::ApplicationImp::getLoadManager
LoadManager & getLoadManager() override
Definition: Application.cpp:682
ripple::ApplicationImp::m_orderBookDB
OrderBookDB m_orderBookDB
Definition: Application.cpp:192
ripple::ApplicationImp::mFeeTrack
std::unique_ptr< LoadFeeTrack > mFeeTrack
Definition: Application.cpp:209
@@ -2350,7 +2351,7 @@ $(function() {
ripple::ApplicationImp::validatorSites
ValidatorSite & validatorSites() override
Definition: Application.cpp:742
ripple::ApplicationImp::peerReservations
PeerReservationTable & peerReservations() override
Definition: Application.cpp:766
ripple::ApplicationImp::publisherManifests
ManifestCache & publisherManifests() override
Definition: Application.cpp:754
-
ripple::ApplicationImp::fdRequired
int fdRequired() const override
Definition: Application.cpp:1673
+
ripple::ApplicationImp::fdRequired
int fdRequired() const override
Definition: Application.cpp:1674
ripple::ApplicationImp::getMasterMutex
Application::MutexType & getMasterMutex() override
Definition: Application.cpp:676
ripple::ApplicationImp::m_ledgerMaster
std::unique_ptr< LedgerMaster > m_ledgerMaster
Definition: Application.cpp:194
ripple::ApplicationImp::getMasterTransaction
TransactionMaster & getMasterTransaction() override
Definition: Application.cpp:652
@@ -2363,7 +2364,7 @@ $(function() {
ripple::ApplicationImp::overlay_
std::unique_ptr< Overlay > overlay_
Definition: Application.cpp:220
ripple::ApplicationImp::hashRouter_
std::unique_ptr< HashRouter > hashRouter_
Definition: Application.cpp:210
ripple::ApplicationImp::getRelationalDatabase
RelationalDatabase & getRelationalDatabase() override
Definition: Application.cpp:813
-
ripple::ApplicationImp::serverOkay
bool serverOkay(std::string &reason) override
Definition: Application.cpp:2109
+
ripple::ApplicationImp::serverOkay
bool serverOkay(std::string &reason) override
Definition: Application.cpp:2110
ripple::ApplicationImp::openLedger
OpenLedger & openLedger() override
Definition: Application.cpp:784
ripple::ApplicationImp::stoppingMutex_
std::mutex stoppingMutex_
Definition: Application.cpp:228
ripple::ApplicationImp::timeKeeper
TimeKeeper & timeKeeper() override
Definition: Application.cpp:550
@@ -2384,7 +2385,7 @@ $(function() {
ripple::ApplicationImp::serverHandler_
std::unique_ptr< ServerHandler > serverHandler_
Definition: Application.cpp:207
ripple::ApplicationImp::getLedgerMaster
LedgerMaster & getLedgerMaster() override
Definition: Application.cpp:609
ripple::ApplicationImp::gotTXSet
void gotTXSet(std::shared_ptr< SHAMap > const &set, bool fromAcquire)
Definition: Application.cpp:645
-
ripple::ApplicationImp::start
void start(bool withTimers) override
Definition: Application.cpp:1523
+
ripple::ApplicationImp::start
void start(bool withTimers) override
Definition: Application.cpp:1524
ripple::ApplicationImp::publisherManifests_
std::unique_ptr< ManifestCache > publisherManifests_
Definition: Application.cpp:204
ripple::ApplicationImp::m_signals
boost::asio::signal_set m_signals
Definition: Application.cpp:223
ripple::ApplicationImp::m_loadManager
std::unique_ptr< LoadManager > m_loadManager
Definition: Application.cpp:212
@@ -2395,16 +2396,16 @@ $(function() {
ripple::ApplicationImp::m_masterMutex
Application::MutexType m_masterMutex
Definition: Application.cpp:170
ripple::ApplicationImp::perfLog_
std::unique_ptr< perf::PerfLog > perfLog_
Definition: Application.cpp:169
ripple::ApplicationImp::initRelationalDatabase
bool initRelationalDatabase()
Definition: Application.cpp:840
-
ripple::ApplicationImp::checkSigs
bool checkSigs() const override
Definition: Application.cpp:1655
+
ripple::ApplicationImp::checkSigs
bool checkSigs() const override
Definition: Application.cpp:1656
ripple::ApplicationImp::timeKeeper_
std::unique_ptr< TimeKeeper > timeKeeper_
Definition: Application.cpp:164
-
ripple::ApplicationImp::run
void run() override
Definition: Application.cpp:1546
+
ripple::ApplicationImp::run
void run() override
Definition: Application.cpp:1547
ripple::ApplicationImp::getNodeStore
NodeStore::Database & getNodeStore() override
Definition: Application.cpp:670
ripple::ApplicationImp::pendingSaves
PendingSaves & pendingSaves() override
Definition: Application.cpp:778
ripple::ApplicationImp::m_amendmentTable
std::unique_ptr< AmendmentTable > m_amendmentTable
Definition: Application.cpp:208
ripple::ApplicationImp::trapTxID_
std::optional< uint256 > trapTxID_
Definition: Application.cpp:221
ripple::ApplicationImp::ApplicationImp
ApplicationImp(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:265
ripple::ApplicationImp::mWalletDB
std::unique_ptr< DatabaseCon > mWalletDB
Definition: Application.cpp:219
-
ripple::ApplicationImp::journal
beast::Journal journal(std::string const &name) override
Definition: Application.cpp:2157
+
ripple::ApplicationImp::journal
beast::Journal journal(std::string const &name) override
Definition: Application.cpp:2158
ripple::ApplicationImp::getPathRequests
PathRequests & getPathRequests() override
Definition: Application.cpp:700
ripple::ApplicationImp::nodeIdentity_
std::optional< std::pair< PublicKey, SecretKey > > nodeIdentity_
Definition: Application.cpp:184
ripple::ApplicationImp::sweepTimer_
boost::asio::steady_timer sweepTimer_
Definition: Application.cpp:215
@@ -2439,7 +2440,7 @@ $(function() {
ripple::Config
Definition: Config.h:93
ripple::Config::IO_WORKERS
int IO_WORKERS
Definition: Config.h:242
ripple::Config::FORCE_MULTI_THREAD
bool FORCE_MULTI_THREAD
Definition: Config.h:246
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::WORKERS
int WORKERS
Definition: Config.h:241
ripple::Config::NODE_SIZE
std::size_t NODE_SIZE
Definition: Config.h:220
ripple::DatabaseCon
Definition: DatabaseCon.h:84
@@ -2532,7 +2533,7 @@ $(function() {
ripple::setup_TxQ
TxQ::Setup setup_TxQ(Config const &config)
Build a TxQ::Setup object from application configuration.
Definition: TxQ.cpp:1914
ripple::loadByIndex
std::shared_ptr< Ledger > loadByIndex(std::uint32_t ledgerIndex, Application &app, bool acquire)
Definition: Ledger.cpp:1122
ripple::make_LoadManager
std::unique_ptr< LoadManager > make_LoadManager(Application &app, beast::Journal journal)
Definition: LoadManager.cpp:199
-
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2182
+
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2183
ripple::make_ServerHandler
std::unique_ptr< ServerHandler > make_ServerHandler(Application &app, boost::asio::io_service &io_service, JobQueue &jobQueue, NetworkOPs &networkOPs, Resource::Manager &resourceManager, CollectorManager &cm)
Definition: ServerHandler.cpp:1255
ripple::initAccountIdCache
void initAccountIdCache(std::size_t count)
Initialize the global cache used to map AccountID to base58 conversions.
Definition: AccountID.cpp:99
ripple::make_NetworkOPs
std::unique_ptr< NetworkOPs > make_NetworkOPs(Application &app, NetworkOPs::clock_type &clock, bool standalone, std::size_t minPeerCount, bool startvalid, JobQueue &job_queue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_service &io_svc, beast::Journal journal, beast::insight::Collector::ptr const &collector)
Definition: NetworkOPs.cpp:4552
diff --git a/Application_8h_source.html b/Application_8h_source.html index a348153809..21c937af54 100644 --- a/Application_8h_source.html +++ b/Application_8h_source.html @@ -395,7 +395,7 @@ $(function() {
ripple::Application::validatorSites
virtual ValidatorSite & validatorSites()=0
ripple::Application::getWalletDB
virtual DatabaseCon & getWalletDB()=0
Retrieve the "wallet database".
ripple::Application::getResourceManager
virtual Resource::Manager & getResourceManager()=0
-
ripple::Application::Application
Application()
Definition: Application.cpp:2175
+
ripple::Application::Application
Application()
Definition: Application.cpp:2176
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::Application::signalStop
virtual void signalStop(std::string msg="")=0
@@ -472,7 +472,7 @@ $(function() {
memory
mutex
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2182
+
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2183
ripple::SLE
STLedgerEntry SLE
Definition: STLedgerEntry.h:97
std::optional
std::pair
diff --git a/ConfigSections_8h_source.html b/ConfigSections_8h_source.html index 5700ad9702..89938f7906 100644 --- a/ConfigSections_8h_source.html +++ b/ConfigSections_8h_source.html @@ -169,14 +169,15 @@ $(function() {
91#define SECTION_VALIDATOR_KEY_REVOCATION "validator_key_revocation"
92#define SECTION_VALIDATOR_LIST_KEYS "validator_list_keys"
93#define SECTION_VALIDATOR_LIST_SITES "validator_list_sites"
-
94#define SECTION_VALIDATORS "validators"
-
95#define SECTION_VALIDATOR_TOKEN "validator_token"
-
96#define SECTION_VETO_AMENDMENTS "veto_amendments"
-
97#define SECTION_WORKERS "workers"
-
98
-
99} // namespace ripple
-
100
-
101#endif
+
94#define SECTION_VALIDATOR_LIST_THRESHOLD "validator_list_threshold"
+
95#define SECTION_VALIDATORS "validators"
+
96#define SECTION_VALIDATOR_TOKEN "validator_token"
+
97#define SECTION_VETO_AMENDMENTS "veto_amendments"
+
98#define SECTION_WORKERS "workers"
+
99
+
100} // namespace ripple
+
101
+
102#endif
std::string
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
string
diff --git a/Config_8cpp_source.html b/Config_8cpp_source.html index ae4458dfaf..7f475dd195 100644 --- a/Config_8cpp_source.html +++ b/Config_8cpp_source.html @@ -990,132 +990,171 @@ $(function() {
912 if (valListKeys)
913 section(SECTION_VALIDATOR_LIST_KEYS).append(*valListKeys);
914
-
915 if (!entries && !valKeyEntries && !valListKeys)
-
916 Throw<std::runtime_error>(
-
917 "The file specified in [" SECTION_VALIDATORS_FILE
-
918 "] "
-
919 "does not contain a [" SECTION_VALIDATORS
-
920 "], "
-
921 "[" SECTION_VALIDATOR_KEYS
-
922 "] or "
-
923 "[" SECTION_VALIDATOR_LIST_KEYS
-
924 "]"
-
925 " section: " +
-
926 validatorsFile.string());
-
927 }
-
928
-
929 // Consolidate [validator_keys] and [validators]
-
930 section(SECTION_VALIDATORS)
-
931 .append(section(SECTION_VALIDATOR_KEYS).lines());
-
932
-
933 if (!section(SECTION_VALIDATOR_LIST_SITES).lines().empty() &&
-
934 section(SECTION_VALIDATOR_LIST_KEYS).lines().empty())
-
935 {
-
936 Throw<std::runtime_error>(
-
937 "[" + std::string(SECTION_VALIDATOR_LIST_KEYS) +
-
938 "] config section is missing");
-
939 }
-
940 }
-
941
-
942 {
-
943 auto const part = section("features");
-
944 for (auto const& s : part.values())
-
945 {
-
946 if (auto const f = getRegisteredFeature(s))
-
947 features.insert(*f);
-
948 else
-
949 Throw<std::runtime_error>(
-
950 "Unknown feature: " + s + " in config file.");
-
951 }
-
952 }
-
953
-
954 // This doesn't properly belong here, but check to make sure that the
-
955 // value specified for network_quorum is achievable:
-
956 {
-
957 auto pm = PEERS_MAX;
-
958
-
959 // FIXME this apparently magic value is actually defined as a constant
-
960 // elsewhere (see defaultMaxPeers) but we handle this check here.
-
961 if (pm == 0)
-
962 pm = 21;
-
963
-
964 if (NETWORK_QUORUM > pm)
-
965 {
-
966 Throw<std::runtime_error>(
-
967 "The minimum number of required peers (network_quorum) exceeds "
-
968 "the maximum number of allowed peers (peers_max)");
-
969 }
-
970 }
-
971}
-
972
-
973boost::filesystem::path
-
974Config::getDebugLogFile() const
-
975{
-
976 auto log_file = DEBUG_LOGFILE;
-
977
-
978 if (!log_file.empty() && !log_file.is_absolute())
-
979 {
-
980 // Unless an absolute path for the log file is specified, the
-
981 // path is relative to the config file directory.
-
982 log_file = boost::filesystem::absolute(log_file, CONFIG_DIR);
-
983 }
-
984
-
985 if (!log_file.empty())
-
986 {
-
987 auto log_dir = log_file.parent_path();
-
988
-
989 if (!boost::filesystem::is_directory(log_dir))
-
990 {
-
991 boost::system::error_code ec;
-
992 boost::filesystem::create_directories(log_dir, ec);
-
993
-
994 // If we fail, we warn but continue so that the calling code can
-
995 // decide how to handle this situation.
-
996 if (ec)
-
997 {
-
998 std::cerr << "Unable to create log file path " << log_dir
-
999 << ": " << ec.message() << '\n';
-
1000 }
-
1001 }
-
1002 }
-
1003
-
1004 return log_file;
-
1005}
-
1006
-
1007int
-
1008Config::getValueFor(SizedItem item, std::optional<std::size_t> node) const
-
1009{
-
1010 auto const index = static_cast<std::underlying_type_t<SizedItem>>(item);
-
1011 XRPL_ASSERT(
-
1012 index < sizedItems.size(),
-
1013 "ripple::Config::getValueFor : valid index input");
-
1014 XRPL_ASSERT(
-
1015 !node || *node <= 4,
-
1016 "ripple::Config::getValueFor : unset or valid node");
-
1017 return sizedItems.at(index).second.at(node.value_or(NODE_SIZE));
-
1018}
-
1019
-
1020FeeSetup
-
1021setup_FeeVote(Section const& section)
-
1022{
-
1023 FeeSetup setup;
-
1024 {
-
1025 std::uint64_t temp;
-
1026 if (set(temp, "reference_fee", section) &&
-
1027 temp <= std::numeric_limits<XRPAmount::value_type>::max())
-
1028 setup.reference_fee = temp;
-
1029 }
-
1030 {
-
1031 std::uint32_t temp;
-
1032 if (set(temp, "account_reserve", section))
-
1033 setup.account_reserve = temp;
-
1034 if (set(temp, "owner_reserve", section))
-
1035 setup.owner_reserve = temp;
-
1036 }
-
1037 return setup;
-
1038}
-
1039
-
1040} // namespace ripple
+
915 auto valListThreshold =
+
916 getIniFileSection(iniFile, SECTION_VALIDATOR_LIST_THRESHOLD);
+
917
+
918 if (valListThreshold)
+
919 section(SECTION_VALIDATOR_LIST_THRESHOLD)
+
920 .append(*valListThreshold);
+
921
+
922 if (!entries && !valKeyEntries && !valListKeys)
+
923 Throw<std::runtime_error>(
+
924 "The file specified in [" SECTION_VALIDATORS_FILE
+
925 "] "
+
926 "does not contain a [" SECTION_VALIDATORS
+
927 "], "
+
928 "[" SECTION_VALIDATOR_KEYS
+
929 "] or "
+
930 "[" SECTION_VALIDATOR_LIST_KEYS
+
931 "]"
+
932 " section: " +
+
933 validatorsFile.string());
+
934 }
+
935
+
936 VALIDATOR_LIST_THRESHOLD = [&]() -> std::optional<std::size_t> {
+
937 auto const& listThreshold =
+
938 section(SECTION_VALIDATOR_LIST_THRESHOLD);
+
939 if (listThreshold.lines().empty())
+
940 return std::nullopt;
+
941 else if (listThreshold.values().size() == 1)
+
942 {
+
943 auto strTemp = listThreshold.values()[0];
+
944 auto const listThreshold =
+
945 beast::lexicalCastThrow<std::size_t>(strTemp);
+
946 if (listThreshold == 0)
+
947 return std::nullopt; // NOTE: Explicitly ask for computed
+
948 else if (
+
949 listThreshold >
+
950 section(SECTION_VALIDATOR_LIST_KEYS).values().size())
+
951 {
+
952 Throw<std::runtime_error>(
+
953 "Value in config section "
+
954 "[" SECTION_VALIDATOR_LIST_THRESHOLD
+
955 "] exceeds the number of configured list keys");
+
956 }
+
957 return listThreshold;
+
958 }
+
959 else
+
960 {
+
961 Throw<std::runtime_error>(
+
962 "Config section "
+
963 "[" SECTION_VALIDATOR_LIST_THRESHOLD
+
964 "] should contain single value only");
+
965 }
+
966 }();
+
967
+
968 // Consolidate [validator_keys] and [validators]
+
969 section(SECTION_VALIDATORS)
+
970 .append(section(SECTION_VALIDATOR_KEYS).lines());
+
971
+
972 if (!section(SECTION_VALIDATOR_LIST_SITES).lines().empty() &&
+
973 section(SECTION_VALIDATOR_LIST_KEYS).lines().empty())
+
974 {
+
975 Throw<std::runtime_error>(
+
976 "[" + std::string(SECTION_VALIDATOR_LIST_KEYS) +
+
977 "] config section is missing");
+
978 }
+
979 }
+
980
+
981 {
+
982 auto const part = section("features");
+
983 for (auto const& s : part.values())
+
984 {
+
985 if (auto const f = getRegisteredFeature(s))
+
986 features.insert(*f);
+
987 else
+
988 Throw<std::runtime_error>(
+
989 "Unknown feature: " + s + " in config file.");
+
990 }
+
991 }
+
992
+
993 // This doesn't properly belong here, but check to make sure that the
+
994 // value specified for network_quorum is achievable:
+
995 {
+
996 auto pm = PEERS_MAX;
+
997
+
998 // FIXME this apparently magic value is actually defined as a constant
+
999 // elsewhere (see defaultMaxPeers) but we handle this check here.
+
1000 if (pm == 0)
+
1001 pm = 21;
+
1002
+
1003 if (NETWORK_QUORUM > pm)
+
1004 {
+
1005 Throw<std::runtime_error>(
+
1006 "The minimum number of required peers (network_quorum) exceeds "
+
1007 "the maximum number of allowed peers (peers_max)");
+
1008 }
+
1009 }
+
1010}
+
1011
+
1012boost::filesystem::path
+
1013Config::getDebugLogFile() const
+
1014{
+
1015 auto log_file = DEBUG_LOGFILE;
+
1016
+
1017 if (!log_file.empty() && !log_file.is_absolute())
+
1018 {
+
1019 // Unless an absolute path for the log file is specified, the
+
1020 // path is relative to the config file directory.
+
1021 log_file = boost::filesystem::absolute(log_file, CONFIG_DIR);
+
1022 }
+
1023
+
1024 if (!log_file.empty())
+
1025 {
+
1026 auto log_dir = log_file.parent_path();
+
1027
+
1028 if (!boost::filesystem::is_directory(log_dir))
+
1029 {
+
1030 boost::system::error_code ec;
+
1031 boost::filesystem::create_directories(log_dir, ec);
+
1032
+
1033 // If we fail, we warn but continue so that the calling code can
+
1034 // decide how to handle this situation.
+
1035 if (ec)
+
1036 {
+
1037 std::cerr << "Unable to create log file path " << log_dir
+
1038 << ": " << ec.message() << '\n';
+
1039 }
+
1040 }
+
1041 }
+
1042
+
1043 return log_file;
+
1044}
+
1045
+
1046int
+
1047Config::getValueFor(SizedItem item, std::optional<std::size_t> node) const
+
1048{
+
1049 auto const index = static_cast<std::underlying_type_t<SizedItem>>(item);
+
1050 XRPL_ASSERT(
+
1051 index < sizedItems.size(),
+
1052 "ripple::Config::getValueFor : valid index input");
+
1053 XRPL_ASSERT(
+
1054 !node || *node <= 4,
+
1055 "ripple::Config::getValueFor : unset or valid node");
+
1056 return sizedItems.at(index).second.at(node.value_or(NODE_SIZE));
+
1057}
+
1058
+
1059FeeSetup
+
1060setup_FeeVote(Section const& section)
+
1061{
+
1062 FeeSetup setup;
+
1063 {
+
1064 std::uint64_t temp;
+
1065 if (set(temp, "reference_fee", section) &&
+
1066 temp <= std::numeric_limits<XRPAmount::value_type>::max())
+
1067 setup.reference_fee = temp;
+
1068 }
+
1069 {
+
1070 std::uint32_t temp;
+
1071 if (set(temp, "account_reserve", section))
+
1072 setup.account_reserve = temp;
+
1073 if (set(temp, "owner_reserve", section))
+
1074 setup.owner_reserve = temp;
+
1075 }
+
1076 return setup;
+
1077}
+
1078
+
1079} // namespace ripple
algorithm
std::array
std::regex
@@ -1152,11 +1191,12 @@ $(function() {
ripple::Config::BETA_RPC_API
bool BETA_RPC_API
Definition: Config.h:295
ripple::Config::j_
beast::Journal const j_
Definition: Config.h:115
ripple::Config::LEDGER_REPLAY
bool LEDGER_REPLAY
Definition: Config.h:230
+
ripple::Config::VALIDATOR_LIST_THRESHOLD
std::optional< std::size_t > VALIDATOR_LIST_THRESHOLD
Definition: Config.h:308
ripple::Config::PATH_SEARCH_MAX
int PATH_SEARCH_MAX
Definition: Config.h:205
ripple::Config::PATH_SEARCH_FAST
int PATH_SEARCH_FAST
Definition: Config.h:204
ripple::Config::RELAY_UNTRUSTED_PROPOSALS
int RELAY_UNTRUSTED_PROPOSALS
Definition: Config.h:177
ripple::Config::TX_REDUCE_RELAY_ENABLE
bool TX_REDUCE_RELAY_ENABLE
Definition: Config.h:266
-
ripple::Config::getDebugLogFile
boost::filesystem::path getDebugLogFile() const
Returns the full path and filename of the debug log file.
Definition: Config.cpp:974
+
ripple::Config::getDebugLogFile
boost::filesystem::path getDebugLogFile() const
Returns the full path and filename of the debug log file.
Definition: Config.cpp:1013
ripple::Config::load
void load()
Definition: Config.cpp:424
ripple::Config::FAST_LOAD
bool FAST_LOAD
Definition: Config.h:298
ripple::Config::WORKERS
int WORKERS
Definition: Config.h:241
@@ -1172,7 +1212,7 @@ $(function() {
ripple::Config::SSL_VERIFY
bool SSL_VERIFY
Definition: Config.h:222
ripple::Config::CONFIG_FILE
boost::filesystem::path CONFIG_FILE
Definition: Config.h:105
ripple::Config::USE_TX_TABLES
bool USE_TX_TABLES
Definition: Config.h:130
-
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1008
+
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1047
ripple::Config::FEES
FeeSetup FEES
Definition: Config.h:211
ripple::Config::signingEnabled_
bool signingEnabled_
Determines if the server will sign a tx, given an account's secret seed.
Definition: Config.h:138
ripple::Config::DEBUG_LOGFILE
boost::filesystem::path DEBUG_LOGFILE
Definition: Config.h:111
@@ -1236,7 +1276,7 @@ $(function() {
ripple::AttestationMatch::match
@ match
ripple::getFileContents
std::string getFileContents(boost::system::error_code &ec, boost::filesystem::path const &sourcePath, std::optional< std::size_t > maxSize=std::nullopt)
Definition: FileUtilities.cpp:25
ripple::parseIniFile
IniFileSections parseIniFile(std::string const &strInput, const bool bTrim)
Definition: Config.cpp:159
-
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1021
+
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1060
ripple::isProperlyFormedTomlDomain
bool isProperlyFormedTomlDomain(std::string_view domain)
Determines if the given string looks like a TOML-file hosting domain.
Definition: StringUtilities.cpp:123
ripple::sizedItems
constexpr std::array< std::pair< SizedItem, std::array< int, 5 > >, 13 > sizedItems
Definition: Config.cpp:112
std::chrono
diff --git a/Config_8h_source.html b/Config_8h_source.html index 5f4a955586..4503f3a2be 100644 --- a/Config_8h_source.html +++ b/Config_8h_source.html @@ -359,76 +359,78 @@ $(function() {
305 std::optional<std::pair<std::uint32_t, std::uint32_t>>
306 FORCED_LEDGER_RANGE_PRESENT;
307
-
308public:
-
309 Config();
-
310
-
311 /* Be very careful to make sure these bool params
-
312 are in the right order. */
-
313 void
-
314 setup(
-
315 std::string const& strConf,
-
316 bool bQuiet,
-
317 bool bSilent,
-
318 bool bStandalone);
-
319
-
320 void
-
321 setupControl(bool bQuiet, bool bSilent, bool bStandalone);
-
322
-
328 void
-
329 loadFromString(std::string const& fileContents);
-
330
-
331 bool
-
332 quiet() const
-
333 {
-
334 return QUIET;
-
335 }
-
336 bool
-
337 silent() const
-
338 {
-
339 return SILENT;
-
340 }
-
341 bool
-
342 standalone() const
-
343 {
-
344 return RUN_STANDALONE;
-
345 }
-
346
-
347 bool
-
348 useTxTables() const
-
349 {
-
350 return USE_TX_TABLES;
-
351 }
-
352
-
353 bool
-
354 canSign() const
-
355 {
-
356 return signingEnabled_;
-
357 }
-
358
-
376 int
-
377 getValueFor(SizedItem item, std::optional<std::size_t> node = std::nullopt)
-
378 const;
-
379
-
380 beast::Journal
-
381 journal() const
-
382 {
-
383 return j_;
-
384 }
-
385};
-
386
-
387FeeSetup
-
388setup_FeeVote(Section const& section);
-
389
-
390} // namespace ripple
+
308 std::optional<std::size_t> VALIDATOR_LIST_THRESHOLD;
+
309
+
310public:
+
311 Config();
+
312
+
313 /* Be very careful to make sure these bool params
+
314 are in the right order. */
+
315 void
+
316 setup(
+
317 std::string const& strConf,
+
318 bool bQuiet,
+
319 bool bSilent,
+
320 bool bStandalone);
+
321
+
322 void
+
323 setupControl(bool bQuiet, bool bSilent, bool bStandalone);
+
324
+
330 void
+
331 loadFromString(std::string const& fileContents);
+
332
+
333 bool
+
334 quiet() const
+
335 {
+
336 return QUIET;
+
337 }
+
338 bool
+
339 silent() const
+
340 {
+
341 return SILENT;
+
342 }
+
343 bool
+
344 standalone() const
+
345 {
+
346 return RUN_STANDALONE;
+
347 }
+
348
+
349 bool
+
350 useTxTables() const
+
351 {
+
352 return USE_TX_TABLES;
+
353 }
+
354
+
355 bool
+
356 canSign() const
+
357 {
+
358 return signingEnabled_;
+
359 }
+
360
+
378 int
+
379 getValueFor(SizedItem item, std::optional<std::size_t> node = std::nullopt)
+
380 const;
+
381
+
382 beast::Journal
+
383 journal() const
+
384 {
+
385 return j_;
+
386 }
+
387};
+
388
+
389FeeSetup
+
390setup_FeeVote(Section const& section);
391
-
392#endif
+
392} // namespace ripple
+
393
+
394#endif
algorithm
std::string
chrono
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:59
ripple::BasicConfig
Holds unparsed configuration information.
Definition: BasicConfig.h:216
ripple::Config
Definition: Config.h:93
-
ripple::Config::silent
bool silent() const
Definition: Config.h:337
+
ripple::Config::silent
bool silent() const
Definition: Config.h:339
ripple::Config::NETWORK_ID
uint32_t NETWORK_ID
Definition: Config.h:163
ripple::Config::PATH_SEARCH
int PATH_SEARCH
Definition: Config.h:203
ripple::Config::ELB_SUPPORT
bool ELB_SUPPORT
Definition: Config.h:145
@@ -450,12 +452,12 @@ $(function() {
ripple::Config::configFileName
static char const *const configFileName
Definition: Config.h:96
ripple::Config::FORCE_MULTI_THREAD
bool FORCE_MULTI_THREAD
Definition: Config.h:246
ripple::Config::SILENT
bool SILENT
Definition: Config.h:118
-
ripple::Config::canSign
bool canSign() const
Definition: Config.h:354
+
ripple::Config::canSign
bool canSign() const
Definition: Config.h:356
ripple::Config::IPS
std::vector< std::string > IPS
Definition: Config.h:148
ripple::Config::VP_REDUCE_RELAY_ENABLE
bool VP_REDUCE_RELAY_ENABLE
Definition: Config.h:255
ripple::Config::PEERS_IN_MAX
std::size_t PEERS_IN_MAX
Definition: Config.h:188
ripple::Config::PEER_PRIVATE
bool PEER_PRIVATE
Definition: Config.h:180
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::rpc_ip
std::optional< beast::IP::Endpoint > rpc_ip
Definition: Config.h:282
ripple::Config::TX_REDUCE_RELAY_MIN_PEERS
std::size_t TX_REDUCE_RELAY_MIN_PEERS
Definition: Config.h:276
ripple::Config::BETA_RPC_API
bool BETA_RPC_API
Definition: Config.h:295
@@ -468,22 +470,23 @@ $(function() {
ripple::Config::LOAD_FILE
@ LOAD_FILE
Definition: Config.h:153
ripple::Config::NORMAL
@ NORMAL
Definition: Config.h:153
ripple::Config::LEDGER_REPLAY
bool LEDGER_REPLAY
Definition: Config.h:230
+
ripple::Config::VALIDATOR_LIST_THRESHOLD
std::optional< std::size_t > VALIDATOR_LIST_THRESHOLD
Definition: Config.h:308
ripple::Config::PATH_SEARCH_MAX
int PATH_SEARCH_MAX
Definition: Config.h:205
ripple::Config::PATH_SEARCH_FAST
int PATH_SEARCH_FAST
Definition: Config.h:204
ripple::Config::RELAY_UNTRUSTED_PROPOSALS
int RELAY_UNTRUSTED_PROPOSALS
Definition: Config.h:177
ripple::Config::Config
Config()
Definition: Config.cpp:260
-
ripple::Config::journal
beast::Journal journal() const
Definition: Config.h:381
+
ripple::Config::journal
beast::Journal journal() const
Definition: Config.h:383
ripple::Config::TX_REDUCE_RELAY_ENABLE
bool TX_REDUCE_RELAY_ENABLE
Definition: Config.h:266
-
ripple::Config::getDebugLogFile
boost::filesystem::path getDebugLogFile() const
Returns the full path and filename of the debug log file.
Definition: Config.cpp:974
+
ripple::Config::getDebugLogFile
boost::filesystem::path getDebugLogFile() const
Returns the full path and filename of the debug log file.
Definition: Config.cpp:1013
ripple::Config::load
void load()
Definition: Config.cpp:424
ripple::Config::FAST_LOAD
bool FAST_LOAD
Definition: Config.h:298
ripple::Config::WORKERS
int WORKERS
Definition: Config.h:241
-
ripple::Config::quiet
bool quiet() const
Definition: Config.h:332
+
ripple::Config::quiet
bool quiet() const
Definition: Config.h:334
ripple::Config::TX_REDUCE_RELAY_METRICS
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:273
ripple::Config::MIN_JOB_QUEUE_TX
static constexpr int MIN_JOB_QUEUE_TX
Definition: Config.h:235
ripple::Config::RUN_STANDALONE
bool RUN_STANDALONE
Operate in stand-alone mode.
Definition: Config.h:128
ripple::Config::TX_RELAY_PERCENTAGE
std::size_t TX_RELAY_PERCENTAGE
Definition: Config.h:279
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
ripple::Config::SERVER_DOMAIN
std::string SERVER_DOMAIN
Definition: Config.h:286
ripple::Config::MAX_JOB_QUEUE_TX
static constexpr int MAX_JOB_QUEUE_TX
Definition: Config.h:234
ripple::Config::MAX_TRANSACTIONS
int MAX_TRANSACTIONS
Definition: Config.h:233
@@ -494,7 +497,7 @@ $(function() {
ripple::Config::CONFIG_FILE
boost::filesystem::path CONFIG_FILE
Definition: Config.h:105
ripple::Config::USE_TX_TABLES
bool USE_TX_TABLES
Definition: Config.h:130
ripple::Config::doImport
bool doImport
Definition: Config.h:144
-
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1008
+
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1047
ripple::Config::FEES
FeeSetup FEES
Definition: Config.h:211
ripple::Config::signingEnabled_
bool signingEnabled_
Determines if the server will sign a tx, given an account's secret seed.
Definition: Config.h:138
ripple::Config::DEBUG_LOGFILE
boost::filesystem::path DEBUG_LOGFILE
Definition: Config.h:111
@@ -536,7 +539,7 @@ $(function() {
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::SizedItem::ledgerAge
@ ledgerAge
ripple::defaultAmendmentMajorityTime
constexpr std::chrono::seconds const defaultAmendmentMajorityTime
The minimum amount of time an amendment must hold a majority.
Definition: SystemParameters.h:85
-
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1021
+
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1060
ripple::DROPS_PER_XRP
constexpr XRPAmount DROPS_PER_XRP
Number of drops per 1 XRP.
Definition: XRPAmount.h:259
optional
std::size_t
diff --git a/Config__test_8cpp_source.html b/Config__test_8cpp_source.html index 8f35383a87..08f1a3b55c 100644 --- a/Config__test_8cpp_source.html +++ b/Config__test_8cpp_source.html @@ -100,1281 +100,1471 @@ $(function() {
22#include <xrpld/core/Config.h>
23#include <xrpld/core/ConfigSections.h>
24#include <xrpl/basics/contract.h>
-
25#include <xrpl/server/Port.h>
-
26#include <boost/filesystem.hpp>
-
27#include <boost/format.hpp>
-
28#include <fstream>
-
29#include <iostream>
-
30
-
31namespace ripple {
-
32namespace detail {
-
33std::string
-
34configContents(std::string const& dbPath, std::string const& validatorsFile)
-
35{
-
36 static boost::format configContentsTemplate(R"rippleConfig(
-
37[server]
-
38port_rpc
-
39port_peer
-
40port_wss_admin
-
41
-
42[port_rpc]
-
43port = 5005
-
44ip = 127.0.0.1
-
45admin = 127.0.0.1, ::1
-
46protocol = https
-
47
-
48[port_peer]
-
49port = 51235
-
50ip = 0.0.0.0
-
51protocol = peer
-
52
-
53[port_wss_admin]
-
54port = 6006
-
55ip = 127.0.0.1
-
56admin = 127.0.0.1
-
57protocol = wss
-
58
-
59#[port_ws_public]
-
60#port = 5005
-
61#ip = 127.0.0.1
-
62#protocol = wss
-
63
-
64#-------------------------------------------------------------------------------
-
65
-
66[node_size]
-
67medium
-
68
-
69# This is primary persistent datastore for rippled. This includes transaction
-
70# metadata, account states, and ledger headers. Helpful information can be
-
71# found on https://xrpl.org/capacity-planning.html#node-db-type
-
72# delete old ledgers while maintaining at least 2000. Do not require an
-
73# external administrative command to initiate deletion.
-
74[node_db]
-
75type=memory
-
76path=/Users/dummy/ripple/config/db/rocksdb
-
77open_files=2000
-
78filter_bits=12
-
79cache_mb=256
-
80file_size_mb=8
-
81file_size_mult=2
-
82
-
83%1%
-
84
-
85%2%
-
86
-
87# This needs to be an absolute directory reference, not a relative one.
-
88# Modify this value as required.
-
89[debug_logfile]
-
90/Users/dummy/ripple/config/log/debug.log
-
91
-
92[sntp_servers]
-
93time.windows.com
-
94time.apple.com
-
95time.nist.gov
-
96pool.ntp.org
-
97
-
98# Where to find some other servers speaking the Ripple protocol.
-
99#
-
100[ips]
-
101r.ripple.com 51235
-
102
-
103# Turn down default logging to save disk space in the long run.
-
104# Valid values here are trace, debug, info, warning, error, and fatal
-
105[rpc_startup]
-
106{ "command": "log_level", "severity": "warning" }
-
107
-
108# Defaults to 1 ("yes") so that certificates will be validated. To allow the use
-
109# of self-signed certificates for development or internal use, set to 0 ("no").
-
110[ssl_verify]
-
1110
-
112
-
113[sqdb]
-
114backend=sqlite
-
115)rippleConfig");
-
116
-
117 std::string dbPathSection =
-
118 dbPath.empty() ? "" : "[database_path]\n" + dbPath;
-
119 std::string valFileSection =
-
120 validatorsFile.empty() ? "" : "[validators_file]\n" + validatorsFile;
-
121 return boost::str(configContentsTemplate % dbPathSection % valFileSection);
-
122}
-
123
-
127class RippledCfgGuard : public ripple::test::detail::FileDirGuard
-
128{
-
129private:
-
130 path dataDir_;
-
131
-
132 bool rmDataDir_{false};
-
133
-
134 Config config_;
-
135
-
136public:
-
137 RippledCfgGuard(
-
138 beast::unit_test::suite& test,
-
139 path subDir,
-
140 path const& dbPath,
-
141 path const& validatorsFile,
-
142 bool useCounter = true)
-
143 : FileDirGuard(
-
144 test,
-
145 std::move(subDir),
-
146 path(Config::configFileName),
-
147 configContents(dbPath.string(), validatorsFile.string()),
-
148 useCounter)
-
149 , dataDir_(dbPath)
-
150 {
-
151 if (dbPath.empty())
-
152 dataDir_ = subdir() / path(Config::databaseDirName);
-
153
-
154 rmDataDir_ = !exists(dataDir_);
-
155 config_.setup(
-
156 file_.string(),
-
157 /* bQuiet */ true,
-
158 /* bSilent */ false,
-
159 /* bStandalone */ false);
-
160 }
-
161
-
162 Config const&
-
163 config() const
-
164 {
-
165 return config_;
-
166 }
-
167
-
168 std::string
-
169 configFile() const
-
170 {
-
171 return file().string();
-
172 }
-
173
-
174 bool
-
175 dataDirExists() const
-
176 {
-
177 return boost::filesystem::is_directory(dataDir_);
-
178 }
-
179
-
180 bool
-
181 configFileExists() const
-
182 {
-
183 return fileExists();
-
184 }
-
185
-
186 ~RippledCfgGuard()
-
187 {
-
188 try
-
189 {
-
190 using namespace boost::filesystem;
-
191 if (rmDataDir_)
-
192 rmDir(dataDir_);
-
193 }
-
194 catch (std::exception& e)
-
195 {
-
196 // if we throw here, just let it die.
-
197 test_.log << "Error in ~RippledCfgGuard: " << e.what() << std::endl;
-
198 };
-
199 }
-
200};
-
201
-
202std::string
-
203valFileContents()
-
204{
-
205 std::string configContents(R"rippleConfig(
-
206[validators]
-
207n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
-
208n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
-
209n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
-
210n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
-
211n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
-
212
-
213[validator_keys]
-
214nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
-
215nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
-
216nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz
-
217
-
218[validator_list_sites]
-
219recommendedripplevalidators.com
-
220moreripplevalidators.net
-
221
-
222[validator_list_keys]
-
22303E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D
-
224030775A669685BD6ABCEBD80385921C7851783D991A8055FD21D2F3966C96F1B56
-
225)rippleConfig");
-
226 return configContents;
-
227}
-
228
-
232class ValidatorsTxtGuard : public test::detail::FileDirGuard
-
233{
-
234public:
-
235 ValidatorsTxtGuard(
-
236 beast::unit_test::suite& test,
-
237 path subDir,
-
238 path const& validatorsFileName,
-
239 bool useCounter = true)
-
240 : FileDirGuard(
-
241 test,
-
242 std::move(subDir),
-
243 path(
-
244 validatorsFileName.empty() ? Config::validatorsFileName
-
245 : validatorsFileName),
-
246 valFileContents(),
-
247 useCounter)
-
248 {
-
249 }
-
250
-
251 bool
-
252 validatorsFileExists() const
-
253 {
-
254 return fileExists();
-
255 }
-
256
-
257 std::string
-
258 validatorsFile() const
-
259 {
-
260 return absolute(file()).string();
-
261 }
-
262
-
263 ~ValidatorsTxtGuard()
-
264 {
+
25#include <xrpl/beast/unit_test/suite.h>
+
26#include <xrpl/server/Port.h>
+
27#include <boost/filesystem.hpp>
+
28#include <boost/format.hpp>
+
29#include <fstream>
+
30#include <iostream>
+
31
+
32namespace ripple {
+
33namespace detail {
+
34std::string
+
35configContents(std::string const& dbPath, std::string const& validatorsFile)
+
36{
+
37 static boost::format configContentsTemplate(R"rippleConfig(
+
38[server]
+
39port_rpc
+
40port_peer
+
41port_wss_admin
+
42
+
43[port_rpc]
+
44port = 5005
+
45ip = 127.0.0.1
+
46admin = 127.0.0.1, ::1
+
47protocol = https
+
48
+
49[port_peer]
+
50port = 51235
+
51ip = 0.0.0.0
+
52protocol = peer
+
53
+
54[port_wss_admin]
+
55port = 6006
+
56ip = 127.0.0.1
+
57admin = 127.0.0.1
+
58protocol = wss
+
59
+
60#[port_ws_public]
+
61#port = 5005
+
62#ip = 127.0.0.1
+
63#protocol = wss
+
64
+
65#-------------------------------------------------------------------------------
+
66
+
67[node_size]
+
68medium
+
69
+
70# This is primary persistent datastore for rippled. This includes transaction
+
71# metadata, account states, and ledger headers. Helpful information can be
+
72# found on https://xrpl.org/capacity-planning.html#node-db-type
+
73# delete old ledgers while maintaining at least 2000. Do not require an
+
74# external administrative command to initiate deletion.
+
75[node_db]
+
76type=memory
+
77path=/Users/dummy/ripple/config/db/rocksdb
+
78open_files=2000
+
79filter_bits=12
+
80cache_mb=256
+
81file_size_mb=8
+
82file_size_mult=2
+
83
+
84%1%
+
85
+
86%2%
+
87
+
88# This needs to be an absolute directory reference, not a relative one.
+
89# Modify this value as required.
+
90[debug_logfile]
+
91/Users/dummy/ripple/config/log/debug.log
+
92
+
93[sntp_servers]
+
94time.windows.com
+
95time.apple.com
+
96time.nist.gov
+
97pool.ntp.org
+
98
+
99# Where to find some other servers speaking the Ripple protocol.
+
100#
+
101[ips]
+
102r.ripple.com 51235
+
103
+
104# Turn down default logging to save disk space in the long run.
+
105# Valid values here are trace, debug, info, warning, error, and fatal
+
106[rpc_startup]
+
107{ "command": "log_level", "severity": "warning" }
+
108
+
109# Defaults to 1 ("yes") so that certificates will be validated. To allow the use
+
110# of self-signed certificates for development or internal use, set to 0 ("no").
+
111[ssl_verify]
+
1120
+
113
+
114[sqdb]
+
115backend=sqlite
+
116)rippleConfig");
+
117
+
118 std::string dbPathSection =
+
119 dbPath.empty() ? "" : "[database_path]\n" + dbPath;
+
120 std::string valFileSection =
+
121 validatorsFile.empty() ? "" : "[validators_file]\n" + validatorsFile;
+
122 return boost::str(configContentsTemplate % dbPathSection % valFileSection);
+
123}
+
124
+
128class RippledCfgGuard : public ripple::test::detail::FileDirGuard
+
129{
+
130private:
+
131 path dataDir_;
+
132
+
133 bool rmDataDir_{false};
+
134
+
135 Config config_;
+
136
+
137public:
+
138 RippledCfgGuard(
+
139 beast::unit_test::suite& test,
+
140 path subDir,
+
141 path const& dbPath,
+
142 path const& validatorsFile,
+
143 bool useCounter = true)
+
144 : FileDirGuard(
+
145 test,
+
146 std::move(subDir),
+
147 path(Config::configFileName),
+
148 configContents(dbPath.string(), validatorsFile.string()),
+
149 useCounter)
+
150 , dataDir_(dbPath)
+
151 {
+
152 if (dbPath.empty())
+
153 dataDir_ = subdir() / path(Config::databaseDirName);
+
154
+
155 rmDataDir_ = !exists(dataDir_);
+
156 config_.setup(
+
157 file_.string(),
+
158 /* bQuiet */ true,
+
159 /* bSilent */ false,
+
160 /* bStandalone */ false);
+
161 }
+
162
+
163 Config const&
+
164 config() const
+
165 {
+
166 return config_;
+
167 }
+
168
+
169 std::string
+
170 configFile() const
+
171 {
+
172 return file().string();
+
173 }
+
174
+
175 bool
+
176 dataDirExists() const
+
177 {
+
178 return boost::filesystem::is_directory(dataDir_);
+
179 }
+
180
+
181 bool
+
182 configFileExists() const
+
183 {
+
184 return fileExists();
+
185 }
+
186
+
187 ~RippledCfgGuard()
+
188 {
+
189 try
+
190 {
+
191 using namespace boost::filesystem;
+
192 if (rmDataDir_)
+
193 rmDir(dataDir_);
+
194 }
+
195 catch (std::exception& e)
+
196 {
+
197 // if we throw here, just let it die.
+
198 test_.log << "Error in ~RippledCfgGuard: " << e.what() << std::endl;
+
199 };
+
200 }
+
201};
+
202
+
203std::string
+
204valFileContents()
+
205{
+
206 std::string configContents(R"rippleConfig(
+
207[validators]
+
208n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
+
209n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
+
210n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
+
211n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
+
212n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
+
213
+
214[validator_keys]
+
215nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
+
216nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
+
217nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz
+
218
+
219[validator_list_sites]
+
220recommendedripplevalidators.com
+
221moreripplevalidators.net
+
222
+
223[validator_list_keys]
+
22403E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D
+
225030775A669685BD6ABCEBD80385921C7851783D991A8055FD21D2F3966C96F1B56
+
226
+
227[validator_list_threshold]
+
2282
+
229)rippleConfig");
+
230 return configContents;
+
231}
+
232
+
236class ValidatorsTxtGuard : public test::detail::FileDirGuard
+
237{
+
238public:
+
239 ValidatorsTxtGuard(
+
240 beast::unit_test::suite& test,
+
241 path subDir,
+
242 path const& validatorsFileName,
+
243 bool useCounter = true)
+
244 : FileDirGuard(
+
245 test,
+
246 std::move(subDir),
+
247 path(
+
248 validatorsFileName.empty() ? Config::validatorsFileName
+
249 : validatorsFileName),
+
250 valFileContents(),
+
251 useCounter)
+
252 {
+
253 }
+
254
+
255 bool
+
256 validatorsFileExists() const
+
257 {
+
258 return fileExists();
+
259 }
+
260
+
261 std::string
+
262 validatorsFile() const
+
263 {
+
264 return absolute(file()).string();
265 }
-
266};
-
267} // namespace detail
-
268
-
269class Config_test final : public TestSuite
-
270{
-
271private:
-
272 using path = boost::filesystem::path;
-
273
-
274public:
-
275 void
-
276 testLegacy()
-
277 {
-
278 testcase("legacy");
-
279
-
280 Config c;
-
281
-
282 std::string toLoad(R"rippleConfig(
-
283[server]
-
284port_rpc
-
285port_peer
-
286port_wss_admin
-
287
-
288[ssl_verify]
-
2890
-
290)rippleConfig");
+
266
+
267 ~ValidatorsTxtGuard()
+
268 {
+
269 }
+
270};
+
271} // namespace detail
+
272
+
273class Config_test final : public TestSuite
+
274{
+
275private:
+
276 using path = boost::filesystem::path;
+
277
+
278public:
+
279 void
+
280 testLegacy()
+
281 {
+
282 testcase("legacy");
+
283
+
284 Config c;
+
285
+
286 std::string toLoad(R"rippleConfig(
+
287[server]
+
288port_rpc
+
289port_peer
+
290port_wss_admin
291
-
292 c.loadFromString(toLoad);
-
293
-
294 BEAST_EXPECT(c.legacy("ssl_verify") == "0");
-
295 expectException([&c] { c.legacy("server"); }); // not a single line
-
296
-
297 // set a legacy value
-
298 BEAST_EXPECT(c.legacy("not_in_file") == "");
-
299 c.legacy("not_in_file", "new_value");
-
300 BEAST_EXPECT(c.legacy("not_in_file") == "new_value");
-
301 }
-
302 void
-
303 testDbPath()
-
304 {
-
305 testcase("database_path");
-
306
-
307 using namespace boost::filesystem;
-
308 {
-
309 boost::format cc("[database_path]\n%1%\n");
+
292[ssl_verify]
+
2930
+
294)rippleConfig");
+
295
+
296 c.loadFromString(toLoad);
+
297
+
298 BEAST_EXPECT(c.legacy("ssl_verify") == "0");
+
299 expectException([&c] { c.legacy("server"); }); // not a single line
+
300
+
301 // set a legacy value
+
302 BEAST_EXPECT(c.legacy("not_in_file") == "");
+
303 c.legacy("not_in_file", "new_value");
+
304 BEAST_EXPECT(c.legacy("not_in_file") == "new_value");
+
305 }
+
306 void
+
307 testDbPath()
+
308 {
+
309 testcase("database_path");
310
-
311 auto const cwd = current_path();
-
312 path const dataDirRel("test_data_dir");
-
313 path const dataDirAbs(cwd / dataDirRel);
-
314 {
-
315 // Dummy test - do we get back what we put in
-
316 Config c;
-
317 c.loadFromString(boost::str(cc % dataDirAbs.string()));
-
318 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
-
319 }
-
320 {
-
321 // Rel paths should convert to abs paths
-
322 Config c;
-
323 c.loadFromString(boost::str(cc % dataDirRel.string()));
-
324 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
-
325 }
-
326 {
-
327 // No db section.
-
328 // N.B. Config::setup will give database_path a default,
-
329 // load will not.
-
330 Config c;
-
331 c.loadFromString("");
-
332 BEAST_EXPECT(c.legacy("database_path") == "");
-
333 }
-
334 }
-
335 {
-
336 // read from file absolute path
-
337 auto const cwd = current_path();
-
338 ripple::test::detail::DirGuard const g0(*this, "test_db");
-
339 path const dataDirRel("test_data_dir");
-
340 path const dataDirAbs(cwd / g0.subdir() / dataDirRel);
-
341 detail::RippledCfgGuard const g(
-
342 *this, g0.subdir(), dataDirAbs, "", false);
-
343 auto const& c(g.config());
-
344 BEAST_EXPECT(g.dataDirExists());
-
345 BEAST_EXPECT(g.configFileExists());
-
346 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
-
347 }
-
348 {
-
349 // read from file relative path
-
350 std::string const dbPath("my_db");
-
351 detail::RippledCfgGuard const g(*this, "test_db", dbPath, "");
-
352 auto const& c(g.config());
-
353 std::string const nativeDbPath = absolute(path(dbPath)).string();
-
354 BEAST_EXPECT(g.dataDirExists());
-
355 BEAST_EXPECT(g.configFileExists());
-
356 BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
-
357 }
-
358 {
-
359 // read from file no path
-
360 detail::RippledCfgGuard const g(*this, "test_db", "", "");
-
361 auto const& c(g.config());
-
362 std::string const nativeDbPath =
-
363 absolute(g.subdir() / path(Config::databaseDirName)).string();
-
364 BEAST_EXPECT(g.dataDirExists());
-
365 BEAST_EXPECT(g.configFileExists());
-
366 BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
-
367 }
-
368 }
-
369
-
370 void
-
371 testValidatorKeys()
-
372 {
-
373 testcase("validator keys");
-
374
-
375 std::string const validationSeed = "spA4sh1qTvwq92X715tYyGQKmAKfa";
-
376
-
377 auto const token =
-
378 "eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiOWVkNDVmODY2MjQxY2MxOGEyNzQ3Yj"
-
379 "U0Mzg3YzA2MjU5MDc5NzJmNGU3MTkwMjMxZmFhOTM3NDU3ZmE5ZGFmNiIsIm1hbmlm"
-
380 "ZXN0IjoiSkFBQUFBRnhJZTFGdHdtaW12R3RIMmlDY01KcUM5Z1ZGS2lsR2Z3MS92Q3"
-
381 "hIWFhMcGxjMkduTWhBa0UxYWdxWHhCd0R3RGJJRDZPTVNZdU0wRkRBbHBBZ05rOFNL"
-
382 "Rm43TU8yZmRrY3dSUUloQU9uZ3U5c0FLcVhZb3VKK2wyVjBXK3NBT2tWQitaUlM2UF"
-
383 "NobEpBZlVzWGZBaUJzVkpHZXNhYWRPSmMvYUFab2tTMXZ5bUdtVnJsSFBLV1gzWXl3"
-
384 "dTZpbjhIQVNRS1B1Z0JENjdrTWFSRkd2bXBBVEhsR0tKZHZERmxXUFl5NUFxRGVkRn"
-
385 "Y1VEphMncwaTIxZXEzTVl5d0xWSlpuRk9yN0Mwa3cyQWlUelNDakl6ZGl0UTg9In0"
-
386 "=";
-
387
-
388 {
-
389 Config c;
-
390 static boost::format configTemplate(R"rippleConfig(
-
391[validation_seed]
-
392%1%
-
393
-
394[validator_token]
-
395%2%
-
396)rippleConfig");
-
397 std::string error;
-
398 auto const expectedError =
-
399 "Cannot have both [validation_seed] "
-
400 "and [validator_token] config sections";
-
401 try
-
402 {
-
403 c.loadFromString(
-
404 boost::str(configTemplate % validationSeed % token));
-
405 }
-
406 catch (std::runtime_error& e)
-
407 {
-
408 error = e.what();
+
311 using namespace boost::filesystem;
+
312 {
+
313 boost::format cc("[database_path]\n%1%\n");
+
314
+
315 auto const cwd = current_path();
+
316 path const dataDirRel("test_data_dir");
+
317 path const dataDirAbs(cwd / dataDirRel);
+
318 {
+
319 // Dummy test - do we get back what we put in
+
320 Config c;
+
321 c.loadFromString(boost::str(cc % dataDirAbs.string()));
+
322 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
+
323 }
+
324 {
+
325 // Rel paths should convert to abs paths
+
326 Config c;
+
327 c.loadFromString(boost::str(cc % dataDirRel.string()));
+
328 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
+
329 }
+
330 {
+
331 // No db section.
+
332 // N.B. Config::setup will give database_path a default,
+
333 // load will not.
+
334 Config c;
+
335 c.loadFromString("");
+
336 BEAST_EXPECT(c.legacy("database_path") == "");
+
337 }
+
338 }
+
339 {
+
340 // read from file absolute path
+
341 auto const cwd = current_path();
+
342 ripple::test::detail::DirGuard const g0(*this, "test_db");
+
343 path const dataDirRel("test_data_dir");
+
344 path const dataDirAbs(cwd / g0.subdir() / dataDirRel);
+
345 detail::RippledCfgGuard const g(
+
346 *this, g0.subdir(), dataDirAbs, "", false);
+
347 auto const& c(g.config());
+
348 BEAST_EXPECT(g.dataDirExists());
+
349 BEAST_EXPECT(g.configFileExists());
+
350 BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
+
351 }
+
352 {
+
353 // read from file relative path
+
354 std::string const dbPath("my_db");
+
355 detail::RippledCfgGuard const g(*this, "test_db", dbPath, "");
+
356 auto const& c(g.config());
+
357 std::string const nativeDbPath = absolute(path(dbPath)).string();
+
358 BEAST_EXPECT(g.dataDirExists());
+
359 BEAST_EXPECT(g.configFileExists());
+
360 BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
+
361 }
+
362 {
+
363 // read from file no path
+
364 detail::RippledCfgGuard const g(*this, "test_db", "", "");
+
365 auto const& c(g.config());
+
366 std::string const nativeDbPath =
+
367 absolute(g.subdir() / path(Config::databaseDirName)).string();
+
368 BEAST_EXPECT(g.dataDirExists());
+
369 BEAST_EXPECT(g.configFileExists());
+
370 BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
+
371 }
+
372 }
+
373
+
374 void
+
375 testValidatorKeys()
+
376 {
+
377 testcase("validator keys");
+
378
+
379 std::string const validationSeed = "spA4sh1qTvwq92X715tYyGQKmAKfa";
+
380
+
381 auto const token =
+
382 "eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiOWVkNDVmODY2MjQxY2MxOGEyNzQ3Yj"
+
383 "U0Mzg3YzA2MjU5MDc5NzJmNGU3MTkwMjMxZmFhOTM3NDU3ZmE5ZGFmNiIsIm1hbmlm"
+
384 "ZXN0IjoiSkFBQUFBRnhJZTFGdHdtaW12R3RIMmlDY01KcUM5Z1ZGS2lsR2Z3MS92Q3"
+
385 "hIWFhMcGxjMkduTWhBa0UxYWdxWHhCd0R3RGJJRDZPTVNZdU0wRkRBbHBBZ05rOFNL"
+
386 "Rm43TU8yZmRrY3dSUUloQU9uZ3U5c0FLcVhZb3VKK2wyVjBXK3NBT2tWQitaUlM2UF"
+
387 "NobEpBZlVzWGZBaUJzVkpHZXNhYWRPSmMvYUFab2tTMXZ5bUdtVnJsSFBLV1gzWXl3"
+
388 "dTZpbjhIQVNRS1B1Z0JENjdrTWFSRkd2bXBBVEhsR0tKZHZERmxXUFl5NUFxRGVkRn"
+
389 "Y1VEphMncwaTIxZXEzTVl5d0xWSlpuRk9yN0Mwa3cyQWlUelNDakl6ZGl0UTg9In0"
+
390 "=";
+
391
+
392 {
+
393 Config c;
+
394 static boost::format configTemplate(R"rippleConfig(
+
395[validation_seed]
+
396%1%
+
397
+
398[validator_token]
+
399%2%
+
400)rippleConfig");
+
401 std::string error;
+
402 auto const expectedError =
+
403 "Cannot have both [validation_seed] "
+
404 "and [validator_token] config sections";
+
405 try
+
406 {
+
407 c.loadFromString(
+
408 boost::str(configTemplate % validationSeed % token));
409 }
-
410 BEAST_EXPECT(error == expectedError);
-
411 }
-
412 }
-
413
-
414 void
-
415 testNetworkID()
-
416 {
-
417 testcase("network id");
-
418 std::string error;
-
419 Config c;
-
420 try
-
421 {
-
422 c.loadFromString(R"rippleConfig(
-
423[network_id]
-
424main
-
425)rippleConfig");
-
426 }
-
427 catch (std::runtime_error& e)
-
428 {
-
429 error = e.what();
-
430 }
-
431
-
432 BEAST_EXPECT(error == "");
-
433 BEAST_EXPECT(c.NETWORK_ID == 0);
-
434
-
435 try
-
436 {
-
437 c.loadFromString(R"rippleConfig(
-
438)rippleConfig");
-
439 }
-
440 catch (std::runtime_error& e)
-
441 {
-
442 error = e.what();
-
443 }
-
444
-
445 BEAST_EXPECT(error == "");
-
446 BEAST_EXPECT(c.NETWORK_ID == 0);
-
447
-
448 try
-
449 {
-
450 c.loadFromString(R"rippleConfig(
-
451[network_id]
-
452255
-
453)rippleConfig");
-
454 }
-
455 catch (std::runtime_error& e)
-
456 {
-
457 error = e.what();
-
458 }
-
459
-
460 BEAST_EXPECT(error == "");
-
461 BEAST_EXPECT(c.NETWORK_ID == 255);
-
462
-
463 try
-
464 {
-
465 c.loadFromString(R"rippleConfig(
-
466[network_id]
-
46710000
-
468)rippleConfig");
-
469 }
-
470 catch (std::runtime_error& e)
-
471 {
-
472 error = e.what();
-
473 }
-
474
-
475 BEAST_EXPECT(error == "");
-
476 BEAST_EXPECT(c.NETWORK_ID == 10000);
-
477 }
+
410 catch (std::runtime_error& e)
+
411 {
+
412 error = e.what();
+
413 }
+
414 BEAST_EXPECT(error == expectedError);
+
415 }
+
416 }
+
417
+
418 void
+
419 testNetworkID()
+
420 {
+
421 testcase("network id");
+
422 std::string error;
+
423 Config c;
+
424 try
+
425 {
+
426 c.loadFromString(R"rippleConfig(
+
427[network_id]
+
428main
+
429)rippleConfig");
+
430 }
+
431 catch (std::runtime_error& e)
+
432 {
+
433 error = e.what();
+
434 }
+
435
+
436 BEAST_EXPECT(error == "");
+
437 BEAST_EXPECT(c.NETWORK_ID == 0);
+
438
+
439 try
+
440 {
+
441 c.loadFromString(R"rippleConfig(
+
442)rippleConfig");
+
443 }
+
444 catch (std::runtime_error& e)
+
445 {
+
446 error = e.what();
+
447 }
+
448
+
449 BEAST_EXPECT(error == "");
+
450 BEAST_EXPECT(c.NETWORK_ID == 0);
+
451
+
452 try
+
453 {
+
454 c.loadFromString(R"rippleConfig(
+
455[network_id]
+
456255
+
457)rippleConfig");
+
458 }
+
459 catch (std::runtime_error& e)
+
460 {
+
461 error = e.what();
+
462 }
+
463
+
464 BEAST_EXPECT(error == "");
+
465 BEAST_EXPECT(c.NETWORK_ID == 255);
+
466
+
467 try
+
468 {
+
469 c.loadFromString(R"rippleConfig(
+
470[network_id]
+
47110000
+
472)rippleConfig");
+
473 }
+
474 catch (std::runtime_error& e)
+
475 {
+
476 error = e.what();
+
477 }
478
-
479 void
-
480 testValidatorsFile()
-
481 {
-
482 testcase("validators_file");
-
483
-
484 using namespace boost::filesystem;
-
485 {
-
486 // load should throw for missing specified validators file
-
487 boost::format cc("[validators_file]\n%1%\n");
-
488 std::string error;
-
489 std::string const missingPath = "/no/way/this/path/exists";
-
490 auto const expectedError =
-
491 "The file specified in [validators_file] does not exist: " +
-
492 missingPath;
-
493 try
-
494 {
-
495 Config c;
-
496 c.loadFromString(boost::str(cc % missingPath));
-
497 }
-
498 catch (std::runtime_error& e)
-
499 {
-
500 error = e.what();
+
479 BEAST_EXPECT(error == "");
+
480 BEAST_EXPECT(c.NETWORK_ID == 10000);
+
481 }
+
482
+
483 void
+
484 testValidatorsFile()
+
485 {
+
486 testcase("validators_file");
+
487
+
488 using namespace boost::filesystem;
+
489 {
+
490 // load should throw for missing specified validators file
+
491 boost::format cc("[validators_file]\n%1%\n");
+
492 std::string error;
+
493 std::string const missingPath = "/no/way/this/path/exists";
+
494 auto const expectedError =
+
495 "The file specified in [validators_file] does not exist: " +
+
496 missingPath;
+
497 try
+
498 {
+
499 Config c;
+
500 c.loadFromString(boost::str(cc % missingPath));
501 }
-
502 BEAST_EXPECT(error == expectedError);
-
503 }
-
504 {
-
505 // load should throw for invalid [validators_file]
-
506 detail::ValidatorsTxtGuard const vtg(
-
507 *this, "test_cfg", "validators.cfg");
-
508 path const invalidFile = current_path() / vtg.subdir();
-
509 boost::format cc("[validators_file]\n%1%\n");
-
510 std::string error;
-
511 auto const expectedError =
-
512 "Invalid file specified in [validators_file]: " +
-
513 invalidFile.string();
-
514 try
-
515 {
-
516 Config c;
-
517 c.loadFromString(boost::str(cc % invalidFile.string()));
-
518 }
-
519 catch (std::runtime_error& e)
-
520 {
-
521 error = e.what();
+
502 catch (std::runtime_error& e)
+
503 {
+
504 error = e.what();
+
505 }
+
506 BEAST_EXPECT(error == expectedError);
+
507 }
+
508 {
+
509 // load should throw for invalid [validators_file]
+
510 detail::ValidatorsTxtGuard const vtg(
+
511 *this, "test_cfg", "validators.cfg");
+
512 path const invalidFile = current_path() / vtg.subdir();
+
513 boost::format cc("[validators_file]\n%1%\n");
+
514 std::string error;
+
515 auto const expectedError =
+
516 "Invalid file specified in [validators_file]: " +
+
517 invalidFile.string();
+
518 try
+
519 {
+
520 Config c;
+
521 c.loadFromString(boost::str(cc % invalidFile.string()));
522 }
-
523 BEAST_EXPECT(error == expectedError);
-
524 }
-
525 {
-
526 // load validators from config into single section
-
527 Config c;
-
528 std::string toLoad(R"rippleConfig(
-
529[validators]
-
530n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
-
531n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
-
532n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
-
533
-
534[validator_keys]
-
535nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
-
536nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
-
537)rippleConfig");
-
538 c.loadFromString(toLoad);
-
539 BEAST_EXPECT(c.legacy("validators_file").empty());
-
540 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 5);
-
541 }
-
542 {
-
543 // load validator list sites and keys from config
-
544 Config c;
-
545 std::string toLoad(R"rippleConfig(
-
546[validator_list_sites]
-
547ripplevalidators.com
-
548trustthesevalidators.gov
-
549
-
550[validator_list_keys]
-
551021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
-
552)rippleConfig");
-
553 c.loadFromString(toLoad);
-
554 BEAST_EXPECT(
-
555 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
-
556 BEAST_EXPECT(
-
557 c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
-
558 "ripplevalidators.com");
-
559 BEAST_EXPECT(
-
560 c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
-
561 "trustthesevalidators.gov");
-
562 BEAST_EXPECT(
-
563 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1);
-
564 BEAST_EXPECT(
-
565 c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] ==
-
566 "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801"
-
567 "E566");
-
568 }
-
569 {
-
570 // load should throw if [validator_list_sites] is configured but
-
571 // [validator_list_keys] is not
-
572 Config c;
-
573 std::string toLoad(R"rippleConfig(
-
574[validator_list_sites]
-
575ripplevalidators.com
-
576trustthesevalidators.gov
-
577)rippleConfig");
-
578 std::string error;
-
579 auto const expectedError =
-
580 "[validator_list_keys] config section is missing";
-
581 try
-
582 {
-
583 c.loadFromString(toLoad);
-
584 }
-
585 catch (std::runtime_error& e)
-
586 {
-
587 error = e.what();
-
588 }
-
589 BEAST_EXPECT(error == expectedError);
-
590 }
-
591 {
-
592 // load from specified [validators_file] absolute path
-
593 detail::ValidatorsTxtGuard const vtg(
-
594 *this, "test_cfg", "validators.cfg");
-
595 BEAST_EXPECT(vtg.validatorsFileExists());
-
596 Config c;
-
597 boost::format cc("[validators_file]\n%1%\n");
-
598 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
-
599 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
-
600 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
-
601 BEAST_EXPECT(
-
602 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
523 catch (std::runtime_error& e)
+
524 {
+
525 error = e.what();
+
526 }
+
527 BEAST_EXPECT(error == expectedError);
+
528 }
+
529 {
+
530 // load validators from config into single section
+
531 Config c;
+
532 std::string toLoad(R"rippleConfig(
+
533[validators]
+
534n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
+
535n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
+
536n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
+
537
+
538[validator_keys]
+
539nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
+
540nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
+
541)rippleConfig");
+
542 c.loadFromString(toLoad);
+
543 BEAST_EXPECT(c.legacy("validators_file").empty());
+
544 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 5);
+
545 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::nullopt);
+
546 }
+
547 {
+
548 // load validator list sites and keys from config
+
549 Config c;
+
550 std::string toLoad(R"rippleConfig(
+
551[validator_list_sites]
+
552ripplevalidators.com
+
553trustthesevalidators.gov
+
554
+
555[validator_list_keys]
+
556021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
+
557
+
558[validator_list_threshold]
+
5591
+
560)rippleConfig");
+
561 c.loadFromString(toLoad);
+
562 BEAST_EXPECT(
+
563 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
564 BEAST_EXPECT(
+
565 c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
+
566 "ripplevalidators.com");
+
567 BEAST_EXPECT(
+
568 c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
+
569 "trustthesevalidators.gov");
+
570 BEAST_EXPECT(
+
571 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1);
+
572 BEAST_EXPECT(
+
573 c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] ==
+
574 "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801"
+
575 "E566");
+
576 BEAST_EXPECT(
+
577 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
578 1);
+
579 BEAST_EXPECT(
+
580 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "1");
+
581 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::size_t(1));
+
582 }
+
583 {
+
584 // load validator list sites and keys from config
+
585 Config c;
+
586 std::string toLoad(R"rippleConfig(
+
587[validator_list_sites]
+
588ripplevalidators.com
+
589trustthesevalidators.gov
+
590
+
591[validator_list_keys]
+
592021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
+
593
+
594[validator_list_threshold]
+
5950
+
596)rippleConfig");
+
597 c.loadFromString(toLoad);
+
598 BEAST_EXPECT(
+
599 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
600 BEAST_EXPECT(
+
601 c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
+
602 "ripplevalidators.com");
603 BEAST_EXPECT(
-
604 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
-
605 }
-
606 {
-
607 // load from specified [validators_file] file name
-
608 // in config directory
-
609 std::string const valFileName = "validators.txt";
-
610 detail::ValidatorsTxtGuard const vtg(
-
611 *this, "test_cfg", valFileName);
-
612 detail::RippledCfgGuard const rcg(
-
613 *this, vtg.subdir(), "", valFileName, false);
-
614 BEAST_EXPECT(vtg.validatorsFileExists());
-
615 BEAST_EXPECT(rcg.configFileExists());
-
616 auto const& c(rcg.config());
-
617 BEAST_EXPECT(c.legacy("validators_file") == valFileName);
-
618 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
-
619 BEAST_EXPECT(
-
620 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
-
621 BEAST_EXPECT(
-
622 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
-
623 }
-
624 {
-
625 // load from specified [validators_file] relative path
-
626 // to config directory
-
627 detail::ValidatorsTxtGuard const vtg(
-
628 *this, "test_cfg", "validators.txt");
-
629 auto const valFilePath = ".." / vtg.subdir() / "validators.txt";
-
630 detail::RippledCfgGuard const rcg(
-
631 *this, vtg.subdir(), "", valFilePath, false);
-
632 BEAST_EXPECT(vtg.validatorsFileExists());
-
633 BEAST_EXPECT(rcg.configFileExists());
-
634 auto const& c(rcg.config());
-
635 BEAST_EXPECT(c.legacy("validators_file") == valFilePath);
-
636 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
-
637 BEAST_EXPECT(
-
638 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
-
639 BEAST_EXPECT(
-
640 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
-
641 }
-
642 {
-
643 // load from validators file in default location
-
644 detail::ValidatorsTxtGuard const vtg(
-
645 *this, "test_cfg", "validators.txt");
-
646 detail::RippledCfgGuard const rcg(
-
647 *this, vtg.subdir(), "", "", false);
-
648 BEAST_EXPECT(vtg.validatorsFileExists());
-
649 BEAST_EXPECT(rcg.configFileExists());
-
650 auto const& c(rcg.config());
-
651 BEAST_EXPECT(c.legacy("validators_file").empty());
-
652 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
-
653 BEAST_EXPECT(
-
654 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
-
655 BEAST_EXPECT(
-
656 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
-
657 }
-
658 {
-
659 // load from specified [validators_file] instead
-
660 // of default location
-
661 detail::ValidatorsTxtGuard const vtg(
-
662 *this, "test_cfg", "validators.cfg");
-
663 BEAST_EXPECT(vtg.validatorsFileExists());
-
664 detail::ValidatorsTxtGuard const vtgDefault(
-
665 *this, vtg.subdir(), "validators.txt", false);
-
666 BEAST_EXPECT(vtgDefault.validatorsFileExists());
-
667 detail::RippledCfgGuard const rcg(
-
668 *this, vtg.subdir(), "", vtg.validatorsFile(), false);
-
669 BEAST_EXPECT(rcg.configFileExists());
-
670 auto const& c(rcg.config());
-
671 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
-
672 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
-
673 BEAST_EXPECT(
-
674 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
-
675 BEAST_EXPECT(
-
676 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
+
604 c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
+
605 "trustthesevalidators.gov");
+
606 BEAST_EXPECT(
+
607 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1);
+
608 BEAST_EXPECT(
+
609 c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] ==
+
610 "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801"
+
611 "E566");
+
612 BEAST_EXPECT(
+
613 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
614 1);
+
615 BEAST_EXPECT(
+
616 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values()[0] == "0");
+
617 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == std::nullopt);
+
618 }
+
619 {
+
620 // load should throw if [validator_list_threshold] is greater than
+
621 // the number of [validator_list_keys]
+
622 Config c;
+
623 std::string toLoad(R"rippleConfig(
+
624[validator_list_sites]
+
625ripplevalidators.com
+
626trustthesevalidators.gov
+
627
+
628[validator_list_keys]
+
629021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
+
630
+
631[validator_list_threshold]
+
6322
+
633)rippleConfig");
+
634 std::string error;
+
635 auto const expectedError =
+
636 "Value in config section [validator_list_threshold] exceeds "
+
637 "the number of configured list keys";
+
638 try
+
639 {
+
640 c.loadFromString(toLoad);
+
641 fail();
+
642 }
+
643 catch (std::runtime_error& e)
+
644 {
+
645 error = e.what();
+
646 }
+
647 BEAST_EXPECT(error == expectedError);
+
648 }
+
649 {
+
650 // load should throw if [validator_list_threshold] is malformed
+
651 Config c;
+
652 std::string toLoad(R"rippleConfig(
+
653[validator_list_sites]
+
654ripplevalidators.com
+
655trustthesevalidators.gov
+
656
+
657[validator_list_keys]
+
658021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
+
659
+
660[validator_list_threshold]
+
661value = 2
+
662)rippleConfig");
+
663 std::string error;
+
664 auto const expectedError =
+
665 "Config section [validator_list_threshold] should contain "
+
666 "single value only";
+
667 try
+
668 {
+
669 c.loadFromString(toLoad);
+
670 fail();
+
671 }
+
672 catch (std::runtime_error& e)
+
673 {
+
674 error = e.what();
+
675 }
+
676 BEAST_EXPECT(error == expectedError);
677 }
-
678
-
679 {
-
680 // load validators from both config and validators file
-
681 boost::format cc(R"rippleConfig(
-
682[validators_file]
-
683%1%
-
684
-
685[validators]
-
686n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
-
687n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
-
688n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
-
689n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
-
690n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
-
691
-
692[validator_keys]
-
693nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v
-
694nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB
-
695
-
696[validator_list_sites]
-
697ripplevalidators.com
-
698trustthesevalidators.gov
-
699
-
700[validator_list_keys]
-
701021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
-
702)rippleConfig");
-
703 detail::ValidatorsTxtGuard const vtg(
-
704 *this, "test_cfg", "validators.cfg");
-
705 BEAST_EXPECT(vtg.validatorsFileExists());
-
706 Config c;
-
707 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
-
708 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
-
709 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 15);
-
710 BEAST_EXPECT(
-
711 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 4);
-
712 BEAST_EXPECT(
-
713 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 3);
-
714 }
-
715 {
-
716 // load should throw if [validators], [validator_keys] and
-
717 // [validator_list_keys] are missing from rippled cfg and
-
718 // validators file
-
719 Config c;
-
720 boost::format cc("[validators_file]\n%1%\n");
-
721 std::string error;
-
722 detail::ValidatorsTxtGuard const vtg(
-
723 *this, "test_cfg", "validators.cfg");
-
724 BEAST_EXPECT(vtg.validatorsFileExists());
-
725 auto const expectedError =
-
726 "The file specified in [validators_file] does not contain a "
-
727 "[validators], [validator_keys] or [validator_list_keys] "
-
728 "section: " +
-
729 vtg.validatorsFile();
-
730 std::ofstream o(vtg.validatorsFile());
-
731 try
-
732 {
-
733 Config c2;
-
734 c2.loadFromString(boost::str(cc % vtg.validatorsFile()));
-
735 }
-
736 catch (std::runtime_error& e)
-
737 {
-
738 error = e.what();
-
739 }
-
740 BEAST_EXPECT(error == expectedError);
-
741 }
-
742 }
-
743
-
744 void
-
745 testSetup(bool explicitPath)
-
746 {
-
747 detail::RippledCfgGuard const cfg(
-
748 *this, "testSetup", explicitPath ? "test_db" : "", "");
-
749 /* RippledCfgGuard has a Config object that gets loaded on
-
750 construction, but Config::setup is not reentrant, so we
-
751 need a fresh config for every test case, so ignore it.
-
752 */
-
753 {
-
754 Config config;
-
755 config.setup(
-
756 cfg.configFile(),
-
757 /*bQuiet*/ false,
-
758 /* bSilent */ false,
-
759 /* bStandalone */ false);
-
760 BEAST_EXPECT(!config.quiet());
-
761 BEAST_EXPECT(!config.silent());
-
762 BEAST_EXPECT(!config.standalone());
-
763 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
-
764 BEAST_EXPECT(!config.legacy("database_path").empty());
-
765 }
-
766 {
-
767 Config config;
-
768 config.setup(
-
769 cfg.configFile(),
-
770 /*bQuiet*/ true,
-
771 /* bSilent */ false,
-
772 /* bStandalone */ false);
-
773 BEAST_EXPECT(config.quiet());
-
774 BEAST_EXPECT(!config.silent());
-
775 BEAST_EXPECT(!config.standalone());
-
776 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
-
777 BEAST_EXPECT(!config.legacy("database_path").empty());
-
778 }
-
779 {
-
780 Config config;
-
781 config.setup(
-
782 cfg.configFile(),
-
783 /*bQuiet*/ false,
-
784 /* bSilent */ true,
-
785 /* bStandalone */ false);
-
786 BEAST_EXPECT(config.quiet());
-
787 BEAST_EXPECT(config.silent());
-
788 BEAST_EXPECT(!config.standalone());
-
789 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
-
790 BEAST_EXPECT(!config.legacy("database_path").empty());
-
791 }
-
792 {
-
793 Config config;
-
794 config.setup(
-
795 cfg.configFile(),
-
796 /*bQuiet*/ true,
-
797 /* bSilent */ true,
-
798 /* bStandalone */ false);
-
799 BEAST_EXPECT(config.quiet());
-
800 BEAST_EXPECT(config.silent());
-
801 BEAST_EXPECT(!config.standalone());
-
802 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
-
803 BEAST_EXPECT(!config.legacy("database_path").empty());
-
804 }
-
805 {
-
806 Config config;
-
807 config.setup(
-
808 cfg.configFile(),
-
809 /*bQuiet*/ false,
-
810 /* bSilent */ false,
-
811 /* bStandalone */ true);
-
812 BEAST_EXPECT(!config.quiet());
-
813 BEAST_EXPECT(!config.silent());
-
814 BEAST_EXPECT(config.standalone());
-
815 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
-
816 BEAST_EXPECT(
-
817 config.legacy("database_path").empty() == !explicitPath);
-
818 }
-
819 {
-
820 Config config;
-
821 config.setup(
-
822 cfg.configFile(),
-
823 /*bQuiet*/ true,
-
824 /* bSilent */ false,
-
825 /* bStandalone */ true);
-
826 BEAST_EXPECT(config.quiet());
-
827 BEAST_EXPECT(!config.silent());
-
828 BEAST_EXPECT(config.standalone());
-
829 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
-
830 BEAST_EXPECT(
-
831 config.legacy("database_path").empty() == !explicitPath);
-
832 }
-
833 {
-
834 Config config;
-
835 config.setup(
-
836 cfg.configFile(),
-
837 /*bQuiet*/ false,
-
838 /* bSilent */ true,
-
839 /* bStandalone */ true);
-
840 BEAST_EXPECT(config.quiet());
-
841 BEAST_EXPECT(config.silent());
-
842 BEAST_EXPECT(config.standalone());
-
843 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
-
844 BEAST_EXPECT(
-
845 config.legacy("database_path").empty() == !explicitPath);
-
846 }
-
847 {
-
848 Config config;
-
849 config.setup(
-
850 cfg.configFile(),
-
851 /*bQuiet*/ true,
-
852 /* bSilent */ true,
-
853 /* bStandalone */ true);
-
854 BEAST_EXPECT(config.quiet());
-
855 BEAST_EXPECT(config.silent());
-
856 BEAST_EXPECT(config.standalone());
-
857 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
-
858 BEAST_EXPECT(
-
859 config.legacy("database_path").empty() == !explicitPath);
-
860 }
-
861 }
-
862
-
863 void
-
864 testPort()
-
865 {
-
866 detail::RippledCfgGuard const cfg(*this, "testPort", "", "");
-
867 auto const& conf = cfg.config();
-
868 if (!BEAST_EXPECT(conf.exists("port_rpc")))
-
869 return;
-
870 if (!BEAST_EXPECT(conf.exists("port_wss_admin")))
-
871 return;
-
872 ParsedPort rpc;
-
873 if (!unexcept([&]() { parse_Port(rpc, conf["port_rpc"], log); }))
-
874 return;
-
875 BEAST_EXPECT(rpc.admin_nets_v4.size() + rpc.admin_nets_v6.size() == 2);
-
876 ParsedPort wss;
-
877 if (!unexcept([&]() { parse_Port(wss, conf["port_wss_admin"], log); }))
-
878 return;
-
879 BEAST_EXPECT(wss.admin_nets_v4.size() + wss.admin_nets_v6.size() == 1);
-
880 }
-
881
-
882 void
-
883 testWhitespace()
-
884 {
-
885 Config cfg;
-
886 /* NOTE: this string includes some explicit
-
887 * space chars in order to verify proper trimming */
-
888 std::string toLoad(R"(
-
889[port_rpc])"
-
890 "\x20"
-
891 R"(
-
892# comment
-
893 # indented comment
-
894)"
-
895 "\x20\x20"
-
896 R"(
-
897[ips])"
-
898 "\x20"
-
899 R"(
-
900r.ripple.com 51235
-
901
-
902 [ips_fixed])"
-
903 "\x20\x20"
-
904 R"(
-
905 # COMMENT
-
906 s1.ripple.com 51235
-
907 s2.ripple.com 51235
-
908
-
909)");
-
910 cfg.loadFromString(toLoad);
-
911 BEAST_EXPECT(
-
912 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() &&
-
913 cfg.section("port_rpc").values().empty());
-
914 BEAST_EXPECT(
-
915 cfg.exists(SECTION_IPS) &&
-
916 cfg.section(SECTION_IPS).lines().size() == 1 &&
-
917 cfg.section(SECTION_IPS).values().size() == 1);
-
918 BEAST_EXPECT(
-
919 cfg.exists(SECTION_IPS_FIXED) &&
-
920 cfg.section(SECTION_IPS_FIXED).lines().size() == 2 &&
-
921 cfg.section(SECTION_IPS_FIXED).values().size() == 2);
-
922 }
-
923
-
924 void
-
925 testColons()
-
926 {
-
927 Config cfg;
-
928 /* NOTE: this string includes some explicit
-
929 * space chars in order to verify proper trimming */
-
930 std::string toLoad(R"(
-
931[port_rpc])"
-
932 "\x20"
-
933 R"(
-
934# comment
-
935 # indented comment
-
936)"
-
937 "\x20\x20"
-
938 R"(
-
939[ips])"
-
940 "\x20"
-
941 R"(
-
942r.ripple.com:51235
-
943
-
944 [ips_fixed])"
-
945 "\x20\x20"
-
946 R"(
-
947 # COMMENT
-
948 s1.ripple.com:51235
-
949 s2.ripple.com 51235
-
950 anotherserversansport
-
951 anotherserverwithport:12
-
952 1.1.1.1:1
-
953 1.1.1.1 1
-
954 12.34.12.123:12345
-
955 12.34.12.123 12345
-
956 ::
-
957 2001:db8::
-
958 ::1
-
959 ::1:12345
-
960 [::1]:12345
-
961 2001:db8:3333:4444:5555:6666:7777:8888:12345
-
962 [2001:db8:3333:4444:5555:6666:7777:8888]:1
-
963
-
964
-
965)");
-
966 cfg.loadFromString(toLoad);
-
967 BEAST_EXPECT(
-
968 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() &&
-
969 cfg.section("port_rpc").values().empty());
-
970 BEAST_EXPECT(
-
971 cfg.exists(SECTION_IPS) &&
-
972 cfg.section(SECTION_IPS).lines().size() == 1 &&
-
973 cfg.section(SECTION_IPS).values().size() == 1);
-
974 BEAST_EXPECT(
-
975 cfg.exists(SECTION_IPS_FIXED) &&
-
976 cfg.section(SECTION_IPS_FIXED).lines().size() == 15 &&
-
977 cfg.section(SECTION_IPS_FIXED).values().size() == 15);
-
978 BEAST_EXPECT(cfg.IPS[0] == "r.ripple.com 51235");
-
979
-
980 BEAST_EXPECT(cfg.IPS_FIXED[0] == "s1.ripple.com 51235");
-
981 BEAST_EXPECT(cfg.IPS_FIXED[1] == "s2.ripple.com 51235");
-
982 BEAST_EXPECT(cfg.IPS_FIXED[2] == "anotherserversansport");
-
983 BEAST_EXPECT(cfg.IPS_FIXED[3] == "anotherserverwithport 12");
-
984 BEAST_EXPECT(cfg.IPS_FIXED[4] == "1.1.1.1 1");
-
985 BEAST_EXPECT(cfg.IPS_FIXED[5] == "1.1.1.1 1");
-
986 BEAST_EXPECT(cfg.IPS_FIXED[6] == "12.34.12.123 12345");
-
987 BEAST_EXPECT(cfg.IPS_FIXED[7] == "12.34.12.123 12345");
-
988
-
989 // all ipv6 should be ignored by colon replacer, howsoever formated
-
990 BEAST_EXPECT(cfg.IPS_FIXED[8] == "::");
-
991 BEAST_EXPECT(cfg.IPS_FIXED[9] == "2001:db8::");
-
992 BEAST_EXPECT(cfg.IPS_FIXED[10] == "::1");
-
993 BEAST_EXPECT(cfg.IPS_FIXED[11] == "::1:12345");
-
994 BEAST_EXPECT(cfg.IPS_FIXED[12] == "[::1]:12345");
-
995 BEAST_EXPECT(
-
996 cfg.IPS_FIXED[13] ==
-
997 "2001:db8:3333:4444:5555:6666:7777:8888:12345");
-
998 BEAST_EXPECT(
-
999 cfg.IPS_FIXED[14] == "[2001:db8:3333:4444:5555:6666:7777:8888]:1");
-
1000 }
-
1001
-
1002 void
-
1003 testComments()
-
1004 {
-
1005 struct TestCommentData
-
1006 {
-
1007 std::string_view line;
-
1008 std::string_view field;
-
1009 std::string_view expect;
-
1010 bool had_comment;
-
1011 };
-
1012
-
1013 std::array<TestCommentData, 13> tests = {
-
1014 {{"password = aaaa\\#bbbb", "password", "aaaa#bbbb", false},
-
1015 {"password = aaaa#bbbb", "password", "aaaa", true},
-
1016 {"password = aaaa #bbbb", "password", "aaaa", true},
-
1017 // since the value is all comment, this doesn't parse as k=v :
-
1018 {"password = #aaaa #bbbb", "", "password =", true},
-
1019 {"password = aaaa\\# #bbbb", "password", "aaaa#", true},
-
1020 {"password = aaaa\\##bbbb", "password", "aaaa#", true},
-
1021 {"aaaa#bbbb", "", "aaaa", true},
-
1022 {"aaaa\\#bbbb", "", "aaaa#bbbb", false},
-
1023 {"aaaa\\##bbbb", "", "aaaa#", true},
-
1024 {"aaaa #bbbb", "", "aaaa", true},
-
1025 {"1 #comment", "", "1", true},
-
1026 {"#whole thing is comment", "", "", false},
-
1027 {" #whole comment with space", "", "", false}}};
-
1028
-
1029 for (auto const& t : tests)
-
1030 {
-
1031 Section s;
-
1032 s.append(t.line.data());
-
1033 BEAST_EXPECT(s.had_trailing_comments() == t.had_comment);
-
1034 if (t.field.empty())
-
1035 {
-
1036 BEAST_EXPECTS(s.legacy() == t.expect, s.legacy());
-
1037 }
-
1038 else
-
1039 {
-
1040 std::string field;
-
1041 BEAST_EXPECTS(set(field, t.field.data(), s), t.line);
-
1042 BEAST_EXPECTS(field == t.expect, t.line);
-
1043 }
-
1044 }
-
1045
-
1046 {
-
1047 Section s;
-
1048 s.append("online_delete = 3000");
-
1049 std::uint32_t od = 0;
-
1050 BEAST_EXPECT(set(od, "online_delete", s));
-
1051 BEAST_EXPECTS(od == 3000, *(s.get<std::string>("online_delete")));
-
1052 }
-
1053
-
1054 {
-
1055 Section s;
-
1056 s.append("online_delete = 2000 #my comment on this");
-
1057 std::uint32_t od = 0;
-
1058 BEAST_EXPECT(set(od, "online_delete", s));
-
1059 BEAST_EXPECTS(od == 2000, *(s.get<std::string>("online_delete")));
-
1060 }
-
1061 }
-
1062
-
1063 void
-
1064 testGetters()
-
1065 {
-
1066 using namespace std::string_literals;
-
1067 Section s{"MySection"};
-
1068 s.append("a_string = mystring");
-
1069 s.append("positive_int = 2");
-
1070 s.append("negative_int = -3");
-
1071 s.append("bool_ish = 1");
-
1072
-
1073 {
-
1074 auto val_1 = "value 1"s;
-
1075 BEAST_EXPECT(set(val_1, "a_string", s));
-
1076 BEAST_EXPECT(val_1 == "mystring");
-
1077
-
1078 auto val_2 = "value 2"s;
-
1079 BEAST_EXPECT(!set(val_2, "not_a_key", s));
-
1080 BEAST_EXPECT(val_2 == "value 2");
-
1081 BEAST_EXPECT(!set(val_2, "default"s, "not_a_key", s));
-
1082 BEAST_EXPECT(val_2 == "default");
-
1083
-
1084 auto val_3 = get<std::string>(s, "a_string");
-
1085 BEAST_EXPECT(val_3 == "mystring");
-
1086 auto val_4 = get<std::string>(s, "not_a_key");
-
1087 BEAST_EXPECT(val_4 == "");
-
1088 auto val_5 = get<std::string>(s, "not_a_key", "default");
-
1089 BEAST_EXPECT(val_5 == "default");
-
1090
-
1091 auto val_6 = "value 6"s;
-
1092 BEAST_EXPECT(get_if_exists(s, "a_string", val_6));
-
1093 BEAST_EXPECT(val_6 == "mystring");
-
1094
-
1095 auto val_7 = "value 7"s;
-
1096 BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_7));
-
1097 BEAST_EXPECT(val_7 == "value 7");
-
1098 }
-
1099
-
1100 {
-
1101 int val_1 = 1;
-
1102 BEAST_EXPECT(set(val_1, "positive_int", s));
-
1103 BEAST_EXPECT(val_1 == 2);
-
1104
-
1105 int val_2 = 2;
-
1106 BEAST_EXPECT(set(val_2, "negative_int", s));
-
1107 BEAST_EXPECT(val_2 == -3);
-
1108
-
1109 int val_3 = 3;
-
1110 BEAST_EXPECT(!set(val_3, "a_string", s));
-
1111 BEAST_EXPECT(val_3 == 3);
+
678 {
+
679 // load should throw if [validator_list_threshold] is negative
+
680 Config c;
+
681 std::string toLoad(R"rippleConfig(
+
682[validator_list_sites]
+
683ripplevalidators.com
+
684trustthesevalidators.gov
+
685
+
686[validator_list_keys]
+
687021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
+
688
+
689[validator_list_threshold]
+
690-1
+
691)rippleConfig");
+
692 bool error = false;
+
693 try
+
694 {
+
695 c.loadFromString(toLoad);
+
696 fail();
+
697 }
+
698 catch (std::bad_cast& e)
+
699 {
+
700 error = true;
+
701 }
+
702 BEAST_EXPECT(error);
+
703 }
+
704 {
+
705 // load should throw if [validator_list_sites] is configured but
+
706 // [validator_list_keys] is not
+
707 Config c;
+
708 std::string toLoad(R"rippleConfig(
+
709[validator_list_sites]
+
710ripplevalidators.com
+
711trustthesevalidators.gov
+
712)rippleConfig");
+
713 std::string error;
+
714 auto const expectedError =
+
715 "[validator_list_keys] config section is missing";
+
716 try
+
717 {
+
718 c.loadFromString(toLoad);
+
719 fail();
+
720 }
+
721 catch (std::runtime_error& e)
+
722 {
+
723 error = e.what();
+
724 }
+
725 BEAST_EXPECT(error == expectedError);
+
726 }
+
727 {
+
728 // load from specified [validators_file] absolute path
+
729 detail::ValidatorsTxtGuard const vtg(
+
730 *this, "test_cfg", "validators.cfg");
+
731 BEAST_EXPECT(vtg.validatorsFileExists());
+
732 Config c;
+
733 boost::format cc("[validators_file]\n%1%\n");
+
734 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
+
735 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
+
736 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
+
737 BEAST_EXPECT(
+
738 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
739 BEAST_EXPECT(
+
740 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
+
741 BEAST_EXPECT(
+
742 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
743 1);
+
744 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
+
745 }
+
746 {
+
747 // load from specified [validators_file] file name
+
748 // in config directory
+
749 std::string const valFileName = "validators.txt";
+
750 detail::ValidatorsTxtGuard const vtg(
+
751 *this, "test_cfg", valFileName);
+
752 detail::RippledCfgGuard const rcg(
+
753 *this, vtg.subdir(), "", valFileName, false);
+
754 BEAST_EXPECT(vtg.validatorsFileExists());
+
755 BEAST_EXPECT(rcg.configFileExists());
+
756 auto const& c(rcg.config());
+
757 BEAST_EXPECT(c.legacy("validators_file") == valFileName);
+
758 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
+
759 BEAST_EXPECT(
+
760 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
761 BEAST_EXPECT(
+
762 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
+
763 BEAST_EXPECT(
+
764 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
765 1);
+
766 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
+
767 }
+
768 {
+
769 // load from specified [validators_file] relative path
+
770 // to config directory
+
771 detail::ValidatorsTxtGuard const vtg(
+
772 *this, "test_cfg", "validators.txt");
+
773 auto const valFilePath = ".." / vtg.subdir() / "validators.txt";
+
774 detail::RippledCfgGuard const rcg(
+
775 *this, vtg.subdir(), "", valFilePath, false);
+
776 BEAST_EXPECT(vtg.validatorsFileExists());
+
777 BEAST_EXPECT(rcg.configFileExists());
+
778 auto const& c(rcg.config());
+
779 BEAST_EXPECT(c.legacy("validators_file") == valFilePath);
+
780 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
+
781 BEAST_EXPECT(
+
782 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
783 BEAST_EXPECT(
+
784 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
+
785 BEAST_EXPECT(
+
786 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
787 1);
+
788 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
+
789 }
+
790 {
+
791 // load from validators file in default location
+
792 detail::ValidatorsTxtGuard const vtg(
+
793 *this, "test_cfg", "validators.txt");
+
794 detail::RippledCfgGuard const rcg(
+
795 *this, vtg.subdir(), "", "", false);
+
796 BEAST_EXPECT(vtg.validatorsFileExists());
+
797 BEAST_EXPECT(rcg.configFileExists());
+
798 auto const& c(rcg.config());
+
799 BEAST_EXPECT(c.legacy("validators_file").empty());
+
800 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
+
801 BEAST_EXPECT(
+
802 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
803 BEAST_EXPECT(
+
804 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
+
805 BEAST_EXPECT(
+
806 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
807 1);
+
808 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
+
809 }
+
810 {
+
811 // load from specified [validators_file] instead
+
812 // of default location
+
813 detail::ValidatorsTxtGuard const vtg(
+
814 *this, "test_cfg", "validators.cfg");
+
815 BEAST_EXPECT(vtg.validatorsFileExists());
+
816 detail::ValidatorsTxtGuard const vtgDefault(
+
817 *this, vtg.subdir(), "validators.txt", false);
+
818 BEAST_EXPECT(vtgDefault.validatorsFileExists());
+
819 detail::RippledCfgGuard const rcg(
+
820 *this, vtg.subdir(), "", vtg.validatorsFile(), false);
+
821 BEAST_EXPECT(rcg.configFileExists());
+
822 auto const& c(rcg.config());
+
823 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
+
824 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
+
825 BEAST_EXPECT(
+
826 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
+
827 BEAST_EXPECT(
+
828 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
+
829 BEAST_EXPECT(
+
830 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
831 1);
+
832 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
+
833 }
+
834
+
835 {
+
836 // load validators from both config and validators file
+
837 boost::format cc(R"rippleConfig(
+
838[validators_file]
+
839%1%
+
840
+
841[validators]
+
842n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
+
843n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
+
844n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
+
845n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
+
846n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
+
847
+
848[validator_keys]
+
849nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v
+
850nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB
+
851
+
852[validator_list_sites]
+
853ripplevalidators.com
+
854trustthesevalidators.gov
+
855
+
856[validator_list_keys]
+
857021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
+
858)rippleConfig");
+
859 detail::ValidatorsTxtGuard const vtg(
+
860 *this, "test_cfg", "validators.cfg");
+
861 BEAST_EXPECT(vtg.validatorsFileExists());
+
862 Config c;
+
863 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
+
864 BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
+
865 BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 15);
+
866 BEAST_EXPECT(
+
867 c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 4);
+
868 BEAST_EXPECT(
+
869 c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 3);
+
870 BEAST_EXPECT(
+
871 c.section(SECTION_VALIDATOR_LIST_THRESHOLD).values().size() ==
+
872 1);
+
873 BEAST_EXPECT(c.VALIDATOR_LIST_THRESHOLD == 2);
+
874 }
+
875 {
+
876 // load should throw if [validator_list_threshold] is present both
+
877 // in rippled cfg and validators file
+
878 boost::format cc(R"rippleConfig(
+
879[validators_file]
+
880%1%
+
881
+
882[validator_list_threshold]
+
8831
+
884)rippleConfig");
+
885 std::string error;
+
886 detail::ValidatorsTxtGuard const vtg(
+
887 *this, "test_cfg", "validators.cfg");
+
888 BEAST_EXPECT(vtg.validatorsFileExists());
+
889 auto const expectedError =
+
890 "Config section [validator_list_threshold] should contain "
+
891 "single value only";
+
892 try
+
893 {
+
894 Config c;
+
895 c.loadFromString(boost::str(cc % vtg.validatorsFile()));
+
896 fail();
+
897 }
+
898 catch (std::runtime_error& e)
+
899 {
+
900 error = e.what();
+
901 }
+
902 BEAST_EXPECT(error == expectedError);
+
903 }
+
904 {
+
905 // load should throw if [validators], [validator_keys] and
+
906 // [validator_list_keys] are missing from rippled cfg and
+
907 // validators file
+
908 Config c;
+
909 boost::format cc("[validators_file]\n%1%\n");
+
910 std::string error;
+
911 detail::ValidatorsTxtGuard const vtg(
+
912 *this, "test_cfg", "validators.cfg");
+
913 BEAST_EXPECT(vtg.validatorsFileExists());
+
914 auto const expectedError =
+
915 "The file specified in [validators_file] does not contain a "
+
916 "[validators], [validator_keys] or [validator_list_keys] "
+
917 "section: " +
+
918 vtg.validatorsFile();
+
919 std::ofstream o(vtg.validatorsFile());
+
920 try
+
921 {
+
922 Config c2;
+
923 c2.loadFromString(boost::str(cc % vtg.validatorsFile()));
+
924 }
+
925 catch (std::runtime_error& e)
+
926 {
+
927 error = e.what();
+
928 }
+
929 BEAST_EXPECT(error == expectedError);
+
930 }
+
931 }
+
932
+
933 void
+
934 testSetup(bool explicitPath)
+
935 {
+
936 detail::RippledCfgGuard const cfg(
+
937 *this, "testSetup", explicitPath ? "test_db" : "", "");
+
938 /* RippledCfgGuard has a Config object that gets loaded on
+
939 construction, but Config::setup is not reentrant, so we
+
940 need a fresh config for every test case, so ignore it.
+
941 */
+
942 {
+
943 Config config;
+
944 config.setup(
+
945 cfg.configFile(),
+
946 /*bQuiet*/ false,
+
947 /* bSilent */ false,
+
948 /* bStandalone */ false);
+
949 BEAST_EXPECT(!config.quiet());
+
950 BEAST_EXPECT(!config.silent());
+
951 BEAST_EXPECT(!config.standalone());
+
952 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
+
953 BEAST_EXPECT(!config.legacy("database_path").empty());
+
954 }
+
955 {
+
956 Config config;
+
957 config.setup(
+
958 cfg.configFile(),
+
959 /*bQuiet*/ true,
+
960 /* bSilent */ false,
+
961 /* bStandalone */ false);
+
962 BEAST_EXPECT(config.quiet());
+
963 BEAST_EXPECT(!config.silent());
+
964 BEAST_EXPECT(!config.standalone());
+
965 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
+
966 BEAST_EXPECT(!config.legacy("database_path").empty());
+
967 }
+
968 {
+
969 Config config;
+
970 config.setup(
+
971 cfg.configFile(),
+
972 /*bQuiet*/ false,
+
973 /* bSilent */ true,
+
974 /* bStandalone */ false);
+
975 BEAST_EXPECT(config.quiet());
+
976 BEAST_EXPECT(config.silent());
+
977 BEAST_EXPECT(!config.standalone());
+
978 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
+
979 BEAST_EXPECT(!config.legacy("database_path").empty());
+
980 }
+
981 {
+
982 Config config;
+
983 config.setup(
+
984 cfg.configFile(),
+
985 /*bQuiet*/ true,
+
986 /* bSilent */ true,
+
987 /* bStandalone */ false);
+
988 BEAST_EXPECT(config.quiet());
+
989 BEAST_EXPECT(config.silent());
+
990 BEAST_EXPECT(!config.standalone());
+
991 BEAST_EXPECT(config.LEDGER_HISTORY == 256);
+
992 BEAST_EXPECT(!config.legacy("database_path").empty());
+
993 }
+
994 {
+
995 Config config;
+
996 config.setup(
+
997 cfg.configFile(),
+
998 /*bQuiet*/ false,
+
999 /* bSilent */ false,
+
1000 /* bStandalone */ true);
+
1001 BEAST_EXPECT(!config.quiet());
+
1002 BEAST_EXPECT(!config.silent());
+
1003 BEAST_EXPECT(config.standalone());
+
1004 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
+
1005 BEAST_EXPECT(
+
1006 config.legacy("database_path").empty() == !explicitPath);
+
1007 }
+
1008 {
+
1009 Config config;
+
1010 config.setup(
+
1011 cfg.configFile(),
+
1012 /*bQuiet*/ true,
+
1013 /* bSilent */ false,
+
1014 /* bStandalone */ true);
+
1015 BEAST_EXPECT(config.quiet());
+
1016 BEAST_EXPECT(!config.silent());
+
1017 BEAST_EXPECT(config.standalone());
+
1018 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
+
1019 BEAST_EXPECT(
+
1020 config.legacy("database_path").empty() == !explicitPath);
+
1021 }
+
1022 {
+
1023 Config config;
+
1024 config.setup(
+
1025 cfg.configFile(),
+
1026 /*bQuiet*/ false,
+
1027 /* bSilent */ true,
+
1028 /* bStandalone */ true);
+
1029 BEAST_EXPECT(config.quiet());
+
1030 BEAST_EXPECT(config.silent());
+
1031 BEAST_EXPECT(config.standalone());
+
1032 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
+
1033 BEAST_EXPECT(
+
1034 config.legacy("database_path").empty() == !explicitPath);
+
1035 }
+
1036 {
+
1037 Config config;
+
1038 config.setup(
+
1039 cfg.configFile(),
+
1040 /*bQuiet*/ true,
+
1041 /* bSilent */ true,
+
1042 /* bStandalone */ true);
+
1043 BEAST_EXPECT(config.quiet());
+
1044 BEAST_EXPECT(config.silent());
+
1045 BEAST_EXPECT(config.standalone());
+
1046 BEAST_EXPECT(config.LEDGER_HISTORY == 0);
+
1047 BEAST_EXPECT(
+
1048 config.legacy("database_path").empty() == !explicitPath);
+
1049 }
+
1050 }
+
1051
+
1052 void
+
1053 testPort()
+
1054 {
+
1055 detail::RippledCfgGuard const cfg(*this, "testPort", "", "");
+
1056 auto const& conf = cfg.config();
+
1057 if (!BEAST_EXPECT(conf.exists("port_rpc")))
+
1058 return;
+
1059 if (!BEAST_EXPECT(conf.exists("port_wss_admin")))
+
1060 return;
+
1061 ParsedPort rpc;
+
1062 if (!unexcept([&]() { parse_Port(rpc, conf["port_rpc"], log); }))
+
1063 return;
+
1064 BEAST_EXPECT(rpc.admin_nets_v4.size() + rpc.admin_nets_v6.size() == 2);
+
1065 ParsedPort wss;
+
1066 if (!unexcept([&]() { parse_Port(wss, conf["port_wss_admin"], log); }))
+
1067 return;
+
1068 BEAST_EXPECT(wss.admin_nets_v4.size() + wss.admin_nets_v6.size() == 1);
+
1069 }
+
1070
+
1071 void
+
1072 testWhitespace()
+
1073 {
+
1074 Config cfg;
+
1075 /* NOTE: this string includes some explicit
+
1076 * space chars in order to verify proper trimming */
+
1077 std::string toLoad(R"(
+
1078[port_rpc])"
+
1079 "\x20"
+
1080 R"(
+
1081# comment
+
1082 # indented comment
+
1083)"
+
1084 "\x20\x20"
+
1085 R"(
+
1086[ips])"
+
1087 "\x20"
+
1088 R"(
+
1089r.ripple.com 51235
+
1090
+
1091 [ips_fixed])"
+
1092 "\x20\x20"
+
1093 R"(
+
1094 # COMMENT
+
1095 s1.ripple.com 51235
+
1096 s2.ripple.com 51235
+
1097
+
1098)");
+
1099 cfg.loadFromString(toLoad);
+
1100 BEAST_EXPECT(
+
1101 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() &&
+
1102 cfg.section("port_rpc").values().empty());
+
1103 BEAST_EXPECT(
+
1104 cfg.exists(SECTION_IPS) &&
+
1105 cfg.section(SECTION_IPS).lines().size() == 1 &&
+
1106 cfg.section(SECTION_IPS).values().size() == 1);
+
1107 BEAST_EXPECT(
+
1108 cfg.exists(SECTION_IPS_FIXED) &&
+
1109 cfg.section(SECTION_IPS_FIXED).lines().size() == 2 &&
+
1110 cfg.section(SECTION_IPS_FIXED).values().size() == 2);
+
1111 }
1112
-
1113 auto val_4 = get<int>(s, "positive_int");
-
1114 BEAST_EXPECT(val_4 == 2);
-
1115 auto val_5 = get<int>(s, "not_a_key");
-
1116 BEAST_EXPECT(val_5 == 0);
-
1117 auto val_6 = get<int>(s, "not_a_key", 5);
-
1118 BEAST_EXPECT(val_6 == 5);
-
1119 auto val_7 = get<int>(s, "a_string", 6);
-
1120 BEAST_EXPECT(val_7 == 6);
-
1121
-
1122 int val_8 = 8;
-
1123 BEAST_EXPECT(get_if_exists(s, "positive_int", val_8));
-
1124 BEAST_EXPECT(val_8 == 2);
-
1125
-
1126 auto val_9 = 9;
-
1127 BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_9));
-
1128 BEAST_EXPECT(val_9 == 9);
-
1129
-
1130 auto val_10 = 10;
-
1131 BEAST_EXPECT(!get_if_exists(s, "a_string", val_10));
-
1132 BEAST_EXPECT(val_10 == 10);
-
1133
-
1134 BEAST_EXPECT(s.get<int>("not_a_key") == std::nullopt);
-
1135 try
-
1136 {
-
1137 s.get<int>("a_string");
-
1138 fail();
-
1139 }
-
1140 catch (boost::bad_lexical_cast&)
-
1141 {
-
1142 pass();
-
1143 }
-
1144 }
-
1145
-
1146 {
-
1147 bool flag_1 = false;
-
1148 BEAST_EXPECT(get_if_exists(s, "bool_ish", flag_1));
-
1149 BEAST_EXPECT(flag_1 == true);
-
1150
-
1151 bool flag_2 = false;
-
1152 BEAST_EXPECT(!get_if_exists(s, "not_a_key", flag_2));
-
1153 BEAST_EXPECT(flag_2 == false);
-
1154 }
-
1155 }
-
1156
-
1157 void
-
1158 testAmendment()
-
1159 {
-
1160 testcase("amendment");
-
1161 struct ConfigUnit
-
1162 {
-
1163 std::string unit;
-
1164 std::uint32_t numSeconds;
-
1165 std::uint32_t configVal;
-
1166 bool shouldPass;
-
1167 };
+
1113 void
+
1114 testColons()
+
1115 {
+
1116 Config cfg;
+
1117 /* NOTE: this string includes some explicit
+
1118 * space chars in order to verify proper trimming */
+
1119 std::string toLoad(R"(
+
1120[port_rpc])"
+
1121 "\x20"
+
1122 R"(
+
1123# comment
+
1124 # indented comment
+
1125)"
+
1126 "\x20\x20"
+
1127 R"(
+
1128[ips])"
+
1129 "\x20"
+
1130 R"(
+
1131r.ripple.com:51235
+
1132
+
1133 [ips_fixed])"
+
1134 "\x20\x20"
+
1135 R"(
+
1136 # COMMENT
+
1137 s1.ripple.com:51235
+
1138 s2.ripple.com 51235
+
1139 anotherserversansport
+
1140 anotherserverwithport:12
+
1141 1.1.1.1:1
+
1142 1.1.1.1 1
+
1143 12.34.12.123:12345
+
1144 12.34.12.123 12345
+
1145 ::
+
1146 2001:db8::
+
1147 ::1
+
1148 ::1:12345
+
1149 [::1]:12345
+
1150 2001:db8:3333:4444:5555:6666:7777:8888:12345
+
1151 [2001:db8:3333:4444:5555:6666:7777:8888]:1
+
1152
+
1153
+
1154)");
+
1155 cfg.loadFromString(toLoad);
+
1156 BEAST_EXPECT(
+
1157 cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() &&
+
1158 cfg.section("port_rpc").values().empty());
+
1159 BEAST_EXPECT(
+
1160 cfg.exists(SECTION_IPS) &&
+
1161 cfg.section(SECTION_IPS).lines().size() == 1 &&
+
1162 cfg.section(SECTION_IPS).values().size() == 1);
+
1163 BEAST_EXPECT(
+
1164 cfg.exists(SECTION_IPS_FIXED) &&
+
1165 cfg.section(SECTION_IPS_FIXED).lines().size() == 15 &&
+
1166 cfg.section(SECTION_IPS_FIXED).values().size() == 15);
+
1167 BEAST_EXPECT(cfg.IPS[0] == "r.ripple.com 51235");
1168
-
1169 std::vector<ConfigUnit> units = {
-
1170 {"seconds", 1, 15 * 60, false},
-
1171 {"minutes", 60, 14, false},
-
1172 {"minutes", 60, 15, true},
-
1173 {"hours", 3600, 10, true},
-
1174 {"days", 86400, 10, true},
-
1175 {"weeks", 604800, 2, true},
-
1176 {"months", 2592000, 1, false},
-
1177 {"years", 31536000, 1, false}};
-
1178
-
1179 std::string space = "";
-
1180 for (auto& [unit, sec, val, shouldPass] : units)
-
1181 {
-
1182 Config c;
-
1183 std::string toLoad(R"rippleConfig(
-
1184[amendment_majority_time]
-
1185)rippleConfig");
-
1186 toLoad += std::to_string(val) + space + unit;
-
1187 space = space == "" ? " " : "";
-
1188
-
1189 try
-
1190 {
-
1191 c.loadFromString(toLoad);
-
1192 if (shouldPass)
-
1193 BEAST_EXPECT(
-
1194 c.AMENDMENT_MAJORITY_TIME.count() == val * sec);
-
1195 else
-
1196 fail();
-
1197 }
-
1198 catch (std::runtime_error&)
-
1199 {
-
1200 if (!shouldPass)
-
1201 pass();
-
1202 else
-
1203 fail();
-
1204 }
-
1205 }
-
1206 }
-
1207
-
1208 void
-
1209 testOverlay()
-
1210 {
-
1211 testcase("overlay: unknown time");
-
1212
-
1213 auto testUnknown =
-
1214 [](std::string value) -> std::optional<std::chrono::seconds> {
-
1215 try
-
1216 {
-
1217 Config c;
-
1218 c.loadFromString("[overlay]\nmax_unknown_time=" + value);
-
1219 return c.MAX_UNKNOWN_TIME;
-
1220 }
-
1221 catch (std::runtime_error&)
-
1222 {
-
1223 return {};
-
1224 }
-
1225 };
-
1226
-
1227 // Failures
-
1228 BEAST_EXPECT(!testUnknown("none"));
-
1229 BEAST_EXPECT(!testUnknown("0.5"));
-
1230 BEAST_EXPECT(!testUnknown("180 seconds"));
-
1231 BEAST_EXPECT(!testUnknown("9 minutes"));
-
1232
-
1233 // Below lower bound
-
1234 BEAST_EXPECT(!testUnknown("299"));
-
1235
-
1236 // In bounds
-
1237 BEAST_EXPECT(testUnknown("300") == std::chrono::seconds{300});
-
1238 BEAST_EXPECT(testUnknown("301") == std::chrono::seconds{301});
-
1239 BEAST_EXPECT(testUnknown("1799") == std::chrono::seconds{1799});
-
1240 BEAST_EXPECT(testUnknown("1800") == std::chrono::seconds{1800});
-
1241
-
1242 // Above upper bound
-
1243 BEAST_EXPECT(!testUnknown("1801"));
-
1244
-
1245 testcase("overlay: diverged time");
-
1246
-
1247 // In bounds:
-
1248 auto testDiverged =
-
1249 [](std::string value) -> std::optional<std::chrono::seconds> {
-
1250 try
-
1251 {
-
1252 Config c;
-
1253 c.loadFromString("[overlay]\nmax_diverged_time=" + value);
-
1254 return c.MAX_DIVERGED_TIME;
-
1255 }
-
1256 catch (std::runtime_error&)
-
1257 {
-
1258 return {};
-
1259 }
-
1260 };
+
1169 BEAST_EXPECT(cfg.IPS_FIXED[0] == "s1.ripple.com 51235");
+
1170 BEAST_EXPECT(cfg.IPS_FIXED[1] == "s2.ripple.com 51235");
+
1171 BEAST_EXPECT(cfg.IPS_FIXED[2] == "anotherserversansport");
+
1172 BEAST_EXPECT(cfg.IPS_FIXED[3] == "anotherserverwithport 12");
+
1173 BEAST_EXPECT(cfg.IPS_FIXED[4] == "1.1.1.1 1");
+
1174 BEAST_EXPECT(cfg.IPS_FIXED[5] == "1.1.1.1 1");
+
1175 BEAST_EXPECT(cfg.IPS_FIXED[6] == "12.34.12.123 12345");
+
1176 BEAST_EXPECT(cfg.IPS_FIXED[7] == "12.34.12.123 12345");
+
1177
+
1178 // all ipv6 should be ignored by colon replacer, howsoever formated
+
1179 BEAST_EXPECT(cfg.IPS_FIXED[8] == "::");
+
1180 BEAST_EXPECT(cfg.IPS_FIXED[9] == "2001:db8::");
+
1181 BEAST_EXPECT(cfg.IPS_FIXED[10] == "::1");
+
1182 BEAST_EXPECT(cfg.IPS_FIXED[11] == "::1:12345");
+
1183 BEAST_EXPECT(cfg.IPS_FIXED[12] == "[::1]:12345");
+
1184 BEAST_EXPECT(
+
1185 cfg.IPS_FIXED[13] ==
+
1186 "2001:db8:3333:4444:5555:6666:7777:8888:12345");
+
1187 BEAST_EXPECT(
+
1188 cfg.IPS_FIXED[14] == "[2001:db8:3333:4444:5555:6666:7777:8888]:1");
+
1189 }
+
1190
+
1191 void
+
1192 testComments()
+
1193 {
+
1194 struct TestCommentData
+
1195 {
+
1196 std::string_view line;
+
1197 std::string_view field;
+
1198 std::string_view expect;
+
1199 bool had_comment;
+
1200 };
+
1201
+
1202 std::array<TestCommentData, 13> tests = {
+
1203 {{"password = aaaa\\#bbbb", "password", "aaaa#bbbb", false},
+
1204 {"password = aaaa#bbbb", "password", "aaaa", true},
+
1205 {"password = aaaa #bbbb", "password", "aaaa", true},
+
1206 // since the value is all comment, this doesn't parse as k=v :
+
1207 {"password = #aaaa #bbbb", "", "password =", true},
+
1208 {"password = aaaa\\# #bbbb", "password", "aaaa#", true},
+
1209 {"password = aaaa\\##bbbb", "password", "aaaa#", true},
+
1210 {"aaaa#bbbb", "", "aaaa", true},
+
1211 {"aaaa\\#bbbb", "", "aaaa#bbbb", false},
+
1212 {"aaaa\\##bbbb", "", "aaaa#", true},
+
1213 {"aaaa #bbbb", "", "aaaa", true},
+
1214 {"1 #comment", "", "1", true},
+
1215 {"#whole thing is comment", "", "", false},
+
1216 {" #whole comment with space", "", "", false}}};
+
1217
+
1218 for (auto const& t : tests)
+
1219 {
+
1220 Section s;
+
1221 s.append(t.line.data());
+
1222 BEAST_EXPECT(s.had_trailing_comments() == t.had_comment);
+
1223 if (t.field.empty())
+
1224 {
+
1225 BEAST_EXPECTS(s.legacy() == t.expect, s.legacy());
+
1226 }
+
1227 else
+
1228 {
+
1229 std::string field;
+
1230 BEAST_EXPECTS(set(field, t.field.data(), s), t.line);
+
1231 BEAST_EXPECTS(field == t.expect, t.line);
+
1232 }
+
1233 }
+
1234
+
1235 {
+
1236 Section s;
+
1237 s.append("online_delete = 3000");
+
1238 std::uint32_t od = 0;
+
1239 BEAST_EXPECT(set(od, "online_delete", s));
+
1240 BEAST_EXPECTS(od == 3000, *(s.get<std::string>("online_delete")));
+
1241 }
+
1242
+
1243 {
+
1244 Section s;
+
1245 s.append("online_delete = 2000 #my comment on this");
+
1246 std::uint32_t od = 0;
+
1247 BEAST_EXPECT(set(od, "online_delete", s));
+
1248 BEAST_EXPECTS(od == 2000, *(s.get<std::string>("online_delete")));
+
1249 }
+
1250 }
+
1251
+
1252 void
+
1253 testGetters()
+
1254 {
+
1255 using namespace std::string_literals;
+
1256 Section s{"MySection"};
+
1257 s.append("a_string = mystring");
+
1258 s.append("positive_int = 2");
+
1259 s.append("negative_int = -3");
+
1260 s.append("bool_ish = 1");
1261
-
1262 // Failures
-
1263 BEAST_EXPECT(!testDiverged("none"));
-
1264 BEAST_EXPECT(!testDiverged("0.5"));
-
1265 BEAST_EXPECT(!testDiverged("180 seconds"));
-
1266 BEAST_EXPECT(!testDiverged("9 minutes"));
-
1267
-
1268 // Below lower bound
-
1269 BEAST_EXPECT(!testDiverged("0"));
-
1270 BEAST_EXPECT(!testDiverged("59"));
-
1271
-
1272 // In bounds
-
1273 BEAST_EXPECT(testDiverged("60") == std::chrono::seconds{60});
-
1274 BEAST_EXPECT(testDiverged("61") == std::chrono::seconds{61});
-
1275 BEAST_EXPECT(testDiverged("899") == std::chrono::seconds{899});
-
1276 BEAST_EXPECT(testDiverged("900") == std::chrono::seconds{900});
-
1277
-
1278 // Above upper bound
-
1279 BEAST_EXPECT(!testDiverged("901"));
-
1280 }
-
1281
-
1282 void
-
1283 run() override
-
1284 {
-
1285 testLegacy();
-
1286 testDbPath();
-
1287 testValidatorKeys();
-
1288 testValidatorsFile();
-
1289 testSetup(false);
-
1290 testSetup(true);
-
1291 testPort();
-
1292 testWhitespace();
-
1293 testColons();
-
1294 testComments();
-
1295 testGetters();
-
1296 testAmendment();
-
1297 testOverlay();
-
1298 testNetworkID();
-
1299 }
-
1300};
+
1262 {
+
1263 auto val_1 = "value 1"s;
+
1264 BEAST_EXPECT(set(val_1, "a_string", s));
+
1265 BEAST_EXPECT(val_1 == "mystring");
+
1266
+
1267 auto val_2 = "value 2"s;
+
1268 BEAST_EXPECT(!set(val_2, "not_a_key", s));
+
1269 BEAST_EXPECT(val_2 == "value 2");
+
1270 BEAST_EXPECT(!set(val_2, "default"s, "not_a_key", s));
+
1271 BEAST_EXPECT(val_2 == "default");
+
1272
+
1273 auto val_3 = get<std::string>(s, "a_string");
+
1274 BEAST_EXPECT(val_3 == "mystring");
+
1275 auto val_4 = get<std::string>(s, "not_a_key");
+
1276 BEAST_EXPECT(val_4 == "");
+
1277 auto val_5 = get<std::string>(s, "not_a_key", "default");
+
1278 BEAST_EXPECT(val_5 == "default");
+
1279
+
1280 auto val_6 = "value 6"s;
+
1281 BEAST_EXPECT(get_if_exists(s, "a_string", val_6));
+
1282 BEAST_EXPECT(val_6 == "mystring");
+
1283
+
1284 auto val_7 = "value 7"s;
+
1285 BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_7));
+
1286 BEAST_EXPECT(val_7 == "value 7");
+
1287 }
+
1288
+
1289 {
+
1290 int val_1 = 1;
+
1291 BEAST_EXPECT(set(val_1, "positive_int", s));
+
1292 BEAST_EXPECT(val_1 == 2);
+
1293
+
1294 int val_2 = 2;
+
1295 BEAST_EXPECT(set(val_2, "negative_int", s));
+
1296 BEAST_EXPECT(val_2 == -3);
+
1297
+
1298 int val_3 = 3;
+
1299 BEAST_EXPECT(!set(val_3, "a_string", s));
+
1300 BEAST_EXPECT(val_3 == 3);
1301
-
1302BEAST_DEFINE_TESTSUITE(Config, core, ripple);
-
1303
-
1304} // namespace ripple
+
1302 auto val_4 = get<int>(s, "positive_int");
+
1303 BEAST_EXPECT(val_4 == 2);
+
1304 auto val_5 = get<int>(s, "not_a_key");
+
1305 BEAST_EXPECT(val_5 == 0);
+
1306 auto val_6 = get<int>(s, "not_a_key", 5);
+
1307 BEAST_EXPECT(val_6 == 5);
+
1308 auto val_7 = get<int>(s, "a_string", 6);
+
1309 BEAST_EXPECT(val_7 == 6);
+
1310
+
1311 int val_8 = 8;
+
1312 BEAST_EXPECT(get_if_exists(s, "positive_int", val_8));
+
1313 BEAST_EXPECT(val_8 == 2);
+
1314
+
1315 auto val_9 = 9;
+
1316 BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_9));
+
1317 BEAST_EXPECT(val_9 == 9);
+
1318
+
1319 auto val_10 = 10;
+
1320 BEAST_EXPECT(!get_if_exists(s, "a_string", val_10));
+
1321 BEAST_EXPECT(val_10 == 10);
+
1322
+
1323 BEAST_EXPECT(s.get<int>("not_a_key") == std::nullopt);
+
1324 try
+
1325 {
+
1326 s.get<int>("a_string");
+
1327 fail();
+
1328 }
+
1329 catch (boost::bad_lexical_cast&)
+
1330 {
+
1331 pass();
+
1332 }
+
1333 }
+
1334
+
1335 {
+
1336 bool flag_1 = false;
+
1337 BEAST_EXPECT(get_if_exists(s, "bool_ish", flag_1));
+
1338 BEAST_EXPECT(flag_1 == true);
+
1339
+
1340 bool flag_2 = false;
+
1341 BEAST_EXPECT(!get_if_exists(s, "not_a_key", flag_2));
+
1342 BEAST_EXPECT(flag_2 == false);
+
1343 }
+
1344 }
+
1345
+
1346 void
+
1347 testAmendment()
+
1348 {
+
1349 testcase("amendment");
+
1350 struct ConfigUnit
+
1351 {
+
1352 std::string unit;
+
1353 std::uint32_t numSeconds;
+
1354 std::uint32_t configVal;
+
1355 bool shouldPass;
+
1356 };
+
1357
+
1358 std::vector<ConfigUnit> units = {
+
1359 {"seconds", 1, 15 * 60, false},
+
1360 {"minutes", 60, 14, false},
+
1361 {"minutes", 60, 15, true},
+
1362 {"hours", 3600, 10, true},
+
1363 {"days", 86400, 10, true},
+
1364 {"weeks", 604800, 2, true},
+
1365 {"months", 2592000, 1, false},
+
1366 {"years", 31536000, 1, false}};
+
1367
+
1368 std::string space = "";
+
1369 for (auto& [unit, sec, val, shouldPass] : units)
+
1370 {
+
1371 Config c;
+
1372 std::string toLoad(R"rippleConfig(
+
1373[amendment_majority_time]
+
1374)rippleConfig");
+
1375 toLoad += std::to_string(val) + space + unit;
+
1376 space = space == "" ? " " : "";
+
1377
+
1378 try
+
1379 {
+
1380 c.loadFromString(toLoad);
+
1381 if (shouldPass)
+
1382 BEAST_EXPECT(
+
1383 c.AMENDMENT_MAJORITY_TIME.count() == val * sec);
+
1384 else
+
1385 fail();
+
1386 }
+
1387 catch (std::runtime_error&)
+
1388 {
+
1389 if (!shouldPass)
+
1390 pass();
+
1391 else
+
1392 fail();
+
1393 }
+
1394 }
+
1395 }
+
1396
+
1397 void
+
1398 testOverlay()
+
1399 {
+
1400 testcase("overlay: unknown time");
+
1401
+
1402 auto testUnknown =
+
1403 [](std::string value) -> std::optional<std::chrono::seconds> {
+
1404 try
+
1405 {
+
1406 Config c;
+
1407 c.loadFromString("[overlay]\nmax_unknown_time=" + value);
+
1408 return c.MAX_UNKNOWN_TIME;
+
1409 }
+
1410 catch (std::runtime_error&)
+
1411 {
+
1412 return {};
+
1413 }
+
1414 };
+
1415
+
1416 // Failures
+
1417 BEAST_EXPECT(!testUnknown("none"));
+
1418 BEAST_EXPECT(!testUnknown("0.5"));
+
1419 BEAST_EXPECT(!testUnknown("180 seconds"));
+
1420 BEAST_EXPECT(!testUnknown("9 minutes"));
+
1421
+
1422 // Below lower bound
+
1423 BEAST_EXPECT(!testUnknown("299"));
+
1424
+
1425 // In bounds
+
1426 BEAST_EXPECT(testUnknown("300") == std::chrono::seconds{300});
+
1427 BEAST_EXPECT(testUnknown("301") == std::chrono::seconds{301});
+
1428 BEAST_EXPECT(testUnknown("1799") == std::chrono::seconds{1799});
+
1429 BEAST_EXPECT(testUnknown("1800") == std::chrono::seconds{1800});
+
1430
+
1431 // Above upper bound
+
1432 BEAST_EXPECT(!testUnknown("1801"));
+
1433
+
1434 testcase("overlay: diverged time");
+
1435
+
1436 // In bounds:
+
1437 auto testDiverged =
+
1438 [](std::string value) -> std::optional<std::chrono::seconds> {
+
1439 try
+
1440 {
+
1441 Config c;
+
1442 c.loadFromString("[overlay]\nmax_diverged_time=" + value);
+
1443 return c.MAX_DIVERGED_TIME;
+
1444 }
+
1445 catch (std::runtime_error&)
+
1446 {
+
1447 return {};
+
1448 }
+
1449 };
+
1450
+
1451 // Failures
+
1452 BEAST_EXPECT(!testDiverged("none"));
+
1453 BEAST_EXPECT(!testDiverged("0.5"));
+
1454 BEAST_EXPECT(!testDiverged("180 seconds"));
+
1455 BEAST_EXPECT(!testDiverged("9 minutes"));
+
1456
+
1457 // Below lower bound
+
1458 BEAST_EXPECT(!testDiverged("0"));
+
1459 BEAST_EXPECT(!testDiverged("59"));
+
1460
+
1461 // In bounds
+
1462 BEAST_EXPECT(testDiverged("60") == std::chrono::seconds{60});
+
1463 BEAST_EXPECT(testDiverged("61") == std::chrono::seconds{61});
+
1464 BEAST_EXPECT(testDiverged("899") == std::chrono::seconds{899});
+
1465 BEAST_EXPECT(testDiverged("900") == std::chrono::seconds{900});
+
1466
+
1467 // Above upper bound
+
1468 BEAST_EXPECT(!testDiverged("901"));
+
1469 }
+
1470
+
1471 void
+
1472 run() override
+
1473 {
+
1474 testLegacy();
+
1475 testDbPath();
+
1476 testValidatorKeys();
+
1477 testValidatorsFile();
+
1478 testSetup(false);
+
1479 testSetup(true);
+
1480 testPort();
+
1481 testWhitespace();
+
1482 testColons();
+
1483 testComments();
+
1484 testGetters();
+
1485 testAmendment();
+
1486 testOverlay();
+
1487 testNetworkID();
+
1488 }
+
1489};
+
1490
+
1491BEAST_DEFINE_TESTSUITE(Config, core, ripple);
+
1492
+
1493} // namespace ripple
std::array
+
std::bad_cast
std::ofstream
std::string
std::string_view
@@ -1387,53 +1577,54 @@ $(function() {
ripple::BasicConfig::exists
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
Definition: BasicConfig.cpp:121
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127
ripple::BasicConfig::legacy
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Definition: BasicConfig.cpp:164
-
ripple::Config_test
Definition: Config_test.cpp:270
-
ripple::Config_test::testNetworkID
void testNetworkID()
Definition: Config_test.cpp:415
-
ripple::Config_test::testSetup
void testSetup(bool explicitPath)
Definition: Config_test.cpp:745
-
ripple::Config_test::testDbPath
void testDbPath()
Definition: Config_test.cpp:303
-
ripple::Config_test::run
void run() override
Runs the suite.
Definition: Config_test.cpp:1245
-
ripple::Config_test::testValidatorKeys
void testValidatorKeys()
Definition: Config_test.cpp:371
-
ripple::Config_test::testAmendment
void testAmendment()
Definition: Config_test.cpp:1120
-
ripple::Config_test::testLegacy
void testLegacy()
Definition: Config_test.cpp:276
-
ripple::Config_test::testComments
void testComments()
Definition: Config_test.cpp:965
-
ripple::Config_test::path
boost::filesystem::path path
Definition: Config_test.cpp:272
-
ripple::Config_test::testValidatorsFile
void testValidatorsFile()
Definition: Config_test.cpp:480
-
ripple::Config_test::testColons
void testColons()
Definition: Config_test.cpp:913
-
ripple::Config_test::testWhitespace
void testWhitespace()
Definition: Config_test.cpp:883
-
ripple::Config_test::testGetters
void testGetters()
Definition: Config_test.cpp:1026
-
ripple::Config_test::testOverlay
void testOverlay()
Definition: Config_test.cpp:1171
-
ripple::Config_test::testPort
void testPort()
Definition: Config_test.cpp:864
+
ripple::Config_test
Definition: Config_test.cpp:274
+
ripple::Config_test::testNetworkID
void testNetworkID()
Definition: Config_test.cpp:419
+
ripple::Config_test::testSetup
void testSetup(bool explicitPath)
Definition: Config_test.cpp:934
+
ripple::Config_test::testDbPath
void testDbPath()
Definition: Config_test.cpp:307
+
ripple::Config_test::run
void run() override
Runs the suite.
Definition: Config_test.cpp:1434
+
ripple::Config_test::testValidatorKeys
void testValidatorKeys()
Definition: Config_test.cpp:375
+
ripple::Config_test::testAmendment
void testAmendment()
Definition: Config_test.cpp:1309
+
ripple::Config_test::testLegacy
void testLegacy()
Definition: Config_test.cpp:280
+
ripple::Config_test::testComments
void testComments()
Definition: Config_test.cpp:1154
+
ripple::Config_test::path
boost::filesystem::path path
Definition: Config_test.cpp:276
+
ripple::Config_test::testValidatorsFile
void testValidatorsFile()
Definition: Config_test.cpp:484
+
ripple::Config_test::testColons
void testColons()
Definition: Config_test.cpp:1102
+
ripple::Config_test::testWhitespace
void testWhitespace()
Definition: Config_test.cpp:1072
+
ripple::Config_test::testGetters
void testGetters()
Definition: Config_test.cpp:1215
+
ripple::Config_test::testOverlay
void testOverlay()
Definition: Config_test.cpp:1360
+
ripple::Config_test::testPort
void testPort()
Definition: Config_test.cpp:1053
ripple::Config
Definition: Config.h:93
-
ripple::Config::silent
bool silent() const
Definition: Config.h:337
+
ripple::Config::silent
bool silent() const
Definition: Config.h:339
ripple::Config::NETWORK_ID
uint32_t NETWORK_ID
Definition: Config.h:163
ripple::Config::databaseDirName
static char const *const databaseDirName
Definition: Config.h:97
ripple::Config::LEDGER_HISTORY
std::uint32_t LEDGER_HISTORY
Definition: Config.h:214
ripple::Config::IPS_FIXED
std::vector< std::string > IPS_FIXED
Definition: Config.h:151
ripple::Config::setup
void setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)
Definition: Config.cpp:309
ripple::Config::IPS
std::vector< std::string > IPS
Definition: Config.h:148
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
-
ripple::Config::quiet
bool quiet() const
Definition: Config.h:332
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
+
ripple::Config::VALIDATOR_LIST_THRESHOLD
std::optional< std::size_t > VALIDATOR_LIST_THRESHOLD
Definition: Config.h:308
+
ripple::Config::quiet
bool quiet() const
Definition: Config.h:334
ripple::Config::MAX_DIVERGED_TIME
std::chrono::seconds MAX_DIVERGED_TIME
Definition: Config.h:292
ripple::Config::loadFromString
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:446
ripple::Section::lines
std::vector< std::string > const & lines() const
Returns all the lines in the section.
Definition: BasicConfig.h:68
ripple::Section::values
std::vector< std::string > const & values() const
Returns all the values in the section.
Definition: BasicConfig.h:77
ripple::TestSuite
Definition: TestSuite.h:29
ripple::TestSuite::expectException
bool expectException(Functor f, std::string const &message="")
Definition: TestSuite.h:99
-
ripple::detail::RippledCfgGuard
Write a rippled config file and remove when done.
Definition: Config_test.cpp:128
-
ripple::detail::RippledCfgGuard::dataDirExists
bool dataDirExists() const
Definition: Config_test.cpp:175
-
ripple::detail::RippledCfgGuard::rmDataDir_
bool rmDataDir_
Definition: Config_test.cpp:132
-
ripple::detail::RippledCfgGuard::configFileExists
bool configFileExists() const
Definition: Config_test.cpp:181
-
ripple::detail::RippledCfgGuard::config
Config const & config() const
Definition: Config_test.cpp:163
-
ripple::detail::RippledCfgGuard::dataDir_
path dataDir_
Definition: Config_test.cpp:130
-
ripple::detail::RippledCfgGuard::RippledCfgGuard
RippledCfgGuard(beast::unit_test::suite &test, path subDir, path const &dbPath, path const &validatorsFile, bool useCounter=true)
Definition: Config_test.cpp:137
-
ripple::detail::RippledCfgGuard::~RippledCfgGuard
~RippledCfgGuard()
Definition: Config_test.cpp:186
-
ripple::detail::RippledCfgGuard::configFile
std::string configFile() const
Definition: Config_test.cpp:169
-
ripple::detail::RippledCfgGuard::config_
Config config_
Definition: Config_test.cpp:134
-
ripple::detail::ValidatorsTxtGuard
Write a validators.txt file and remove when done.
Definition: Config_test.cpp:233
-
ripple::detail::ValidatorsTxtGuard::~ValidatorsTxtGuard
~ValidatorsTxtGuard()
Definition: Config_test.cpp:263
-
ripple::detail::ValidatorsTxtGuard::validatorsFile
std::string validatorsFile() const
Definition: Config_test.cpp:258
-
ripple::detail::ValidatorsTxtGuard::validatorsFileExists
bool validatorsFileExists() const
Definition: Config_test.cpp:252
-
ripple::detail::ValidatorsTxtGuard::ValidatorsTxtGuard
ValidatorsTxtGuard(beast::unit_test::suite &test, path subDir, path const &validatorsFileName, bool useCounter=true)
Definition: Config_test.cpp:235
+
ripple::detail::RippledCfgGuard
Write a rippled config file and remove when done.
Definition: Config_test.cpp:129
+
ripple::detail::RippledCfgGuard::dataDirExists
bool dataDirExists() const
Definition: Config_test.cpp:176
+
ripple::detail::RippledCfgGuard::rmDataDir_
bool rmDataDir_
Definition: Config_test.cpp:133
+
ripple::detail::RippledCfgGuard::configFileExists
bool configFileExists() const
Definition: Config_test.cpp:182
+
ripple::detail::RippledCfgGuard::config
Config const & config() const
Definition: Config_test.cpp:164
+
ripple::detail::RippledCfgGuard::dataDir_
path dataDir_
Definition: Config_test.cpp:131
+
ripple::detail::RippledCfgGuard::RippledCfgGuard
RippledCfgGuard(beast::unit_test::suite &test, path subDir, path const &dbPath, path const &validatorsFile, bool useCounter=true)
Definition: Config_test.cpp:138
+
ripple::detail::RippledCfgGuard::~RippledCfgGuard
~RippledCfgGuard()
Definition: Config_test.cpp:187
+
ripple::detail::RippledCfgGuard::configFile
std::string configFile() const
Definition: Config_test.cpp:170
+
ripple::detail::RippledCfgGuard::config_
Config config_
Definition: Config_test.cpp:135
+
ripple::detail::ValidatorsTxtGuard
Write a validators.txt file and remove when done.
Definition: Config_test.cpp:237
+
ripple::detail::ValidatorsTxtGuard::~ValidatorsTxtGuard
~ValidatorsTxtGuard()
Definition: Config_test.cpp:267
+
ripple::detail::ValidatorsTxtGuard::validatorsFile
std::string validatorsFile() const
Definition: Config_test.cpp:262
+
ripple::detail::ValidatorsTxtGuard::validatorsFileExists
bool validatorsFileExists() const
Definition: Config_test.cpp:256
+
ripple::detail::ValidatorsTxtGuard::ValidatorsTxtGuard
ValidatorsTxtGuard(beast::unit_test::suite &test, path subDir, path const &validatorsFileName, bool useCounter=true)
Definition: Config_test.cpp:239
ripple::test::detail::DirGuard
Create a directory and remove it when it's done.
Definition: FileDirGuard.h:35
ripple::test::detail::DirGuard::subdir
path const & subdir() const
Definition: FileDirGuard.h:98
ripple::test::detail::DirGuard::rmDir
auto rmDir(path const &toRm)
Definition: FileDirGuard.h:47
@@ -1452,8 +1643,8 @@ $(function() {
std::uint32_t
iostream
beast::field
field_t< CharT, Traits, Allocator > field(std::basic_string< CharT, Traits, Allocator > const &text, int width=8, int pad=0, bool right=false)
Definition: iosformat.h:162
-
ripple::detail::configContents
std::string configContents(std::string const &dbPath, std::string const &validatorsFile)
Definition: Config_test.cpp:34
-
ripple::detail::valFileContents
std::string valFileContents()
Definition: Config_test.cpp:203
+
ripple::detail::configContents
std::string configContents(std::string const &dbPath, std::string const &validatorsFile)
Definition: Config_test.cpp:35
+
ripple::detail::valFileContents
std::string valFileContents()
Definition: Config_test.cpp:204
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::validationSeed
static std::optional< Seed > validationSeed(Json::Value const &params)
Definition: ValidationCreate.cpp:30
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:313
@@ -1463,6 +1654,7 @@ $(function() {
std::optional
std::runtime_error
std::vector::size
T size(T... args)
+
std::size_t
std::experimental::filesystem::space
T space(T... args)
ripple::ParsedPort
Definition: Port.h:97
ripple::ParsedPort::admin_nets_v4
std::vector< boost::asio::ip::network_v4 > admin_nets_v4
Definition: Port.h:116
diff --git a/Connect_8cpp_source.html b/Connect_8cpp_source.html index b4cee9c95d..08870ee2cc 100644 --- a/Connect_8cpp_source.html +++ b/Connect_8cpp_source.html @@ -156,7 +156,7 @@ $(function() {
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:49
ripple::Application::config
virtual Config & config()=0
ripple::Application::overlay
virtual Overlay & overlay()=0
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Overlay::connect
virtual void connect(beast::IP::Endpoint const &address)=0
Establish a peer connection to the specified endpoint.
Json::intValue
@ intValue
signed integer value
Definition: json_value.h:37
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:180
diff --git a/DatabaseCon_8cpp_source.html b/DatabaseCon_8cpp_source.html index a1366990cf..359ed09775 100644 --- a/DatabaseCon_8cpp_source.html +++ b/DatabaseCon_8cpp_source.html @@ -375,7 +375,7 @@ $(function() {
ripple::CheckpointersCollection::nextId_
std::uintptr_t nextId_
Definition: DatabaseCon.cpp:35
ripple::Config
Definition: Config.h:93
ripple::Config::LEDGER_HISTORY
std::uint32_t LEDGER_HISTORY
Definition: Config.h:214
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::START_UP
StartUpType START_UP
Definition: Config.h:154
ripple::DatabaseCon::setupCheckpointing
void setupCheckpointing(JobQueue *, Logs &)
Definition: DatabaseCon.cpp:279
ripple::DatabaseCon::~DatabaseCon
~DatabaseCon()
Definition: DatabaseCon.cpp:84
diff --git a/Env_8cpp_source.html b/Env_8cpp_source.html index 7efb414e1d..9e6e848b9d 100644 --- a/Env_8cpp_source.html +++ b/Env_8cpp_source.html @@ -796,7 +796,7 @@ $(function() {
ripple::telENV_RPC_FAILED
@ telENV_RPC_FAILED
Definition: TER.h:68
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::rpcINTERNAL
@ rpcINTERNAL
Definition: ErrorCodes.h:130
-
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2182
+
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2183
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::transToken
std::string transToken(TER code)
Definition: TER.cpp:251
ripple::asfDefaultRipple
constexpr std::uint32_t asfDefaultRipple
Definition: TxFlags.h:83
diff --git a/FeeVote__test_8cpp_source.html b/FeeVote__test_8cpp_source.html index 86a6ea1888..d914e8ddd2 100644 --- a/FeeVote__test_8cpp_source.html +++ b/FeeVote__test_8cpp_source.html @@ -191,7 +191,7 @@ $(function() {
ripple::test::FeeVote_test::run
void run() override
Runs the suite.
Definition: FeeVote_test.cpp:97
std::uint32_t
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1021
+
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1060
std::numeric_limits
ripple::FeeSetup
Fee schedule for startup / standalone, and to vote for.
Definition: Config.h:73
ripple::FeeSetup::reference_fee
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition: Config.h:75
diff --git a/GetCounts_8cpp_source.html b/GetCounts_8cpp_source.html index 218957903a..c1f0ac5575 100644 --- a/GetCounts_8cpp_source.html +++ b/GetCounts_8cpp_source.html @@ -239,7 +239,7 @@ $(function() {
ripple::Application::getNodeFamily
virtual Family & getNodeFamily()=0
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Application::getRelationalDatabase
virtual RelationalDatabase & getRelationalDatabase()=0
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
ripple::CountedObjects::getInstance
static CountedObjects & getInstance() noexcept
Definition: CountedObject.cpp:27
ripple::CountedObjects::getCounts
List getCounts(int minimumThreshold) const
Definition: CountedObject.cpp:39
ripple::Family::getFullBelowCache
virtual std::shared_ptr< FullBelowCache > getFullBelowCache()=0
Return a pointer to the Family Full Below Cache.
diff --git a/LedgerAccept_8cpp_source.html b/LedgerAccept_8cpp_source.html index 910af08e78..ee7b8cef6a 100644 --- a/LedgerAccept_8cpp_source.html +++ b/LedgerAccept_8cpp_source.html @@ -133,7 +133,7 @@ $(function() {
Json::Value
Represents a JSON value.
Definition: json_value.h:147
ripple::Application::config
virtual Config & config()=0
ripple::Application::getMasterMutex
virtual MutexType & getMasterMutex()=0
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::LedgerMaster::getCurrentLedgerIndex
LedgerIndex getCurrentLedgerIndex()
Definition: LedgerMaster.cpp:127
ripple::NetworkOPs::acceptLedger
virtual std::uint32_t acceptLedger(std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)=0
Accepts the current transaction tree, return the new ledger's sequence.
mutex
diff --git a/LedgerMaster_8cpp_source.html b/LedgerMaster_8cpp_source.html index c6ea53c667..4c077263fa 100644 --- a/LedgerMaster_8cpp_source.html +++ b/LedgerMaster_8cpp_source.html @@ -2538,9 +2538,9 @@ $(function() {
ripple::Validations::getTrustedForLedger
std::vector< WrappedValidationType > getTrustedForLedger(ID const &ledgerID, Seq const &seq)
Get trusted full validations for a specific ledger.
Definition: Validations.h:1058
ripple::Validations::currentTrusted
std::vector< WrappedValidationType > currentTrusted()
Get the currently trusted full validations.
Definition: Validations.h:999
ripple::Validations::fees
std::vector< std::uint32_t > fees(ID const &ledgerID, std::uint32_t baseFee)
Returns fees reported by trusted full validators in the given ledger.
Definition: Validations.h:1081
-
ripple::ValidatorList::negativeUNLFilter
std::vector< std::shared_ptr< STValidation > > negativeUNLFilter(std::vector< std::shared_ptr< STValidation > > &&validations) const
Remove validations that are from validators on the negative UNL.
Definition: ValidatorList.cpp:2054
-
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:502
-
ripple::ValidatorList::getQuorumKeys
QuorumKeys getQuorumKeys() const
Get the quorum and all of the trusted keys.
Definition: ValidatorList.h:669
+
ripple::ValidatorList::negativeUNLFilter
std::vector< std::shared_ptr< STValidation > > negativeUNLFilter(std::vector< std::shared_ptr< STValidation > > &&validations) const
Remove validations that are from validators on the negative UNL.
Definition: ValidatorList.cpp:2133
+
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:506
+
ripple::ValidatorList::getQuorumKeys
QuorumKeys getQuorumKeys() const
Get the quorum and all of the trusted keys.
Definition: ValidatorList.h:673
ripple::base_uint< 256 >
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:544
ripple::scope_unlock
Automatically unlocks and re-locks a unique_lock object.
Definition: scope.h:231
diff --git a/Main_8cpp_source.html b/Main_8cpp_source.html index 3355b808b9..7c0d1248de 100644 --- a/Main_8cpp_source.html +++ b/Main_8cpp_source.html @@ -997,7 +997,7 @@ $(function() {
ripple::systemName
static std::string const & systemName()
Definition: SystemParameters.h:34
ripple::setup_DatabaseCon
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
Definition: DatabaseCon.cpp:106
ripple::printHelp
void printHelp(const po::options_description &desc)
Definition: Main.cpp:126
-
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2182
+
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2183
ripple::run
int run(int argc, char **argv)
Definition: Main.cpp:350
ripple::TxSearched::all
@ all
ripple::PublisherStatus::available
@ available
diff --git a/NetworkOPs_8cpp_source.html b/NetworkOPs_8cpp_source.html index d68375dabc..55f1fa85a2 100644 --- a/NetworkOPs_8cpp_source.html +++ b/NetworkOPs_8cpp_source.html @@ -4902,10 +4902,10 @@ $(function() {
ripple::TxQ::getMetrics
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition: TxQ.cpp:1777
ripple::UptimeClock::now
static time_point now()
Definition: UptimeClock.cpp:63
ripple::ValidatorKeys
Validator keys and manifest as set in configuration file.
Definition: ValidatorKeys.h:37
-
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:1520
-
ripple::ValidatorList::localPublicKey
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
Definition: ValidatorList.cpp:1472
-
ripple::ValidatorList::expires
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1576
-
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:502
+
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:1552
+
ripple::ValidatorList::localPublicKey
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
Definition: ValidatorList.cpp:1504
+
ripple::ValidatorList::expires
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1608
+
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:506
ripple::XRPAmount
Definition: XRPAmount.h:43
ripple::XRPAmount::decimalXRP
constexpr double decimalXRP() const
Definition: XRPAmount.h:262
ripple::XRPAmount::jsonClipped
Json::Value jsonClipped() const
Definition: XRPAmount.h:218
@@ -5015,7 +5015,7 @@ $(function() {
ripple::makeRulesGivenLedger
Rules makeRulesGivenLedger(DigestAwareReadView const &ledger, Rules const &current)
Definition: ReadView.cpp:69
ripple::to_string_iso
std::string to_string_iso(date::sys_time< Duration > tp)
Definition: chrono.h:93
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1021
+
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1060
ripple::root
Number root(Number f, unsigned d)
Definition: Number.cpp:630
ripple::mulDiv
std::optional< std::uint64_t > mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
Return value*mul/div accurately.
Definition: mulDiv.cpp:27
ripple::ApplyFlags
ApplyFlags
Definition: ApplyView.h:30
diff --git a/Node_8cpp_source.html b/Node_8cpp_source.html index f752c019e2..59a5117910 100644 --- a/Node_8cpp_source.html +++ b/Node_8cpp_source.html @@ -1364,8 +1364,8 @@ $(function() {
ripple::Config::LOAD
@ LOAD
Definition: Config.h:153
ripple::Config::REPLAY
@ REPLAY
Definition: Config.h:153
ripple::Config::LOAD_FILE
@ LOAD_FILE
Definition: Config.h:153
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
-
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1008
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
+
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1047
ripple::DatabaseCon
Definition: DatabaseCon.h:84
ripple::DatabaseCon::checkoutDb
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:188
ripple::LedgerMaster
Definition: LedgerMaster.h:53
diff --git a/OrderBookDB_8cpp_source.html b/OrderBookDB_8cpp_source.html index 6e53d485fb..2f542ea273 100644 --- a/OrderBookDB_8cpp_source.html +++ b/OrderBookDB_8cpp_source.html @@ -394,7 +394,7 @@ $(function() {
ripple::Book
Specifies an order book.
Definition: Book.h:34
ripple::Book::in
Issue in
Definition: Book.h:36
ripple::Book::out
Issue out
Definition: Book.h:37
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::PATH_SEARCH_MAX
int PATH_SEARCH_MAX
Definition: Config.h:205
ripple::Issue
A currency issued by an account.
Definition: Issue.h:36
ripple::Issue::account
AccountID account
Definition: Issue.h:39
diff --git a/OverlayImpl_8cpp_source.html b/OverlayImpl_8cpp_source.html index 09cc4a5557..3f3528d449 100644 --- a/OverlayImpl_8cpp_source.html +++ b/OverlayImpl_8cpp_source.html @@ -1674,7 +1674,7 @@ $(function() {
ripple::Cluster::member
std::optional< std::string > member(PublicKey const &node) const
Determines whether a node belongs in the cluster.
Definition: Cluster.cpp:37
ripple::Config::IPS_FIXED
std::vector< std::string > IPS_FIXED
Definition: Config.h:151
ripple::Config::IPS
std::vector< std::string > IPS
Definition: Config.h:148
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::TX_REDUCE_RELAY_MIN_PEERS
std::size_t TX_REDUCE_RELAY_MIN_PEERS
Definition: Config.h:276
ripple::Config::TX_REDUCE_RELAY_ENABLE
bool TX_REDUCE_RELAY_ENABLE
Definition: Config.h:266
ripple::Config::TX_REDUCE_RELAY_METRICS
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:273
@@ -1782,9 +1782,9 @@ $(function() {
ripple::TrafficCount::getCounts
auto const & getCounts() const
An up-to-date copy of all the counters.
Definition: TrafficCount.h:198
ripple::TrafficCount::category
category
Definition: TrafficCount.h:68
ripple::TrafficCount::addCount
void addCount(category cat, bool inbound, int bytes)
Account for traffic associated with the given category.
Definition: TrafficCount.h:173
-
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:1409
-
ripple::ValidatorList::getAvailable
std::optional< Json::Value > getAvailable(std::string_view pubKey, std::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
Definition: ValidatorList.cpp:1753
-
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1583
+
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:1441
+
ripple::ValidatorList::getAvailable
std::optional< Json::Value > getAvailable(std::string_view pubKey, std::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
Definition: ValidatorList.cpp:1787
+
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1615
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:672
ripple::base_uint< 256 >
std::set::count
T count(T... args)
diff --git a/PeerImp_8cpp_source.html b/PeerImp_8cpp_source.html index 6c63d63433..2e414268b2 100644 --- a/PeerImp_8cpp_source.html +++ b/PeerImp_8cpp_source.html @@ -3665,8 +3665,8 @@ $(function() {
ripple::TrafficCount::gl_tsc_share
@ gl_tsc_share
Definition: TrafficCount.h:100
ripple::TrafficCount::get_transactions
@ get_transactions
Definition: TrafficCount.h:140
ripple::TrafficCount::ld_tsc_get
@ ld_tsc_get
Definition: TrafficCount.h:84
-
ripple::ValidatorList::sendValidatorList
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:785
-
ripple::ValidatorList::for_each_available
void for_each_available(std::function< void(std::string const &manifest, std::uint32_t version, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, PublicKey const &pubKey, std::size_t maxSequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
Definition: ValidatorList.cpp:1724
+
ripple::ValidatorList::sendValidatorList
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:817
+
ripple::ValidatorList::for_each_available
void for_each_available(std::function< void(std::string const &manifest, std::uint32_t version, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, PublicKey const &pubKey, std::size_t maxSequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
Definition: ValidatorList.cpp:1758
ripple::base_uint< 256 >
ripple::base_uint::zero
void zero()
Definition: base_uint.h:549
ripple::base_uint::data
pointer data()
Definition: base_uint.h:124
diff --git a/PeerfinderConfig_8cpp_source.html b/PeerfinderConfig_8cpp_source.html index bf894ef572..9f3c27b2aa 100644 --- a/PeerfinderConfig_8cpp_source.html +++ b/PeerfinderConfig_8cpp_source.html @@ -220,7 +220,7 @@ $(function() {
ripple::Config
Definition: Config.h:93
ripple::Config::PEERS_IN_MAX
std::size_t PEERS_IN_MAX
Definition: Config.h:188
ripple::Config::PEER_PRIVATE
bool PEER_PRIVATE
Definition: Config.h:180
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::PEERS_OUT_MAX
std::size_t PEERS_OUT_MAX
Definition: Config.h:187
ripple::Config::PEERS_MAX
std::size_t PEERS_MAX
Definition: Config.h:186
std::uint16_t
diff --git a/RCLValidations_8cpp_source.html b/RCLValidations_8cpp_source.html index d8d0a9cf0c..01676961c0 100644 --- a/RCLValidations_8cpp_source.html +++ b/RCLValidations_8cpp_source.html @@ -362,8 +362,8 @@ $(function() {
ripple::RCLValidationsAdaptor::j_
beast::Journal j_
Definition: RCLValidations.h:236
ripple::TimeKeeper::closeTime
time_point closeTime() const
Returns the predicted close time, in network time.
Definition: TimeKeeper.h:76
ripple::Validations::add
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
Definition: Validations.h:623
-
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1456
-
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1434
+
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1488
+
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1466
ripple::base_uint< 256 >
std::uint32_t
std::max
T max(T... args)
diff --git a/RPCCall_8cpp_source.html b/RPCCall_8cpp_source.html index 655566ea6d..371584c8b4 100644 --- a/RPCCall_8cpp_source.html +++ b/RPCCall_8cpp_source.html @@ -1770,7 +1770,7 @@ $(function() {
beast::basic_logstream
Definition: Journal.h:431
ripple::Config
Definition: Config.h:93
ripple::Config::rpc_ip
std::optional< beast::IP::Endpoint > rpc_ip
Definition: Config.h:282
-
ripple::Config::quiet
bool quiet() const
Definition: Config.h:332
+
ripple::Config::quiet
bool quiet() const
Definition: Config.h:334
ripple::HTTPClient::request
static void request(bool bSSL, boost::asio::io_service &io_service, std::string strSite, const unsigned short port, std::function< void(boost::asio::streambuf &sb, std::string const &strHost)> build, std::size_t responseMax, std::chrono::seconds timeout, std::function< bool(const boost::system::error_code &ecResult, int iStatus, std::string const &strData)> complete, beast::Journal &j)
Definition: HTTPClient.cpp:585
ripple::Logs
Manages partitions for logging.
Definition: Log.h:49
ripple::Logs::journal
beast::Journal journal(std::string const &name)
Definition: Log.cpp:144
diff --git a/RPCHelpers_8cpp_source.html b/RPCHelpers_8cpp_source.html index f97fe61b68..834bb2fa10 100644 --- a/RPCHelpers_8cpp_source.html +++ b/RPCHelpers_8cpp_source.html @@ -1232,7 +1232,7 @@ $(function() {
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::InboundLedger::Reason::GENERIC
@ GENERIC
ripple::InboundLedgers::acquire
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason)=0
ripple::InboundLedgers::find
virtual std::shared_ptr< InboundLedger > find(LedgerHash const &hash)=0
diff --git a/RipplePathFind_8cpp_source.html b/RipplePathFind_8cpp_source.html index 2553b83caa..1bf96dd77a 100644 --- a/RipplePathFind_8cpp_source.html +++ b/RipplePathFind_8cpp_source.html @@ -258,7 +258,7 @@ $(function() {
ripple::Application::config
virtual Config & config()=0
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Application::getPathRequests
virtual PathRequests & getPathRequests()=0
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::PATH_SEARCH_MAX
int PATH_SEARCH_MAX
Definition: Config.h:205
ripple::LedgerMaster::getClosedLedger
std::shared_ptr< Ledger const > getClosedLedger()
Definition: LedgerMaster.h:80
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:194
diff --git a/SHAMapStoreImp_8cpp_source.html b/SHAMapStoreImp_8cpp_source.html index 64c571d528..be2c2082f2 100644 --- a/SHAMapStoreImp_8cpp_source.html +++ b/SHAMapStoreImp_8cpp_source.html @@ -786,8 +786,8 @@ $(function() {
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127
ripple::BasicConfig::legacy
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Definition: BasicConfig.cpp:164
ripple::Config
Definition: Config.h:93
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
-
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1008
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
+
ripple::Config::getValueFor
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1047
ripple::Family::getFullBelowCache
virtual std::shared_ptr< FullBelowCache > getFullBelowCache()=0
Return a pointer to the Family Full Below Cache.
ripple::Family::getTreeNodeCache
virtual std::shared_ptr< TreeNodeCache > getTreeNodeCache()=0
Return a pointer to the Family Tree Node Cache.
ripple::LedgerMaster::clearLedgerCachePrior
void clearLedgerCachePrior(LedgerIndex seq)
Definition: LedgerMaster.cpp:1796
diff --git a/ServerHandler_8cpp_source.html b/ServerHandler_8cpp_source.html index 6a59cd360d..addd38b737 100644 --- a/ServerHandler_8cpp_source.html +++ b/ServerHandler_8cpp_source.html @@ -1385,7 +1385,7 @@ $(function() {
ripple::CollectorManager
Provides the beast::insight::Collector service.
Definition: CollectorManager.h:30
ripple::CollectorManager::group
virtual beast::insight::Group::ptr const & group(std::string const &name)=0
ripple::Config
Definition: Config.h:93
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::BETA_RPC_API
bool BETA_RPC_API
Definition: Config.h:295
ripple::JobQueue
A pool of threads to perform work.
Definition: JobQueue.h:56
ripple::JobQueue::postCoro
std::shared_ptr< Coro > postCoro(JobType t, std::string const &name, F &&f)
Creates a coroutine and adds a job to the queue which will run it.
Definition: JobQueue.h:411
diff --git a/SignFor_8cpp_source.html b/SignFor_8cpp_source.html index f92eb7665d..0b540e9af5 100644 --- a/SignFor_8cpp_source.html +++ b/SignFor_8cpp_source.html @@ -141,7 +141,7 @@ $(function() {
Json::Value
Represents a JSON value.
Definition: json_value.h:147
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::Application::config
virtual Config & config()=0
-
ripple::Config::canSign
bool canSign() const
Definition: Config.h:354
+
ripple::Config::canSign
bool canSign() const
Definition: Config.h:356
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:194
ripple::NetworkOPs::doFailHard
static FailHard doFailHard(bool noMeansDont)
Definition: NetworkOPs.h:93
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:180
diff --git a/SignHandler_8cpp_source.html b/SignHandler_8cpp_source.html index e66a2fdf4e..5c547f7783 100644 --- a/SignHandler_8cpp_source.html +++ b/SignHandler_8cpp_source.html @@ -142,7 +142,7 @@ $(function() {
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:943
ripple::Application::config
virtual Config & config()=0
-
ripple::Config::canSign
bool canSign() const
Definition: Config.h:354
+
ripple::Config::canSign
bool canSign() const
Definition: Config.h:356
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:194
ripple::NetworkOPs::doFailHard
static FailHard doFailHard(bool noMeansDont)
Definition: NetworkOPs.h:93
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:91
diff --git a/Submit_8cpp_source.html b/Submit_8cpp_source.html index 484df01d1a..23a7c54b85 100644 --- a/Submit_8cpp_source.html +++ b/Submit_8cpp_source.html @@ -281,7 +281,7 @@ $(function() {
ripple::Application::config
virtual Config & config()=0
ripple::Application::checkSigs
virtual bool checkSigs() const =0
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
-
ripple::Config::canSign
bool canSign() const
Definition: Config.h:354
+
ripple::Config::canSign
bool canSign() const
Definition: Config.h:356
ripple::LedgerMaster::getCurrentLedger
std::shared_ptr< ReadView const > getCurrentLedger()
Definition: LedgerMaster.cpp:1570
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:194
ripple::NetworkOPs::doFailHard
static FailHard doFailHard(bool noMeansDont)
Definition: NetworkOPs.h:93
diff --git a/Subscribe_8cpp_source.html b/Subscribe_8cpp_source.html index 592674a800..7f7d3aa76c 100644 --- a/Subscribe_8cpp_source.html +++ b/Subscribe_8cpp_source.html @@ -471,7 +471,7 @@ $(function() {
ripple::Book
Specifies an order book.
Definition: Book.h:34
ripple::Book::in
Issue in
Definition: Book.h:36
ripple::Book::out
Issue out
Definition: Book.h:37
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
ripple::InfoSub::Source::subAccountHistory
virtual error_code_i subAccountHistory(ref ispListener, AccountID const &account)=0
subscribe an account's new transactions and retrieve the account's historical transactions
ripple::InfoSub::Source::subValidations
virtual bool subValidations(ref ispListener)=0
ripple::InfoSub::Source::subBook
virtual bool subBook(ref ispListener, Book const &)=0
diff --git a/TransactionSign_8cpp_source.html b/TransactionSign_8cpp_source.html index 544ef41a8e..0772cced3a 100644 --- a/TransactionSign_8cpp_source.html +++ b/TransactionSign_8cpp_source.html @@ -1372,7 +1372,7 @@ $(function() {
ripple::Buffer::size
std::size_t size() const noexcept
Returns the number of bytes in the buffer.
Definition: Buffer.h:127
ripple::Config
Definition: Config.h:93
ripple::Config::PATH_SEARCH_OLD
int PATH_SEARCH_OLD
Definition: Config.h:202
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::Config::BETA_RPC_API
bool BETA_RPC_API
Definition: Config.h:295
ripple::Config::FEES
FeeSetup FEES
Definition: Config.h:211
ripple::Issue::account
AccountID account
Definition: Issue.h:39
diff --git a/TxHistory_8cpp_source.html b/TxHistory_8cpp_source.html index f74194e3a1..c806549fd5 100644 --- a/TxHistory_8cpp_source.html +++ b/TxHistory_8cpp_source.html @@ -156,7 +156,7 @@ $(function() {
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:943
ripple::Application::config
virtual Config & config()=0
ripple::Application::getRelationalDatabase
virtual RelationalDatabase & getRelationalDatabase()=0
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
ripple::RelationalDatabase::getTxHistory
virtual std::vector< std::shared_ptr< Transaction > > getTxHistory(LedgerIndex startIndex)=0
getTxHistory Returns the 20 most recent transactions starting from the given number.
ripple::RPC::insertDeliverMax
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Definition: DeliverMax.cpp:28
ripple::Resource::feeMediumBurdenRPC
Charge const feeMediumBurdenRPC
diff --git a/TxQ_8cpp_source.html b/TxQ_8cpp_source.html index f311ca1f11..e41c723ef9 100644 --- a/TxQ_8cpp_source.html +++ b/TxQ_8cpp_source.html @@ -2069,7 +2069,7 @@ $(function() {
ripple::ApplyViewImpl
Editable, discardable view that can build metadata for one tx.
Definition: ApplyViewImpl.h:37
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127
ripple::Config
Definition: Config.h:93
-
ripple::Config::standalone
bool standalone() const
Definition: Config.h:342
+
ripple::Config::standalone
bool standalone() const
Definition: Config.h:344
ripple::NumberSO
RAII class to set and restore the Number switchover.
Definition: IOUAmount.h:204
ripple::OpenLedger::current
std::shared_ptr< OpenView const > current() const
Returns a view to the current open ledger.
Definition: OpenLedger.cpp:50
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:56
diff --git a/Tx_8cpp_source.html b/Tx_8cpp_source.html index fa38e98233..279a400804 100644 --- a/Tx_8cpp_source.html +++ b/Tx_8cpp_source.html @@ -433,7 +433,7 @@ $(function() {
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Application::getMasterTransaction
virtual TransactionMaster & getMasterTransaction()=0
ripple::Config::NETWORK_ID
uint32_t NETWORK_ID
Definition: Config.h:163
-
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:348
+
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:350
ripple::LedgerMaster
Definition: LedgerMaster.h:53
ripple::LedgerMaster::getCloseTimeBySeq
std::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
Definition: LedgerMaster.cpp:1611
ripple::LedgerMaster::txnIdFromIndex
std::optional< uint256 > txnIdFromIndex(uint32_t ledgerSeq, uint32_t txnIndex)
Definition: LedgerMaster.cpp:2253
diff --git a/UnlList_8cpp_source.html b/UnlList_8cpp_source.html index a0aa64ff8a..e64e61786b 100644 --- a/UnlList_8cpp_source.html +++ b/UnlList_8cpp_source.html @@ -128,7 +128,7 @@ $(function() {
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:891
ripple::Application::validators
virtual ValidatorList & validators()=0
ripple::PublicKey
A public key.
Definition: PublicKey.h:62
-
ripple::ValidatorList::for_each_listed
void for_each_listed(std::function< void(PublicKey const &, bool)> func) const
Invokes the callback once for every listed validation public key.
Definition: ValidatorList.cpp:1714
+
ripple::ValidatorList::for_each_listed
void for_each_listed(std::function< void(PublicKey const &, bool)> func) const
Invokes the callback once for every listed validation public key.
Definition: ValidatorList.cpp:1748
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
diff --git a/ValidatorList_8cpp_source.html b/ValidatorList_8cpp_source.html index 5888aa5ab4..03b80d027c 100644 --- a/ValidatorList_8cpp_source.html +++ b/ValidatorList_8cpp_source.html @@ -207,1959 +207,2038 @@ $(function() {
129 , j_(j)
130 , quorum_(minimumQuorum.value_or(1)) // Genesis ledger quorum
131 , minimumQuorum_(minimumQuorum)
-
132{
-
133}
-
134
-
135bool
-
136ValidatorList::load(
-
137 std::optional<PublicKey> const& localSigningKey,
-
138 std::vector<std::string> const& configKeys,
-
139 std::vector<std::string> const& publisherKeys)
-
140{
-
141 static boost::regex const re(
-
142 "[[:space:]]*" // skip leading whitespace
-
143 "([[:alnum:]]+)" // node identity
-
144 "(?:" // begin optional comment block
-
145 "[[:space:]]+" // (skip all leading whitespace)
-
146 "(?:" // begin optional comment
-
147 "(.*[^[:space:]]+)" // the comment
-
148 "[[:space:]]*" // (skip all trailing whitespace)
-
149 ")?" // end optional comment
-
150 ")?" // end optional comment block
-
151 );
-
152
-
153 std::lock_guard lock{mutex_};
+
132 , listThreshold_(1)
+
133{
+
134}
+
135
+
136bool
+
137ValidatorList::load(
+
138 std::optional<PublicKey> const& localSigningKey,
+
139 std::vector<std::string> const& configKeys,
+
140 std::vector<std::string> const& publisherKeys,
+
141 std::optional<std::size_t> listThreshold)
+
142{
+
143 static boost::regex const re(
+
144 "[[:space:]]*" // skip leading whitespace
+
145 "([[:alnum:]]+)" // node identity
+
146 "(?:" // begin optional comment block
+
147 "[[:space:]]+" // (skip all leading whitespace)
+
148 "(?:" // begin optional comment
+
149 "(.*[^[:space:]]+)" // the comment
+
150 "[[:space:]]*" // (skip all trailing whitespace)
+
151 ")?" // end optional comment
+
152 ")?" // end optional comment block
+
153 );
154
-
155 JLOG(j_.debug())
-
156 << "Loading configured trusted validator list publisher keys";
-
157
-
158 std::size_t count = 0;
-
159 for (auto key : publisherKeys)
-
160 {
-
161 JLOG(j_.trace()) << "Processing '" << key << "'";
-
162
-
163 auto const ret = strUnHex(key);
+
155 std::lock_guard lock{mutex_};
+
156
+
157 JLOG(j_.debug())
+
158 << "Loading configured trusted validator list publisher keys";
+
159
+
160 std::size_t count = 0;
+
161 for (auto key : publisherKeys)
+
162 {
+
163 JLOG(j_.trace()) << "Processing '" << key << "'";
164
-
165 if (!ret || !publicKeyType(makeSlice(*ret)))
-
166 {
-
167 JLOG(j_.error()) << "Invalid validator list publisher key: " << key;
-
168 return false;
-
169 }
-
170
-
171 auto id = PublicKey(makeSlice(*ret));
-
172 auto status = PublisherStatus::unavailable;
-
173
-
174 if (publisherManifests_.revoked(id))
-
175 {
-
176 JLOG(j_.warn())
-
177 << "Configured validator list publisher key is revoked: "
-
178 << key;
-
179 status = PublisherStatus::revoked;
-
180 }
-
181
-
182 if (publisherLists_.count(id))
-
183 {
-
184 JLOG(j_.warn())
-
185 << "Duplicate validator list publisher key: " << key;
-
186 continue;
-
187 }
-
188
-
189 publisherLists_[id].status = status;
-
190 ++count;
-
191 }
-
192
-
193 JLOG(j_.debug()) << "Loaded " << count << " keys";
+
165 auto const ret = strUnHex(key);
+
166
+
167 if (!ret || !publicKeyType(makeSlice(*ret)))
+
168 {
+
169 JLOG(j_.error()) << "Invalid validator list publisher key: " << key;
+
170 return false;
+
171 }
+
172
+
173 auto id = PublicKey(makeSlice(*ret));
+
174 auto status = PublisherStatus::unavailable;
+
175
+
176 if (publisherManifests_.revoked(id))
+
177 {
+
178 JLOG(j_.warn())
+
179 << "Configured validator list publisher key is revoked: "
+
180 << key;
+
181 status = PublisherStatus::revoked;
+
182 }
+
183
+
184 if (publisherLists_.count(id))
+
185 {
+
186 JLOG(j_.warn())
+
187 << "Duplicate validator list publisher key: " << key;
+
188 continue;
+
189 }
+
190
+
191 publisherLists_[id].status = status;
+
192 ++count;
+
193 }
194
-
195 if (localSigningKey)
-
196 localPubKey_ = validatorManifests_.getMasterKey(*localSigningKey);
-
197
-
198 // Treat local validator key as though it was listed in the config
-
199 if (localPubKey_)
-
200 keyListings_.insert({*localPubKey_, 1});
-
201
-
202 JLOG(j_.debug()) << "Loading configured validator keys";
-
203
-
204 count = 0;
-
205 for (auto const& n : configKeys)
+
195 if (listThreshold)
+
196 {
+
197 listThreshold_ = *listThreshold;
+
198 // This should be enforced by Config class
+
199 XRPL_ASSERT(
+
200 listThreshold_ > 0 && listThreshold_ <= publisherLists_.size(),
+
201 "ripple::ValidatorList::load : list threshold inside range");
+
202 JLOG(j_.debug()) << "Validator list threshold set in configuration to "
+
203 << listThreshold_;
+
204 }
+
205 else
206 {
-
207 JLOG(j_.trace()) << "Processing '" << n << "'";
-
208
-
209 boost::smatch match;
-
210
-
211 if (!boost::regex_match(n, match, re))
-
212 {
-
213 JLOG(j_.error()) << "Malformed entry: '" << n << "'";
-
214 return false;
-
215 }
+
207 // Want truncated result when dividing an odd integer
+
208 listThreshold_ = (publisherLists_.size() < 3)
+
209 ? 1 //
+
210 : publisherLists_.size() / 2 + 1;
+
211 JLOG(j_.debug()) << "Validator list threshold computed as "
+
212 << listThreshold_;
+
213 }
+
214
+
215 JLOG(j_.debug()) << "Loaded " << count << " keys";
216
-
217 auto const id =
-
218 parseBase58<PublicKey>(TokenType::NodePublic, match[1].str());
+
217 if (localSigningKey)
+
218 localPubKey_ = validatorManifests_.getMasterKey(*localSigningKey);
219
-
220 if (!id)
-
221 {
-
222 JLOG(j_.error()) << "Invalid node identity: " << match[1];
-
223 return false;
-
224 }
-
225
-
226 // Skip local key which was already added
-
227 if (*id == localPubKey_ || *id == localSigningKey)
-
228 continue;
-
229
-
230 auto ret = keyListings_.insert({*id, 1});
-
231 if (!ret.second)
-
232 {
-
233 JLOG(j_.warn()) << "Duplicate node identity: " << match[1];
-
234 continue;
-
235 }
-
236 localPublisherList.list.emplace_back(*id);
-
237 ++count;
-
238 }
-
239
-
240 // Config listed keys never expire
-
241 // set the expiration time for the newly created publisher list
-
242 // exactly once
-
243 if (count > 0)
-
244 localPublisherList.validUntil = TimeKeeper::time_point::max();
-
245
-
246 JLOG(j_.debug()) << "Loaded " << count << " entries";
-
247
-
248 return true;
-
249}
-
250
-
251boost::filesystem::path
-
252ValidatorList::getCacheFileName(
-
253 ValidatorList::lock_guard const&,
-
254 PublicKey const& pubKey) const
-
255{
-
256 return dataPath_ / (filePrefix_ + strHex(pubKey));
-
257}
-
258
-
259// static
-
260Json::Value
-
261ValidatorList::buildFileData(
-
262 std::string const& pubKey,
-
263 ValidatorList::PublisherListCollection const& pubCollection,
-
264 beast::Journal j)
-
265{
-
266 return buildFileData(pubKey, pubCollection, {}, j);
-
267}
-
268
-
269// static
-
270Json::Value
-
271ValidatorList::buildFileData(
-
272 std::string const& pubKey,
-
273 ValidatorList::PublisherListCollection const& pubCollection,
-
274 std::optional<std::uint32_t> forceVersion,
-
275 beast::Journal j)
-
276{
-
277 Json::Value value(Json::objectValue);
-
278
-
279 XRPL_ASSERT(
-
280 pubCollection.rawVersion == 2 || pubCollection.remaining.empty(),
-
281 "ripple::ValidatorList::buildFileData : valid publisher list input");
-
282 auto const effectiveVersion =
-
283 forceVersion ? *forceVersion : pubCollection.rawVersion;
-
284
-
285 value[jss::manifest] = pubCollection.rawManifest;
-
286 value[jss::version] = effectiveVersion;
-
287 value[jss::public_key] = pubKey;
-
288
-
289 switch (effectiveVersion)
-
290 {
-
291 case 1: {
-
292 auto const& current = pubCollection.current;
-
293 value[jss::blob] = current.rawBlob;
-
294 value[jss::signature] = current.rawSignature;
-
295 // This is only possible if "downgrading" a v2 UNL to v1, for
-
296 // example for the /vl/ endpoint.
-
297 if (current.rawManifest &&
-
298 *current.rawManifest != pubCollection.rawManifest)
-
299 value[jss::manifest] = *current.rawManifest;
-
300 break;
-
301 }
-
302 case 2: {
-
303 Json::Value blobs(Json::arrayValue);
-
304
-
305 auto add = [&blobs, &outerManifest = pubCollection.rawManifest](
-
306 PublisherList const& pubList) {
-
307 auto& blob = blobs.append(Json::objectValue);
-
308 blob[jss::blob] = pubList.rawBlob;
-
309 blob[jss::signature] = pubList.rawSignature;
-
310 if (pubList.rawManifest &&
-
311 *pubList.rawManifest != outerManifest)
-
312 blob[jss::manifest] = *pubList.rawManifest;
-
313 };
-
314
-
315 add(pubCollection.current);
-
316 for (auto const& [_, pending] : pubCollection.remaining)
-
317 {
-
318 (void)_;
-
319 add(pending);
-
320 }
-
321
-
322 value[jss::blobs_v2] = std::move(blobs);
-
323 break;
-
324 }
-
325 default:
-
326 JLOG(j.trace())
-
327 << "Invalid VL version provided: " << effectiveVersion;
-
328 value = Json::nullValue;
-
329 }
-
330
-
331 return value;
-
332}
-
333
-
334void
-
335ValidatorList::cacheValidatorFile(
-
336 ValidatorList::lock_guard const& lock,
-
337 PublicKey const& pubKey) const
-
338{
-
339 if (dataPath_.empty())
-
340 return;
-
341
-
342 boost::filesystem::path const filename = getCacheFileName(lock, pubKey);
-
343
-
344 boost::system::error_code ec;
-
345
-
346 Json::Value value =
-
347 buildFileData(strHex(pubKey), publisherLists_.at(pubKey), j_);
-
348 // rippled should be the only process writing to this file, so
-
349 // if it ever needs to be read, it is not expected to change externally, so
-
350 // delay the refresh as long as possible: 24 hours. (See also
-
351 // `ValidatorSite::missingSite()`)
-
352 value[jss::refresh_interval] = 24 * 60;
+
220 // Treat local validator key as though it was listed in the config
+
221 if (localPubKey_)
+
222 {
+
223 // The local validator must meet listThreshold_ so the validator does
+
224 // not ignore itself.
+
225 auto const [_, inserted] =
+
226 keyListings_.insert({*localPubKey_, listThreshold_});
+
227 if (inserted)
+
228 {
+
229 JLOG(j_.debug()) << "Added own master key "
+
230 << toBase58(TokenType::NodePublic, *localPubKey_);
+
231 }
+
232 }
+
233
+
234 JLOG(j_.debug()) << "Loading configured validator keys";
+
235
+
236 count = 0;
+
237 for (auto const& n : configKeys)
+
238 {
+
239 JLOG(j_.trace()) << "Processing '" << n << "'";
+
240
+
241 boost::smatch match;
+
242
+
243 if (!boost::regex_match(n, match, re))
+
244 {
+
245 JLOG(j_.error()) << "Malformed entry: '" << n << "'";
+
246 return false;
+
247 }
+
248
+
249 auto const id =
+
250 parseBase58<PublicKey>(TokenType::NodePublic, match[1].str());
+
251
+
252 if (!id)
+
253 {
+
254 JLOG(j_.error()) << "Invalid node identity: " << match[1];
+
255 return false;
+
256 }
+
257
+
258 // Skip local key which was already added
+
259 if (*id == localPubKey_ || *id == localSigningKey)
+
260 continue;
+
261
+
262 auto ret = keyListings_.insert({*id, listThreshold_});
+
263 if (!ret.second)
+
264 {
+
265 JLOG(j_.warn()) << "Duplicate node identity: " << match[1];
+
266 continue;
+
267 }
+
268 localPublisherList.list.emplace_back(*id);
+
269 ++count;
+
270 }
+
271
+
272 // Config listed keys never expire
+
273 // set the expiration time for the newly created publisher list
+
274 // exactly once
+
275 if (count > 0)
+
276 localPublisherList.validUntil = TimeKeeper::time_point::max();
+
277
+
278 JLOG(j_.debug()) << "Loaded " << count << " entries";
+
279
+
280 return true;
+
281}
+
282
+
283boost::filesystem::path
+
284ValidatorList::getCacheFileName(
+
285 ValidatorList::lock_guard const&,
+
286 PublicKey const& pubKey) const
+
287{
+
288 return dataPath_ / (filePrefix_ + strHex(pubKey));
+
289}
+
290
+
291// static
+
292Json::Value
+
293ValidatorList::buildFileData(
+
294 std::string const& pubKey,
+
295 ValidatorList::PublisherListCollection const& pubCollection,
+
296 beast::Journal j)
+
297{
+
298 return buildFileData(pubKey, pubCollection, {}, j);
+
299}
+
300
+
301// static
+
302Json::Value
+
303ValidatorList::buildFileData(
+
304 std::string const& pubKey,
+
305 ValidatorList::PublisherListCollection const& pubCollection,
+
306 std::optional<std::uint32_t> forceVersion,
+
307 beast::Journal j)
+
308{
+
309 Json::Value value(Json::objectValue);
+
310
+
311 XRPL_ASSERT(
+
312 pubCollection.rawVersion == 2 || pubCollection.remaining.empty(),
+
313 "ripple::ValidatorList::buildFileData : valid publisher list input");
+
314 auto const effectiveVersion =
+
315 forceVersion ? *forceVersion : pubCollection.rawVersion;
+
316
+
317 value[jss::manifest] = pubCollection.rawManifest;
+
318 value[jss::version] = effectiveVersion;
+
319 value[jss::public_key] = pubKey;
+
320
+
321 switch (effectiveVersion)
+
322 {
+
323 case 1: {
+
324 auto const& current = pubCollection.current;
+
325 value[jss::blob] = current.rawBlob;
+
326 value[jss::signature] = current.rawSignature;
+
327 // This is only possible if "downgrading" a v2 UNL to v1, for
+
328 // example for the /vl/ endpoint.
+
329 if (current.rawManifest &&
+
330 *current.rawManifest != pubCollection.rawManifest)
+
331 value[jss::manifest] = *current.rawManifest;
+
332 break;
+
333 }
+
334 case 2: {
+
335 Json::Value blobs(Json::arrayValue);
+
336
+
337 auto add = [&blobs, &outerManifest = pubCollection.rawManifest](
+
338 PublisherList const& pubList) {
+
339 auto& blob = blobs.append(Json::objectValue);
+
340 blob[jss::blob] = pubList.rawBlob;
+
341 blob[jss::signature] = pubList.rawSignature;
+
342 if (pubList.rawManifest &&
+
343 *pubList.rawManifest != outerManifest)
+
344 blob[jss::manifest] = *pubList.rawManifest;
+
345 };
+
346
+
347 add(pubCollection.current);
+
348 for (auto const& [_, pending] : pubCollection.remaining)
+
349 {
+
350 (void)_;
+
351 add(pending);
+
352 }
353
-
354 writeFileContents(ec, filename, value.toStyledString());
-
355
-
356 if (ec)
-
357 {
-
358 // Log and ignore any file I/O exceptions
-
359 JLOG(j_.error()) << "Problem writing " << filename << " " << ec.value()
-
360 << ": " << ec.message();
+
354 value[jss::blobs_v2] = std::move(blobs);
+
355 break;
+
356 }
+
357 default:
+
358 JLOG(j.trace())
+
359 << "Invalid VL version provided: " << effectiveVersion;
+
360 value = Json::nullValue;
361 }
-
362}
-
363
-
364// static
-
365std::vector<ValidatorBlobInfo>
-
366ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body)
-
367{
-
368 std::vector<ValidatorBlobInfo> result;
-
369 switch (version)
-
370 {
-
371 case 1: {
-
372 if (!body.isMember(jss::blob) || !body[jss::blob].isString() ||
-
373 !body.isMember(jss::signature) ||
-
374 !body[jss::signature].isString() ||
-
375 // If the v2 field is present, the VL is malformed
-
376 body.isMember(jss::blobs_v2))
-
377 return {};
-
378 ValidatorBlobInfo& info = result.emplace_back();
-
379 info.blob = body[jss::blob].asString();
-
380 info.signature = body[jss::signature].asString();
-
381 XRPL_ASSERT(
-
382 result.size() == 1,
-
383 "ripple::ValidatorList::parseBlobs : single element result");
-
384 return result;
-
385 }
-
386 // Treat unknown versions as if they're the latest version. This
-
387 // will likely break a bunch of unit tests each time we introduce a
-
388 // new version, so don't do it casually. Note that the version is
-
389 // validated elsewhere.
-
390 case 2:
-
391 default: {
-
392 if (!body.isMember(jss::blobs_v2) ||
-
393 !body[jss::blobs_v2].isArray() ||
-
394 body[jss::blobs_v2].size() > maxSupportedBlobs ||
-
395 // If any of the v1 fields are present, the VL is malformed
-
396 body.isMember(jss::blob) || body.isMember(jss::signature))
-
397 return {};
-
398 auto const& blobs = body[jss::blobs_v2];
-
399 result.reserve(blobs.size());
-
400 for (auto const& blobInfo : blobs)
-
401 {
-
402 if (!blobInfo.isObject() ||
-
403 !blobInfo.isMember(jss::signature) ||
-
404 !blobInfo[jss::signature].isString() ||
-
405 !blobInfo.isMember(jss::blob) ||
-
406 !blobInfo[jss::blob].isString())
-
407 return {};
-
408 ValidatorBlobInfo& info = result.emplace_back();
-
409 info.blob = blobInfo[jss::blob].asString();
-
410 info.signature = blobInfo[jss::signature].asString();
-
411 if (blobInfo.isMember(jss::manifest))
-
412 {
-
413 if (!blobInfo[jss::manifest].isString())
-
414 return {};
-
415 info.manifest = blobInfo[jss::manifest].asString();
-
416 }
-
417 }
-
418 XRPL_ASSERT(
-
419 result.size() == blobs.size(),
-
420 "ripple::ValidatorList::parseBlobs(version, Jason::Value) : "
-
421 "result size matches");
-
422 return result;
-
423 }
-
424 }
-
425}
-
426
-
427// static
-
428std::vector<ValidatorBlobInfo>
-
429ValidatorList::parseBlobs(protocol::TMValidatorList const& body)
-
430{
-
431 return {{body.blob(), body.signature(), {}}};
-
432}
-
433
-
434// static
-
435std::vector<ValidatorBlobInfo>
-
436ValidatorList::parseBlobs(protocol::TMValidatorListCollection const& body)
-
437{
-
438 if (body.blobs_size() > maxSupportedBlobs)
-
439 return {};
-
440 std::vector<ValidatorBlobInfo> result;
-
441 result.reserve(body.blobs_size());
-
442 for (auto const& blob : body.blobs())
-
443 {
-
444 ValidatorBlobInfo& info = result.emplace_back();
-
445 info.blob = blob.blob();
-
446 info.signature = blob.signature();
-
447 if (blob.has_manifest())
-
448 {
-
449 info.manifest = blob.manifest();
-
450 }
-
451 }
-
452 XRPL_ASSERT(
-
453 result.size() == body.blobs_size(),
-
454 "ripple::ValidatorList::parseBlobs(TMValidatorList) : result size "
-
455 "match");
-
456 return result;
+
362
+
363 return value;
+
364}
+
365
+
366void
+
367ValidatorList::cacheValidatorFile(
+
368 ValidatorList::lock_guard const& lock,
+
369 PublicKey const& pubKey) const
+
370{
+
371 if (dataPath_.empty())
+
372 return;
+
373
+
374 boost::filesystem::path const filename = getCacheFileName(lock, pubKey);
+
375
+
376 boost::system::error_code ec;
+
377
+
378 Json::Value value =
+
379 buildFileData(strHex(pubKey), publisherLists_.at(pubKey), j_);
+
380 // rippled should be the only process writing to this file, so
+
381 // if it ever needs to be read, it is not expected to change externally, so
+
382 // delay the refresh as long as possible: 24 hours. (See also
+
383 // `ValidatorSite::missingSite()`)
+
384 value[jss::refresh_interval] = 24 * 60;
+
385
+
386 writeFileContents(ec, filename, value.toStyledString());
+
387
+
388 if (ec)
+
389 {
+
390 // Log and ignore any file I/O exceptions
+
391 JLOG(j_.error()) << "Problem writing " << filename << " " << ec.value()
+
392 << ": " << ec.message();
+
393 }
+
394}
+
395
+
396// static
+
397std::vector<ValidatorBlobInfo>
+
398ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body)
+
399{
+
400 std::vector<ValidatorBlobInfo> result;
+
401 switch (version)
+
402 {
+
403 case 1: {
+
404 if (!body.isMember(jss::blob) || !body[jss::blob].isString() ||
+
405 !body.isMember(jss::signature) ||
+
406 !body[jss::signature].isString() ||
+
407 // If the v2 field is present, the VL is malformed
+
408 body.isMember(jss::blobs_v2))
+
409 return {};
+
410 ValidatorBlobInfo& info = result.emplace_back();
+
411 info.blob = body[jss::blob].asString();
+
412 info.signature = body[jss::signature].asString();
+
413 XRPL_ASSERT(
+
414 result.size() == 1,
+
415 "ripple::ValidatorList::parseBlobs : single element result");
+
416 return result;
+
417 }
+
418 // Treat unknown versions as if they're the latest version. This
+
419 // will likely break a bunch of unit tests each time we introduce a
+
420 // new version, so don't do it casually. Note that the version is
+
421 // validated elsewhere.
+
422 case 2:
+
423 default: {
+
424 if (!body.isMember(jss::blobs_v2) ||
+
425 !body[jss::blobs_v2].isArray() ||
+
426 body[jss::blobs_v2].size() > maxSupportedBlobs ||
+
427 // If any of the v1 fields are present, the VL is malformed
+
428 body.isMember(jss::blob) || body.isMember(jss::signature))
+
429 return {};
+
430 auto const& blobs = body[jss::blobs_v2];
+
431 result.reserve(blobs.size());
+
432 for (auto const& blobInfo : blobs)
+
433 {
+
434 if (!blobInfo.isObject() ||
+
435 !blobInfo.isMember(jss::signature) ||
+
436 !blobInfo[jss::signature].isString() ||
+
437 !blobInfo.isMember(jss::blob) ||
+
438 !blobInfo[jss::blob].isString())
+
439 return {};
+
440 ValidatorBlobInfo& info = result.emplace_back();
+
441 info.blob = blobInfo[jss::blob].asString();
+
442 info.signature = blobInfo[jss::signature].asString();
+
443 if (blobInfo.isMember(jss::manifest))
+
444 {
+
445 if (!blobInfo[jss::manifest].isString())
+
446 return {};
+
447 info.manifest = blobInfo[jss::manifest].asString();
+
448 }
+
449 }
+
450 XRPL_ASSERT(
+
451 result.size() == blobs.size(),
+
452 "ripple::ValidatorList::parseBlobs(version, Jason::Value) : "
+
453 "result size matches");
+
454 return result;
+
455 }
+
456 }
457}
458
-
459std::size_t
-
460splitMessageParts(
-
461 std::vector<ValidatorList::MessageWithHash>& messages,
-
462 protocol::TMValidatorListCollection const& largeMsg,
-
463 std::size_t maxSize,
-
464 std::size_t begin,
-
465 std::size_t end);
-
466
-
467std::size_t
-
468splitMessage(
-
469 std::vector<ValidatorList::MessageWithHash>& messages,
-
470 protocol::TMValidatorListCollection const& largeMsg,
-
471 std::size_t maxSize,
-
472 std::size_t begin = 0,
-
473 std::size_t end = 0)
-
474{
-
475 if (begin == 0 && end == 0)
-
476 end = largeMsg.blobs_size();
-
477 XRPL_ASSERT(begin < end, "ripple::splitMessage : valid inputs");
-
478 if (end <= begin)
-
479 return 0;
-
480
-
481 auto mid = (begin + end) / 2;
-
482 // The parts function will do range checking
-
483 // Use two separate calls to ensure deterministic order
-
484 auto result = splitMessageParts(messages, largeMsg, maxSize, begin, mid);
-
485 return result + splitMessageParts(messages, largeMsg, maxSize, mid, end);
-
486}
-
487
-
488std::size_t
-
489splitMessageParts(
-
490 std::vector<ValidatorList::MessageWithHash>& messages,
-
491 protocol::TMValidatorListCollection const& largeMsg,
-
492 std::size_t maxSize,
-
493 std::size_t begin,
-
494 std::size_t end)
-
495{
-
496 if (end <= begin)
-
497 return 0;
-
498 if (end - begin == 1)
-
499 {
-
500 protocol::TMValidatorList smallMsg;
-
501 smallMsg.set_version(1);
-
502 smallMsg.set_manifest(largeMsg.manifest());
-
503
-
504 auto const& blob = largeMsg.blobs(begin);
-
505 smallMsg.set_blob(blob.blob());
-
506 smallMsg.set_signature(blob.signature());
-
507 // This is only possible if "downgrading" a v2 UNL to v1.
-
508 if (blob.has_manifest())
-
509 smallMsg.set_manifest(blob.manifest());
-
510
-
511 XRPL_ASSERT(
-
512 Message::totalSize(smallMsg) <= maximiumMessageSize,
-
513 "ripple::splitMessageParts : maximum message size");
-
514
-
515 messages.emplace_back(
-
516 std::make_shared<Message>(smallMsg, protocol::mtVALIDATORLIST),
-
517 sha512Half(smallMsg),
-
518 1);
-
519 return messages.back().numVLs;
-
520 }
-
521 else
-
522 {
-
523 std::optional<protocol::TMValidatorListCollection> smallMsg;
-
524 smallMsg.emplace();
-
525 smallMsg->set_version(largeMsg.version());
-
526 smallMsg->set_manifest(largeMsg.manifest());
-
527
-
528 for (std::size_t i = begin; i < end; ++i)
-
529 {
-
530 *smallMsg->add_blobs() = largeMsg.blobs(i);
-
531 }
-
532
-
533 if (Message::totalSize(*smallMsg) > maxSize)
-
534 {
-
535 // free up the message space
-
536 smallMsg.reset();
-
537 return splitMessage(messages, largeMsg, maxSize, begin, end);
-
538 }
-
539 else
-
540 {
-
541 messages.emplace_back(
-
542 std::make_shared<Message>(
-
543 *smallMsg, protocol::mtVALIDATORLISTCOLLECTION),
-
544 sha512Half(*smallMsg),
-
545 smallMsg->blobs_size());
-
546 return messages.back().numVLs;
-
547 }
-
548 }
-
549 return 0;
-
550}
-
551
-
552// Build a v1 protocol message using only the current VL
-
553std::size_t
-
554buildValidatorListMessage(
-
555 std::vector<ValidatorList::MessageWithHash>& messages,
-
556 std::uint32_t rawVersion,
-
557 std::string const& rawManifest,
-
558 ValidatorBlobInfo const& currentBlob,
-
559 std::size_t maxSize)
-
560{
-
561 XRPL_ASSERT(
-
562 messages.empty(),
-
563 "ripple::buildValidatorListMessage(ValidatorBlobInfo) : empty messages "
-
564 "input");
-
565 protocol::TMValidatorList msg;
-
566 auto const manifest =
-
567 currentBlob.manifest ? *currentBlob.manifest : rawManifest;
-
568 auto const version = 1;
-
569 msg.set_manifest(manifest);
-
570 msg.set_blob(currentBlob.blob);
-
571 msg.set_signature(currentBlob.signature);
-
572 // Override the version
-
573 msg.set_version(version);
-
574
-
575 XRPL_ASSERT(
-
576 Message::totalSize(msg) <= maximiumMessageSize,
-
577 "ripple::buildValidatorListMessage(ValidatorBlobInfo) : maximum "
-
578 "message size");
-
579 messages.emplace_back(
-
580 std::make_shared<Message>(msg, protocol::mtVALIDATORLIST),
-
581 sha512Half(msg),
-
582 1);
-
583 return 1;
-
584}
-
585
-
586// Build a v2 protocol message using all the VLs with sequence larger than the
-
587// peer's
-
588std::size_t
-
589buildValidatorListMessage(
-
590 std::vector<ValidatorList::MessageWithHash>& messages,
-
591 std::uint64_t peerSequence,
-
592 std::uint32_t rawVersion,
-
593 std::string const& rawManifest,
-
594 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
595 std::size_t maxSize)
-
596{
-
597 XRPL_ASSERT(
-
598 messages.empty(),
-
599 "ripple::buildValidatorListMessage(std::map<std::size_t, "
-
600 "ValidatorBlobInfo>) : empty messages input");
-
601 protocol::TMValidatorListCollection msg;
-
602 auto const version = rawVersion < 2 ? 2 : rawVersion;
-
603 msg.set_version(version);
-
604 msg.set_manifest(rawManifest);
-
605
-
606 for (auto const& [sequence, blobInfo] : blobInfos)
-
607 {
-
608 if (sequence <= peerSequence)
-
609 continue;
-
610 protocol::ValidatorBlobInfo& blob = *msg.add_blobs();
-
611 blob.set_blob(blobInfo.blob);
-
612 blob.set_signature(blobInfo.signature);
-
613 if (blobInfo.manifest)
-
614 blob.set_manifest(*blobInfo.manifest);
-
615 }
-
616 XRPL_ASSERT(
-
617 msg.blobs_size() > 0,
-
618 "ripple::buildValidatorListMessage(std::map<std::size_t, "
-
619 "ValidatorBlobInfo>) : minimum message blobs");
-
620 if (Message::totalSize(msg) > maxSize)
-
621 {
-
622 // split into smaller messages
-
623 return splitMessage(messages, msg, maxSize);
-
624 }
-
625 else
-
626 {
-
627 messages.emplace_back(
-
628 std::make_shared<Message>(msg, protocol::mtVALIDATORLISTCOLLECTION),
-
629 sha512Half(msg),
-
630 msg.blobs_size());
-
631 return messages.back().numVLs;
-
632 }
-
633}
-
634
-
635[[nodiscard]]
-
636// static
-
637std::pair<std::size_t, std::size_t>
-
638ValidatorList::buildValidatorListMessages(
-
639 std::size_t messageVersion,
-
640 std::uint64_t peerSequence,
-
641 std::size_t maxSequence,
-
642 std::uint32_t rawVersion,
-
643 std::string const& rawManifest,
-
644 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
645 std::vector<ValidatorList::MessageWithHash>& messages,
-
646 std::size_t maxSize /*= maximiumMessageSize*/)
-
647{
+
459// static
+
460std::vector<ValidatorBlobInfo>
+
461ValidatorList::parseBlobs(protocol::TMValidatorList const& body)
+
462{
+
463 return {{body.blob(), body.signature(), {}}};
+
464}
+
465
+
466// static
+
467std::vector<ValidatorBlobInfo>
+
468ValidatorList::parseBlobs(protocol::TMValidatorListCollection const& body)
+
469{
+
470 if (body.blobs_size() > maxSupportedBlobs)
+
471 return {};
+
472 std::vector<ValidatorBlobInfo> result;
+
473 result.reserve(body.blobs_size());
+
474 for (auto const& blob : body.blobs())
+
475 {
+
476 ValidatorBlobInfo& info = result.emplace_back();
+
477 info.blob = blob.blob();
+
478 info.signature = blob.signature();
+
479 if (blob.has_manifest())
+
480 {
+
481 info.manifest = blob.manifest();
+
482 }
+
483 }
+
484 XRPL_ASSERT(
+
485 result.size() == body.blobs_size(),
+
486 "ripple::ValidatorList::parseBlobs(TMValidatorList) : result size "
+
487 "match");
+
488 return result;
+
489}
+
490
+
491std::size_t
+
492splitMessageParts(
+
493 std::vector<ValidatorList::MessageWithHash>& messages,
+
494 protocol::TMValidatorListCollection const& largeMsg,
+
495 std::size_t maxSize,
+
496 std::size_t begin,
+
497 std::size_t end);
+
498
+
499std::size_t
+
500splitMessage(
+
501 std::vector<ValidatorList::MessageWithHash>& messages,
+
502 protocol::TMValidatorListCollection const& largeMsg,
+
503 std::size_t maxSize,
+
504 std::size_t begin = 0,
+
505 std::size_t end = 0)
+
506{
+
507 if (begin == 0 && end == 0)
+
508 end = largeMsg.blobs_size();
+
509 XRPL_ASSERT(begin < end, "ripple::splitMessage : valid inputs");
+
510 if (end <= begin)
+
511 return 0;
+
512
+
513 auto mid = (begin + end) / 2;
+
514 // The parts function will do range checking
+
515 // Use two separate calls to ensure deterministic order
+
516 auto result = splitMessageParts(messages, largeMsg, maxSize, begin, mid);
+
517 return result + splitMessageParts(messages, largeMsg, maxSize, mid, end);
+
518}
+
519
+
520std::size_t
+
521splitMessageParts(
+
522 std::vector<ValidatorList::MessageWithHash>& messages,
+
523 protocol::TMValidatorListCollection const& largeMsg,
+
524 std::size_t maxSize,
+
525 std::size_t begin,
+
526 std::size_t end)
+
527{
+
528 if (end <= begin)
+
529 return 0;
+
530 if (end - begin == 1)
+
531 {
+
532 protocol::TMValidatorList smallMsg;
+
533 smallMsg.set_version(1);
+
534 smallMsg.set_manifest(largeMsg.manifest());
+
535
+
536 auto const& blob = largeMsg.blobs(begin);
+
537 smallMsg.set_blob(blob.blob());
+
538 smallMsg.set_signature(blob.signature());
+
539 // This is only possible if "downgrading" a v2 UNL to v1.
+
540 if (blob.has_manifest())
+
541 smallMsg.set_manifest(blob.manifest());
+
542
+
543 XRPL_ASSERT(
+
544 Message::totalSize(smallMsg) <= maximiumMessageSize,
+
545 "ripple::splitMessageParts : maximum message size");
+
546
+
547 messages.emplace_back(
+
548 std::make_shared<Message>(smallMsg, protocol::mtVALIDATORLIST),
+
549 sha512Half(smallMsg),
+
550 1);
+
551 return messages.back().numVLs;
+
552 }
+
553 else
+
554 {
+
555 std::optional<protocol::TMValidatorListCollection> smallMsg;
+
556 smallMsg.emplace();
+
557 smallMsg->set_version(largeMsg.version());
+
558 smallMsg->set_manifest(largeMsg.manifest());
+
559
+
560 for (std::size_t i = begin; i < end; ++i)
+
561 {
+
562 *smallMsg->add_blobs() = largeMsg.blobs(i);
+
563 }
+
564
+
565 if (Message::totalSize(*smallMsg) > maxSize)
+
566 {
+
567 // free up the message space
+
568 smallMsg.reset();
+
569 return splitMessage(messages, largeMsg, maxSize, begin, end);
+
570 }
+
571 else
+
572 {
+
573 messages.emplace_back(
+
574 std::make_shared<Message>(
+
575 *smallMsg, protocol::mtVALIDATORLISTCOLLECTION),
+
576 sha512Half(*smallMsg),
+
577 smallMsg->blobs_size());
+
578 return messages.back().numVLs;
+
579 }
+
580 }
+
581 return 0;
+
582}
+
583
+
584// Build a v1 protocol message using only the current VL
+
585std::size_t
+
586buildValidatorListMessage(
+
587 std::vector<ValidatorList::MessageWithHash>& messages,
+
588 std::uint32_t rawVersion,
+
589 std::string const& rawManifest,
+
590 ValidatorBlobInfo const& currentBlob,
+
591 std::size_t maxSize)
+
592{
+
593 XRPL_ASSERT(
+
594 messages.empty(),
+
595 "ripple::buildValidatorListMessage(ValidatorBlobInfo) : empty messages "
+
596 "input");
+
597 protocol::TMValidatorList msg;
+
598 auto const manifest =
+
599 currentBlob.manifest ? *currentBlob.manifest : rawManifest;
+
600 auto const version = 1;
+
601 msg.set_manifest(manifest);
+
602 msg.set_blob(currentBlob.blob);
+
603 msg.set_signature(currentBlob.signature);
+
604 // Override the version
+
605 msg.set_version(version);
+
606
+
607 XRPL_ASSERT(
+
608 Message::totalSize(msg) <= maximiumMessageSize,
+
609 "ripple::buildValidatorListMessage(ValidatorBlobInfo) : maximum "
+
610 "message size");
+
611 messages.emplace_back(
+
612 std::make_shared<Message>(msg, protocol::mtVALIDATORLIST),
+
613 sha512Half(msg),
+
614 1);
+
615 return 1;
+
616}
+
617
+
618// Build a v2 protocol message using all the VLs with sequence larger than the
+
619// peer's
+
620std::size_t
+
621buildValidatorListMessage(
+
622 std::vector<ValidatorList::MessageWithHash>& messages,
+
623 std::uint64_t peerSequence,
+
624 std::uint32_t rawVersion,
+
625 std::string const& rawManifest,
+
626 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
627 std::size_t maxSize)
+
628{
+
629 XRPL_ASSERT(
+
630 messages.empty(),
+
631 "ripple::buildValidatorListMessage(std::map<std::size_t, "
+
632 "ValidatorBlobInfo>) : empty messages input");
+
633 protocol::TMValidatorListCollection msg;
+
634 auto const version = rawVersion < 2 ? 2 : rawVersion;
+
635 msg.set_version(version);
+
636 msg.set_manifest(rawManifest);
+
637
+
638 for (auto const& [sequence, blobInfo] : blobInfos)
+
639 {
+
640 if (sequence <= peerSequence)
+
641 continue;
+
642 protocol::ValidatorBlobInfo& blob = *msg.add_blobs();
+
643 blob.set_blob(blobInfo.blob);
+
644 blob.set_signature(blobInfo.signature);
+
645 if (blobInfo.manifest)
+
646 blob.set_manifest(*blobInfo.manifest);
+
647 }
648 XRPL_ASSERT(
-
649 !blobInfos.empty(),
-
650 "ripple::ValidatorList::buildValidatorListMessages : empty messages "
-
651 "input");
-
652 auto const& [currentSeq, currentBlob] = *blobInfos.begin();
-
653 auto numVLs = std::accumulate(
-
654 messages.begin(),
-
655 messages.end(),
-
656 0,
-
657 [](std::size_t total, MessageWithHash const& m) {
-
658 return total + m.numVLs;
-
659 });
-
660 if (messageVersion == 2 && peerSequence < maxSequence)
-
661 {
-
662 // Version 2
-
663 if (messages.empty())
-
664 {
-
665 numVLs = buildValidatorListMessage(
-
666 messages,
-
667 peerSequence,
-
668 rawVersion,
-
669 rawManifest,
-
670 blobInfos,
-
671 maxSize);
-
672 if (messages.empty())
-
673 // No message was generated. Create an empty placeholder so we
-
674 // dont' repeat the work later.
-
675 messages.emplace_back();
-
676 }
-
677
-
678 // Don't send it next time.
-
679 return {maxSequence, numVLs};
-
680 }
-
681 else if (messageVersion == 1 && peerSequence < currentSeq)
-
682 {
-
683 // Version 1
-
684 if (messages.empty())
-
685 {
-
686 numVLs = buildValidatorListMessage(
-
687 messages,
-
688 rawVersion,
-
689 currentBlob.manifest ? *currentBlob.manifest : rawManifest,
-
690 currentBlob,
-
691 maxSize);
-
692 if (messages.empty())
-
693 // No message was generated. Create an empty placeholder so we
-
694 // dont' repeat the work later.
-
695 messages.emplace_back();
-
696 }
-
697
-
698 // Don't send it next time.
-
699 return {currentSeq, numVLs};
-
700 }
-
701 return {0, 0};
-
702}
-
703
-
704// static
-
705void
-
706ValidatorList::sendValidatorList(
-
707 Peer& peer,
-
708 std::uint64_t peerSequence,
-
709 PublicKey const& publisherKey,
-
710 std::size_t maxSequence,
-
711 std::uint32_t rawVersion,
-
712 std::string const& rawManifest,
-
713 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
714 std::vector<ValidatorList::MessageWithHash>& messages,
-
715 HashRouter& hashRouter,
-
716 beast::Journal j)
-
717{
-
718 std::size_t const messageVersion =
-
719 peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation) ? 2
-
720 : peer.supportsFeature(ProtocolFeature::ValidatorListPropagation) ? 1
-
721 : 0;
-
722 if (!messageVersion)
-
723 return;
-
724 auto const [newPeerSequence, numVLs] = buildValidatorListMessages(
-
725 messageVersion,
-
726 peerSequence,
-
727 maxSequence,
-
728 rawVersion,
-
729 rawManifest,
-
730 blobInfos,
-
731 messages);
-
732 if (newPeerSequence)
-
733 {
-
734 XRPL_ASSERT(
-
735 !messages.empty(),
-
736 "ripple::ValidatorList::sendValidatorList : non-empty messages "
-
737 "input");
-
738 // Don't send it next time.
-
739 peer.setPublisherListSequence(publisherKey, newPeerSequence);
-
740
-
741 bool sent = false;
-
742 for (auto const& message : messages)
-
743 {
-
744 if (message.message)
-
745 {
-
746 peer.send(message.message);
-
747 hashRouter.addSuppressionPeer(message.hash, peer.id());
-
748 sent = true;
-
749 }
-
750 }
-
751 // The only way sent wil be false is if the messages was too big, and
-
752 // thus there will only be one entry without a message
-
753 XRPL_ASSERT(
-
754 sent || messages.size() == 1,
-
755 "ripple::ValidatorList::sendValidatorList : sent or one message");
-
756 if (sent)
-
757 {
-
758 if (messageVersion > 1)
-
759 JLOG(j.debug())
-
760 << "Sent " << messages.size()
-
761 << " validator list collection(s) containing " << numVLs
-
762 << " validator list(s) for " << strHex(publisherKey)
-
763 << " with sequence range " << peerSequence << ", "
-
764 << newPeerSequence << " to "
-
765 << peer.getRemoteAddress().to_string() << " [" << peer.id()
-
766 << "]";
-
767 else
-
768 {
-
769 XRPL_ASSERT(
-
770 numVLs == 1,
-
771 "ripple::ValidatorList::sendValidatorList : one validator "
-
772 "list");
-
773 JLOG(j.debug())
-
774 << "Sent validator list for " << strHex(publisherKey)
-
775 << " with sequence " << newPeerSequence << " to "
-
776 << peer.getRemoteAddress().to_string() << " [" << peer.id()
-
777 << "]";
-
778 }
-
779 }
-
780 }
-
781}
-
782
-
783// static
-
784void
-
785ValidatorList::sendValidatorList(
-
786 Peer& peer,
-
787 std::uint64_t peerSequence,
-
788 PublicKey const& publisherKey,
-
789 std::size_t maxSequence,
-
790 std::uint32_t rawVersion,
-
791 std::string const& rawManifest,
-
792 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
793 HashRouter& hashRouter,
-
794 beast::Journal j)
-
795{
-
796 std::vector<ValidatorList::MessageWithHash> messages;
-
797 sendValidatorList(
-
798 peer,
-
799 peerSequence,
-
800 publisherKey,
-
801 maxSequence,
-
802 rawVersion,
-
803 rawManifest,
-
804 blobInfos,
-
805 messages,
-
806 hashRouter,
-
807 j);
-
808}
-
809
-
810// static
-
811void
-
812ValidatorList::buildBlobInfos(
-
813 std::map<std::size_t, ValidatorBlobInfo>& blobInfos,
-
814 ValidatorList::PublisherListCollection const& lists)
-
815{
-
816 auto const& current = lists.current;
-
817 auto const& remaining = lists.remaining;
-
818 blobInfos[current.sequence] = {
-
819 current.rawBlob, current.rawSignature, current.rawManifest};
-
820 for (auto const& [sequence, vl] : remaining)
-
821 {
-
822 blobInfos[sequence] = {vl.rawBlob, vl.rawSignature, vl.rawManifest};
-
823 }
-
824}
-
825
-
826// static
-
827std::map<std::size_t, ValidatorBlobInfo>
-
828ValidatorList::buildBlobInfos(
-
829 ValidatorList::PublisherListCollection const& lists)
-
830{
-
831 std::map<std::size_t, ValidatorBlobInfo> result;
-
832 buildBlobInfos(result, lists);
-
833 return result;
-
834}
-
835
-
836// static
-
837void
-
838ValidatorList::broadcastBlobs(
-
839 PublicKey const& publisherKey,
-
840 ValidatorList::PublisherListCollection const& lists,
-
841 std::size_t maxSequence,
-
842 uint256 const& hash,
-
843 Overlay& overlay,
-
844 HashRouter& hashRouter,
-
845 beast::Journal j)
-
846{
-
847 auto const toSkip = hashRouter.shouldRelay(hash);
-
848
-
849 if (toSkip)
-
850 {
-
851 // We don't know what messages or message versions we're sending
-
852 // until we examine our peer's properties. Build the message(s) on
-
853 // demand, but reuse them when possible.
-
854
-
855 // This will hold a v1 message with only the current VL if we have
-
856 // any peers that don't support v2
-
857 std::vector<ValidatorList::MessageWithHash> messages1;
-
858 // This will hold v2 messages indexed by the peer's
-
859 // `publisherListSequence`. For each `publisherListSequence`, we'll
-
860 // only send the VLs with higher sequences.
-
861 std::map<std::size_t, std::vector<ValidatorList::MessageWithHash>>
-
862 messages2;
-
863 // If any peers are found that are worth considering, this list will
-
864 // be built to hold info for all of the valid VLs.
-
865 std::map<std::size_t, ValidatorBlobInfo> blobInfos;
-
866
-
867 XRPL_ASSERT(
-
868 lists.current.sequence == maxSequence ||
-
869 lists.remaining.count(maxSequence) == 1,
-
870 "ripple::ValidatorList::broadcastBlobs : valid sequence");
-
871 // Can't use overlay.foreach here because we need to modify
-
872 // the peer, and foreach provides a const&
-
873 for (auto& peer : overlay.getActivePeers())
-
874 {
-
875 if (toSkip->count(peer->id()) == 0)
-
876 {
-
877 auto const peerSequence =
-
878 peer->publisherListSequence(publisherKey).value_or(0);
-
879 if (peerSequence < maxSequence)
-
880 {
-
881 if (blobInfos.empty())
-
882 buildBlobInfos(blobInfos, lists);
-
883 auto const v2 = peer->supportsFeature(
-
884 ProtocolFeature::ValidatorList2Propagation);
-
885 sendValidatorList(
-
886 *peer,
-
887 peerSequence,
-
888 publisherKey,
-
889 maxSequence,
-
890 lists.rawVersion,
-
891 lists.rawManifest,
-
892 blobInfos,
-
893 v2 ? messages2[peerSequence] : messages1,
-
894 hashRouter,
-
895 j);
-
896 // Even if the peer doesn't support the messages,
-
897 // suppress it so it'll be ignored next time.
-
898 hashRouter.addSuppressionPeer(hash, peer->id());
-
899 }
-
900 }
-
901 }
-
902 }
-
903}
-
904
-
905ValidatorList::PublisherListStats
-
906ValidatorList::applyListsAndBroadcast(
-
907 std::string const& manifest,
-
908 std::uint32_t version,
-
909 std::vector<ValidatorBlobInfo> const& blobs,
-
910 std::string siteUri,
-
911 uint256 const& hash,
-
912 Overlay& overlay,
-
913 HashRouter& hashRouter,
-
914 NetworkOPs& networkOPs)
-
915{
-
916 auto const result =
-
917 applyLists(manifest, version, blobs, std::move(siteUri), hash);
-
918 auto const disposition = result.bestDisposition();
-
919
-
920 if (disposition == ListDisposition::accepted)
-
921 {
-
922 bool good = true;
-
923
-
924 // localPublisherList never expires, so localPublisherList is excluded
-
925 // from the below check.
-
926 for (auto const& [_, listCollection] : publisherLists_)
-
927 {
-
928 if (listCollection.status != PublisherStatus::available)
-
929 {
-
930 good = false;
-
931 break;
+
649 msg.blobs_size() > 0,
+
650 "ripple::buildValidatorListMessage(std::map<std::size_t, "
+
651 "ValidatorBlobInfo>) : minimum message blobs");
+
652 if (Message::totalSize(msg) > maxSize)
+
653 {
+
654 // split into smaller messages
+
655 return splitMessage(messages, msg, maxSize);
+
656 }
+
657 else
+
658 {
+
659 messages.emplace_back(
+
660 std::make_shared<Message>(msg, protocol::mtVALIDATORLISTCOLLECTION),
+
661 sha512Half(msg),
+
662 msg.blobs_size());
+
663 return messages.back().numVLs;
+
664 }
+
665}
+
666
+
667[[nodiscard]]
+
668// static
+
669std::pair<std::size_t, std::size_t>
+
670ValidatorList::buildValidatorListMessages(
+
671 std::size_t messageVersion,
+
672 std::uint64_t peerSequence,
+
673 std::size_t maxSequence,
+
674 std::uint32_t rawVersion,
+
675 std::string const& rawManifest,
+
676 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
677 std::vector<ValidatorList::MessageWithHash>& messages,
+
678 std::size_t maxSize /*= maximiumMessageSize*/)
+
679{
+
680 XRPL_ASSERT(
+
681 !blobInfos.empty(),
+
682 "ripple::ValidatorList::buildValidatorListMessages : empty messages "
+
683 "input");
+
684 auto const& [currentSeq, currentBlob] = *blobInfos.begin();
+
685 auto numVLs = std::accumulate(
+
686 messages.begin(),
+
687 messages.end(),
+
688 0,
+
689 [](std::size_t total, MessageWithHash const& m) {
+
690 return total + m.numVLs;
+
691 });
+
692 if (messageVersion == 2 && peerSequence < maxSequence)
+
693 {
+
694 // Version 2
+
695 if (messages.empty())
+
696 {
+
697 numVLs = buildValidatorListMessage(
+
698 messages,
+
699 peerSequence,
+
700 rawVersion,
+
701 rawManifest,
+
702 blobInfos,
+
703 maxSize);
+
704 if (messages.empty())
+
705 // No message was generated. Create an empty placeholder so we
+
706 // dont' repeat the work later.
+
707 messages.emplace_back();
+
708 }
+
709
+
710 // Don't send it next time.
+
711 return {maxSequence, numVLs};
+
712 }
+
713 else if (messageVersion == 1 && peerSequence < currentSeq)
+
714 {
+
715 // Version 1
+
716 if (messages.empty())
+
717 {
+
718 numVLs = buildValidatorListMessage(
+
719 messages,
+
720 rawVersion,
+
721 currentBlob.manifest ? *currentBlob.manifest : rawManifest,
+
722 currentBlob,
+
723 maxSize);
+
724 if (messages.empty())
+
725 // No message was generated. Create an empty placeholder so we
+
726 // dont' repeat the work later.
+
727 messages.emplace_back();
+
728 }
+
729
+
730 // Don't send it next time.
+
731 return {currentSeq, numVLs};
+
732 }
+
733 return {0, 0};
+
734}
+
735
+
736// static
+
737void
+
738ValidatorList::sendValidatorList(
+
739 Peer& peer,
+
740 std::uint64_t peerSequence,
+
741 PublicKey const& publisherKey,
+
742 std::size_t maxSequence,
+
743 std::uint32_t rawVersion,
+
744 std::string const& rawManifest,
+
745 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
746 std::vector<ValidatorList::MessageWithHash>& messages,
+
747 HashRouter& hashRouter,
+
748 beast::Journal j)
+
749{
+
750 std::size_t const messageVersion =
+
751 peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation) ? 2
+
752 : peer.supportsFeature(ProtocolFeature::ValidatorListPropagation) ? 1
+
753 : 0;
+
754 if (!messageVersion)
+
755 return;
+
756 auto const [newPeerSequence, numVLs] = buildValidatorListMessages(
+
757 messageVersion,
+
758 peerSequence,
+
759 maxSequence,
+
760 rawVersion,
+
761 rawManifest,
+
762 blobInfos,
+
763 messages);
+
764 if (newPeerSequence)
+
765 {
+
766 XRPL_ASSERT(
+
767 !messages.empty(),
+
768 "ripple::ValidatorList::sendValidatorList : non-empty messages "
+
769 "input");
+
770 // Don't send it next time.
+
771 peer.setPublisherListSequence(publisherKey, newPeerSequence);
+
772
+
773 bool sent = false;
+
774 for (auto const& message : messages)
+
775 {
+
776 if (message.message)
+
777 {
+
778 peer.send(message.message);
+
779 hashRouter.addSuppressionPeer(message.hash, peer.id());
+
780 sent = true;
+
781 }
+
782 }
+
783 // The only way sent wil be false is if the messages was too big, and
+
784 // thus there will only be one entry without a message
+
785 XRPL_ASSERT(
+
786 sent || messages.size() == 1,
+
787 "ripple::ValidatorList::sendValidatorList : sent or one message");
+
788 if (sent)
+
789 {
+
790 if (messageVersion > 1)
+
791 JLOG(j.debug())
+
792 << "Sent " << messages.size()
+
793 << " validator list collection(s) containing " << numVLs
+
794 << " validator list(s) for " << strHex(publisherKey)
+
795 << " with sequence range " << peerSequence << ", "
+
796 << newPeerSequence << " to "
+
797 << peer.getRemoteAddress().to_string() << " [" << peer.id()
+
798 << "]";
+
799 else
+
800 {
+
801 XRPL_ASSERT(
+
802 numVLs == 1,
+
803 "ripple::ValidatorList::sendValidatorList : one validator "
+
804 "list");
+
805 JLOG(j.debug())
+
806 << "Sent validator list for " << strHex(publisherKey)
+
807 << " with sequence " << newPeerSequence << " to "
+
808 << peer.getRemoteAddress().to_string() << " [" << peer.id()
+
809 << "]";
+
810 }
+
811 }
+
812 }
+
813}
+
814
+
815// static
+
816void
+
817ValidatorList::sendValidatorList(
+
818 Peer& peer,
+
819 std::uint64_t peerSequence,
+
820 PublicKey const& publisherKey,
+
821 std::size_t maxSequence,
+
822 std::uint32_t rawVersion,
+
823 std::string const& rawManifest,
+
824 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
825 HashRouter& hashRouter,
+
826 beast::Journal j)
+
827{
+
828 std::vector<ValidatorList::MessageWithHash> messages;
+
829 sendValidatorList(
+
830 peer,
+
831 peerSequence,
+
832 publisherKey,
+
833 maxSequence,
+
834 rawVersion,
+
835 rawManifest,
+
836 blobInfos,
+
837 messages,
+
838 hashRouter,
+
839 j);
+
840}
+
841
+
842// static
+
843void
+
844ValidatorList::buildBlobInfos(
+
845 std::map<std::size_t, ValidatorBlobInfo>& blobInfos,
+
846 ValidatorList::PublisherListCollection const& lists)
+
847{
+
848 auto const& current = lists.current;
+
849 auto const& remaining = lists.remaining;
+
850 blobInfos[current.sequence] = {
+
851 current.rawBlob, current.rawSignature, current.rawManifest};
+
852 for (auto const& [sequence, vl] : remaining)
+
853 {
+
854 blobInfos[sequence] = {vl.rawBlob, vl.rawSignature, vl.rawManifest};
+
855 }
+
856}
+
857
+
858// static
+
859std::map<std::size_t, ValidatorBlobInfo>
+
860ValidatorList::buildBlobInfos(
+
861 ValidatorList::PublisherListCollection const& lists)
+
862{
+
863 std::map<std::size_t, ValidatorBlobInfo> result;
+
864 buildBlobInfos(result, lists);
+
865 return result;
+
866}
+
867
+
868// static
+
869void
+
870ValidatorList::broadcastBlobs(
+
871 PublicKey const& publisherKey,
+
872 ValidatorList::PublisherListCollection const& lists,
+
873 std::size_t maxSequence,
+
874 uint256 const& hash,
+
875 Overlay& overlay,
+
876 HashRouter& hashRouter,
+
877 beast::Journal j)
+
878{
+
879 auto const toSkip = hashRouter.shouldRelay(hash);
+
880
+
881 if (toSkip)
+
882 {
+
883 // We don't know what messages or message versions we're sending
+
884 // until we examine our peer's properties. Build the message(s) on
+
885 // demand, but reuse them when possible.
+
886
+
887 // This will hold a v1 message with only the current VL if we have
+
888 // any peers that don't support v2
+
889 std::vector<ValidatorList::MessageWithHash> messages1;
+
890 // This will hold v2 messages indexed by the peer's
+
891 // `publisherListSequence`. For each `publisherListSequence`, we'll
+
892 // only send the VLs with higher sequences.
+
893 std::map<std::size_t, std::vector<ValidatorList::MessageWithHash>>
+
894 messages2;
+
895 // If any peers are found that are worth considering, this list will
+
896 // be built to hold info for all of the valid VLs.
+
897 std::map<std::size_t, ValidatorBlobInfo> blobInfos;
+
898
+
899 XRPL_ASSERT(
+
900 lists.current.sequence == maxSequence ||
+
901 lists.remaining.count(maxSequence) == 1,
+
902 "ripple::ValidatorList::broadcastBlobs : valid sequence");
+
903 // Can't use overlay.foreach here because we need to modify
+
904 // the peer, and foreach provides a const&
+
905 for (auto& peer : overlay.getActivePeers())
+
906 {
+
907 if (toSkip->count(peer->id()) == 0)
+
908 {
+
909 auto const peerSequence =
+
910 peer->publisherListSequence(publisherKey).value_or(0);
+
911 if (peerSequence < maxSequence)
+
912 {
+
913 if (blobInfos.empty())
+
914 buildBlobInfos(blobInfos, lists);
+
915 auto const v2 = peer->supportsFeature(
+
916 ProtocolFeature::ValidatorList2Propagation);
+
917 sendValidatorList(
+
918 *peer,
+
919 peerSequence,
+
920 publisherKey,
+
921 maxSequence,
+
922 lists.rawVersion,
+
923 lists.rawManifest,
+
924 blobInfos,
+
925 v2 ? messages2[peerSequence] : messages1,
+
926 hashRouter,
+
927 j);
+
928 // Even if the peer doesn't support the messages,
+
929 // suppress it so it'll be ignored next time.
+
930 hashRouter.addSuppressionPeer(hash, peer->id());
+
931 }
932 }
933 }
-
934 if (good)
-
935 {
-
936 networkOPs.clearUNLBlocked();
-
937 }
-
938 }
-
939 bool broadcast = disposition <= ListDisposition::known_sequence;
-
940
-
941 // this function is only called for PublicKeys which are not specified
-
942 // in the config file (Note: Keys specified in the local config file are
-
943 // stored in ValidatorList::localPublisherList data member).
-
944 if (broadcast && result.status <= PublisherStatus::expired &&
-
945 result.publisherKey &&
-
946 publisherLists_[*result.publisherKey].maxSequence)
-
947 {
-
948 auto const& pubCollection = publisherLists_[*result.publisherKey];
-
949
-
950 broadcastBlobs(
-
951 *result.publisherKey,
-
952 pubCollection,
-
953 *pubCollection.maxSequence,
-
954 hash,
-
955 overlay,
-
956 hashRouter,
-
957 j_);
-
958 }
-
959
-
960 return result;
-
961}
-
962
-
963ValidatorList::PublisherListStats
-
964ValidatorList::applyLists(
-
965 std::string const& manifest,
-
966 std::uint32_t version,
-
967 std::vector<ValidatorBlobInfo> const& blobs,
-
968 std::string siteUri,
-
969 std::optional<uint256> const& hash /* = {} */)
-
970{
-
971 if (std::count(
-
972 std::begin(supportedListVersions),
-
973 std::end(supportedListVersions),
-
974 version) != 1)
-
975 return PublisherListStats{ListDisposition::unsupported_version};
-
976
-
977 std::lock_guard lock{mutex_};
-
978
-
979 PublisherListStats result;
-
980 for (auto const& blobInfo : blobs)
-
981 {
-
982 auto stats = applyList(
-
983 manifest,
-
984 blobInfo.manifest,
-
985 blobInfo.blob,
-
986 blobInfo.signature,
-
987 version,
-
988 siteUri,
-
989 hash,
-
990 lock);
+
934 }
+
935}
+
936
+
937ValidatorList::PublisherListStats
+
938ValidatorList::applyListsAndBroadcast(
+
939 std::string const& manifest,
+
940 std::uint32_t version,
+
941 std::vector<ValidatorBlobInfo> const& blobs,
+
942 std::string siteUri,
+
943 uint256 const& hash,
+
944 Overlay& overlay,
+
945 HashRouter& hashRouter,
+
946 NetworkOPs& networkOPs)
+
947{
+
948 auto const result =
+
949 applyLists(manifest, version, blobs, std::move(siteUri), hash);
+
950 auto const disposition = result.bestDisposition();
+
951
+
952 if (disposition == ListDisposition::accepted)
+
953 {
+
954 bool good = true;
+
955
+
956 // localPublisherList never expires, so localPublisherList is excluded
+
957 // from the below check.
+
958 for (auto const& [_, listCollection] : publisherLists_)
+
959 {
+
960 if (listCollection.status != PublisherStatus::available)
+
961 {
+
962 good = false;
+
963 break;
+
964 }
+
965 }
+
966 if (good)
+
967 {
+
968 networkOPs.clearUNLBlocked();
+
969 }
+
970 }
+
971 bool broadcast = disposition <= ListDisposition::known_sequence;
+
972
+
973 // this function is only called for PublicKeys which are not specified
+
974 // in the config file (Note: Keys specified in the local config file are
+
975 // stored in ValidatorList::localPublisherList data member).
+
976 if (broadcast && result.status <= PublisherStatus::expired &&
+
977 result.publisherKey &&
+
978 publisherLists_[*result.publisherKey].maxSequence)
+
979 {
+
980 auto const& pubCollection = publisherLists_[*result.publisherKey];
+
981
+
982 broadcastBlobs(
+
983 *result.publisherKey,
+
984 pubCollection,
+
985 *pubCollection.maxSequence,
+
986 hash,
+
987 overlay,
+
988 hashRouter,
+
989 j_);
+
990 }
991
-
992 if (stats.bestDisposition() < result.bestDisposition() ||
-
993 (stats.bestDisposition() == result.bestDisposition() &&
-
994 stats.sequence > result.sequence))
-
995 {
-
996 stats.mergeDispositions(result);
-
997 result = std::move(stats);
-
998 }
-
999 else
-
1000 result.mergeDispositions(stats);
-
1002 }
-
1003
-
1004 // Clean up the collection, because some of the processing may have made it
-
1005 // inconsistent
-
1006 if (result.publisherKey && publisherLists_.count(*result.publisherKey))
-
1007 {
-
1008 auto& pubCollection = publisherLists_[*result.publisherKey];
-
1009 auto& remaining = pubCollection.remaining;
-
1010 auto const& current = pubCollection.current;
-
1011 for (auto iter = remaining.begin(); iter != remaining.end();)
-
1012 {
-
1013 auto next = std::next(iter);
-
1014 XRPL_ASSERT(
-
1015 next == remaining.end() || next->first > iter->first,
-
1016 "ripple::ValidatorList::applyLists : next is valid");
-
1017 if (iter->first <= current.sequence ||
-
1018 (next != remaining.end() &&
-
1019 next->second.validFrom <= iter->second.validFrom))
-
1020 {
-
1021 iter = remaining.erase(iter);
-
1022 }
-
1023 else
-
1024 {
-
1025 iter = next;
-
1026 }
-
1027 }
-
1028
-
1029 cacheValidatorFile(lock, *result.publisherKey);
-
1030
-
1031 pubCollection.fullHash = sha512Half(pubCollection);
-
1032
-
1033 result.sequence = *pubCollection.maxSequence;
+
992 return result;
+
993}
+
994
+
995ValidatorList::PublisherListStats
+
996ValidatorList::applyLists(
+
997 std::string const& manifest,
+
998 std::uint32_t version,
+
999 std::vector<ValidatorBlobInfo> const& blobs,
+
1000 std::string siteUri,
+
1001 std::optional<uint256> const& hash /* = {} */)
+
1002{
+
1003 if (std::count(
+
1004 std::begin(supportedListVersions),
+
1005 std::end(supportedListVersions),
+
1006 version) != 1)
+
1007 return PublisherListStats{ListDisposition::unsupported_version};
+
1008
+
1009 std::lock_guard lock{mutex_};
+
1010
+
1011 PublisherListStats result;
+
1012 for (auto const& blobInfo : blobs)
+
1013 {
+
1014 auto stats = applyList(
+
1015 manifest,
+
1016 blobInfo.manifest,
+
1017 blobInfo.blob,
+
1018 blobInfo.signature,
+
1019 version,
+
1020 siteUri,
+
1021 hash,
+
1022 lock);
+
1023
+
1024 if (stats.bestDisposition() < result.bestDisposition() ||
+
1025 (stats.bestDisposition() == result.bestDisposition() &&
+
1026 stats.sequence > result.sequence))
+
1027 {
+
1028 stats.mergeDispositions(result);
+
1029 result = std::move(stats);
+
1030 }
+
1031 else
+
1032 result.mergeDispositions(stats);
1034 }
1035
-
1036 return result;
-
1037}
-
1038
-
1039void
-
1040ValidatorList::updatePublisherList(
-
1041 PublicKey const& pubKey,
-
1042 PublisherList const& current,
-
1043 std::vector<PublicKey> const& oldList,
-
1044 ValidatorList::lock_guard const&)
-
1045{
-
1046 // Update keyListings_ for added and removed keys
-
1047 std::vector<PublicKey> const& publisherList = current.list;
-
1048 std::vector<std::string> const& manifests = current.manifests;
-
1049 auto iNew = publisherList.begin();
-
1050 auto iOld = oldList.begin();
-
1051 while (iNew != publisherList.end() || iOld != oldList.end())
-
1052 {
-
1053 if (iOld == oldList.end() ||
-
1054 (iNew != publisherList.end() && *iNew < *iOld))
-
1055 {
-
1056 // Increment list count for added keys
-
1057 ++keyListings_[*iNew];
-
1058 ++iNew;
+
1036 // Clean up the collection, because some of the processing may have made it
+
1037 // inconsistent
+
1038 if (result.publisherKey && publisherLists_.count(*result.publisherKey))
+
1039 {
+
1040 auto& pubCollection = publisherLists_[*result.publisherKey];
+
1041 auto& remaining = pubCollection.remaining;
+
1042 auto const& current = pubCollection.current;
+
1043 for (auto iter = remaining.begin(); iter != remaining.end();)
+
1044 {
+
1045 auto next = std::next(iter);
+
1046 XRPL_ASSERT(
+
1047 next == remaining.end() || next->first > iter->first,
+
1048 "ripple::ValidatorList::applyLists : next is valid");
+
1049 if (iter->first <= current.sequence ||
+
1050 (next != remaining.end() &&
+
1051 next->second.validFrom <= iter->second.validFrom))
+
1052 {
+
1053 iter = remaining.erase(iter);
+
1054 }
+
1055 else
+
1056 {
+
1057 iter = next;
+
1058 }
1059 }
-
1060 else if (
-
1061 iNew == publisherList.end() ||
-
1062 (iOld != oldList.end() && *iOld < *iNew))
-
1063 {
-
1064 // Decrement list count for removed keys
-
1065 if (keyListings_[*iOld] <= 1)
-
1066 keyListings_.erase(*iOld);
-
1067 else
-
1068 --keyListings_[*iOld];
-
1069 ++iOld;
-
1070 }
-
1071 else
-
1072 {
-
1073 ++iNew;
-
1074 ++iOld;
-
1075 }
-
1076 }
-
1077
-
1078 if (publisherList.empty())
-
1079 {
-
1080 JLOG(j_.warn()) << "No validator keys included in valid list";
-
1081 }
-
1082
-
1083 for (auto const& valManifest : manifests)
+
1060
+
1061 cacheValidatorFile(lock, *result.publisherKey);
+
1062
+
1063 pubCollection.fullHash = sha512Half(pubCollection);
+
1064
+
1065 result.sequence = *pubCollection.maxSequence;
+
1066 }
+
1067
+
1068 return result;
+
1069}
+
1070
+
1071void
+
1072ValidatorList::updatePublisherList(
+
1073 PublicKey const& pubKey,
+
1074 PublisherList const& current,
+
1075 std::vector<PublicKey> const& oldList,
+
1076 ValidatorList::lock_guard const&)
+
1077{
+
1078 // Update keyListings_ for added and removed keys
+
1079 std::vector<PublicKey> const& publisherList = current.list;
+
1080 std::vector<std::string> const& manifests = current.manifests;
+
1081 auto iNew = publisherList.begin();
+
1082 auto iOld = oldList.begin();
+
1083 while (iNew != publisherList.end() || iOld != oldList.end())
1084 {
-
1085 auto m = deserializeManifest(base64_decode(valManifest));
-
1086
-
1087 if (!m || !keyListings_.count(m->masterKey))
-
1088 {
-
1089 JLOG(j_.warn()) << "List for " << strHex(pubKey)
-
1090 << " contained untrusted validator manifest";
-
1091 continue;
-
1092 }
-
1093
-
1094 if (auto const r = validatorManifests_.applyManifest(std::move(*m));
-
1095 r == ManifestDisposition::invalid)
-
1096 {
-
1097 JLOG(j_.warn()) << "List for " << strHex(pubKey)
-
1098 << " contained invalid validator manifest";
-
1099 }
-
1100 }
-
1101}
-
1102
-
1103ValidatorList::PublisherListStats
-
1104ValidatorList::applyList(
-
1105 std::string const& globalManifest,
-
1106 std::optional<std::string> const& localManifest,
-
1107 std::string const& blob,
-
1108 std::string const& signature,
-
1109 std::uint32_t version,
-
1110 std::string siteUri,
-
1111 std::optional<uint256> const& hash,
-
1112 ValidatorList::lock_guard const& lock)
-
1113{
-
1114 using namespace std::string_literals;
-
1115
-
1116 Json::Value list;
-
1117 auto const& manifest = localManifest ? *localManifest : globalManifest;
-
1118 auto [result, pubKeyOpt] = verify(lock, list, manifest, blob, signature);
-
1119
-
1120 if (!pubKeyOpt)
-
1121 {
-
1122 JLOG(j_.info()) << "ValidatorList::applyList unable to retrieve the "
-
1123 "master public key from the verify function\n";
-
1124 return PublisherListStats{result};
-
1125 }
-
1126
-
1127 if (!publicKeyType(*pubKeyOpt))
-
1128 {
-
1129 JLOG(j_.info()) << "ValidatorList::applyList Invalid Public Key type"
-
1130 " retrieved from the verify function\n ";
-
1131 return PublisherListStats{result};
+
1085 if (iOld == oldList.end() ||
+
1086 (iNew != publisherList.end() && *iNew < *iOld))
+
1087 {
+
1088 // Increment list count for added keys
+
1089 ++keyListings_[*iNew];
+
1090 ++iNew;
+
1091 }
+
1092 else if (
+
1093 iNew == publisherList.end() ||
+
1094 (iOld != oldList.end() && *iOld < *iNew))
+
1095 {
+
1096 // Decrement list count for removed keys
+
1097 if (keyListings_[*iOld] <= 1)
+
1098 keyListings_.erase(*iOld);
+
1099 else
+
1100 --keyListings_[*iOld];
+
1101 ++iOld;
+
1102 }
+
1103 else
+
1104 {
+
1105 ++iNew;
+
1106 ++iOld;
+
1107 }
+
1108 }
+
1109
+
1110 if (publisherList.empty())
+
1111 {
+
1112 JLOG(j_.warn()) << "No validator keys included in valid list";
+
1113 }
+
1114
+
1115 for (auto const& valManifest : manifests)
+
1116 {
+
1117 auto m = deserializeManifest(base64_decode(valManifest));
+
1118
+
1119 if (!m || !keyListings_.count(m->masterKey))
+
1120 {
+
1121 JLOG(j_.warn()) << "List for " << strHex(pubKey)
+
1122 << " contained untrusted validator manifest";
+
1123 continue;
+
1124 }
+
1125
+
1126 if (auto const r = validatorManifests_.applyManifest(std::move(*m));
+
1127 r == ManifestDisposition::invalid)
+
1128 {
+
1129 JLOG(j_.warn()) << "List for " << strHex(pubKey)
+
1130 << " contained invalid validator manifest";
+
1131 }
1132 }
-
1133
-
1134 PublicKey pubKey = *pubKeyOpt;
-
1135 if (result > ListDisposition::pending)
-
1136 {
-
1137 if (publisherLists_.count(pubKey))
-
1138 {
-
1139 auto const& pubCollection = publisherLists_[pubKey];
-
1140 if (pubCollection.maxSequence &&
-
1141 (result == ListDisposition::same_sequence ||
-
1142 result == ListDisposition::known_sequence))
-
1143 {
-
1144 // We've seen something valid list for this publisher
-
1145 // already, so return what we know about it.
-
1146 return PublisherListStats{
-
1147 result,
-
1148 pubKey,
-
1149 pubCollection.status,
-
1150 *pubCollection.maxSequence};
-
1151 }
-
1152 }
-
1153 return PublisherListStats{result};
-
1154 }
-
1155
-
1156 // Update publisher's list
-
1157 auto& pubCollection = publisherLists_[pubKey];
-
1158 auto const sequence = list[jss::sequence].asUInt();
-
1159 auto const accepted =
-
1160 (result == ListDisposition::accepted ||
-
1161 result == ListDisposition::expired);
-
1162
-
1163 if (accepted)
-
1164 pubCollection.status = result == ListDisposition::accepted
-
1165 ? PublisherStatus::available
-
1166 : PublisherStatus::expired;
-
1167 pubCollection.rawManifest = globalManifest;
-
1168 if (!pubCollection.maxSequence || sequence > *pubCollection.maxSequence)
-
1169 pubCollection.maxSequence = sequence;
-
1170
-
1171 Json::Value const& newList = list[jss::validators];
-
1172 std::vector<PublicKey> oldList;
-
1173 if (accepted && pubCollection.remaining.count(sequence) != 0)
-
1174 {
-
1175 // We've seen this list before and stored it in "remaining". The
-
1176 // normal expected process is that the processed list would have
-
1177 // already been moved in to "current" by "updateTrusted()", but race
-
1178 // conditions are possible, or the node may have lost sync, so do
-
1179 // some of that work here.
-
1180 auto& publisher = pubCollection.current;
-
1181 // Copy the old validator list
-
1182 oldList = std::move(pubCollection.current.list);
-
1183 // Move the publisher info from "remaining" to "current"
-
1184 publisher = std::move(pubCollection.remaining[sequence]);
-
1185 // Remove the entry in "remaining"
-
1186 pubCollection.remaining.erase(sequence);
-
1187 // Done
-
1188 XRPL_ASSERT(
-
1189 publisher.sequence == sequence,
-
1190 "ripple::ValidatorList::applyList : publisher sequence match");
-
1191 }
-
1192 else
-
1193 {
-
1194 auto& publisher = accepted ? pubCollection.current
-
1195 : pubCollection.remaining[sequence];
-
1196 publisher.sequence = sequence;
-
1197 publisher.validFrom = TimeKeeper::time_point{TimeKeeper::duration{
-
1198 list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
-
1199 publisher.validUntil = TimeKeeper::time_point{
-
1200 TimeKeeper::duration{list[jss::expiration].asUInt()}};
-
1201 publisher.siteUri = std::move(siteUri);
-
1202 publisher.rawBlob = blob;
-
1203 publisher.rawSignature = signature;
-
1204 publisher.rawManifest = localManifest;
-
1205 if (hash)
-
1206 publisher.hash = *hash;
-
1207
-
1208 std::vector<PublicKey>& publisherList = publisher.list;
-
1209 std::vector<std::string>& manifests = publisher.manifests;
-
1210
-
1211 // Copy the old validator list
-
1212 oldList = std::move(publisherList);
-
1213 // Build the new validator list from "newList"
-
1214 publisherList.clear();
-
1215 publisherList.reserve(newList.size());
-
1216 for (auto const& val : newList)
-
1217 {
-
1218 if (val.isObject() && val.isMember(jss::validation_public_key) &&
-
1219 val[jss::validation_public_key].isString())
-
1220 {
-
1221 std::optional<Blob> const ret =
-
1222 strUnHex(val[jss::validation_public_key].asString());
-
1223
-
1224 if (!ret || !publicKeyType(makeSlice(*ret)))
-
1225 {
-
1226 JLOG(j_.error())
-
1227 << "Invalid node identity: "
-
1228 << val[jss::validation_public_key].asString();
-
1229 }
-
1230 else
-
1231 {
-
1232 publisherList.push_back(
-
1233 PublicKey(Slice{ret->data(), ret->size()}));
-
1234 }
-
1235
-
1236 if (val.isMember(jss::manifest) &&
-
1237 val[jss::manifest].isString())
-
1238 manifests.push_back(val[jss::manifest].asString());
-
1239 }
-
1240 }
-
1241
-
1242 // Standardize the list order by sorting
-
1243 std::sort(publisherList.begin(), publisherList.end());
-
1244 }
-
1245 // If this publisher has ever sent a more updated version than the one
-
1246 // in this file, keep it. This scenario is unlikely, but legal.
-
1247 pubCollection.rawVersion = std::max(pubCollection.rawVersion, version);
-
1248 if (!pubCollection.remaining.empty())
-
1249 {
-
1250 // If there are any pending VLs, then this collection must be at least
-
1251 // version 2.
-
1252 pubCollection.rawVersion = std::max(pubCollection.rawVersion, 2u);
-
1253 }
-
1254
-
1255 PublisherListStats const applyResult{
-
1256 result, pubKey, pubCollection.status, *pubCollection.maxSequence};
-
1257
-
1258 if (accepted)
-
1259 {
-
1260 updatePublisherList(pubKey, pubCollection.current, oldList, lock);
-
1261 }
-
1262
-
1263 return applyResult;
-
1264}
-
1265
-
1266std::vector<std::string>
-
1267ValidatorList::loadLists()
-
1268{
-
1269 using namespace std::string_literals;
-
1270 using namespace boost::filesystem;
-
1271 using namespace boost::system::errc;
-
1272
-
1273 std::lock_guard lock{mutex_};
-
1274
-
1275 std::vector<std::string> sites;
-
1276 sites.reserve(publisherLists_.size());
-
1277 for (auto const& [pubKey, publisherCollection] : publisherLists_)
-
1278 {
-
1279 boost::system::error_code ec;
-
1280
-
1281 if (publisherCollection.status == PublisherStatus::available)
-
1282 continue;
-
1283
-
1284 boost::filesystem::path const filename = getCacheFileName(lock, pubKey);
-
1285
-
1286 auto const fullPath{canonical(filename, ec)};
-
1287 if (ec)
-
1288 continue;
+
1133}
+
1134
+
1135ValidatorList::PublisherListStats
+
1136ValidatorList::applyList(
+
1137 std::string const& globalManifest,
+
1138 std::optional<std::string> const& localManifest,
+
1139 std::string const& blob,
+
1140 std::string const& signature,
+
1141 std::uint32_t version,
+
1142 std::string siteUri,
+
1143 std::optional<uint256> const& hash,
+
1144 ValidatorList::lock_guard const& lock)
+
1145{
+
1146 using namespace std::string_literals;
+
1147
+
1148 Json::Value list;
+
1149 auto const& manifest = localManifest ? *localManifest : globalManifest;
+
1150 auto [result, pubKeyOpt] = verify(lock, list, manifest, blob, signature);
+
1151
+
1152 if (!pubKeyOpt)
+
1153 {
+
1154 JLOG(j_.info()) << "ValidatorList::applyList unable to retrieve the "
+
1155 "master public key from the verify function\n";
+
1156 return PublisherListStats{result};
+
1157 }
+
1158
+
1159 if (!publicKeyType(*pubKeyOpt))
+
1160 {
+
1161 JLOG(j_.info()) << "ValidatorList::applyList Invalid Public Key type"
+
1162 " retrieved from the verify function\n ";
+
1163 return PublisherListStats{result};
+
1164 }
+
1165
+
1166 PublicKey pubKey = *pubKeyOpt;
+
1167 if (result > ListDisposition::pending)
+
1168 {
+
1169 if (publisherLists_.count(pubKey))
+
1170 {
+
1171 auto const& pubCollection = publisherLists_[pubKey];
+
1172 if (pubCollection.maxSequence &&
+
1173 (result == ListDisposition::same_sequence ||
+
1174 result == ListDisposition::known_sequence))
+
1175 {
+
1176 // We've seen something valid list for this publisher
+
1177 // already, so return what we know about it.
+
1178 return PublisherListStats{
+
1179 result,
+
1180 pubKey,
+
1181 pubCollection.status,
+
1182 *pubCollection.maxSequence};
+
1183 }
+
1184 }
+
1185 return PublisherListStats{result};
+
1186 }
+
1187
+
1188 // Update publisher's list
+
1189 auto& pubCollection = publisherLists_[pubKey];
+
1190 auto const sequence = list[jss::sequence].asUInt();
+
1191 auto const accepted =
+
1192 (result == ListDisposition::accepted ||
+
1193 result == ListDisposition::expired);
+
1194
+
1195 if (accepted)
+
1196 pubCollection.status = result == ListDisposition::accepted
+
1197 ? PublisherStatus::available
+
1198 : PublisherStatus::expired;
+
1199 pubCollection.rawManifest = globalManifest;
+
1200 if (!pubCollection.maxSequence || sequence > *pubCollection.maxSequence)
+
1201 pubCollection.maxSequence = sequence;
+
1202
+
1203 Json::Value const& newList = list[jss::validators];
+
1204 std::vector<PublicKey> oldList;
+
1205 if (accepted && pubCollection.remaining.count(sequence) != 0)
+
1206 {
+
1207 // We've seen this list before and stored it in "remaining". The
+
1208 // normal expected process is that the processed list would have
+
1209 // already been moved in to "current" by "updateTrusted()", but race
+
1210 // conditions are possible, or the node may have lost sync, so do
+
1211 // some of that work here.
+
1212 auto& publisher = pubCollection.current;
+
1213 // Copy the old validator list
+
1214 oldList = std::move(pubCollection.current.list);
+
1215 // Move the publisher info from "remaining" to "current"
+
1216 publisher = std::move(pubCollection.remaining[sequence]);
+
1217 // Remove the entry in "remaining"
+
1218 pubCollection.remaining.erase(sequence);
+
1219 // Done
+
1220 XRPL_ASSERT(
+
1221 publisher.sequence == sequence,
+
1222 "ripple::ValidatorList::applyList : publisher sequence match");
+
1223 }
+
1224 else
+
1225 {
+
1226 auto& publisher = accepted ? pubCollection.current
+
1227 : pubCollection.remaining[sequence];
+
1228 publisher.sequence = sequence;
+
1229 publisher.validFrom = TimeKeeper::time_point{TimeKeeper::duration{
+
1230 list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
+
1231 publisher.validUntil = TimeKeeper::time_point{
+
1232 TimeKeeper::duration{list[jss::expiration].asUInt()}};
+
1233 publisher.siteUri = std::move(siteUri);
+
1234 publisher.rawBlob = blob;
+
1235 publisher.rawSignature = signature;
+
1236 publisher.rawManifest = localManifest;
+
1237 if (hash)
+
1238 publisher.hash = *hash;
+
1239
+
1240 std::vector<PublicKey>& publisherList = publisher.list;
+
1241 std::vector<std::string>& manifests = publisher.manifests;
+
1242
+
1243 // Copy the old validator list
+
1244 oldList = std::move(publisherList);
+
1245 // Build the new validator list from "newList"
+
1246 publisherList.clear();
+
1247 publisherList.reserve(newList.size());
+
1248 for (auto const& val : newList)
+
1249 {
+
1250 if (val.isObject() && val.isMember(jss::validation_public_key) &&
+
1251 val[jss::validation_public_key].isString())
+
1252 {
+
1253 std::optional<Blob> const ret =
+
1254 strUnHex(val[jss::validation_public_key].asString());
+
1255
+
1256 if (!ret || !publicKeyType(makeSlice(*ret)))
+
1257 {
+
1258 JLOG(j_.error())
+
1259 << "Invalid node identity: "
+
1260 << val[jss::validation_public_key].asString();
+
1261 }
+
1262 else
+
1263 {
+
1264 publisherList.push_back(
+
1265 PublicKey(Slice{ret->data(), ret->size()}));
+
1266 }
+
1267
+
1268 if (val.isMember(jss::manifest) &&
+
1269 val[jss::manifest].isString())
+
1270 manifests.push_back(val[jss::manifest].asString());
+
1271 }
+
1272 }
+
1273
+
1274 // Standardize the list order by sorting
+
1275 std::sort(publisherList.begin(), publisherList.end());
+
1276 }
+
1277 // If this publisher has ever sent a more updated version than the one
+
1278 // in this file, keep it. This scenario is unlikely, but legal.
+
1279 pubCollection.rawVersion = std::max(pubCollection.rawVersion, version);
+
1280 if (!pubCollection.remaining.empty())
+
1281 {
+
1282 // If there are any pending VLs, then this collection must be at least
+
1283 // version 2.
+
1284 pubCollection.rawVersion = std::max(pubCollection.rawVersion, 2u);
+
1285 }
+
1286
+
1287 PublisherListStats const applyResult{
+
1288 result, pubKey, pubCollection.status, *pubCollection.maxSequence};
1289
-
1290 auto size = file_size(fullPath, ec);
-
1291 if (!ec && !size)
-
1292 {
-
1293 // Treat an empty file as a missing file, because
-
1294 // nobody else is going to write it.
-
1295 ec = make_error_code(no_such_file_or_directory);
-
1296 }
-
1297 if (ec)
-
1298 continue;
-
1299
-
1300 std::string const prefix = [&fullPath]() {
-
1301#if _MSC_VER // MSVC: Windows paths need a leading / added
-
1302 {
-
1303 return fullPath.root_path() == "/"s ? "file://" : "file:///";
-
1304 }
-
1305#else
-
1306 {
-
1307 (void)fullPath;
-
1308 return "file://";
-
1309 }
-
1310#endif
-
1311 }();
-
1312 sites.emplace_back(prefix + fullPath.string());
-
1313 }
-
1314
-
1315 // Then let the ValidatorSites do the rest of the work.
-
1316 return sites;
-
1317}
-
1318
-
1319// The returned PublicKey value is read from the manifest. Manifests do not
-
1320// contain the default-constructed public keys
-
1321std::pair<ListDisposition, std::optional<PublicKey>>
-
1322ValidatorList::verify(
-
1323 ValidatorList::lock_guard const& lock,
-
1324 Json::Value& list,
-
1325 std::string const& manifest,
-
1326 std::string const& blob,
-
1327 std::string const& signature)
-
1328{
-
1329 auto m = deserializeManifest(base64_decode(manifest));
-
1330
-
1331 if (!m || !publisherLists_.count(m->masterKey))
-
1332 return {ListDisposition::untrusted, {}};
-
1333
-
1334 PublicKey masterPubKey = m->masterKey;
-
1335 auto const revoked = m->revoked();
-
1336
-
1337 auto const result = publisherManifests_.applyManifest(std::move(*m));
-
1338
-
1339 if (revoked && result == ManifestDisposition::accepted)
-
1340 {
-
1341 removePublisherList(lock, masterPubKey, PublisherStatus::revoked);
-
1342 // If the manifest is revoked, no future list is valid either
-
1343 publisherLists_[masterPubKey].remaining.clear();
-
1344 }
-
1345
-
1346 auto const signingKey = publisherManifests_.getSigningKey(masterPubKey);
-
1347
-
1348 if (revoked || !signingKey || result == ManifestDisposition::invalid)
-
1349 return {ListDisposition::untrusted, masterPubKey};
+
1290 if (accepted)
+
1291 {
+
1292 updatePublisherList(pubKey, pubCollection.current, oldList, lock);
+
1293 }
+
1294
+
1295 return applyResult;
+
1296}
+
1297
+
1298std::vector<std::string>
+
1299ValidatorList::loadLists()
+
1300{
+
1301 using namespace std::string_literals;
+
1302 using namespace boost::filesystem;
+
1303 using namespace boost::system::errc;
+
1304
+
1305 std::lock_guard lock{mutex_};
+
1306
+
1307 std::vector<std::string> sites;
+
1308 sites.reserve(publisherLists_.size());
+
1309 for (auto const& [pubKey, publisherCollection] : publisherLists_)
+
1310 {
+
1311 boost::system::error_code ec;
+
1312
+
1313 if (publisherCollection.status == PublisherStatus::available)
+
1314 continue;
+
1315
+
1316 boost::filesystem::path const filename = getCacheFileName(lock, pubKey);
+
1317
+
1318 auto const fullPath{canonical(filename, ec)};
+
1319 if (ec)
+
1320 continue;
+
1321
+
1322 auto size = file_size(fullPath, ec);
+
1323 if (!ec && !size)
+
1324 {
+
1325 // Treat an empty file as a missing file, because
+
1326 // nobody else is going to write it.
+
1327 ec = make_error_code(no_such_file_or_directory);
+
1328 }
+
1329 if (ec)
+
1330 continue;
+
1331
+
1332 std::string const prefix = [&fullPath]() {
+
1333#if _MSC_VER // MSVC: Windows paths need a leading / added
+
1334 {
+
1335 return fullPath.root_path() == "/"s ? "file://" : "file:///";
+
1336 }
+
1337#else
+
1338 {
+
1339 (void)fullPath;
+
1340 return "file://";
+
1341 }
+
1342#endif
+
1343 }();
+
1344 sites.emplace_back(prefix + fullPath.string());
+
1345 }
+
1346
+
1347 // Then let the ValidatorSites do the rest of the work.
+
1348 return sites;
+
1349}
1350
-
1351 auto const sig = strUnHex(signature);
-
1352 auto const data = base64_decode(blob);
-
1353 if (!sig || !ripple::verify(*signingKey, makeSlice(data), makeSlice(*sig)))
-
1354 return {ListDisposition::invalid, masterPubKey};
-
1355
-
1356 Json::Reader r;
-
1357 if (!r.parse(data, list))
-
1358 return {ListDisposition::invalid, masterPubKey};
-
1359
-
1360 if (list.isMember(jss::sequence) && list[jss::sequence].isInt() &&
-
1361 list.isMember(jss::expiration) && list[jss::expiration].isInt() &&
-
1362 (!list.isMember(jss::effective) || list[jss::effective].isInt()) &&
-
1363 list.isMember(jss::validators) && list[jss::validators].isArray())
-
1364 {
-
1365 auto const sequence = list[jss::sequence].asUInt();
-
1366 auto const validFrom = TimeKeeper::time_point{TimeKeeper::duration{
-
1367 list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
-
1368 auto const validUntil = TimeKeeper::time_point{
-
1369 TimeKeeper::duration{list[jss::expiration].asUInt()}};
-
1370 auto const now = timeKeeper_.now();
-
1371 auto const& listCollection = publisherLists_[masterPubKey];
-
1372 if (validUntil <= validFrom)
-
1373 return {ListDisposition::invalid, masterPubKey};
-
1374 else if (sequence < listCollection.current.sequence)
-
1375 return {ListDisposition::stale, masterPubKey};
-
1376 else if (sequence == listCollection.current.sequence)
-
1377 return {ListDisposition::same_sequence, masterPubKey};
-
1378 else if (validUntil <= now)
-
1379 return {ListDisposition::expired, masterPubKey};
-
1380 else if (validFrom > now)
-
1381 // Not yet valid. Return pending if one of the following is true
-
1382 // * There's no maxSequence, indicating this is the first blob seen
-
1383 // for this publisher
-
1384 // * The sequence is larger than the maxSequence, indicating this
-
1385 // blob is new
-
1386 // * There's no entry for this sequence AND this blob is valid
-
1387 // before the last blob, indicating blobs may be processing out of
-
1388 // order. This may result in some duplicated processing, but
-
1389 // prevents the risk of missing valid data. Else return
-
1390 // known_sequence
-
1391 return !listCollection.maxSequence ||
-
1392 sequence > *listCollection.maxSequence ||
-
1393 (listCollection.remaining.count(sequence) == 0 &&
-
1394 validFrom < listCollection.remaining
-
1395 .at(*listCollection.maxSequence)
-
1396 .validFrom)
-
1397 ? std::make_pair(ListDisposition::pending, masterPubKey)
-
1398 : std::make_pair(ListDisposition::known_sequence, masterPubKey);
-
1399 }
-
1400 else
-
1401 {
-
1402 return {ListDisposition::invalid, masterPubKey};
-
1403 }
-
1404
-
1405 return {ListDisposition::accepted, masterPubKey};
-
1406}
-
1407
-
1408bool
-
1409ValidatorList::listed(PublicKey const& identity) const
-
1410{
-
1411 std::shared_lock read_lock{mutex_};
-
1412
-
1413 auto const pubKey = validatorManifests_.getMasterKey(identity);
-
1414 return keyListings_.find(pubKey) != keyListings_.end();
-
1415}
-
1416
-
1417bool
-
1418ValidatorList::trusted(
-
1419 ValidatorList::shared_lock const&,
-
1420 PublicKey const& identity) const
-
1421{
-
1422 auto const pubKey = validatorManifests_.getMasterKey(identity);
-
1423 return trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end();
-
1424}
-
1425
-
1426bool
-
1427ValidatorList::trusted(PublicKey const& identity) const
-
1428{
-
1429 std::shared_lock read_lock{mutex_};
-
1430 return trusted(read_lock, identity);
-
1431}
-
1432
-
1433std::optional<PublicKey>
-
1434ValidatorList::getListedKey(PublicKey const& identity) const
-
1435{
-
1436 std::shared_lock read_lock{mutex_};
-
1437
-
1438 auto const pubKey = validatorManifests_.getMasterKey(identity);
-
1439 if (keyListings_.find(pubKey) != keyListings_.end())
-
1440 return pubKey;
-
1441 return std::nullopt;
-
1442}
-
1443
-
1444std::optional<PublicKey>
-
1445ValidatorList::getTrustedKey(
-
1446 ValidatorList::shared_lock const&,
-
1447 PublicKey const& identity) const
-
1448{
-
1449 auto const pubKey = validatorManifests_.getMasterKey(identity);
-
1450 if (trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end())
-
1451 return pubKey;
-
1452 return std::nullopt;
-
1453}
-
1454
-
1455std::optional<PublicKey>
-
1456ValidatorList::getTrustedKey(PublicKey const& identity) const
-
1457{
-
1458 std::shared_lock read_lock{mutex_};
-
1459
-
1460 return getTrustedKey(read_lock, identity);
-
1461}
-
1462
-
1463bool
-
1464ValidatorList::trustedPublisher(PublicKey const& identity) const
-
1465{
-
1466 std::shared_lock read_lock{mutex_};
-
1467 return identity.size() && publisherLists_.count(identity) &&
-
1468 publisherLists_.at(identity).status < PublisherStatus::revoked;
-
1469}
-
1470
-
1471std::optional<PublicKey>
-
1472ValidatorList::localPublicKey() const
-
1473{
-
1474 std::shared_lock read_lock{mutex_};
-
1475 return localPubKey_;
-
1476}
-
1477
-
1478bool
-
1479ValidatorList::removePublisherList(
-
1480 ValidatorList::lock_guard const&,
-
1481 PublicKey const& publisherKey,
-
1482 PublisherStatus reason)
-
1483{
-
1484 XRPL_ASSERT(
-
1485 reason != PublisherStatus::available &&
-
1486 reason != PublisherStatus::unavailable,
-
1487 "ripple::ValidatorList::removePublisherList : valid reason input");
-
1488 auto const iList = publisherLists_.find(publisherKey);
-
1489 if (iList == publisherLists_.end())
-
1490 return false;
+
1351// The returned PublicKey value is read from the manifest. Manifests do not
+
1352// contain the default-constructed public keys
+
1353std::pair<ListDisposition, std::optional<PublicKey>>
+
1354ValidatorList::verify(
+
1355 ValidatorList::lock_guard const& lock,
+
1356 Json::Value& list,
+
1357 std::string const& manifest,
+
1358 std::string const& blob,
+
1359 std::string const& signature)
+
1360{
+
1361 auto m = deserializeManifest(base64_decode(manifest));
+
1362
+
1363 if (!m || !publisherLists_.count(m->masterKey))
+
1364 return {ListDisposition::untrusted, {}};
+
1365
+
1366 PublicKey masterPubKey = m->masterKey;
+
1367 auto const revoked = m->revoked();
+
1368
+
1369 auto const result = publisherManifests_.applyManifest(std::move(*m));
+
1370
+
1371 if (revoked && result == ManifestDisposition::accepted)
+
1372 {
+
1373 removePublisherList(lock, masterPubKey, PublisherStatus::revoked);
+
1374 // If the manifest is revoked, no future list is valid either
+
1375 publisherLists_[masterPubKey].remaining.clear();
+
1376 }
+
1377
+
1378 auto const signingKey = publisherManifests_.getSigningKey(masterPubKey);
+
1379
+
1380 if (revoked || !signingKey || result == ManifestDisposition::invalid)
+
1381 return {ListDisposition::untrusted, masterPubKey};
+
1382
+
1383 auto const sig = strUnHex(signature);
+
1384 auto const data = base64_decode(blob);
+
1385 if (!sig || !ripple::verify(*signingKey, makeSlice(data), makeSlice(*sig)))
+
1386 return {ListDisposition::invalid, masterPubKey};
+
1387
+
1388 Json::Reader r;
+
1389 if (!r.parse(data, list))
+
1390 return {ListDisposition::invalid, masterPubKey};
+
1391
+
1392 if (list.isMember(jss::sequence) && list[jss::sequence].isInt() &&
+
1393 list.isMember(jss::expiration) && list[jss::expiration].isInt() &&
+
1394 (!list.isMember(jss::effective) || list[jss::effective].isInt()) &&
+
1395 list.isMember(jss::validators) && list[jss::validators].isArray())
+
1396 {
+
1397 auto const sequence = list[jss::sequence].asUInt();
+
1398 auto const validFrom = TimeKeeper::time_point{TimeKeeper::duration{
+
1399 list.isMember(jss::effective) ? list[jss::effective].asUInt() : 0}};
+
1400 auto const validUntil = TimeKeeper::time_point{
+
1401 TimeKeeper::duration{list[jss::expiration].asUInt()}};
+
1402 auto const now = timeKeeper_.now();
+
1403 auto const& listCollection = publisherLists_[masterPubKey];
+
1404 if (validUntil <= validFrom)
+
1405 return {ListDisposition::invalid, masterPubKey};
+
1406 else if (sequence < listCollection.current.sequence)
+
1407 return {ListDisposition::stale, masterPubKey};
+
1408 else if (sequence == listCollection.current.sequence)
+
1409 return {ListDisposition::same_sequence, masterPubKey};
+
1410 else if (validUntil <= now)
+
1411 return {ListDisposition::expired, masterPubKey};
+
1412 else if (validFrom > now)
+
1413 // Not yet valid. Return pending if one of the following is true
+
1414 // * There's no maxSequence, indicating this is the first blob seen
+
1415 // for this publisher
+
1416 // * The sequence is larger than the maxSequence, indicating this
+
1417 // blob is new
+
1418 // * There's no entry for this sequence AND this blob is valid
+
1419 // before the last blob, indicating blobs may be processing out of
+
1420 // order. This may result in some duplicated processing, but
+
1421 // prevents the risk of missing valid data. Else return
+
1422 // known_sequence
+
1423 return !listCollection.maxSequence ||
+
1424 sequence > *listCollection.maxSequence ||
+
1425 (listCollection.remaining.count(sequence) == 0 &&
+
1426 validFrom < listCollection.remaining
+
1427 .at(*listCollection.maxSequence)
+
1428 .validFrom)
+
1429 ? std::make_pair(ListDisposition::pending, masterPubKey)
+
1430 : std::make_pair(ListDisposition::known_sequence, masterPubKey);
+
1431 }
+
1432 else
+
1433 {
+
1434 return {ListDisposition::invalid, masterPubKey};
+
1435 }
+
1436
+
1437 return {ListDisposition::accepted, masterPubKey};
+
1438}
+
1439
+
1440bool
+
1441ValidatorList::listed(PublicKey const& identity) const
+
1442{
+
1443 std::shared_lock read_lock{mutex_};
+
1444
+
1445 auto const pubKey = validatorManifests_.getMasterKey(identity);
+
1446 return keyListings_.find(pubKey) != keyListings_.end();
+
1447}
+
1448
+
1449bool
+
1450ValidatorList::trusted(
+
1451 ValidatorList::shared_lock const&,
+
1452 PublicKey const& identity) const
+
1453{
+
1454 auto const pubKey = validatorManifests_.getMasterKey(identity);
+
1455 return trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end();
+
1456}
+
1457
+
1458bool
+
1459ValidatorList::trusted(PublicKey const& identity) const
+
1460{
+
1461 std::shared_lock read_lock{mutex_};
+
1462 return trusted(read_lock, identity);
+
1463}
+
1464
+
1465std::optional<PublicKey>
+
1466ValidatorList::getListedKey(PublicKey const& identity) const
+
1467{
+
1468 std::shared_lock read_lock{mutex_};
+
1469
+
1470 auto const pubKey = validatorManifests_.getMasterKey(identity);
+
1471 if (keyListings_.find(pubKey) != keyListings_.end())
+
1472 return pubKey;
+
1473 return std::nullopt;
+
1474}
+
1475
+
1476std::optional<PublicKey>
+
1477ValidatorList::getTrustedKey(
+
1478 ValidatorList::shared_lock const&,
+
1479 PublicKey const& identity) const
+
1480{
+
1481 auto const pubKey = validatorManifests_.getMasterKey(identity);
+
1482 if (trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end())
+
1483 return pubKey;
+
1484 return std::nullopt;
+
1485}
+
1486
+
1487std::optional<PublicKey>
+
1488ValidatorList::getTrustedKey(PublicKey const& identity) const
+
1489{
+
1490 std::shared_lock read_lock{mutex_};
1491
-
1492 JLOG(j_.debug()) << "Removing validator list for publisher "
-
1493 << strHex(publisherKey);
+
1492 return getTrustedKey(read_lock, identity);
+
1493}
1494
-
1495 for (auto const& val : iList->second.current.list)
-
1496 {
-
1497 auto const& iVal = keyListings_.find(val);
-
1498 if (iVal == keyListings_.end())
-
1499 continue;
-
1500
-
1501 if (iVal->second <= 1)
-
1502 keyListings_.erase(iVal);
-
1503 else
-
1504 --iVal->second;
-
1505 }
-
1506
-
1507 iList->second.current.list.clear();
-
1508 iList->second.status = reason;
+
1495bool
+
1496ValidatorList::trustedPublisher(PublicKey const& identity) const
+
1497{
+
1498 std::shared_lock read_lock{mutex_};
+
1499 return identity.size() && publisherLists_.count(identity) &&
+
1500 publisherLists_.at(identity).status < PublisherStatus::revoked;
+
1501}
+
1502
+
1503std::optional<PublicKey>
+
1504ValidatorList::localPublicKey() const
+
1505{
+
1506 std::shared_lock read_lock{mutex_};
+
1507 return localPubKey_;
+
1508}
1509
-
1510 return true;
-
1511}
-
1512
-
1513std::size_t
-
1514ValidatorList::count(ValidatorList::shared_lock const&) const
-
1515{
-
1516 return publisherLists_.size() + (localPublisherList.list.size() > 0);
-
1517}
-
1518
-
1519std::size_t
-
1520ValidatorList::count() const
-
1521{
-
1522 std::shared_lock read_lock{mutex_};
-
1523 return count(read_lock);
-
1524}
-
1525
-
1526std::optional<TimeKeeper::time_point>
-
1527ValidatorList::expires(ValidatorList::shared_lock const&) const
-
1528{
-
1529 std::optional<TimeKeeper::time_point> res{};
-
1530 for (auto const& [_, collection] : publisherLists_)
-
1531 {
-
1532 // Unfetched
-
1533 auto const& current = collection.current;
-
1534 if (current.validUntil == TimeKeeper::time_point{})
-
1535 {
-
1536 return std::nullopt;
-
1537 }
+
1510bool
+
1511ValidatorList::removePublisherList(
+
1512 ValidatorList::lock_guard const&,
+
1513 PublicKey const& publisherKey,
+
1514 PublisherStatus reason)
+
1515{
+
1516 XRPL_ASSERT(
+
1517 reason != PublisherStatus::available &&
+
1518 reason != PublisherStatus::unavailable,
+
1519 "ripple::ValidatorList::removePublisherList : valid reason input");
+
1520 auto const iList = publisherLists_.find(publisherKey);
+
1521 if (iList == publisherLists_.end())
+
1522 return false;
+
1523
+
1524 JLOG(j_.debug()) << "Removing validator list for publisher "
+
1525 << strHex(publisherKey);
+
1526
+
1527 for (auto const& val : iList->second.current.list)
+
1528 {
+
1529 auto const& iVal = keyListings_.find(val);
+
1530 if (iVal == keyListings_.end())
+
1531 continue;
+
1532
+
1533 if (iVal->second <= 1)
+
1534 keyListings_.erase(iVal);
+
1535 else
+
1536 --iVal->second;
+
1537 }
1538
-
1539 // Find the latest validUntil in a chain where the next validFrom
-
1540 // overlaps with the previous validUntil. applyLists has already cleaned
-
1541 // up the list so the validFrom dates are guaranteed increasing.
-
1542 auto chainedExpiration = current.validUntil;
-
1543 for (auto const& [sequence, check] : collection.remaining)
-
1544 {
-
1545 (void)sequence;
-
1546 if (check.validFrom <= chainedExpiration)
-
1547 chainedExpiration = check.validUntil;
-
1548 else
-
1549 break;
-
1550 }
-
1551
-
1552 // Earliest
-
1553 if (!res || chainedExpiration < *res)
-
1554 {
-
1555 res = chainedExpiration;
-
1556 }
-
1557 }
-
1558
-
1559 if (localPublisherList.list.size() > 0)
-
1560 {
-
1561 PublisherList collection = localPublisherList;
-
1562 // Unfetched
-
1563 auto const& current = collection;
-
1564 auto chainedExpiration = current.validUntil;
-
1565
-
1566 // Earliest
-
1567 if (!res || chainedExpiration < *res)
-
1568 {
-
1569 res = chainedExpiration;
-
1570 }
-
1571 }
-
1572 return res;
-
1573}
-
1574
-
1575std::optional<TimeKeeper::time_point>
-
1576ValidatorList::expires() const
-
1577{
-
1578 std::shared_lock read_lock{mutex_};
-
1579 return expires(read_lock);
-
1580}
-
1581
-
1582Json::Value
-
1583ValidatorList::getJson() const
-
1584{
-
1585 Json::Value res(Json::objectValue);
-
1586
-
1587 std::shared_lock read_lock{mutex_};
-
1588
-
1589 res[jss::validation_quorum] = static_cast<Json::UInt>(quorum_);
+
1539 iList->second.current.list.clear();
+
1540 iList->second.status = reason;
+
1541
+
1542 return true;
+
1543}
+
1544
+
1545std::size_t
+
1546ValidatorList::count(ValidatorList::shared_lock const&) const
+
1547{
+
1548 return publisherLists_.size() + (localPublisherList.list.size() > 0);
+
1549}
+
1550
+
1551std::size_t
+
1552ValidatorList::count() const
+
1553{
+
1554 std::shared_lock read_lock{mutex_};
+
1555 return count(read_lock);
+
1556}
+
1557
+
1558std::optional<TimeKeeper::time_point>
+
1559ValidatorList::expires(ValidatorList::shared_lock const&) const
+
1560{
+
1561 std::optional<TimeKeeper::time_point> res{};
+
1562 for (auto const& [_, collection] : publisherLists_)
+
1563 {
+
1564 // Unfetched
+
1565 auto const& current = collection.current;
+
1566 if (current.validUntil == TimeKeeper::time_point{})
+
1567 {
+
1568 return std::nullopt;
+
1569 }
+
1570
+
1571 // Find the latest validUntil in a chain where the next validFrom
+
1572 // overlaps with the previous validUntil. applyLists has already cleaned
+
1573 // up the list so the validFrom dates are guaranteed increasing.
+
1574 auto chainedExpiration = current.validUntil;
+
1575 for (auto const& [sequence, check] : collection.remaining)
+
1576 {
+
1577 (void)sequence;
+
1578 if (check.validFrom <= chainedExpiration)
+
1579 chainedExpiration = check.validUntil;
+
1580 else
+
1581 break;
+
1582 }
+
1583
+
1584 // Earliest
+
1585 if (!res || chainedExpiration < *res)
+
1586 {
+
1587 res = chainedExpiration;
+
1588 }
+
1589 }
1590
-
1591 {
-
1592 auto& x = (res[jss::validator_list] = Json::objectValue);
-
1593
-
1594 x[jss::count] = static_cast<Json::UInt>(count(read_lock));
-
1595
-
1596 if (auto when = expires(read_lock))
-
1597 {
-
1598 if (*when == TimeKeeper::time_point::max())
-
1599 {
-
1600 x[jss::expiration] = "never";
-
1601 x[jss::status] = "active";
-
1602 }
-
1603 else
-
1604 {
-
1605 x[jss::expiration] = to_string(*when);
+
1591 if (localPublisherList.list.size() > 0)
+
1592 {
+
1593 PublisherList collection = localPublisherList;
+
1594 // Unfetched
+
1595 auto const& current = collection;
+
1596 auto chainedExpiration = current.validUntil;
+
1597
+
1598 // Earliest
+
1599 if (!res || chainedExpiration < *res)
+
1600 {
+
1601 res = chainedExpiration;
+
1602 }
+
1603 }
+
1604 return res;
+
1605}
1606
-
1607 if (*when > timeKeeper_.now())
-
1608 x[jss::status] = "active";
-
1609 else
-
1610 x[jss::status] = "expired";
-
1611 }
-
1612 }
-
1613 else
-
1614 {
-
1615 x[jss::status] = "unknown";
-
1616 x[jss::expiration] = "unknown";
-
1617 }
-
1618 }
-
1619
-
1620 // Validator keys listed in the local config file
-
1621 Json::Value& jLocalStaticKeys =
-
1622 (res[jss::local_static_keys] = Json::arrayValue);
-
1623
-
1624 for (auto const& key : localPublisherList.list)
-
1625 jLocalStaticKeys.append(toBase58(TokenType::NodePublic, key));
-
1626
-
1627 // Publisher lists
-
1628 Json::Value& jPublisherLists =
-
1629 (res[jss::publisher_lists] = Json::arrayValue);
-
1630 for (auto const& [publicKey, pubCollection] : publisherLists_)
-
1631 {
-
1632 Json::Value& curr = jPublisherLists.append(Json::objectValue);
-
1633 curr[jss::pubkey_publisher] = strHex(publicKey);
-
1634 curr[jss::available] =
-
1635 pubCollection.status == PublisherStatus::available;
-
1636
-
1637 auto appendList = [](PublisherList const& publisherList,
-
1638 Json::Value& target) {
-
1639 target[jss::uri] = publisherList.siteUri;
-
1640 if (publisherList.validUntil != TimeKeeper::time_point{})
-
1641 {
-
1642 target[jss::seq] =
-
1643 static_cast<Json::UInt>(publisherList.sequence);
-
1644 target[jss::expiration] = to_string(publisherList.validUntil);
-
1645 }
-
1646 if (publisherList.validFrom != TimeKeeper::time_point{})
-
1647 target[jss::effective] = to_string(publisherList.validFrom);
-
1648 Json::Value& keys = (target[jss::list] = Json::arrayValue);
-
1649 for (auto const& key : publisherList.list)
-
1650 {
-
1651 keys.append(toBase58(TokenType::NodePublic, key));
-
1652 }
-
1653 };
-
1654 {
-
1655 auto const& current = pubCollection.current;
-
1656 appendList(current, curr);
-
1657 if (current.validUntil != TimeKeeper::time_point{})
-
1658 {
-
1659 curr[jss::version] = pubCollection.rawVersion;
-
1660 }
-
1661 }
-
1662
-
1663 Json::Value remaining(Json::arrayValue);
-
1664 for (auto const& [sequence, future] : pubCollection.remaining)
-
1665 {
-
1666 using namespace std::chrono_literals;
-
1667
-
1668 (void)sequence;
-
1669 Json::Value& r = remaining.append(Json::objectValue);
-
1670 appendList(future, r);
-
1671 // Race conditions can happen, so make this check "fuzzy"
-
1672 XRPL_ASSERT(
-
1673 future.validFrom > timeKeeper_.now() + 600s,
-
1674 "ripple::ValidatorList::getJson : minimum valid from");
-
1675 }
-
1676 if (remaining.size())
-
1677 curr[jss::remaining] = std::move(remaining);
-
1678 }
-
1679
-
1680 // Trusted validator keys
-
1681 Json::Value& jValidatorKeys =
-
1682 (res[jss::trusted_validator_keys] = Json::arrayValue);
-
1683 for (auto const& k : trustedMasterKeys_)
-
1684 {
-
1685 jValidatorKeys.append(toBase58(TokenType::NodePublic, k));
-
1686 }
-
1687
-
1688 // signing keys
-
1689 Json::Value& jSigningKeys = (res[jss::signing_keys] = Json::objectValue);
-
1690 validatorManifests_.for_each_manifest([&jSigningKeys,
-
1691 this](Manifest const& manifest) {
-
1692 auto it = keyListings_.find(manifest.masterKey);
-
1693 if (it != keyListings_.end() && manifest.signingKey)
-
1694 {
-
1695 jSigningKeys[toBase58(TokenType::NodePublic, manifest.masterKey)] =
-
1696 toBase58(TokenType::NodePublic, *manifest.signingKey);
-
1697 }
-
1698 });
-
1699
-
1700 // Negative UNL
-
1701 if (!negativeUNL_.empty())
-
1702 {
-
1703 Json::Value& jNegativeUNL = (res[jss::NegativeUNL] = Json::arrayValue);
-
1704 for (auto const& k : negativeUNL_)
-
1705 {
-
1706 jNegativeUNL.append(toBase58(TokenType::NodePublic, k));
-
1707 }
-
1708 }
-
1709
-
1710 return res;
-
1711}
-
1712
-
1713void
-
1714ValidatorList::for_each_listed(
-
1715 std::function<void(PublicKey const&, bool)> func) const
-
1716{
-
1717 std::shared_lock read_lock{mutex_};
-
1718
-
1719 for (auto const& v : keyListings_)
-
1720 func(v.first, trusted(read_lock, v.first));
-
1721}
-
1722
-
1723void
-
1724ValidatorList::for_each_available(
-
1725 std::function<void(
-
1726 std::string const& manifest,
-
1727 std::uint32_t version,
-
1728 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
1729 PublicKey const& pubKey,
-
1730 std::size_t maxSequence,
-
1731 uint256 const& hash)> func) const
-
1732{
-
1733 std::shared_lock read_lock{mutex_};
-
1734
-
1735 for (auto const& [key, plCollection] : publisherLists_)
+
1607std::optional<TimeKeeper::time_point>
+
1608ValidatorList::expires() const
+
1609{
+
1610 std::shared_lock read_lock{mutex_};
+
1611 return expires(read_lock);
+
1612}
+
1613
+
1614Json::Value
+
1615ValidatorList::getJson() const
+
1616{
+
1617 Json::Value res(Json::objectValue);
+
1618
+
1619 std::shared_lock read_lock{mutex_};
+
1620
+
1621 res[jss::validation_quorum] = static_cast<Json::UInt>(quorum_);
+
1622
+
1623 {
+
1624 auto& x = (res[jss::validator_list] = Json::objectValue);
+
1625
+
1626 x[jss::count] = static_cast<Json::UInt>(count(read_lock));
+
1627
+
1628 if (auto when = expires(read_lock))
+
1629 {
+
1630 if (*when == TimeKeeper::time_point::max())
+
1631 {
+
1632 x[jss::expiration] = "never";
+
1633 x[jss::status] = "active";
+
1634 }
+
1635 else
+
1636 {
+
1637 x[jss::expiration] = to_string(*when);
+
1638
+
1639 if (*when > timeKeeper_.now())
+
1640 x[jss::status] = "active";
+
1641 else
+
1642 x[jss::status] = "expired";
+
1643 }
+
1644 }
+
1645 else
+
1646 {
+
1647 x[jss::status] = "unknown";
+
1648 x[jss::expiration] = "unknown";
+
1649 }
+
1650
+
1651 x[jss::validator_list_threshold] = Json::UInt(listThreshold_);
+
1652 }
+
1653
+
1654 // Validator keys listed in the local config file
+
1655 Json::Value& jLocalStaticKeys =
+
1656 (res[jss::local_static_keys] = Json::arrayValue);
+
1657
+
1658 for (auto const& key : localPublisherList.list)
+
1659 jLocalStaticKeys.append(toBase58(TokenType::NodePublic, key));
+
1660
+
1661 // Publisher lists
+
1662 Json::Value& jPublisherLists =
+
1663 (res[jss::publisher_lists] = Json::arrayValue);
+
1664 for (auto const& [publicKey, pubCollection] : publisherLists_)
+
1665 {
+
1666 Json::Value& curr = jPublisherLists.append(Json::objectValue);
+
1667 curr[jss::pubkey_publisher] = strHex(publicKey);
+
1668 curr[jss::available] =
+
1669 pubCollection.status == PublisherStatus::available;
+
1670
+
1671 auto appendList = [](PublisherList const& publisherList,
+
1672 Json::Value& target) {
+
1673 target[jss::uri] = publisherList.siteUri;
+
1674 if (publisherList.validUntil != TimeKeeper::time_point{})
+
1675 {
+
1676 target[jss::seq] =
+
1677 static_cast<Json::UInt>(publisherList.sequence);
+
1678 target[jss::expiration] = to_string(publisherList.validUntil);
+
1679 }
+
1680 if (publisherList.validFrom != TimeKeeper::time_point{})
+
1681 target[jss::effective] = to_string(publisherList.validFrom);
+
1682 Json::Value& keys = (target[jss::list] = Json::arrayValue);
+
1683 for (auto const& key : publisherList.list)
+
1684 {
+
1685 keys.append(toBase58(TokenType::NodePublic, key));
+
1686 }
+
1687 };
+
1688 {
+
1689 auto const& current = pubCollection.current;
+
1690 appendList(current, curr);
+
1691 if (current.validUntil != TimeKeeper::time_point{})
+
1692 {
+
1693 curr[jss::version] = pubCollection.rawVersion;
+
1694 }
+
1695 }
+
1696
+
1697 Json::Value remaining(Json::arrayValue);
+
1698 for (auto const& [sequence, future] : pubCollection.remaining)
+
1699 {
+
1700 using namespace std::chrono_literals;
+
1701
+
1702 (void)sequence;
+
1703 Json::Value& r = remaining.append(Json::objectValue);
+
1704 appendList(future, r);
+
1705 // Race conditions can happen, so make this check "fuzzy"
+
1706 XRPL_ASSERT(
+
1707 future.validFrom > timeKeeper_.now() + 600s,
+
1708 "ripple::ValidatorList::getJson : minimum valid from");
+
1709 }
+
1710 if (remaining.size())
+
1711 curr[jss::remaining] = std::move(remaining);
+
1712 }
+
1713
+
1714 // Trusted validator keys
+
1715 Json::Value& jValidatorKeys =
+
1716 (res[jss::trusted_validator_keys] = Json::arrayValue);
+
1717 for (auto const& k : trustedMasterKeys_)
+
1718 {
+
1719 jValidatorKeys.append(toBase58(TokenType::NodePublic, k));
+
1720 }
+
1721
+
1722 // signing keys
+
1723 Json::Value& jSigningKeys = (res[jss::signing_keys] = Json::objectValue);
+
1724 validatorManifests_.for_each_manifest([&jSigningKeys,
+
1725 this](Manifest const& manifest) {
+
1726 auto it = keyListings_.find(manifest.masterKey);
+
1727 if (it != keyListings_.end() && manifest.signingKey)
+
1728 {
+
1729 jSigningKeys[toBase58(TokenType::NodePublic, manifest.masterKey)] =
+
1730 toBase58(TokenType::NodePublic, *manifest.signingKey);
+
1731 }
+
1732 });
+
1733
+
1734 // Negative UNL
+
1735 if (!negativeUNL_.empty())
1736 {
-
1737 if (plCollection.status != PublisherStatus::available)
-
1738 continue;
-
1739 XRPL_ASSERT(
-
1740 plCollection.maxSequence != 0,
-
1741 "ripple::ValidatorList::for_each_available : nonzero maxSequence");
-
1742 func(
-
1743 plCollection.rawManifest,
-
1744 plCollection.rawVersion,
-
1745 buildBlobInfos(plCollection),
-
1746 key,
-
1747 plCollection.maxSequence.value_or(0),
-
1748 plCollection.fullHash);
-
1749 }
-
1750}
-
1751
-
1752std::optional<Json::Value>
-
1753ValidatorList::getAvailable(
-
1754 std::string_view pubKey,
-
1755 std::optional<std::uint32_t> forceVersion /* = {} */)
-
1756{
-
1757 std::shared_lock read_lock{mutex_};
-
1758
-
1759 auto const keyBlob = strViewUnHex(pubKey);
-
1760
-
1761 if (!keyBlob || !publicKeyType(makeSlice(*keyBlob)))
-
1762 {
-
1763 JLOG(j_.info()) << "Invalid requested validator list publisher key: "
-
1764 << pubKey;
-
1765 return {};
-
1766 }
-
1767
-
1768 auto id = PublicKey(makeSlice(*keyBlob));
-
1769
-
1770 auto const iter = publisherLists_.find(id);
-
1771
-
1772 if (iter == publisherLists_.end() ||
-
1773 iter->second.status != PublisherStatus::available)
-
1774 return {};
-
1775
-
1776 Json::Value value =
-
1777 buildFileData(std::string{pubKey}, iter->second, forceVersion, j_);
-
1778
-
1779 return value;
-
1780}
-
1781
-
1782std::size_t
-
1783ValidatorList::calculateQuorum(
-
1784 std::size_t unlSize,
-
1785 std::size_t effectiveUnlSize,
-
1786 std::size_t seenSize)
-
1787{
-
1788 // Use quorum if specified via command line.
-
1789 if (minimumQuorum_ > 0)
-
1790 {
-
1791 JLOG(j_.warn()) << "Using potentially unsafe quorum of "
-
1792 << *minimumQuorum_
-
1793 << " as specified on the command line";
-
1794 return *minimumQuorum_;
-
1795 }
-
1796
-
1797 // Do not use achievable quorum until lists from all configured
-
1798 // publishers are available
-
1799 for (auto const& list : publisherLists_)
-
1800 {
-
1801 if (list.second.status != PublisherStatus::available)
-
1802 return std::numeric_limits<std::size_t>::max();
-
1803 }
-
1804
-
1805 // Use an 80% quorum to balance fork safety, liveness, and required UNL
-
1806 // overlap.
-
1807 //
-
1808 // Theorem 8 of the Analysis of the XRP Ledger Consensus Protocol
-
1809 // (https://arxiv.org/abs/1802.07242) says:
-
1810 // XRP LCP guarantees fork safety if Oi,j > nj/2 + ni − qi + ti,j
-
1811 // for every pair of nodes Pi, Pj.
-
1812 //
-
1813 // ni: size of Pi's UNL
-
1814 // nj: size of Pj's UNL
-
1815 // Oi,j: number of validators in both UNLs
-
1816 // qi: validation quorum for Pi's UNL
-
1817 // ti, tj: maximum number of allowed Byzantine faults in Pi and Pj's
-
1818 // UNLs ti,j: min{ti, tj, Oi,j}
-
1819 //
-
1820 // Assume ni < nj, meaning and ti,j = ti
-
1821 //
-
1822 // For qi = .8*ni, we make ti <= .2*ni
-
1823 // (We could make ti lower and tolerate less UNL overlap. However in
-
1824 // order to prioritize safety over liveness, we need ti >= ni - qi)
-
1825 //
-
1826 // An 80% quorum allows two UNLs to safely have < .2*ni unique
-
1827 // validators between them:
-
1828 //
-
1829 // pi = ni - Oi,j
-
1830 // pj = nj - Oi,j
-
1831 //
-
1832 // Oi,j > nj/2 + ni − qi + ti,j
-
1833 // ni - pi > (ni - pi + pj)/2 + ni − .8*ni + .2*ni
-
1834 // pi + pj < .2*ni
-
1835 //
-
1836 // Note that the negative UNL protocol introduced the
-
1837 // AbsoluteMinimumQuorum which is 60% of the original UNL size. The
-
1838 // effective quorum should not be lower than it.
-
1839 return static_cast<std::size_t>(std::max(
-
1840 std::ceil(effectiveUnlSize * 0.8f), std::ceil(unlSize * 0.6f)));
-
1841}
-
1842
-
1843TrustChanges
-
1844ValidatorList::updateTrusted(
-
1845 hash_set<NodeID> const& seenValidators,
-
1846 NetClock::time_point closeTime,
-
1847 NetworkOPs& ops,
-
1848 Overlay& overlay,
-
1849 HashRouter& hashRouter)
-
1850{
-
1851 using namespace std::chrono_literals;
-
1852 if (timeKeeper_.now() > closeTime + 30s)
-
1853 closeTime = timeKeeper_.now();
-
1854
-
1855 std::lock_guard lock{mutex_};
-
1856
-
1857 // Rotate pending and remove expired published lists
-
1858 bool good = true;
-
1859 // localPublisherList is not processed here. This is because the
-
1860 // Validators specified in the local config file do not expire nor do
-
1861 // they have a "remaining" section of PublisherList.
-
1862 for (auto& [pubKey, collection] : publisherLists_)
-
1863 {
-
1864 {
-
1865 auto& remaining = collection.remaining;
-
1866 auto const firstIter = remaining.begin();
-
1867 auto iter = firstIter;
-
1868 if (iter != remaining.end() && iter->second.validFrom <= closeTime)
-
1869 {
-
1870 // Find the LAST candidate that is ready to go live.
-
1871 for (auto next = std::next(iter); next != remaining.end() &&
-
1872 next->second.validFrom <= closeTime;
-
1873 ++iter, ++next)
-
1874 {
-
1875 XRPL_ASSERT(
-
1876 std::next(iter) == next,
-
1877 "ripple::ValidatorList::updateTrusted : sequential "
-
1878 "remaining");
-
1879 }
-
1880 XRPL_ASSERT(
-
1881 iter != remaining.end(),
-
1882 "ripple::ValidatorList::updateTrusted : non-end of "
-
1883 "remaining");
-
1884
-
1885 // Rotate the pending list in to current
-
1886 auto sequence = iter->first;
-
1887 auto& candidate = iter->second;
-
1888 auto& current = collection.current;
-
1889 XRPL_ASSERT(
-
1890 candidate.validFrom <= closeTime,
-
1891 "ripple::ValidatorList::updateTrusted : maximum time");
-
1892
-
1893 auto const oldList = current.list;
-
1894 current = std::move(candidate);
-
1895 if (collection.status != PublisherStatus::available)
-
1896 collection.status = PublisherStatus::available;
-
1897 XRPL_ASSERT(
-
1898 current.sequence == sequence,
-
1899 "ripple::ValidatorList::updateTrusted : sequence match");
-
1900 // If the list is expired, remove the validators so they don't
-
1901 // get processed in. The expiration check below will do the rest
-
1902 // of the work
-
1903 if (current.validUntil <= closeTime)
-
1904 current.list.clear();
-
1905
-
1906 updatePublisherList(pubKey, current, oldList, lock);
+
1737 Json::Value& jNegativeUNL = (res[jss::NegativeUNL] = Json::arrayValue);
+
1738 for (auto const& k : negativeUNL_)
+
1739 {
+
1740 jNegativeUNL.append(toBase58(TokenType::NodePublic, k));
+
1741 }
+
1742 }
+
1743
+
1744 return res;
+
1745}
+
1746
+
1747void
+
1748ValidatorList::for_each_listed(
+
1749 std::function<void(PublicKey const&, bool)> func) const
+
1750{
+
1751 std::shared_lock read_lock{mutex_};
+
1752
+
1753 for (auto const& v : keyListings_)
+
1754 func(v.first, trusted(read_lock, v.first));
+
1755}
+
1756
+
1757void
+
1758ValidatorList::for_each_available(
+
1759 std::function<void(
+
1760 std::string const& manifest,
+
1761 std::uint32_t version,
+
1762 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
1763 PublicKey const& pubKey,
+
1764 std::size_t maxSequence,
+
1765 uint256 const& hash)> func) const
+
1766{
+
1767 std::shared_lock read_lock{mutex_};
+
1768
+
1769 for (auto const& [key, plCollection] : publisherLists_)
+
1770 {
+
1771 if (plCollection.status != PublisherStatus::available)
+
1772 continue;
+
1773 XRPL_ASSERT(
+
1774 plCollection.maxSequence != 0,
+
1775 "ripple::ValidatorList::for_each_available : nonzero maxSequence");
+
1776 func(
+
1777 plCollection.rawManifest,
+
1778 plCollection.rawVersion,
+
1779 buildBlobInfos(plCollection),
+
1780 key,
+
1781 plCollection.maxSequence.value_or(0),
+
1782 plCollection.fullHash);
+
1783 }
+
1784}
+
1785
+
1786std::optional<Json::Value>
+
1787ValidatorList::getAvailable(
+
1788 std::string_view pubKey,
+
1789 std::optional<std::uint32_t> forceVersion /* = {} */)
+
1790{
+
1791 std::shared_lock read_lock{mutex_};
+
1792
+
1793 auto const keyBlob = strViewUnHex(pubKey);
+
1794
+
1795 if (!keyBlob || !publicKeyType(makeSlice(*keyBlob)))
+
1796 {
+
1797 JLOG(j_.info()) << "Invalid requested validator list publisher key: "
+
1798 << pubKey;
+
1799 return {};
+
1800 }
+
1801
+
1802 auto id = PublicKey(makeSlice(*keyBlob));
+
1803
+
1804 auto const iter = publisherLists_.find(id);
+
1805
+
1806 if (iter == publisherLists_.end() ||
+
1807 iter->second.status != PublisherStatus::available)
+
1808 return {};
+
1809
+
1810 Json::Value value =
+
1811 buildFileData(std::string{pubKey}, iter->second, forceVersion, j_);
+
1812
+
1813 return value;
+
1814}
+
1815
+
1816std::size_t
+
1817ValidatorList::calculateQuorum(
+
1818 std::size_t unlSize,
+
1819 std::size_t effectiveUnlSize,
+
1820 std::size_t seenSize)
+
1821{
+
1822 // Use quorum if specified via command line.
+
1823 if (minimumQuorum_ > 0)
+
1824 {
+
1825 JLOG(j_.warn()) << "Using potentially unsafe quorum of "
+
1826 << *minimumQuorum_
+
1827 << " as specified on the command line";
+
1828 return *minimumQuorum_;
+
1829 }
+
1830
+
1831 if (!publisherLists_.empty())
+
1832 {
+
1833 // Do not use achievable quorum until lists from a sufficient number of
+
1834 // configured publishers are available
+
1835 std::size_t unavailable = 0;
+
1836 for (auto const& list : publisherLists_)
+
1837 {
+
1838 if (list.second.status != PublisherStatus::available)
+
1839 unavailable += 1;
+
1840 }
+
1841 // There are two, subtly different, sides to list threshold:
+
1842 //
+
1843 // 1. The minimum required intersection between lists listThreshold_
+
1844 // for a validator to be included in trustedMasterKeys_.
+
1845 // If this many (or more) publishers are unavailable, we are likely
+
1846 // to NOT include a validator which otherwise would have been used.
+
1847 // We disable quorum if this happens.
+
1848 // 2. The minimum number of publishers which, when unavailable, will
+
1849 // prevent us from hitting the above threshold on ANY validator.
+
1850 // This is calculated as:
+
1851 // N - M + 1
+
1852 // where
+
1853 // N: number of publishers i.e. publisherLists_.size()
+
1854 // M: minimum required intersection i.e. listThreshold_
+
1855 // If this happens, we still have this local validator and we do not
+
1856 // want it to form a quorum of 1, so we disable quorum as well.
+
1857 //
+
1858 // We disable quorum if the number of unavailable publishers exceeds
+
1859 // either of the above thresholds
+
1860 auto const errorThreshold = std::min(
+
1861 listThreshold_, //
+
1862 publisherLists_.size() - listThreshold_ + 1);
+
1863 XRPL_ASSERT(
+
1864 errorThreshold > 0,
+
1865 "ripple::ValidatorList::calculateQuorum : nonzero error threshold");
+
1866 if (unavailable >= errorThreshold)
+
1867 return std::numeric_limits<std::size_t>::max();
+
1868 }
+
1869
+
1870 // Use an 80% quorum to balance fork safety, liveness, and required UNL
+
1871 // overlap.
+
1872 //
+
1873 // Theorem 8 of the Analysis of the XRP Ledger Consensus Protocol
+
1874 // (https://arxiv.org/abs/1802.07242) says:
+
1875 // XRP LCP guarantees fork safety if Oi,j > nj/2 + ni − qi + ti,j
+
1876 // for every pair of nodes Pi, Pj.
+
1877 //
+
1878 // ni: size of Pi's UNL
+
1879 // nj: size of Pj's UNL
+
1880 // Oi,j: number of validators in both UNLs
+
1881 // qi: validation quorum for Pi's UNL
+
1882 // ti, tj: maximum number of allowed Byzantine faults in Pi and Pj's
+
1883 // UNLs ti,j: min{ti, tj, Oi,j}
+
1884 //
+
1885 // Assume ni < nj, meaning and ti,j = ti
+
1886 //
+
1887 // For qi = .8*ni, we make ti <= .2*ni
+
1888 // (We could make ti lower and tolerate less UNL overlap. However in
+
1889 // order to prioritize safety over liveness, we need ti >= ni - qi)
+
1890 //
+
1891 // An 80% quorum allows two UNLs to safely have < .2*ni unique
+
1892 // validators between them:
+
1893 //
+
1894 // pi = ni - Oi,j
+
1895 // pj = nj - Oi,j
+
1896 //
+
1897 // Oi,j > nj/2 + ni − qi + ti,j
+
1898 // ni - pi > (ni - pi + pj)/2 + ni − .8*ni + .2*ni
+
1899 // pi + pj < .2*ni
+
1900 //
+
1901 // Note that the negative UNL protocol introduced the
+
1902 // AbsoluteMinimumQuorum which is 60% of the original UNL size. The
+
1903 // effective quorum should not be lower than it.
+
1904 return static_cast<std::size_t>(std::max(
+
1905 std::ceil(effectiveUnlSize * 0.8f), std::ceil(unlSize * 0.6f)));
+
1906}
1907
-
1908 // Only broadcast the current, which will consequently only
-
1909 // send to peers that don't understand v2, or which are
-
1910 // unknown (unlikely). Those that do understand v2 should
-
1911 // already have this list and are in the process of
-
1912 // switching themselves.
-
1913 broadcastBlobs(
-
1914 pubKey,
-
1915 collection,
-
1916 sequence,
-
1917 current.hash,
-
1918 overlay,
-
1919 hashRouter,
-
1920 j_);
+
1908TrustChanges
+
1909ValidatorList::updateTrusted(
+
1910 hash_set<NodeID> const& seenValidators,
+
1911 NetClock::time_point closeTime,
+
1912 NetworkOPs& ops,
+
1913 Overlay& overlay,
+
1914 HashRouter& hashRouter)
+
1915{
+
1916 using namespace std::chrono_literals;
+
1917 if (timeKeeper_.now() > closeTime + 30s)
+
1918 closeTime = timeKeeper_.now();
+
1919
+
1920 std::lock_guard lock{mutex_};
1921
-
1922 // Erase any candidates that we skipped over, plus this one
-
1923 remaining.erase(firstIter, std::next(iter));
-
1924 }
-
1925 }
-
1926 // Remove if expired
-
1927 // ValidatorLists specified in the local config file never expire.
-
1928 // Hence, the below steps are not relevant for localPublisherList
-
1929 if (collection.status == PublisherStatus::available &&
-
1930 collection.current.validUntil <= closeTime)
-
1931 {
-
1932 removePublisherList(lock, pubKey, PublisherStatus::expired);
-
1933 ops.setUNLBlocked();
-
1934 }
-
1935 if (collection.status != PublisherStatus::available)
-
1936 good = false;
-
1937 }
-
1938 if (good)
-
1939 ops.clearUNLBlocked();
-
1940
-
1941 TrustChanges trustChanges;
-
1942
-
1943 auto it = trustedMasterKeys_.cbegin();
-
1944 while (it != trustedMasterKeys_.cend())
-
1945 {
-
1946 if (!keyListings_.count(*it) || validatorManifests_.revoked(*it))
-
1947 {
-
1948 trustChanges.removed.insert(calcNodeID(*it));
-
1949 it = trustedMasterKeys_.erase(it);
-
1950 }
-
1951 else
-
1952 {
-
1953 ++it;
-
1954 }
-
1955 }
-
1956
-
1957 for (auto const& val : keyListings_)
-
1958 {
-
1959 if (!validatorManifests_.revoked(val.first) &&
-
1960 trustedMasterKeys_.emplace(val.first).second)
-
1961 trustChanges.added.insert(calcNodeID(val.first));
-
1962 }
-
1963
-
1964 // If there were any changes, we need to update the ephemeral signing
-
1965 // keys:
-
1966 if (!trustChanges.added.empty() || !trustChanges.removed.empty())
-
1967 {
-
1968 trustedSigningKeys_.clear();
-
1969
-
1970 // trustedMasterKeys_ contain non-revoked manifests only. Hence the
-
1971 // manifests must contain a valid signingKey
-
1972 for (auto const& k : trustedMasterKeys_)
-
1973 {
-
1974 std::optional<PublicKey> const signingKey =
-
1975 validatorManifests_.getSigningKey(k);
-
1976 XRPL_ASSERT(
-
1977 signingKey,
-
1978 "ripple::ValidatorList::updateTrusted : found signing key");
-
1979 trustedSigningKeys_.insert(*signingKey);
-
1980 }
-
1981 }
-
1982
-
1983 JLOG(j_.debug())
-
1984 << trustedMasterKeys_.size() << " of " << keyListings_.size()
-
1985 << " listed validators eligible for inclusion in the trusted set";
+
1922 // Rotate pending and remove expired published lists
+
1923 bool good = true;
+
1924 // localPublisherList is not processed here. This is because the
+
1925 // Validators specified in the local config file do not expire nor do
+
1926 // they have a "remaining" section of PublisherList.
+
1927 for (auto& [pubKey, collection] : publisherLists_)
+
1928 {
+
1929 {
+
1930 auto& remaining = collection.remaining;
+
1931 auto const firstIter = remaining.begin();
+
1932 auto iter = firstIter;
+
1933 if (iter != remaining.end() && iter->second.validFrom <= closeTime)
+
1934 {
+
1935 // Find the LAST candidate that is ready to go live.
+
1936 for (auto next = std::next(iter); next != remaining.end() &&
+
1937 next->second.validFrom <= closeTime;
+
1938 ++iter, ++next)
+
1939 {
+
1940 XRPL_ASSERT(
+
1941 std::next(iter) == next,
+
1942 "ripple::ValidatorList::updateTrusted : sequential "
+
1943 "remaining");
+
1944 }
+
1945 XRPL_ASSERT(
+
1946 iter != remaining.end(),
+
1947 "ripple::ValidatorList::updateTrusted : non-end of "
+
1948 "remaining");
+
1949
+
1950 // Rotate the pending list in to current
+
1951 auto sequence = iter->first;
+
1952 auto& candidate = iter->second;
+
1953 auto& current = collection.current;
+
1954 XRPL_ASSERT(
+
1955 candidate.validFrom <= closeTime,
+
1956 "ripple::ValidatorList::updateTrusted : maximum time");
+
1957
+
1958 auto const oldList = current.list;
+
1959 current = std::move(candidate);
+
1960 if (collection.status != PublisherStatus::available)
+
1961 collection.status = PublisherStatus::available;
+
1962 XRPL_ASSERT(
+
1963 current.sequence == sequence,
+
1964 "ripple::ValidatorList::updateTrusted : sequence match");
+
1965 // If the list is expired, remove the validators so they don't
+
1966 // get processed in. The expiration check below will do the rest
+
1967 // of the work
+
1968 if (current.validUntil <= closeTime)
+
1969 current.list.clear();
+
1970
+
1971 updatePublisherList(pubKey, current, oldList, lock);
+
1972
+
1973 // Only broadcast the current, which will consequently only
+
1974 // send to peers that don't understand v2, or which are
+
1975 // unknown (unlikely). Those that do understand v2 should
+
1976 // already have this list and are in the process of
+
1977 // switching themselves.
+
1978 broadcastBlobs(
+
1979 pubKey,
+
1980 collection,
+
1981 sequence,
+
1982 current.hash,
+
1983 overlay,
+
1984 hashRouter,
+
1985 j_);
1986
-
1987 auto const unlSize = trustedMasterKeys_.size();
-
1988 auto effectiveUnlSize = unlSize;
-
1989 auto seenSize = seenValidators.size();
-
1990 if (!negativeUNL_.empty())
-
1991 {
-
1992 for (auto const& k : trustedMasterKeys_)
-
1993 {
-
1994 if (negativeUNL_.count(k))
-
1995 --effectiveUnlSize;
-
1996 }
-
1997 hash_set<NodeID> negUnlNodeIDs;
-
1998 for (auto const& k : negativeUNL_)
-
1999 {
-
2000 negUnlNodeIDs.emplace(calcNodeID(k));
-
2001 }
-
2002 for (auto const& nid : seenValidators)
-
2003 {
-
2004 if (negUnlNodeIDs.count(nid))
-
2005 --seenSize;
-
2006 }
-
2007 }
-
2008 quorum_ = calculateQuorum(unlSize, effectiveUnlSize, seenSize);
-
2009
-
2010 JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of "
-
2011 << unlSize << " trusted validators ("
-
2012 << trustChanges.added.size() << " added, "
-
2013 << trustChanges.removed.size() << " removed)";
-
2014
-
2015 if (unlSize < quorum_)
-
2016 {
-
2017 JLOG(j_.warn()) << "New quorum of " << quorum_
-
2018 << " exceeds the number of trusted validators ("
-
2019 << unlSize << ")";
-
2020 }
-
2021
-
2022 if ((publisherLists_.size() || localPublisherList.list.size()) &&
-
2023 unlSize == 0)
-
2024 {
-
2025 // No validators. Lock down.
-
2026 ops.setUNLBlocked();
-
2027 }
-
2028
-
2029 return trustChanges;
-
2030}
-
2031
-
2032hash_set<PublicKey>
-
2033ValidatorList::getTrustedMasterKeys() const
-
2034{
-
2035 std::shared_lock read_lock{mutex_};
-
2036 return trustedMasterKeys_;
-
2037}
-
2038
-
2039hash_set<PublicKey>
-
2040ValidatorList::getNegativeUNL() const
-
2041{
-
2042 std::shared_lock read_lock{mutex_};
-
2043 return negativeUNL_;
-
2044}
-
2045
-
2046void
-
2047ValidatorList::setNegativeUNL(hash_set<PublicKey> const& negUnl)
-
2048{
-
2049 std::lock_guard lock{mutex_};
-
2050 negativeUNL_ = negUnl;
-
2051}
-
2052
-
2053std::vector<std::shared_ptr<STValidation>>
-
2054ValidatorList::negativeUNLFilter(
-
2055 std::vector<std::shared_ptr<STValidation>>&& validations) const
-
2056{
-
2057 // Remove validations that are from validators on the negative UNL.
-
2058 auto ret = std::move(validations);
-
2059
-
2060 std::shared_lock read_lock{mutex_};
-
2061 if (!negativeUNL_.empty())
-
2062 {
-
2063 ret.erase(
-
2064 std::remove_if(
-
2065 ret.begin(),
-
2066 ret.end(),
-
2067 [&](auto const& v) -> bool {
-
2068 if (auto const masterKey =
-
2069 getTrustedKey(read_lock, v->getSignerPublic());
-
2070 masterKey)
-
2071 {
-
2072 return negativeUNL_.count(*masterKey);
-
2073 }
-
2074 else
-
2075 {
-
2076 return false;
-
2077 }
-
2078 }),
-
2079 ret.end());
-
2080 }
+
1987 // Erase any candidates that we skipped over, plus this one
+
1988 remaining.erase(firstIter, std::next(iter));
+
1989 }
+
1990 }
+
1991 // Remove if expired
+
1992 // ValidatorLists specified in the local config file never expire.
+
1993 // Hence, the below steps are not relevant for localPublisherList
+
1994 if (collection.status == PublisherStatus::available &&
+
1995 collection.current.validUntil <= closeTime)
+
1996 {
+
1997 removePublisherList(lock, pubKey, PublisherStatus::expired);
+
1998 ops.setUNLBlocked();
+
1999 }
+
2000 if (collection.status != PublisherStatus::available)
+
2001 good = false;
+
2002 }
+
2003 if (good)
+
2004 ops.clearUNLBlocked();
+
2005
+
2006 TrustChanges trustChanges;
+
2007
+
2008 auto it = trustedMasterKeys_.cbegin();
+
2009 while (it != trustedMasterKeys_.cend())
+
2010 {
+
2011 auto const kit = keyListings_.find(*it);
+
2012 if (kit == keyListings_.end() || //
+
2013 kit->second < listThreshold_ || //
+
2014 validatorManifests_.revoked(*it))
+
2015 {
+
2016 trustChanges.removed.insert(calcNodeID(*it));
+
2017 it = trustedMasterKeys_.erase(it);
+
2018 }
+
2019 else
+
2020 {
+
2021 XRPL_ASSERT(
+
2022 kit->second >= listThreshold_,
+
2023 "ripple::ValidatorList::updateTrusted : count meets threshold");
+
2024 ++it;
+
2025 }
+
2026 }
+
2027
+
2028 for (auto const& val : keyListings_)
+
2029 {
+
2030 if (val.second >= listThreshold_ &&
+
2031 !validatorManifests_.revoked(val.first) &&
+
2032 trustedMasterKeys_.emplace(val.first).second)
+
2033 trustChanges.added.insert(calcNodeID(val.first));
+
2034 }
+
2035
+
2036 // If there were any changes, we need to update the ephemeral signing
+
2037 // keys:
+
2038 if (!trustChanges.added.empty() || !trustChanges.removed.empty())
+
2039 {
+
2040 trustedSigningKeys_.clear();
+
2041
+
2042 // trustedMasterKeys_ contain non-revoked manifests only. Hence the
+
2043 // manifests must contain a valid signingKey
+
2044 for (auto const& k : trustedMasterKeys_)
+
2045 {
+
2046 std::optional<PublicKey> const signingKey =
+
2047 validatorManifests_.getSigningKey(k);
+
2048 XRPL_ASSERT(
+
2049 signingKey,
+
2050 "ripple::ValidatorList::updateTrusted : found signing key");
+
2051 trustedSigningKeys_.insert(*signingKey);
+
2052 }
+
2053 }
+
2054
+
2055 JLOG(j_.debug())
+
2056 << trustedMasterKeys_.size() << " of " << keyListings_.size()
+
2057 << " listed validators eligible for inclusion in the trusted set";
+
2058
+
2059 auto const unlSize = trustedMasterKeys_.size();
+
2060 auto effectiveUnlSize = unlSize;
+
2061 auto seenSize = seenValidators.size();
+
2062 if (!negativeUNL_.empty())
+
2063 {
+
2064 for (auto const& k : trustedMasterKeys_)
+
2065 {
+
2066 if (negativeUNL_.count(k))
+
2067 --effectiveUnlSize;
+
2068 }
+
2069 hash_set<NodeID> negUnlNodeIDs;
+
2070 for (auto const& k : negativeUNL_)
+
2071 {
+
2072 negUnlNodeIDs.emplace(calcNodeID(k));
+
2073 }
+
2074 for (auto const& nid : seenValidators)
+
2075 {
+
2076 if (negUnlNodeIDs.count(nid))
+
2077 --seenSize;
+
2078 }
+
2079 }
+
2080 quorum_ = calculateQuorum(unlSize, effectiveUnlSize, seenSize);
2081
-
2082 return ret;
-
2083}
-
2084
-
2085} // namespace ripple
+
2082 JLOG(j_.debug()) << "Using quorum of " << quorum_ << " for new set of "
+
2083 << unlSize << " trusted validators ("
+
2084 << trustChanges.added.size() << " added, "
+
2085 << trustChanges.removed.size() << " removed)";
+
2086
+
2087 if (unlSize < quorum_)
+
2088 {
+
2089 JLOG(j_.warn()) << "New quorum of " << quorum_
+
2090 << " exceeds the number of trusted validators ("
+
2091 << unlSize << ")";
+
2092 }
+
2093
+
2094 if ((publisherLists_.size() || localPublisherList.list.size()) &&
+
2095 unlSize == 0)
+
2096 {
+
2097 // No validators. Lock down.
+
2098 ops.setUNLBlocked();
+
2099 }
+
2100
+
2101 return trustChanges;
+
2102}
+
2103
+
2104hash_set<PublicKey>
+
2105ValidatorList::getTrustedMasterKeys() const
+
2106{
+
2107 std::shared_lock read_lock{mutex_};
+
2108 return trustedMasterKeys_;
+
2109}
+
2110
+
2111std::size_t
+
2112ValidatorList::getListThreshold() const
+
2113{
+
2114 std::shared_lock read_lock{mutex_};
+
2115 return listThreshold_;
+
2116}
+
2117
+
2118hash_set<PublicKey>
+
2119ValidatorList::getNegativeUNL() const
+
2120{
+
2121 std::shared_lock read_lock{mutex_};
+
2122 return negativeUNL_;
+
2123}
+
2124
+
2125void
+
2126ValidatorList::setNegativeUNL(hash_set<PublicKey> const& negUnl)
+
2127{
+
2128 std::lock_guard lock{mutex_};
+
2129 negativeUNL_ = negUnl;
+
2130}
+
2131
+
2132std::vector<std::shared_ptr<STValidation>>
+
2133ValidatorList::negativeUNLFilter(
+
2134 std::vector<std::shared_ptr<STValidation>>&& validations) const
+
2135{
+
2136 // Remove validations that are from validators on the negative UNL.
+
2137 auto ret = std::move(validations);
+
2138
+
2139 std::shared_lock read_lock{mutex_};
+
2140 if (!negativeUNL_.empty())
+
2141 {
+
2142 ret.erase(
+
2143 std::remove_if(
+
2144 ret.begin(),
+
2145 ret.end(),
+
2146 [&](auto const& v) -> bool {
+
2147 if (auto const masterKey =
+
2148 getTrustedKey(read_lock, v->getSignerPublic());
+
2149 masterKey)
+
2150 {
+
2151 return negativeUNL_.count(*masterKey);
+
2152 }
+
2153 else
+
2154 {
+
2155 return false;
+
2156 }
+
2157 }),
+
2158 ret.end());
+
2159 }
+
2160
+
2161 return ret;
+
2162}
+
2163
+
2164} // namespace ripple
std::accumulate
T accumulate(T... args)
std::vector::back
T back(T... args)
std::string
@@ -2212,48 +2291,49 @@ $(function() {
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:45
ripple::TimeKeeper
Manages various times used by the server.
Definition: TimeKeeper.h:32
ripple::TimeKeeper::now
time_point now() const override
Returns the current time, using the server's clock.
Definition: TimeKeeper.h:64
-
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:1520
-
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1456
-
ripple::ValidatorList::load
bool load(std::optional< PublicKey > const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys)
Load configured trusted keys.
Definition: ValidatorList.cpp:136
-
ripple::ValidatorList::sendValidatorList
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:785
-
ripple::ValidatorList::broadcastBlobs
static void broadcastBlobs(PublicKey const &publisherKey, PublisherListCollection const &lists, std::size_t maxSequence, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:838
-
ripple::ValidatorList::getCacheFileName
boost::filesystem::path getCacheFileName(lock_guard const &, PublicKey const &pubKey) const
Get the filename used for caching UNLs.
Definition: ValidatorList.cpp:252
-
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1267
-
ripple::ValidatorList::localPublisherList
PublisherList localPublisherList
Definition: ValidatorList.h:260
-
ripple::ValidatorList::localPublicKey
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
Definition: ValidatorList.cpp:1472
+
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:1552
+
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1488
+
ripple::ValidatorList::sendValidatorList
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:817
+
ripple::ValidatorList::broadcastBlobs
static void broadcastBlobs(PublicKey const &publisherKey, PublisherListCollection const &lists, std::size_t maxSequence, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:870
+
ripple::ValidatorList::getCacheFileName
boost::filesystem::path getCacheFileName(lock_guard const &, PublicKey const &pubKey) const
Get the filename used for caching UNLs.
Definition: ValidatorList.cpp:284
+
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1299
+
ripple::ValidatorList::localPublisherList
PublisherList localPublisherList
Definition: ValidatorList.h:263
+
ripple::ValidatorList::localPublicKey
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
Definition: ValidatorList.cpp:1504
ripple::ValidatorList::validatorManifests_
ManifestCache & validatorManifests_
Definition: ValidatorList.h:224
ripple::ValidatorList::quorum_
std::atomic< std::size_t > quorum_
Definition: ValidatorList.h:233
-
ripple::ValidatorList::updatePublisherList
void updatePublisherList(PublicKey const &pubKey, PublisherList const &current, std::vector< PublicKey > const &oldList, lock_guard const &)
Definition: ValidatorList.cpp:1040
+
ripple::ValidatorList::updatePublisherList
void updatePublisherList(PublicKey const &pubKey, PublisherList const &current, std::vector< PublicKey > const &oldList, lock_guard const &)
Definition: ValidatorList.cpp:1072
ripple::ValidatorList::timeKeeper_
TimeKeeper & timeKeeper_
Definition: ValidatorList.h:226
-
ripple::ValidatorList::buildFileData
static Json::Value buildFileData(std::string const &pubKey, PublisherListCollection const &pubCollection, beast::Journal j)
Build a Json representation of the collection, suitable for writing to a cache file,...
Definition: ValidatorList.cpp:261
-
ripple::ValidatorList::buildBlobInfos
static void buildBlobInfos(std::map< std::size_t, ValidatorBlobInfo > &blobInfos, PublisherListCollection const &lists)
Definition: ValidatorList.cpp:812
+
ripple::ValidatorList::buildFileData
static Json::Value buildFileData(std::string const &pubKey, PublisherListCollection const &pubCollection, beast::Journal j)
Build a Json representation of the collection, suitable for writing to a cache file,...
Definition: ValidatorList.cpp:293
+
ripple::ValidatorList::buildBlobInfos
static void buildBlobInfos(std::map< std::size_t, ValidatorBlobInfo > &blobInfos, PublisherListCollection const &lists)
Definition: ValidatorList.cpp:844
ripple::ValidatorList::keyListings_
hash_map< PublicKey, std::size_t > keyListings_
Definition: ValidatorList.h:240
-
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:1409
-
ripple::ValidatorList::cacheValidatorFile
void cacheValidatorFile(lock_guard const &lock, PublicKey const &pubKey) const
Write a JSON UNL to a cache file.
Definition: ValidatorList.cpp:335
+
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:1441
+
ripple::ValidatorList::listThreshold_
std::size_t listThreshold_
Definition: ValidatorList.h:246
+
ripple::ValidatorList::cacheValidatorFile
void cacheValidatorFile(lock_guard const &lock, PublicKey const &pubKey) const
Write a JSON UNL to a cache file.
Definition: ValidatorList.cpp:367
ripple::ValidatorList::trustedMasterKeys_
hash_set< PublicKey > trustedMasterKeys_
Definition: ValidatorList.h:243
-
ripple::ValidatorList::applyList
PublisherListStats applyList(std::string const &globalManifest, std::optional< std::string > const &localManifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, std::optional< uint256 > const &hash, lock_guard const &)
Apply published list of public keys.
Definition: ValidatorList.cpp:1104
-
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1583
-
ripple::ValidatorList::expires
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1576
-
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:906
+
ripple::ValidatorList::applyList
PublisherListStats applyList(std::string const &globalManifest, std::optional< std::string > const &localManifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, std::optional< uint256 > const &hash, lock_guard const &)
Apply published list of public keys.
Definition: ValidatorList.cpp:1136
+
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1615
+
ripple::ValidatorList::expires
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1608
+
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:938
ripple::ValidatorList::j_
beast::Journal const j_
Definition: ValidatorList.h:228
-
ripple::ValidatorList::trustedPublisher
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
Definition: ValidatorList.cpp:1464
-
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1434
+
ripple::ValidatorList::trustedPublisher
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
Definition: ValidatorList.cpp:1496
+
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1466
ripple::ValidatorList::dataPath_
boost::filesystem::path const dataPath_
Definition: ValidatorList.h:227
ripple::ValidatorList::mutex_
boost::shared_mutex mutex_
Definition: ValidatorList.h:229
-
ripple::ValidatorList::removePublisherList
bool removePublisherList(lock_guard const &, PublicKey const &publisherKey, PublisherStatus reason)
Stop trusting publisher's list of keys.
Definition: ValidatorList.cpp:1479
-
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:1427
-
ripple::ValidatorList::maxSupportedBlobs
static constexpr std::size_t maxSupportedBlobs
Definition: ValidatorList.h:269
+
ripple::ValidatorList::removePublisherList
bool removePublisherList(lock_guard const &, PublicKey const &publisherKey, PublisherStatus reason)
Stop trusting publisher's list of keys.
Definition: ValidatorList.cpp:1511
+
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:1459
+
ripple::ValidatorList::maxSupportedBlobs
static constexpr std::size_t maxSupportedBlobs
Definition: ValidatorList.h:272
ripple::ValidatorList::ValidatorList
ValidatorList(ManifestCache &validatorManifests, ManifestCache &publisherManifests, TimeKeeper &timeKeeper, std::string const &databasePath, beast::Journal j, std::optional< std::size_t > minimumQuorum=std::nullopt)
Definition: ValidatorList.cpp:118
-
ripple::ValidatorList::verify
std::pair< ListDisposition, std::optional< PublicKey > > verify(lock_guard const &, Json::Value &list, std::string const &manifest, std::string const &blob, std::string const &signature)
Check response for trusted valid published list.
Definition: ValidatorList.cpp:1322
-
ripple::ValidatorList::localPubKey_
std::optional< PublicKey > localPubKey_
Definition: ValidatorList.h:250
+
ripple::ValidatorList::verify
std::pair< ListDisposition, std::optional< PublicKey > > verify(lock_guard const &, Json::Value &list, std::string const &manifest, std::string const &blob, std::string const &signature)
Check response for trusted valid published list.
Definition: ValidatorList.cpp:1354
+
ripple::ValidatorList::localPubKey_
std::optional< PublicKey > localPubKey_
Definition: ValidatorList.h:253
+
ripple::ValidatorList::load
bool load(std::optional< PublicKey > const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys, std::optional< std::size_t > listThreshold={})
Load configured trusted keys.
Definition: ValidatorList.cpp:137
ripple::ValidatorList::minimumQuorum_
std::optional< std::size_t > minimumQuorum_
Definition: ValidatorList.h:234
-
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:366
+
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:398
ripple::ValidatorList::publisherLists_
hash_map< PublicKey, PublisherListCollection > publisherLists_
Definition: ValidatorList.h:237
-
ripple::ValidatorList::applyLists
PublisherListStats applyLists(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, std::optional< uint256 > const &hash={})
Apply multiple published lists of public keys.
Definition: ValidatorList.cpp:964
-
ripple::ValidatorList::buildValidatorListMessages
static std::pair< std::size_t, std::size_t > buildValidatorListMessages(std::size_t messageVersion, std::uint64_t peerSequence, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, std::vector< MessageWithHash > &messages, std::size_t maxSize=maximiumMessageSize)
Definition: ValidatorList.cpp:638
-
ripple::ValidatorList::filePrefix_
static const std::string filePrefix_
Definition: ValidatorList.h:271
+
ripple::ValidatorList::applyLists
PublisherListStats applyLists(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, std::optional< uint256 > const &hash={})
Apply multiple published lists of public keys.
Definition: ValidatorList.cpp:996
+
ripple::ValidatorList::buildValidatorListMessages
static std::pair< std::size_t, std::size_t > buildValidatorListMessages(std::size_t messageVersion, std::uint64_t peerSequence, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, std::vector< MessageWithHash > &messages, std::size_t maxSize=maximiumMessageSize)
Definition: ValidatorList.cpp:670
+
ripple::ValidatorList::filePrefix_
static const std::string filePrefix_
Definition: ValidatorList.h:274
ripple::ValidatorList::publisherManifests_
ManifestCache & publisherManifests_
Definition: ValidatorList.h:225
-
ripple::ValidatorList::supportedListVersions
static constexpr std::uint32_t supportedListVersions[]
Definition: ValidatorList.h:266
+
ripple::ValidatorList::supportedListVersions
static constexpr std::uint32_t supportedListVersions[]
Definition: ValidatorList.h:269
ripple::base_uint< 256 >
std::vector::clear
T clear(T... args)
cmath
@@ -2268,6 +2348,7 @@ $(function() {
std::make_pair
T make_pair(T... args)
std::map
std::max
T max(T... args)
+
std::min
T min(T... args)
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
@@ -2282,8 +2363,8 @@ $(function() {
ripple::ProtocolFeature::ValidatorListPropagation
@ ValidatorListPropagation
ripple::ProtocolFeature::ValidatorList2Propagation
@ ValidatorList2Propagation
ripple::base64_decode
std::string base64_decode(std::string_view data)
Definition: base64.cpp:245
-
ripple::splitMessage
std::size_t splitMessage(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin=0, std::size_t end=0)
Definition: ValidatorList.cpp:468
-
ripple::splitMessageParts
std::size_t splitMessageParts(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin, std::size_t end)
Definition: ValidatorList.cpp:489
+
ripple::splitMessage
std::size_t splitMessage(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin=0, std::size_t end=0)
Definition: ValidatorList.cpp:500
+
ripple::splitMessageParts
std::size_t splitMessageParts(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin, std::size_t end)
Definition: ValidatorList.cpp:521
ripple::ValStatus::current
@ current
This was a new validation and was added.
ripple::ListDisposition
ListDisposition
Definition: ValidatorList.h:55
ripple::ListDisposition::unsupported_version
@ unsupported_version
List version is not supported.
@@ -2314,7 +2395,7 @@ $(function() {
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::writeFileContents
void writeFileContents(boost::system::error_code &ec, boost::filesystem::path const &destPath, std::string const &contents)
Definition: FileUtilities.cpp:66
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:223
-
ripple::buildValidatorListMessage
std::size_t buildValidatorListMessage(std::vector< ValidatorList::MessageWithHash > &messages, std::uint32_t rawVersion, std::string const &rawManifest, ValidatorBlobInfo const &currentBlob, std::size_t maxSize)
Definition: ValidatorList.cpp:554
+
ripple::buildValidatorListMessage
std::size_t buildValidatorListMessage(std::vector< ValidatorList::MessageWithHash > &messages, std::uint32_t rawVersion, std::string const &rawManifest, ValidatorBlobInfo const &currentBlob, std::size_t maxSize)
Definition: ValidatorList.cpp:586
std::next
T next(T... args)
numeric
std::optional
@@ -2336,21 +2417,21 @@ $(function() {
ripple::ValidatorBlobInfo::blob
std::string blob
Definition: ValidatorList.h:119
ripple::ValidatorBlobInfo::signature
std::string signature
Definition: ValidatorList.h:121
ripple::ValidatorBlobInfo::manifest
std::optional< std::string > manifest
Definition: ValidatorList.h:124
-
ripple::ValidatorList::MessageWithHash
Definition: ValidatorList.h:314
+
ripple::ValidatorList::MessageWithHash
Definition: ValidatorList.h:317
ripple::ValidatorList::MessageWithHash::MessageWithHash
MessageWithHash()=default
ripple::ValidatorList::PublisherListCollection
Definition: ValidatorList.h:195
ripple::ValidatorList::PublisherListCollection::rawManifest
std::string rawManifest
Definition: ValidatorList.h:220
ripple::ValidatorList::PublisherListCollection::current
PublisherList current
Definition: ValidatorList.h:207
ripple::ValidatorList::PublisherListCollection::remaining
std::map< std::size_t, PublisherList > remaining
Definition: ValidatorList.h:216
ripple::ValidatorList::PublisherListCollection::rawVersion
std::uint32_t rawVersion
Definition: ValidatorList.h:221
-
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:289
+
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:292
ripple::ValidatorList::PublisherListStats::mergeDispositions
void mergeDispositions(PublisherListStats const &src)
Definition: ValidatorList.cpp:99
ripple::ValidatorList::PublisherListStats::bestDisposition
ListDisposition bestDisposition() const
Definition: ValidatorList.cpp:85
ripple::ValidatorList::PublisherListStats::PublisherListStats
PublisherListStats()=default
ripple::ValidatorList::PublisherListStats::worstDisposition
ListDisposition worstDisposition() const
Definition: ValidatorList.cpp:92
-
ripple::ValidatorList::PublisherListStats::dispositions
std::map< ListDisposition, std::size_t > dispositions
Definition: ValidatorList.h:307
-
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:308
-
ripple::ValidatorList::PublisherListStats::sequence
std::size_t sequence
Definition: ValidatorList.h:310
+
ripple::ValidatorList::PublisherListStats::dispositions
std::map< ListDisposition, std::size_t > dispositions
Definition: ValidatorList.h:310
+
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:311
+
ripple::ValidatorList::PublisherListStats::sequence
std::size_t sequence
Definition: ValidatorList.h:313
ripple::ValidatorList::PublisherList
Definition: ValidatorList.h:175
ripple::ValidatorList::PublisherList::list
std::vector< PublicKey > list
Definition: ValidatorList.h:178
ripple::ValidatorList::PublisherList::siteUri
std::string siteUri
Definition: ValidatorList.h:183
diff --git a/ValidatorList_8h_source.html b/ValidatorList_8h_source.html index d8921e0203..bfd6dcc62a 100644 --- a/ValidatorList_8h_source.html +++ b/ValidatorList_8h_source.html @@ -263,401 +263,408 @@ $(function() {
242 // The current list of trusted master keys
243 hash_set<PublicKey> trustedMasterKeys_;
244
-
245 // The current list of trusted signing keys. For those validators using
-
246 // a manifest, the signing key is the ephemeral key. For the ones using
-
247 // a seed, the signing key is the same as the master key.
-
248 hash_set<PublicKey> trustedSigningKeys_;
-
249
-
250 std::optional<PublicKey> localPubKey_;
-
251
-
252 // The below variable contains the Publisher list specified in the local
-
253 // config file under the title of SECTION_VALIDATORS or [validators].
-
254 // This list is not associated with the masterKey of any publisher.
-
255
-
256 // Appropos PublisherListCollection fields, localPublisherList does not
-
257 // have any "remaining" manifests. It is assumed to be perennially
-
258 // "available". The "validUntil" field is set to the highest possible
-
259 // value of the field, hence this list is always valid.
-
260 PublisherList localPublisherList;
-
261
-
262 // The master public keys of the current negative UNL
-
263 hash_set<PublicKey> negativeUNL_;
+
245 // Minimum number of lists on which a trusted validator must appear on
+
246 std::size_t listThreshold_;
+
247
+
248 // The current list of trusted signing keys. For those validators using
+
249 // a manifest, the signing key is the ephemeral key. For the ones using
+
250 // a seed, the signing key is the same as the master key.
+
251 hash_set<PublicKey> trustedSigningKeys_;
+
252
+
253 std::optional<PublicKey> localPubKey_;
+
254
+
255 // The below variable contains the Publisher list specified in the local
+
256 // config file under the title of SECTION_VALIDATORS or [validators].
+
257 // This list is not associated with the masterKey of any publisher.
+
258
+
259 // Appropos PublisherListCollection fields, localPublisherList does not
+
260 // have any "remaining" manifests. It is assumed to be perennially
+
261 // "available". The "validUntil" field is set to the highest possible
+
262 // value of the field, hence this list is always valid.
+
263 PublisherList localPublisherList;
264
-
265 // Currently supported versions of publisher list format
-
266 static constexpr std::uint32_t supportedListVersions[]{1, 2};
-
267 // In the initial release, to prevent potential abuse and attacks, any VL
-
268 // collection with more than 5 entries will be considered malformed.
-
269 static constexpr std::size_t maxSupportedBlobs = 5;
-
270 // Prefix of the file name used to store cache files.
-
271 static const std::string filePrefix_;
-
272
-
273public:
-
274 ValidatorList(
-
275 ManifestCache& validatorManifests,
-
276 ManifestCache& publisherManifests,
-
277 TimeKeeper& timeKeeper,
-
278 std::string const& databasePath,
-
279 beast::Journal j,
-
280 std::optional<std::size_t> minimumQuorum = std::nullopt);
-
281 ~ValidatorList() = default;
-
282
-
288 struct PublisherListStats
-
289 {
-
290 explicit PublisherListStats() = default;
-
291 explicit PublisherListStats(ListDisposition d);
-
292 PublisherListStats(
-
293 ListDisposition d,
-
294 PublicKey key,
-
295 PublisherStatus stat,
-
296 std::size_t seq);
-
297
-
298 ListDisposition
-
299 bestDisposition() const;
-
300 ListDisposition
-
301 worstDisposition() const;
-
302 void
-
303 mergeDispositions(PublisherListStats const& src);
-
304
-
305 // Tracks the dispositions of each processed list and how many times it
-
306 // occurred
-
307 std::map<ListDisposition, std::size_t> dispositions;
-
308 std::optional<PublicKey> publisherKey;
-
309 PublisherStatus status = PublisherStatus::unavailable;
-
310 std::size_t sequence = 0;
-
311 };
-
312
-
313 struct MessageWithHash
-
314 {
-
315 explicit MessageWithHash() = default;
-
316 explicit MessageWithHash(
-
317 std::shared_ptr<Message> const& message_,
-
318 uint256 hash_,
-
319 std::size_t num_);
-
320 std::shared_ptr<Message> message;
-
321 uint256 hash;
-
322 std::size_t numVLs = 0;
-
323 };
-
324
-
342 bool
-
343 load(
-
344 std::optional<PublicKey> const& localSigningKey,
-
345 std::vector<std::string> const& configKeys,
-
346 std::vector<std::string> const& publisherKeys);
-
347
-
353 static std::vector<ValidatorBlobInfo>
-
354 parseBlobs(std::uint32_t version, Json::Value const& body);
-
355
-
356 static std::vector<ValidatorBlobInfo>
-
357 parseBlobs(protocol::TMValidatorList const& body);
-
358
-
359 static std::vector<ValidatorBlobInfo>
-
360 parseBlobs(protocol::TMValidatorListCollection const& body);
-
361
-
362 static void
-
363 sendValidatorList(
-
364 Peer& peer,
-
365 std::uint64_t peerSequence,
-
366 PublicKey const& publisherKey,
-
367 std::size_t maxSequence,
-
368 std::uint32_t rawVersion,
-
369 std::string const& rawManifest,
-
370 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
371 HashRouter& hashRouter,
-
372 beast::Journal j);
-
373
-
374 [[nodiscard]] static std::pair<std::size_t, std::size_t>
-
375 buildValidatorListMessages(
-
376 std::size_t messageVersion,
-
377 std::uint64_t peerSequence,
-
378 std::size_t maxSequence,
-
379 std::uint32_t rawVersion,
-
380 std::string const& rawManifest,
-
381 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
382 std::vector<MessageWithHash>& messages,
-
383 std::size_t maxSize = maximiumMessageSize);
-
384
-
414 PublisherListStats
-
415 applyListsAndBroadcast(
-
416 std::string const& manifest,
-
417 std::uint32_t version,
-
418 std::vector<ValidatorBlobInfo> const& blobs,
-
419 std::string siteUri,
-
420 uint256 const& hash,
-
421 Overlay& overlay,
-
422 HashRouter& hashRouter,
-
423 NetworkOPs& networkOPs);
-
424
-
445 PublisherListStats
-
446 applyLists(
-
447 std::string const& manifest,
-
448 std::uint32_t version,
-
449 std::vector<ValidatorBlobInfo> const& blobs,
-
450 std::string siteUri,
-
451 std::optional<uint256> const& hash = {});
-
452
-
453 /* Attempt to read previously stored list files. Expected to only be
-
454 called when loading from URL fails.
-
455
-
456 @return A list of valid file:// URLs, if any.
-
457
-
458 @par Thread Safety
+
265 // The master public keys of the current negative UNL
+
266 hash_set<PublicKey> negativeUNL_;
+
267
+
268 // Currently supported versions of publisher list format
+
269 static constexpr std::uint32_t supportedListVersions[]{1, 2};
+
270 // In the initial release, to prevent potential abuse and attacks, any VL
+
271 // collection with more than 5 entries will be considered malformed.
+
272 static constexpr std::size_t maxSupportedBlobs = 5;
+
273 // Prefix of the file name used to store cache files.
+
274 static const std::string filePrefix_;
+
275
+
276public:
+
277 ValidatorList(
+
278 ManifestCache& validatorManifests,
+
279 ManifestCache& publisherManifests,
+
280 TimeKeeper& timeKeeper,
+
281 std::string const& databasePath,
+
282 beast::Journal j,
+
283 std::optional<std::size_t> minimumQuorum = std::nullopt);
+
284 ~ValidatorList() = default;
+
285
+
291 struct PublisherListStats
+
292 {
+
293 explicit PublisherListStats() = default;
+
294 explicit PublisherListStats(ListDisposition d);
+
295 PublisherListStats(
+
296 ListDisposition d,
+
297 PublicKey key,
+
298 PublisherStatus stat,
+
299 std::size_t seq);
+
300
+
301 ListDisposition
+
302 bestDisposition() const;
+
303 ListDisposition
+
304 worstDisposition() const;
+
305 void
+
306 mergeDispositions(PublisherListStats const& src);
+
307
+
308 // Tracks the dispositions of each processed list and how many times it
+
309 // occurred
+
310 std::map<ListDisposition, std::size_t> dispositions;
+
311 std::optional<PublicKey> publisherKey;
+
312 PublisherStatus status = PublisherStatus::unavailable;
+
313 std::size_t sequence = 0;
+
314 };
+
315
+
316 struct MessageWithHash
+
317 {
+
318 explicit MessageWithHash() = default;
+
319 explicit MessageWithHash(
+
320 std::shared_ptr<Message> const& message_,
+
321 uint256 hash_,
+
322 std::size_t num_);
+
323 std::shared_ptr<Message> message;
+
324 uint256 hash;
+
325 std::size_t numVLs = 0;
+
326 };
+
327
+
345 bool
+
346 load(
+
347 std::optional<PublicKey> const& localSigningKey,
+
348 std::vector<std::string> const& configKeys,
+
349 std::vector<std::string> const& publisherKeys,
+
350 std::optional<std::size_t> listThreshold = {});
+
351
+
357 static std::vector<ValidatorBlobInfo>
+
358 parseBlobs(std::uint32_t version, Json::Value const& body);
+
359
+
360 static std::vector<ValidatorBlobInfo>
+
361 parseBlobs(protocol::TMValidatorList const& body);
+
362
+
363 static std::vector<ValidatorBlobInfo>
+
364 parseBlobs(protocol::TMValidatorListCollection const& body);
+
365
+
366 static void
+
367 sendValidatorList(
+
368 Peer& peer,
+
369 std::uint64_t peerSequence,
+
370 PublicKey const& publisherKey,
+
371 std::size_t maxSequence,
+
372 std::uint32_t rawVersion,
+
373 std::string const& rawManifest,
+
374 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
375 HashRouter& hashRouter,
+
376 beast::Journal j);
+
377
+
378 [[nodiscard]] static std::pair<std::size_t, std::size_t>
+
379 buildValidatorListMessages(
+
380 std::size_t messageVersion,
+
381 std::uint64_t peerSequence,
+
382 std::size_t maxSequence,
+
383 std::uint32_t rawVersion,
+
384 std::string const& rawManifest,
+
385 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
386 std::vector<MessageWithHash>& messages,
+
387 std::size_t maxSize = maximiumMessageSize);
+
388
+
418 PublisherListStats
+
419 applyListsAndBroadcast(
+
420 std::string const& manifest,
+
421 std::uint32_t version,
+
422 std::vector<ValidatorBlobInfo> const& blobs,
+
423 std::string siteUri,
+
424 uint256 const& hash,
+
425 Overlay& overlay,
+
426 HashRouter& hashRouter,
+
427 NetworkOPs& networkOPs);
+
428
+
449 PublisherListStats
+
450 applyLists(
+
451 std::string const& manifest,
+
452 std::uint32_t version,
+
453 std::vector<ValidatorBlobInfo> const& blobs,
+
454 std::string siteUri,
+
455 std::optional<uint256> const& hash = {});
+
456
+
457 /* Attempt to read previously stored list files. Expected to only be
+
458 called when loading from URL fails.
459
-
460 May be called concurrently
-
461 */
-
462 std::vector<std::string>
-
463 loadLists();
-
464
-
480 TrustChanges
-
481 updateTrusted(
-
482 hash_set<NodeID> const& seenValidators,
-
483 NetClock::time_point closeTime,
-
484 NetworkOPs& ops,
-
485 Overlay& overlay,
-
486 HashRouter& hashRouter);
-
487
-
501 std::size_t
-
502 quorum() const
-
503 {
-
504 return quorum_;
-
505 }
-
506
-
515 bool
-
516 trusted(PublicKey const& identity) const;
-
517
-
526 bool
-
527 listed(PublicKey const& identity) const;
-
528
-
539 std::optional<PublicKey>
-
540 getTrustedKey(PublicKey const& identity) const;
-
541
-
552 std::optional<PublicKey>
-
553 getListedKey(PublicKey const& identity) const;
-
554
-
563 bool
-
564 trustedPublisher(PublicKey const& identity) const;
-
565
-
573 std::optional<PublicKey>
-
574 localPublicKey() const;
-
575
-
591 void
-
592 for_each_listed(std::function<void(PublicKey const&, bool)> func) const;
-
593
-
621 void
-
622 for_each_available(
-
623 std::function<void(
-
624 std::string const& manifest,
-
625 std::uint32_t version,
-
626 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
627 PublicKey const& pubKey,
-
628 std::size_t maxSequence,
-
629 uint256 const& hash)> func) const;
-
630
-
634 std::optional<Json::Value>
-
635 getAvailable(
-
636 std::string_view pubKey,
-
637 std::optional<std::uint32_t> forceVersion = {});
-
638
-
640 std::size_t
-
641 count() const;
+
460 @return A list of valid file:// URLs, if any.
+
461
+
462 @par Thread Safety
+
463
+
464 May be called concurrently
+
465 */
+
466 std::vector<std::string>
+
467 loadLists();
+
468
+
484 TrustChanges
+
485 updateTrusted(
+
486 hash_set<NodeID> const& seenValidators,
+
487 NetClock::time_point closeTime,
+
488 NetworkOPs& ops,
+
489 Overlay& overlay,
+
490 HashRouter& hashRouter);
+
491
+
505 std::size_t
+
506 quorum() const
+
507 {
+
508 return quorum_;
+
509 }
+
510
+
519 bool
+
520 trusted(PublicKey const& identity) const;
+
521
+
530 bool
+
531 listed(PublicKey const& identity) const;
+
532
+
543 std::optional<PublicKey>
+
544 getTrustedKey(PublicKey const& identity) const;
+
545
+
556 std::optional<PublicKey>
+
557 getListedKey(PublicKey const& identity) const;
+
558
+
567 bool
+
568 trustedPublisher(PublicKey const& identity) const;
+
569
+
577 std::optional<PublicKey>
+
578 localPublicKey() const;
+
579
+
595 void
+
596 for_each_listed(std::function<void(PublicKey const&, bool)> func) const;
+
597
+
625 void
+
626 for_each_available(
+
627 std::function<void(
+
628 std::string const& manifest,
+
629 std::uint32_t version,
+
630 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
631 PublicKey const& pubKey,
+
632 std::size_t maxSequence,
+
633 uint256 const& hash)> func) const;
+
634
+
638 std::optional<Json::Value>
+
639 getAvailable(
+
640 std::string_view pubKey,
+
641 std::optional<std::uint32_t> forceVersion = {});
642
-
652 std::optional<TimeKeeper::time_point>
-
653 expires() const;
-
654
-
660 Json::Value
-
661 getJson() const;
-
662
-
663 using QuorumKeys = std::pair<std::size_t const, hash_set<PublicKey>>;
-
668 QuorumKeys
-
669 getQuorumKeys() const
-
670 {
-
671 shared_lock read_lock{mutex_};
-
672 return {quorum_, trustedSigningKeys_};
-
673 }
-
674
-
679 hash_set<PublicKey>
-
680 getTrustedMasterKeys() const;
-
681
-
686 hash_set<PublicKey>
-
687 getNegativeUNL() const;
-
688
-
693 void
-
694 setNegativeUNL(hash_set<PublicKey> const& negUnl);
-
695
-
702 std::vector<std::shared_ptr<STValidation>>
-
703 negativeUNLFilter(
-
704 std::vector<std::shared_ptr<STValidation>>&& validations) const;
-
705
-
706private:
-
708 std::size_t
-
709 count(shared_lock const&) const;
-
710
-
719 bool
-
720 trusted(shared_lock const&, PublicKey const& identity) const;
+
644 std::size_t
+
645 count() const;
+
646
+
656 std::optional<TimeKeeper::time_point>
+
657 expires() const;
+
658
+
664 Json::Value
+
665 getJson() const;
+
666
+
667 using QuorumKeys = std::pair<std::size_t const, hash_set<PublicKey>>;
+
672 QuorumKeys
+
673 getQuorumKeys() const
+
674 {
+
675 shared_lock read_lock{mutex_};
+
676 return {quorum_, trustedSigningKeys_};
+
677 }
+
678
+
683 hash_set<PublicKey>
+
684 getTrustedMasterKeys() const;
+
685
+
690 std::size_t
+
691 getListThreshold() const;
+
692
+
697 hash_set<PublicKey>
+
698 getNegativeUNL() const;
+
699
+
704 void
+
705 setNegativeUNL(hash_set<PublicKey> const& negUnl);
+
706
+
713 std::vector<std::shared_ptr<STValidation>>
+
714 negativeUNLFilter(
+
715 std::vector<std::shared_ptr<STValidation>>&& validations) const;
+
716
+
717private:
+
719 std::size_t
+
720 count(shared_lock const&) const;
721
-
732 std::optional<PublicKey>
-
733 getTrustedKey(shared_lock const&, PublicKey const& identity) const;
-
734
-
744 std::optional<TimeKeeper::time_point>
-
745 expires(shared_lock const&) const;
-
746
-
769 PublisherListStats
-
770 applyList(
-
771 std::string const& globalManifest,
-
772 std::optional<std::string> const& localManifest,
-
773 std::string const& blob,
-
774 std::string const& signature,
-
775 std::uint32_t version,
-
776 std::string siteUri,
-
777 std::optional<uint256> const& hash,
-
778 lock_guard const&);
-
779
-
780 // This function updates the keyListings_ counts for all the trusted
-
781 // master keys
-
782 void
-
783 updatePublisherList(
-
784 PublicKey const& pubKey,
-
785 PublisherList const& current,
-
786 std::vector<PublicKey> const& oldList,
-
787 lock_guard const&);
-
788
-
789 static void
-
790 buildBlobInfos(
-
791 std::map<std::size_t, ValidatorBlobInfo>& blobInfos,
-
792 PublisherListCollection const& lists);
-
793
-
794 static std::map<std::size_t, ValidatorBlobInfo>
-
795 buildBlobInfos(PublisherListCollection const& lists);
-
796
-
797 static void
-
798 broadcastBlobs(
-
799 PublicKey const& publisherKey,
-
800 PublisherListCollection const& lists,
-
801 std::size_t maxSequence,
-
802 uint256 const& hash,
-
803 Overlay& overlay,
-
804 HashRouter& hashRouter,
-
805 beast::Journal j);
-
806
-
807 static void
-
808 sendValidatorList(
-
809 Peer& peer,
-
810 std::uint64_t peerSequence,
-
811 PublicKey const& publisherKey,
+
730 bool
+
731 trusted(shared_lock const&, PublicKey const& identity) const;
+
732
+
743 std::optional<PublicKey>
+
744 getTrustedKey(shared_lock const&, PublicKey const& identity) const;
+
745
+
755 std::optional<TimeKeeper::time_point>
+
756 expires(shared_lock const&) const;
+
757
+
780 PublisherListStats
+
781 applyList(
+
782 std::string const& globalManifest,
+
783 std::optional<std::string> const& localManifest,
+
784 std::string const& blob,
+
785 std::string const& signature,
+
786 std::uint32_t version,
+
787 std::string siteUri,
+
788 std::optional<uint256> const& hash,
+
789 lock_guard const&);
+
790
+
791 // This function updates the keyListings_ counts for all the trusted
+
792 // master keys
+
793 void
+
794 updatePublisherList(
+
795 PublicKey const& pubKey,
+
796 PublisherList const& current,
+
797 std::vector<PublicKey> const& oldList,
+
798 lock_guard const&);
+
799
+
800 static void
+
801 buildBlobInfos(
+
802 std::map<std::size_t, ValidatorBlobInfo>& blobInfos,
+
803 PublisherListCollection const& lists);
+
804
+
805 static std::map<std::size_t, ValidatorBlobInfo>
+
806 buildBlobInfos(PublisherListCollection const& lists);
+
807
+
808 static void
+
809 broadcastBlobs(
+
810 PublicKey const& publisherKey,
+
811 PublisherListCollection const& lists,
812 std::size_t maxSequence,
-
813 std::uint32_t rawVersion,
-
814 std::string const& rawManifest,
-
815 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
-
816 std::vector<MessageWithHash>& messages,
-
817 HashRouter& hashRouter,
-
818 beast::Journal j);
-
819
-
822 boost::filesystem::path
-
823 getCacheFileName(lock_guard const&, PublicKey const& pubKey) const;
-
824
-
828 static Json::Value
-
829 buildFileData(
-
830 std::string const& pubKey,
-
831 PublisherListCollection const& pubCollection,
-
832 beast::Journal j);
-
833
-
837 static Json::Value
-
838 buildFileData(
-
839 std::string const& pubKey,
-
840 PublisherListCollection const& pubCollection,
-
841 std::optional<std::uint32_t> forceVersion,
-
842 beast::Journal j);
-
843
-
844 template <class Hasher>
-
845 friend void
-
846 hash_append(Hasher& h, PublisherListCollection pl)
-
847 {
-
848 using beast::hash_append;
-
849 hash_append(h, pl.rawManifest, buildBlobInfos(pl), pl.rawVersion);
-
850 }
-
851
-
854 void
-
855 cacheValidatorFile(lock_guard const& lock, PublicKey const& pubKey) const;
-
856
-
865 std::pair<ListDisposition, std::optional<PublicKey>>
-
866 verify(
-
867 lock_guard const&,
-
868 Json::Value& list,
-
869 std::string const& manifest,
-
870 std::string const& blob,
-
871 std::string const& signature);
-
872
-
883 bool
-
884 removePublisherList(
-
885 lock_guard const&,
-
886 PublicKey const& publisherKey,
-
887 PublisherStatus reason);
-
888
-
899 std::size_t
-
900 calculateQuorum(
-
901 std::size_t unlSize,
-
902 std::size_t effectiveUnlSize,
-
903 std::size_t seenSize);
-
904};
-
905
-
906// hashing helpers
-
907template <class Hasher>
-
908void
-
909hash_append(Hasher& h, ValidatorBlobInfo const& blobInfo)
-
910{
-
911 using beast::hash_append;
-
912 hash_append(h, blobInfo.blob, blobInfo.signature);
-
913 if (blobInfo.manifest)
-
914 {
-
915 hash_append(h, *blobInfo.manifest);
-
916 }
-
917}
-
918
-
919template <class Hasher>
-
920void
-
921hash_append(Hasher& h, std::vector<ValidatorBlobInfo> const& blobs)
-
922{
-
923 for (auto const& item : blobs)
-
924 hash_append(h, item);
-
925}
-
926
-
927template <class Hasher>
-
928void
-
929hash_append(Hasher& h, std::map<std::size_t, ValidatorBlobInfo> const& blobs)
-
930{
-
931 for (auto const& [_, item] : blobs)
-
932 {
-
933 (void)_;
-
934 hash_append(h, item);
-
935 }
+
813 uint256 const& hash,
+
814 Overlay& overlay,
+
815 HashRouter& hashRouter,
+
816 beast::Journal j);
+
817
+
818 static void
+
819 sendValidatorList(
+
820 Peer& peer,
+
821 std::uint64_t peerSequence,
+
822 PublicKey const& publisherKey,
+
823 std::size_t maxSequence,
+
824 std::uint32_t rawVersion,
+
825 std::string const& rawManifest,
+
826 std::map<std::size_t, ValidatorBlobInfo> const& blobInfos,
+
827 std::vector<MessageWithHash>& messages,
+
828 HashRouter& hashRouter,
+
829 beast::Journal j);
+
830
+
833 boost::filesystem::path
+
834 getCacheFileName(lock_guard const&, PublicKey const& pubKey) const;
+
835
+
839 static Json::Value
+
840 buildFileData(
+
841 std::string const& pubKey,
+
842 PublisherListCollection const& pubCollection,
+
843 beast::Journal j);
+
844
+
848 static Json::Value
+
849 buildFileData(
+
850 std::string const& pubKey,
+
851 PublisherListCollection const& pubCollection,
+
852 std::optional<std::uint32_t> forceVersion,
+
853 beast::Journal j);
+
854
+
855 template <class Hasher>
+
856 friend void
+
857 hash_append(Hasher& h, PublisherListCollection pl)
+
858 {
+
859 using beast::hash_append;
+
860 hash_append(h, pl.rawManifest, buildBlobInfos(pl), pl.rawVersion);
+
861 }
+
862
+
865 void
+
866 cacheValidatorFile(lock_guard const& lock, PublicKey const& pubKey) const;
+
867
+
876 std::pair<ListDisposition, std::optional<PublicKey>>
+
877 verify(
+
878 lock_guard const&,
+
879 Json::Value& list,
+
880 std::string const& manifest,
+
881 std::string const& blob,
+
882 std::string const& signature);
+
883
+
894 bool
+
895 removePublisherList(
+
896 lock_guard const&,
+
897 PublicKey const& publisherKey,
+
898 PublisherStatus reason);
+
899
+
910 std::size_t
+
911 calculateQuorum(
+
912 std::size_t unlSize,
+
913 std::size_t effectiveUnlSize,
+
914 std::size_t seenSize);
+
915};
+
916
+
917// hashing helpers
+
918template <class Hasher>
+
919void
+
920hash_append(Hasher& h, ValidatorBlobInfo const& blobInfo)
+
921{
+
922 using beast::hash_append;
+
923 hash_append(h, blobInfo.blob, blobInfo.signature);
+
924 if (blobInfo.manifest)
+
925 {
+
926 hash_append(h, *blobInfo.manifest);
+
927 }
+
928}
+
929
+
930template <class Hasher>
+
931void
+
932hash_append(Hasher& h, std::vector<ValidatorBlobInfo> const& blobs)
+
933{
+
934 for (auto const& item : blobs)
+
935 hash_append(h, item);
936}
937
-
938} // namespace ripple
-
939
-
940namespace protocol {
-
941
-
942template <class Hasher>
-
943void
-
944hash_append(Hasher& h, TMValidatorList const& msg)
-
945{
-
946 using beast::hash_append;
-
947 hash_append(h, msg.manifest(), msg.blob(), msg.signature(), msg.version());
-
948}
-
949
-
950template <class Hasher>
-
951void
-
952hash_append(Hasher& h, TMValidatorListCollection const& msg)
-
953{
-
954 using beast::hash_append;
-
955 hash_append(
-
956 h,
-
957 msg.manifest(),
-
958 ripple::ValidatorList::parseBlobs(msg),
-
959 msg.version());
-
960}
-
961
-
962} // namespace protocol
-
963
-
964#endif
+
938template <class Hasher>
+
939void
+
940hash_append(Hasher& h, std::map<std::size_t, ValidatorBlobInfo> const& blobs)
+
941{
+
942 for (auto const& [_, item] : blobs)
+
943 {
+
944 (void)_;
+
945 hash_append(h, item);
+
946 }
+
947}
+
948
+
949} // namespace ripple
+
950
+
951namespace protocol {
+
952
+
953template <class Hasher>
+
954void
+
955hash_append(Hasher& h, TMValidatorList const& msg)
+
956{
+
957 using beast::hash_append;
+
958 hash_append(h, msg.manifest(), msg.blob(), msg.signature(), msg.version());
+
959}
+
960
+
961template <class Hasher>
+
962void
+
963hash_append(Hasher& h, TMValidatorListCollection const& msg)
+
964{
+
965 using beast::hash_append;
+
966 hash_append(
+
967 h,
+
968 msg.manifest(),
+
969 ripple::ValidatorList::parseBlobs(msg),
+
970 msg.version());
+
971}
+
972
+
973} // namespace protocol
+
974
+
975#endif
std::atomic
std::string
std::string_view
@@ -666,70 +673,73 @@ $(function() {
beast::abstract_clock< NetClock >::time_point
typename Clock::time_point time_point
Definition: abstract_clock.h:63
ripple::HashRouter
Routing table for objects identified by hash.
Definition: HashRouter.h:54
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:256
+
ripple::NetClock::time_point
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:70
ripple::NetworkOPs
Provides server functionality for clients.
Definition: NetworkOPs.h:87
ripple::Overlay
Manages the set of connected peers.
Definition: Overlay.h:52
ripple::Peer
Represents a peer connection in the overlay.
Definition: xrpld/overlay/Peer.h:43
ripple::PublicKey
A public key.
Definition: PublicKey.h:62
ripple::TimeKeeper
Manages various times used by the server.
Definition: TimeKeeper.h:32
ripple::ValidatorList
Definition: ValidatorList.h:173
-
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:1520
-
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1456
-
ripple::ValidatorList::load
bool load(std::optional< PublicKey > const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys)
Load configured trusted keys.
Definition: ValidatorList.cpp:136
-
ripple::ValidatorList::sendValidatorList
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:785
-
ripple::ValidatorList::broadcastBlobs
static void broadcastBlobs(PublicKey const &publisherKey, PublisherListCollection const &lists, std::size_t maxSequence, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:838
-
ripple::ValidatorList::getCacheFileName
boost::filesystem::path getCacheFileName(lock_guard const &, PublicKey const &pubKey) const
Get the filename used for caching UNLs.
Definition: ValidatorList.cpp:252
-
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1267
-
ripple::ValidatorList::localPublisherList
PublisherList localPublisherList
Definition: ValidatorList.h:260
-
ripple::ValidatorList::localPublicKey
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
Definition: ValidatorList.cpp:1472
+
ripple::ValidatorList::count
std::size_t count() const
Return the number of configured validator list sites.
Definition: ValidatorList.cpp:1552
+
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1488
+
ripple::ValidatorList::sendValidatorList
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:817
+
ripple::ValidatorList::broadcastBlobs
static void broadcastBlobs(PublicKey const &publisherKey, PublisherListCollection const &lists, std::size_t maxSequence, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, beast::Journal j)
Definition: ValidatorList.cpp:870
+
ripple::ValidatorList::getCacheFileName
boost::filesystem::path getCacheFileName(lock_guard const &, PublicKey const &pubKey) const
Get the filename used for caching UNLs.
Definition: ValidatorList.cpp:284
+
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1299
+
ripple::ValidatorList::localPublisherList
PublisherList localPublisherList
Definition: ValidatorList.h:263
+
ripple::ValidatorList::localPublicKey
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
Definition: ValidatorList.cpp:1504
ripple::ValidatorList::validatorManifests_
ManifestCache & validatorManifests_
Definition: ValidatorList.h:224
-
ripple::ValidatorList::getTrustedMasterKeys
hash_set< PublicKey > getTrustedMasterKeys() const
get the trusted master public keys
Definition: ValidatorList.cpp:2033
+
ripple::ValidatorList::getTrustedMasterKeys
hash_set< PublicKey > getTrustedMasterKeys() const
get the trusted master public keys
Definition: ValidatorList.cpp:2105
ripple::ValidatorList::~ValidatorList
~ValidatorList()=default
ripple::ValidatorList::quorum_
std::atomic< std::size_t > quorum_
Definition: ValidatorList.h:233
-
ripple::ValidatorList::updatePublisherList
void updatePublisherList(PublicKey const &pubKey, PublisherList const &current, std::vector< PublicKey > const &oldList, lock_guard const &)
Definition: ValidatorList.cpp:1040
-
ripple::ValidatorList::setNegativeUNL
void setNegativeUNL(hash_set< PublicKey > const &negUnl)
set the Negative UNL with validators' master public keys
Definition: ValidatorList.cpp:2047
+
ripple::ValidatorList::updatePublisherList
void updatePublisherList(PublicKey const &pubKey, PublisherList const &current, std::vector< PublicKey > const &oldList, lock_guard const &)
Definition: ValidatorList.cpp:1072
+
ripple::ValidatorList::setNegativeUNL
void setNegativeUNL(hash_set< PublicKey > const &negUnl)
set the Negative UNL with validators' master public keys
Definition: ValidatorList.cpp:2126
ripple::ValidatorList::timeKeeper_
TimeKeeper & timeKeeper_
Definition: ValidatorList.h:226
-
ripple::ValidatorList::buildFileData
static Json::Value buildFileData(std::string const &pubKey, PublisherListCollection const &pubCollection, beast::Journal j)
Build a Json representation of the collection, suitable for writing to a cache file,...
Definition: ValidatorList.cpp:261
-
ripple::ValidatorList::buildBlobInfos
static void buildBlobInfos(std::map< std::size_t, ValidatorBlobInfo > &blobInfos, PublisherListCollection const &lists)
Definition: ValidatorList.cpp:812
+
ripple::ValidatorList::buildFileData
static Json::Value buildFileData(std::string const &pubKey, PublisherListCollection const &pubCollection, beast::Journal j)
Build a Json representation of the collection, suitable for writing to a cache file,...
Definition: ValidatorList.cpp:293
+
ripple::ValidatorList::buildBlobInfos
static void buildBlobInfos(std::map< std::size_t, ValidatorBlobInfo > &blobInfos, PublisherListCollection const &lists)
Definition: ValidatorList.cpp:844
ripple::ValidatorList::keyListings_
hash_map< PublicKey, std::size_t > keyListings_
Definition: ValidatorList.h:240
-
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:1409
-
ripple::ValidatorList::cacheValidatorFile
void cacheValidatorFile(lock_guard const &lock, PublicKey const &pubKey) const
Write a JSON UNL to a cache file.
Definition: ValidatorList.cpp:335
+
ripple::ValidatorList::listed
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Definition: ValidatorList.cpp:1441
+
ripple::ValidatorList::listThreshold_
std::size_t listThreshold_
Definition: ValidatorList.h:246
+
ripple::ValidatorList::cacheValidatorFile
void cacheValidatorFile(lock_guard const &lock, PublicKey const &pubKey) const
Write a JSON UNL to a cache file.
Definition: ValidatorList.cpp:367
ripple::ValidatorList::trustedMasterKeys_
hash_set< PublicKey > trustedMasterKeys_
Definition: ValidatorList.h:243
-
ripple::ValidatorList::getAvailable
std::optional< Json::Value > getAvailable(std::string_view pubKey, std::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
Definition: ValidatorList.cpp:1753
-
ripple::ValidatorList::applyList
PublisherListStats applyList(std::string const &globalManifest, std::optional< std::string > const &localManifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, std::optional< uint256 > const &hash, lock_guard const &)
Apply published list of public keys.
Definition: ValidatorList.cpp:1104
-
ripple::ValidatorList::negativeUNL_
hash_set< PublicKey > negativeUNL_
Definition: ValidatorList.h:263
-
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1583
-
ripple::ValidatorList::for_each_available
void for_each_available(std::function< void(std::string const &manifest, std::uint32_t version, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, PublicKey const &pubKey, std::size_t maxSequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
Definition: ValidatorList.cpp:1724
-
ripple::ValidatorList::expires
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1576
-
ripple::ValidatorList::calculateQuorum
std::size_t calculateQuorum(std::size_t unlSize, std::size_t effectiveUnlSize, std::size_t seenSize)
Return quorum for trusted validator set.
Definition: ValidatorList.cpp:1783
-
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:906
+
ripple::ValidatorList::getAvailable
std::optional< Json::Value > getAvailable(std::string_view pubKey, std::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
Definition: ValidatorList.cpp:1787
+
ripple::ValidatorList::applyList
PublisherListStats applyList(std::string const &globalManifest, std::optional< std::string > const &localManifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, std::optional< uint256 > const &hash, lock_guard const &)
Apply published list of public keys.
Definition: ValidatorList.cpp:1136
+
ripple::ValidatorList::negativeUNL_
hash_set< PublicKey > negativeUNL_
Definition: ValidatorList.h:266
+
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1615
+
ripple::ValidatorList::for_each_available
void for_each_available(std::function< void(std::string const &manifest, std::uint32_t version, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, PublicKey const &pubKey, std::size_t maxSequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
Definition: ValidatorList.cpp:1758
+
ripple::ValidatorList::expires
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
Definition: ValidatorList.cpp:1608
+
ripple::ValidatorList::calculateQuorum
std::size_t calculateQuorum(std::size_t unlSize, std::size_t effectiveUnlSize, std::size_t seenSize)
Return quorum for trusted validator set.
Definition: ValidatorList.cpp:1817
+
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:938
ripple::ValidatorList::lock_guard
std::lock_guard< decltype(mutex_)> lock_guard
Definition: ValidatorList.h:230
ripple::ValidatorList::j_
beast::Journal const j_
Definition: ValidatorList.h:228
-
ripple::ValidatorList::trustedPublisher
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
Definition: ValidatorList.cpp:1464
-
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1434
+
ripple::ValidatorList::trustedPublisher
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
Definition: ValidatorList.cpp:1496
+
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1466
ripple::ValidatorList::dataPath_
boost::filesystem::path const dataPath_
Definition: ValidatorList.h:227
ripple::ValidatorList::mutex_
boost::shared_mutex mutex_
Definition: ValidatorList.h:229
-
ripple::ValidatorList::removePublisherList
bool removePublisherList(lock_guard const &, PublicKey const &publisherKey, PublisherStatus reason)
Stop trusting publisher's list of keys.
Definition: ValidatorList.cpp:1479
-
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:1427
-
ripple::ValidatorList::maxSupportedBlobs
static constexpr std::size_t maxSupportedBlobs
Definition: ValidatorList.h:269
-
ripple::ValidatorList::updateTrusted
TrustChanges updateTrusted(hash_set< NodeID > const &seenValidators, NetClock::time_point closeTime, NetworkOPs &ops, Overlay &overlay, HashRouter &hashRouter)
Update trusted nodes.
Definition: ValidatorList.cpp:1844
-
ripple::ValidatorList::verify
std::pair< ListDisposition, std::optional< PublicKey > > verify(lock_guard const &, Json::Value &list, std::string const &manifest, std::string const &blob, std::string const &signature)
Check response for trusted valid published list.
Definition: ValidatorList.cpp:1322
-
ripple::ValidatorList::for_each_listed
void for_each_listed(std::function< void(PublicKey const &, bool)> func) const
Invokes the callback once for every listed validation public key.
Definition: ValidatorList.cpp:1714
-
ripple::ValidatorList::localPubKey_
std::optional< PublicKey > localPubKey_
Definition: ValidatorList.h:250
-
ripple::ValidatorList::negativeUNLFilter
std::vector< std::shared_ptr< STValidation > > negativeUNLFilter(std::vector< std::shared_ptr< STValidation > > &&validations) const
Remove validations that are from validators on the negative UNL.
Definition: ValidatorList.cpp:2054
+
ripple::ValidatorList::removePublisherList
bool removePublisherList(lock_guard const &, PublicKey const &publisherKey, PublisherStatus reason)
Stop trusting publisher's list of keys.
Definition: ValidatorList.cpp:1511
+
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:1459
+
ripple::ValidatorList::maxSupportedBlobs
static constexpr std::size_t maxSupportedBlobs
Definition: ValidatorList.h:272
+
ripple::ValidatorList::updateTrusted
TrustChanges updateTrusted(hash_set< NodeID > const &seenValidators, NetClock::time_point closeTime, NetworkOPs &ops, Overlay &overlay, HashRouter &hashRouter)
Update trusted nodes.
Definition: ValidatorList.cpp:1909
+
ripple::ValidatorList::verify
std::pair< ListDisposition, std::optional< PublicKey > > verify(lock_guard const &, Json::Value &list, std::string const &manifest, std::string const &blob, std::string const &signature)
Check response for trusted valid published list.
Definition: ValidatorList.cpp:1354
+
ripple::ValidatorList::getListThreshold
std::size_t getListThreshold() const
get the validator list threshold
Definition: ValidatorList.cpp:2112
+
ripple::ValidatorList::for_each_listed
void for_each_listed(std::function< void(PublicKey const &, bool)> func) const
Invokes the callback once for every listed validation public key.
Definition: ValidatorList.cpp:1748
+
ripple::ValidatorList::localPubKey_
std::optional< PublicKey > localPubKey_
Definition: ValidatorList.h:253
+
ripple::ValidatorList::negativeUNLFilter
std::vector< std::shared_ptr< STValidation > > negativeUNLFilter(std::vector< std::shared_ptr< STValidation > > &&validations) const
Remove validations that are from validators on the negative UNL.
Definition: ValidatorList.cpp:2133
+
ripple::ValidatorList::load
bool load(std::optional< PublicKey > const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys, std::optional< std::size_t > listThreshold={})
Load configured trusted keys.
Definition: ValidatorList.cpp:137
ripple::ValidatorList::minimumQuorum_
std::optional< std::size_t > minimumQuorum_
Definition: ValidatorList.h:234
-
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:366
-
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:502
-
ripple::ValidatorList::trustedSigningKeys_
hash_set< PublicKey > trustedSigningKeys_
Definition: ValidatorList.h:248
+
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:398
+
ripple::ValidatorList::quorum
std::size_t quorum() const
Get quorum value for current trusted key set.
Definition: ValidatorList.h:506
+
ripple::ValidatorList::trustedSigningKeys_
hash_set< PublicKey > trustedSigningKeys_
Definition: ValidatorList.h:251
ripple::ValidatorList::publisherLists_
hash_map< PublicKey, PublisherListCollection > publisherLists_
Definition: ValidatorList.h:237
-
ripple::ValidatorList::applyLists
PublisherListStats applyLists(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, std::optional< uint256 > const &hash={})
Apply multiple published lists of public keys.
Definition: ValidatorList.cpp:964
-
ripple::ValidatorList::buildValidatorListMessages
static std::pair< std::size_t, std::size_t > buildValidatorListMessages(std::size_t messageVersion, std::uint64_t peerSequence, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, std::vector< MessageWithHash > &messages, std::size_t maxSize=maximiumMessageSize)
Definition: ValidatorList.cpp:638
-
ripple::ValidatorList::getQuorumKeys
QuorumKeys getQuorumKeys() const
Get the quorum and all of the trusted keys.
Definition: ValidatorList.h:669
-
ripple::ValidatorList::filePrefix_
static const std::string filePrefix_
Definition: ValidatorList.h:271
+
ripple::ValidatorList::applyLists
PublisherListStats applyLists(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, std::optional< uint256 > const &hash={})
Apply multiple published lists of public keys.
Definition: ValidatorList.cpp:996
+
ripple::ValidatorList::buildValidatorListMessages
static std::pair< std::size_t, std::size_t > buildValidatorListMessages(std::size_t messageVersion, std::uint64_t peerSequence, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, std::vector< MessageWithHash > &messages, std::size_t maxSize=maximiumMessageSize)
Definition: ValidatorList.cpp:670
+
ripple::ValidatorList::getQuorumKeys
QuorumKeys getQuorumKeys() const
Get the quorum and all of the trusted keys.
Definition: ValidatorList.h:673
+
ripple::ValidatorList::filePrefix_
static const std::string filePrefix_
Definition: ValidatorList.h:274
ripple::ValidatorList::shared_lock
std::shared_lock< decltype(mutex_)> shared_lock
Definition: ValidatorList.h:231
ripple::ValidatorList::publisherManifests_
ManifestCache & publisherManifests_
Definition: ValidatorList.h:225
-
ripple::ValidatorList::supportedListVersions
static constexpr std::uint32_t supportedListVersions[]
Definition: ValidatorList.h:266
-
ripple::ValidatorList::getNegativeUNL
hash_set< PublicKey > getNegativeUNL() const
get the master public keys of Negative UNL validators
Definition: ValidatorList.cpp:2040
-
ripple::ValidatorList::hash_append
friend void hash_append(Hasher &h, PublisherListCollection pl)
Definition: ValidatorList.h:846
+
ripple::ValidatorList::supportedListVersions
static constexpr std::uint32_t supportedListVersions[]
Definition: ValidatorList.h:269
+
ripple::ValidatorList::getNegativeUNL
hash_set< PublicKey > getNegativeUNL() const
get the master public keys of Negative UNL validators
Definition: ValidatorList.cpp:2119
+
ripple::ValidatorList::hash_append
friend void hash_append(Hasher &h, PublisherListCollection pl)
Definition: ValidatorList.h:857
ripple::base_uint< 256 >
std::function
std::uint32_t
@@ -738,7 +748,7 @@ $(function() {
mutex
beast::hash_append
std::enable_if_t< is_contiguously_hashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
Definition: hash_append.h:236
protocol
Definition: ValidatorList.h:38
-
protocol::hash_append
void hash_append(Hasher &h, TMValidatorList const &msg)
Definition: ValidatorList.h:944
+
protocol::hash_append
void hash_append(Hasher &h, TMValidatorList const &msg)
Definition: ValidatorList.h:955
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::hash_append
void hash_append(Hasher &h, Slice const &v)
Definition: Slice.h:198
ripple::ValStatus::current
@ current
This was a new validation and was added.
@@ -774,11 +784,11 @@ $(function() {
ripple::ValidatorBlobInfo::blob
std::string blob
Definition: ValidatorList.h:119
ripple::ValidatorBlobInfo::signature
std::string signature
Definition: ValidatorList.h:121
ripple::ValidatorBlobInfo::manifest
std::optional< std::string > manifest
Definition: ValidatorList.h:124
-
ripple::ValidatorList::MessageWithHash
Definition: ValidatorList.h:314
+
ripple::ValidatorList::MessageWithHash
Definition: ValidatorList.h:317
ripple::ValidatorList::MessageWithHash::MessageWithHash
MessageWithHash()=default
-
ripple::ValidatorList::MessageWithHash::hash
uint256 hash
Definition: ValidatorList.h:321
-
ripple::ValidatorList::MessageWithHash::message
std::shared_ptr< Message > message
Definition: ValidatorList.h:320
-
ripple::ValidatorList::MessageWithHash::numVLs
std::size_t numVLs
Definition: ValidatorList.h:322
+
ripple::ValidatorList::MessageWithHash::hash
uint256 hash
Definition: ValidatorList.h:324
+
ripple::ValidatorList::MessageWithHash::message
std::shared_ptr< Message > message
Definition: ValidatorList.h:323
+
ripple::ValidatorList::MessageWithHash::numVLs
std::size_t numVLs
Definition: ValidatorList.h:325
ripple::ValidatorList::PublisherListCollection
Definition: ValidatorList.h:195
ripple::ValidatorList::PublisherListCollection::rawManifest
std::string rawManifest
Definition: ValidatorList.h:220
ripple::ValidatorList::PublisherListCollection::current
PublisherList current
Definition: ValidatorList.h:207
@@ -787,15 +797,15 @@ $(function() {
ripple::ValidatorList::PublisherListCollection::fullHash
uint256 fullHash
Definition: ValidatorList.h:219
ripple::ValidatorList::PublisherListCollection::maxSequence
std::optional< std::size_t > maxSequence
Definition: ValidatorList.h:217
ripple::ValidatorList::PublisherListCollection::status
PublisherStatus status
Definition: ValidatorList.h:196
-
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:289
+
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:292
ripple::ValidatorList::PublisherListStats::mergeDispositions
void mergeDispositions(PublisherListStats const &src)
Definition: ValidatorList.cpp:99
ripple::ValidatorList::PublisherListStats::bestDisposition
ListDisposition bestDisposition() const
Definition: ValidatorList.cpp:85
ripple::ValidatorList::PublisherListStats::PublisherListStats
PublisherListStats()=default
ripple::ValidatorList::PublisherListStats::worstDisposition
ListDisposition worstDisposition() const
Definition: ValidatorList.cpp:92
-
ripple::ValidatorList::PublisherListStats::dispositions
std::map< ListDisposition, std::size_t > dispositions
Definition: ValidatorList.h:307
-
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:308
-
ripple::ValidatorList::PublisherListStats::sequence
std::size_t sequence
Definition: ValidatorList.h:310
-
ripple::ValidatorList::PublisherListStats::status
PublisherStatus status
Definition: ValidatorList.h:309
+
ripple::ValidatorList::PublisherListStats::dispositions
std::map< ListDisposition, std::size_t > dispositions
Definition: ValidatorList.h:310
+
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:311
+
ripple::ValidatorList::PublisherListStats::sequence
std::size_t sequence
Definition: ValidatorList.h:313
+
ripple::ValidatorList::PublisherListStats::status
PublisherStatus status
Definition: ValidatorList.h:312
ripple::ValidatorList::PublisherList
Definition: ValidatorList.h:175
ripple::ValidatorList::PublisherList::list
std::vector< PublicKey > list
Definition: ValidatorList.h:178
ripple::ValidatorList::PublisherList::hash
uint256 hash
Definition: ValidatorList.h:191
@@ -808,7 +818,6 @@ $(function() {
ripple::ValidatorList::PublisherList::validUntil
TimeKeeper::time_point validUntil
Definition: ValidatorList.h:182
ripple::ValidatorList::PublisherList::validFrom
TimeKeeper::time_point validFrom
Definition: ValidatorList.h:181
ripple::ValidatorList::PublisherList::manifests
std::vector< std::string > manifests
Definition: ValidatorList.h:179
-
std::chrono::time_point
std::unordered_map
std::unordered_set
std::vector
diff --git a/ValidatorList__test_8cpp_source.html b/ValidatorList__test_8cpp_source.html index f28862d810..d5e34dec7e 100644 --- a/ValidatorList__test_8cpp_source.html +++ b/ValidatorList__test_8cpp_source.html @@ -504,1996 +504,3734 @@ $(function() {
426 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
427 for (auto const& key : keys)
428 BEAST_EXPECT(trustedKeys->trustedPublisher(key));
-
429 }
-
430 {
-
431 // Attempt to load a publisher key that has been revoked.
-
432 // Should fail
-
433 ManifestCache valManifests;
-
434 ManifestCache pubManifests;
-
435 auto trustedKeys = std::make_unique<ValidatorList>(
-
436 valManifests,
-
437 pubManifests,
-
438 env.timeKeeper(),
-
439 app.config().legacy("database_path"),
-
440 env.journal);
-
441
-
442 auto const pubRevokedSecret = randomSecretKey();
-
443 auto const pubRevokedPublic =
-
444 derivePublicKey(KeyType::ed25519, pubRevokedSecret);
-
445 auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
-
446 // make this manifest revoked (seq num = max)
-
447 // -- thus should not be loaded
-
448 pubManifests.applyManifest(*deserializeManifest(makeManifestString(
-
449 pubRevokedPublic,
-
450 pubRevokedSecret,
-
451 pubRevokedSigning.first,
-
452 pubRevokedSigning.second,
-
453 std::numeric_limits<std::uint32_t>::max())));
-
454
-
455 // this one is not revoked (and not in manifest cache at all.)
-
456 auto legitKey = randomMasterKey();
-
457
-
458 std::vector<std::string> cfgPublishers = {
-
459 strHex(pubRevokedPublic), strHex(legitKey)};
-
460 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
-
461
-
462 BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
-
463 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey));
-
464 }
-
465 }
-
466
-
467 void
-
468 testApplyLists()
-
469 {
-
470 testcase("Apply list");
-
471 using namespace std::chrono_literals;
-
472
-
473 std::string const siteUri = "testApplyList.test";
-
474
-
475 auto checkAvailable =
-
476 [this](
-
477 auto const& trustedKeys,
-
478 auto const& hexPublic,
-
479 auto const& manifest,
-
480 auto const version,
-
481 std::vector<std::pair<std::string, std::string>> const&
-
482 expected) {
-
483 const auto available = trustedKeys->getAvailable(hexPublic);
-
484
-
485 BEAST_EXPECT(!version || available);
-
486 if (available)
-
487 {
-
488 auto const& a = *available;
-
489 BEAST_EXPECT(a[jss::public_key] == hexPublic);
-
490 BEAST_EXPECT(a[jss::manifest] == manifest);
-
491 // Because multiple lists were processed, the version was
-
492 // overridden
-
493 BEAST_EXPECT(a[jss::version] == version);
-
494 if (version == 1)
-
495 {
-
496 BEAST_EXPECT(expected.size() == 1);
-
497 BEAST_EXPECT(a[jss::blob] == expected[0].first);
-
498 BEAST_EXPECT(a[jss::signature] == expected[0].second);
-
499 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
-
500 }
-
501 else if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
-
502 {
-
503 BEAST_EXPECT(!a.isMember(jss::blob));
-
504 BEAST_EXPECT(!a.isMember(jss::signature));
-
505 auto const& blobs_v2 = a[jss::blobs_v2];
-
506 BEAST_EXPECT(
-
507 blobs_v2.isArray() &&
-
508 blobs_v2.size() == expected.size());
-
509
-
510 for (unsigned int i = 0; i < expected.size(); ++i)
-
511 {
-
512 BEAST_EXPECT(
-
513 blobs_v2[i][jss::blob] == expected[i].first);
-
514 BEAST_EXPECT(
-
515 blobs_v2[i][jss::signature] ==
-
516 expected[i].second);
-
517 }
-
518 }
-
519 }
-
520 };
-
521
-
522 ManifestCache manifests;
-
523 jtx::Env env(*this);
-
524 auto& app = env.app();
-
525 auto trustedKeys = std::make_unique<ValidatorList>(
-
526 manifests,
-
527 manifests,
-
528 env.app().timeKeeper(),
-
529 app.config().legacy("database_path"),
-
530 env.journal);
-
531
-
532 auto expectTrusted =
-
533 [this, &trustedKeys](std::vector<Validator> const& list) {
-
534 for (auto const& val : list)
-
535 {
-
536 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
-
537 BEAST_EXPECT(trustedKeys->listed(val.signingPublic));
-
538 }
-
539 };
-
540
-
541 auto expectUntrusted =
-
542 [this, &trustedKeys](std::vector<Validator> const& list) {
-
543 for (auto const& val : list)
-
544 {
-
545 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
-
546 BEAST_EXPECT(!trustedKeys->listed(val.signingPublic));
-
547 }
-
548 };
-
549
-
550 auto const publisherSecret = randomSecretKey();
-
551 auto const publisherPublic =
-
552 derivePublicKey(KeyType::ed25519, publisherSecret);
-
553 const auto hexPublic =
-
554 strHex(publisherPublic.begin(), publisherPublic.end());
-
555 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
-
556 auto const manifest1 = base64_encode(makeManifestString(
-
557 publisherPublic,
-
558 publisherSecret,
-
559 pubSigningKeys1.first,
-
560 pubSigningKeys1.second,
-
561 1));
-
562
-
563 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
-
564 std::vector<std::string> emptyCfgKeys;
-
565
-
566 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
-
567
-
568 std::map<std::size_t, std::vector<Validator>> const lists = []() {
-
569 auto constexpr listSize = 20;
-
570 auto constexpr numLists = 9;
-
571 std::map<std::size_t, std::vector<Validator>> lists;
-
572 // 1-based to correspond with the individually named blobs below.
-
573 for (auto i = 1; i <= numLists; ++i)
-
574 {
-
575 auto& list = lists[i];
-
576 list.reserve(listSize);
-
577 while (list.size() < listSize)
-
578 list.push_back(randomValidator());
-
579 }
-
580 return lists;
-
581 }();
-
582
-
583 // Attempt an expired list (fail) and a single list (succeed)
-
584 env.timeKeeper().set(env.timeKeeper().now() + 1s);
-
585 auto const version = 1;
-
586 auto const sequence1 = 1;
-
587 auto const expiredblob = makeList(
-
588 lists.at(1),
-
589 sequence1,
-
590 env.timeKeeper().now().time_since_epoch().count());
-
591 auto const expiredSig = signList(expiredblob, pubSigningKeys1);
-
592
-
593 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
-
594 auto const sequence2 = 2;
-
595 auto const blob2 = makeList(
-
596 lists.at(2), sequence2, validUntil.time_since_epoch().count());
-
597 auto const sig2 = signList(blob2, pubSigningKeys1);
-
598
-
599 checkResult(
-
600 trustedKeys->applyLists(
-
601 manifest1,
-
602 version,
-
603 {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}},
-
604 siteUri),
-
605 publisherPublic,
-
606 ListDisposition::expired,
-
607 ListDisposition::accepted);
-
608
-
609 expectTrusted(lists.at(2));
-
610
-
611 checkAvailable(
-
612 trustedKeys, hexPublic, manifest1, version, {{blob2, sig2}});
-
613
-
614 // Do not apply future lists, but process them
-
615 auto const version2 = 2;
-
616 auto const sequence7 = 7;
-
617 auto const effective7 = validUntil - 60s;
-
618 auto const expiration7 = effective7 + 3600s;
-
619 auto const blob7 = makeList(
-
620 lists.at(7),
-
621 sequence7,
-
622 expiration7.time_since_epoch().count(),
-
623 effective7.time_since_epoch().count());
-
624 auto const sig7 = signList(blob7, pubSigningKeys1);
-
625
-
626 auto const sequence8 = 8;
-
627 auto const effective8 = expiration7 - 60s;
-
628 auto const expiration8 = effective8 + 3600s;
-
629 auto const blob8 = makeList(
-
630 lists.at(8),
-
631 sequence8,
-
632 expiration8.time_since_epoch().count(),
-
633 effective8.time_since_epoch().count());
-
634 auto const sig8 = signList(blob8, pubSigningKeys1);
-
635
-
636 checkResult(
-
637 trustedKeys->applyLists(
-
638 manifest1,
-
639 version2,
-
640 {{blob7, sig7, {}}, {blob8, sig8, {}}},
-
641 siteUri),
-
642 publisherPublic,
-
643 ListDisposition::pending,
-
644 ListDisposition::pending);
-
645
-
646 expectUntrusted(lists.at(7));
-
647 expectUntrusted(lists.at(8));
-
648
-
649 // Do not apply out-of-order future list, but process it
-
650 auto const sequence6 = 6;
-
651 auto const effective6 = effective7 - 60s;
-
652 auto const expiration6 = effective6 + 3600s;
-
653 auto const blob6 = makeList(
-
654 lists.at(6),
-
655 sequence6,
-
656 expiration6.time_since_epoch().count(),
-
657 effective6.time_since_epoch().count());
-
658 auto const sig6 = signList(blob6, pubSigningKeys1);
-
659
-
660 // Process future list that is overridden by a later list
-
661 auto const sequence6a = 5;
-
662 auto const effective6a = effective6 + 60s;
-
663 auto const expiration6a = effective6a + 3600s;
-
664 auto const blob6a = makeList(
-
665 lists.at(5),
-
666 sequence6a,
-
667 expiration6a.time_since_epoch().count(),
-
668 effective6a.time_since_epoch().count());
-
669 auto const sig6a = signList(blob6a, pubSigningKeys1);
-
670
-
671 checkResult(
-
672 trustedKeys->applyLists(
-
673 manifest1,
-
674 version,
-
675 {{blob6a, sig6a, {}}, {blob6, sig6, {}}},
-
676 siteUri),
-
677 publisherPublic,
-
678 ListDisposition::pending,
-
679 ListDisposition::pending);
-
680
-
681 expectUntrusted(lists.at(6));
-
682 expectTrusted(lists.at(2));
-
683
-
684 // Do not apply re-process lists known future sequence numbers
-
685
-
686 checkResult(
-
687 trustedKeys->applyLists(
-
688 manifest1,
-
689 version,
-
690 {{blob7, sig7, {}}, {blob6, sig6, {}}},
-
691 siteUri),
-
692 publisherPublic,
-
693 ListDisposition::known_sequence,
-
694 ListDisposition::known_sequence);
-
695
-
696 expectUntrusted(lists.at(6));
-
697 expectUntrusted(lists.at(7));
-
698 expectTrusted(lists.at(2));
-
699
-
700 // do not use list from untrusted publisher
-
701 auto const untrustedManifest = base64_encode(makeManifestString(
-
702 randomMasterKey(),
-
703 publisherSecret,
-
704 pubSigningKeys1.first,
-
705 pubSigningKeys1.second,
-
706 1));
-
707
-
708 checkResult(
-
709 trustedKeys->applyLists(
-
710 untrustedManifest, version, {{blob2, sig2, {}}}, siteUri),
+
429 BEAST_EXPECT(
+
430 trustedKeys->getListThreshold() == keys.size() / 2 + 1);
+
431 }
+
432 {
+
433 ManifestCache manifests;
+
434 auto trustedKeys = std::make_unique<ValidatorList>(
+
435 manifests,
+
436 manifests,
+
437 env.timeKeeper(),
+
438 app.config().legacy("database_path"),
+
439 env.journal);
+
440
+
441 std::vector<PublicKey> keys(
+
442 {randomMasterKey(),
+
443 randomMasterKey(),
+
444 randomMasterKey(),
+
445 randomMasterKey()});
+
446 std::vector<std::string> cfgPublishers;
+
447 for (auto const& key : keys)
+
448 cfgPublishers.push_back(strHex(key));
+
449
+
450 // explicitly set the list threshold
+
451 BEAST_EXPECT(trustedKeys->load(
+
452 {}, emptyCfgKeys, cfgPublishers, std::size_t(2)));
+
453 for (auto const& key : keys)
+
454 BEAST_EXPECT(trustedKeys->trustedPublisher(key));
+
455 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
456 }
+
457 {
+
458 // Attempt to load a publisher key that has been revoked.
+
459 // Should fail
+
460 ManifestCache valManifests;
+
461 ManifestCache pubManifests;
+
462 auto trustedKeys = std::make_unique<ValidatorList>(
+
463 valManifests,
+
464 pubManifests,
+
465 env.timeKeeper(),
+
466 app.config().legacy("database_path"),
+
467 env.journal);
+
468
+
469 auto const pubRevokedSecret = randomSecretKey();
+
470 auto const pubRevokedPublic =
+
471 derivePublicKey(KeyType::ed25519, pubRevokedSecret);
+
472 auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
+
473 // make this manifest revoked (seq num = max)
+
474 // -- thus should not be loaded
+
475 pubManifests.applyManifest(*deserializeManifest(makeManifestString(
+
476 pubRevokedPublic,
+
477 pubRevokedSecret,
+
478 pubRevokedSigning.first,
+
479 pubRevokedSigning.second,
+
480 std::numeric_limits<std::uint32_t>::max())));
+
481
+
482 // these two are not revoked (and not in the manifest cache at all.)
+
483 auto legitKey1 = randomMasterKey();
+
484 auto legitKey2 = randomMasterKey();
+
485
+
486 std::vector<std::string> cfgPublishers = {
+
487 strHex(pubRevokedPublic), strHex(legitKey1), strHex(legitKey2)};
+
488 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
+
489
+
490 BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
+
491 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey1));
+
492 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey2));
+
493 // 2 is the threshold for 3 publishers (even though 1 is revoked)
+
494 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
495 }
+
496 {
+
497 // One (of two) publisher keys has been revoked, the user had
+
498 // explicitly set validator list threshold to 2.
+
499 ManifestCache valManifests;
+
500 ManifestCache pubManifests;
+
501 auto trustedKeys = std::make_unique<ValidatorList>(
+
502 valManifests,
+
503 pubManifests,
+
504 env.timeKeeper(),
+
505 app.config().legacy("database_path"),
+
506 env.journal);
+
507
+
508 auto const pubRevokedSecret = randomSecretKey();
+
509 auto const pubRevokedPublic =
+
510 derivePublicKey(KeyType::ed25519, pubRevokedSecret);
+
511 auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
+
512 // make this manifest revoked (seq num = max)
+
513 // -- thus should not be loaded
+
514 pubManifests.applyManifest(*deserializeManifest(makeManifestString(
+
515 pubRevokedPublic,
+
516 pubRevokedSecret,
+
517 pubRevokedSigning.first,
+
518 pubRevokedSigning.second,
+
519 std::numeric_limits<std::uint32_t>::max())));
+
520
+
521 // this one is not revoked (and not in the manifest cache at all.)
+
522 auto legitKey = randomMasterKey();
+
523
+
524 std::vector<std::string> cfgPublishers = {
+
525 strHex(pubRevokedPublic), strHex(legitKey)};
+
526 BEAST_EXPECT(trustedKeys->load(
+
527 {}, emptyCfgKeys, cfgPublishers, std::size_t(2)));
+
528
+
529 BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
+
530 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey));
+
531 // 2 is the threshold, as requested in configuration
+
532 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
533 }
+
534 }
+
535
+
536 void
+
537 testApplyLists()
+
538 {
+
539 testcase("Apply list");
+
540 using namespace std::chrono_literals;
+
541
+
542 std::string const siteUri = "testApplyList.test";
+
543
+
544 auto checkAvailable =
+
545 [this](
+
546 auto const& trustedKeys,
+
547 auto const& hexPublic,
+
548 auto const& manifest,
+
549 auto const version,
+
550 std::vector<std::pair<std::string, std::string>> const&
+
551 expected) {
+
552 const auto available = trustedKeys->getAvailable(hexPublic);
+
553
+
554 BEAST_EXPECT(!version || available);
+
555 if (available)
+
556 {
+
557 auto const& a = *available;
+
558 BEAST_EXPECT(a[jss::public_key] == hexPublic);
+
559 BEAST_EXPECT(a[jss::manifest] == manifest);
+
560 // Because multiple lists were processed, the version was
+
561 // overridden
+
562 BEAST_EXPECT(a[jss::version] == version);
+
563 if (version == 1)
+
564 {
+
565 BEAST_EXPECT(expected.size() == 1);
+
566 BEAST_EXPECT(a[jss::blob] == expected[0].first);
+
567 BEAST_EXPECT(a[jss::signature] == expected[0].second);
+
568 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
+
569 }
+
570 else if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
+
571 {
+
572 BEAST_EXPECT(!a.isMember(jss::blob));
+
573 BEAST_EXPECT(!a.isMember(jss::signature));
+
574 auto const& blobs_v2 = a[jss::blobs_v2];
+
575 BEAST_EXPECT(
+
576 blobs_v2.isArray() &&
+
577 blobs_v2.size() == expected.size());
+
578
+
579 for (unsigned int i = 0; i < expected.size(); ++i)
+
580 {
+
581 BEAST_EXPECT(
+
582 blobs_v2[i][jss::blob] == expected[i].first);
+
583 BEAST_EXPECT(
+
584 blobs_v2[i][jss::signature] ==
+
585 expected[i].second);
+
586 }
+
587 }
+
588 }
+
589 };
+
590
+
591 ManifestCache manifests;
+
592 jtx::Env env(*this);
+
593 auto& app = env.app();
+
594 auto trustedKeys = std::make_unique<ValidatorList>(
+
595 manifests,
+
596 manifests,
+
597 env.app().timeKeeper(),
+
598 app.config().legacy("database_path"),
+
599 env.journal);
+
600
+
601 auto expectTrusted =
+
602 [this, &trustedKeys](std::vector<Validator> const& list) {
+
603 for (auto const& val : list)
+
604 {
+
605 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
606 BEAST_EXPECT(trustedKeys->listed(val.signingPublic));
+
607 }
+
608 };
+
609
+
610 auto expectUntrusted =
+
611 [this, &trustedKeys](std::vector<Validator> const& list) {
+
612 for (auto const& val : list)
+
613 {
+
614 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
+
615 BEAST_EXPECT(!trustedKeys->listed(val.signingPublic));
+
616 }
+
617 };
+
618
+
619 auto const publisherSecret = randomSecretKey();
+
620 auto const publisherPublic =
+
621 derivePublicKey(KeyType::ed25519, publisherSecret);
+
622 const auto hexPublic =
+
623 strHex(publisherPublic.begin(), publisherPublic.end());
+
624 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
+
625 auto const manifest1 = base64_encode(makeManifestString(
+
626 publisherPublic,
+
627 publisherSecret,
+
628 pubSigningKeys1.first,
+
629 pubSigningKeys1.second,
+
630 1));
+
631
+
632 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
+
633 std::vector<std::string> emptyCfgKeys;
+
634
+
635 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
+
636
+
637 std::map<std::size_t, std::vector<Validator>> const lists = []() {
+
638 auto constexpr listSize = 20;
+
639 auto constexpr numLists = 9;
+
640 std::map<std::size_t, std::vector<Validator>> lists;
+
641 // 1-based to correspond with the individually named blobs below.
+
642 for (auto i = 1; i <= numLists; ++i)
+
643 {
+
644 auto& list = lists[i];
+
645 list.reserve(listSize);
+
646 while (list.size() < listSize)
+
647 list.push_back(randomValidator());
+
648 }
+
649 return lists;
+
650 }();
+
651
+
652 // Attempt an expired list (fail) and a single list (succeed)
+
653 env.timeKeeper().set(env.timeKeeper().now() + 1s);
+
654 auto const version = 1;
+
655 auto const sequence1 = 1;
+
656 auto const expiredblob = makeList(
+
657 lists.at(1),
+
658 sequence1,
+
659 env.timeKeeper().now().time_since_epoch().count());
+
660 auto const expiredSig = signList(expiredblob, pubSigningKeys1);
+
661
+
662 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
+
663 auto const sequence2 = 2;
+
664 auto const blob2 = makeList(
+
665 lists.at(2), sequence2, validUntil.time_since_epoch().count());
+
666 auto const sig2 = signList(blob2, pubSigningKeys1);
+
667
+
668 checkResult(
+
669 trustedKeys->applyLists(
+
670 manifest1,
+
671 version,
+
672 {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}},
+
673 siteUri),
+
674 publisherPublic,
+
675 ListDisposition::expired,
+
676 ListDisposition::accepted);
+
677
+
678 expectTrusted(lists.at(2));
+
679
+
680 checkAvailable(
+
681 trustedKeys, hexPublic, manifest1, version, {{blob2, sig2}});
+
682
+
683 // Do not apply future lists, but process them
+
684 auto const version2 = 2;
+
685 auto const sequence7 = 7;
+
686 auto const effective7 = validUntil - 60s;
+
687 auto const expiration7 = effective7 + 3600s;
+
688 auto const blob7 = makeList(
+
689 lists.at(7),
+
690 sequence7,
+
691 expiration7.time_since_epoch().count(),
+
692 effective7.time_since_epoch().count());
+
693 auto const sig7 = signList(blob7, pubSigningKeys1);
+
694
+
695 auto const sequence8 = 8;
+
696 auto const effective8 = expiration7 - 60s;
+
697 auto const expiration8 = effective8 + 3600s;
+
698 auto const blob8 = makeList(
+
699 lists.at(8),
+
700 sequence8,
+
701 expiration8.time_since_epoch().count(),
+
702 effective8.time_since_epoch().count());
+
703 auto const sig8 = signList(blob8, pubSigningKeys1);
+
704
+
705 checkResult(
+
706 trustedKeys->applyLists(
+
707 manifest1,
+
708 version2,
+
709 {{blob7, sig7, {}}, {blob8, sig8, {}}},
+
710 siteUri),
711 publisherPublic,
-
712 ListDisposition::untrusted,
-
713 ListDisposition::untrusted);
+
712 ListDisposition::pending,
+
713 ListDisposition::pending);
714
-
715 // do not use list with unhandled version
-
716 auto const badVersion = 666;
-
717 checkResult(
-
718 trustedKeys->applyLists(
-
719 manifest1, badVersion, {{blob2, sig2, {}}}, siteUri),
-
720 publisherPublic,
-
721 ListDisposition::unsupported_version,
-
722 ListDisposition::unsupported_version);
-
723
-
724 // apply list with highest sequence number
-
725 auto const sequence3 = 3;
-
726 auto const blob3 = makeList(
-
727 lists.at(3), sequence3, validUntil.time_since_epoch().count());
-
728 auto const sig3 = signList(blob3, pubSigningKeys1);
-
729
-
730 checkResult(
-
731 trustedKeys->applyLists(
-
732 manifest1, version, {{blob3, sig3, {}}}, siteUri),
-
733 publisherPublic,
-
734 ListDisposition::accepted,
-
735 ListDisposition::accepted);
-
736
-
737 expectUntrusted(lists.at(1));
-
738 expectUntrusted(lists.at(2));
-
739 expectTrusted(lists.at(3));
-
740
-
741 // Note that blob6a is not present, because it was dropped during
-
742 // processing
-
743 checkAvailable(
-
744 trustedKeys,
-
745 hexPublic,
-
746 manifest1,
-
747 2,
-
748 {{blob3, sig3}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
+
715 expectUntrusted(lists.at(7));
+
716 expectUntrusted(lists.at(8));
+
717
+
718 // Do not apply out-of-order future list, but process it
+
719 auto const sequence6 = 6;
+
720 auto const effective6 = effective7 - 60s;
+
721 auto const expiration6 = effective6 + 3600s;
+
722 auto const blob6 = makeList(
+
723 lists.at(6),
+
724 sequence6,
+
725 expiration6.time_since_epoch().count(),
+
726 effective6.time_since_epoch().count());
+
727 auto const sig6 = signList(blob6, pubSigningKeys1);
+
728
+
729 // Process future list that is overridden by a later list
+
730 auto const sequence6a = 5;
+
731 auto const effective6a = effective6 + 60s;
+
732 auto const expiration6a = effective6a + 3600s;
+
733 auto const blob6a = makeList(
+
734 lists.at(5),
+
735 sequence6a,
+
736 expiration6a.time_since_epoch().count(),
+
737 effective6a.time_since_epoch().count());
+
738 auto const sig6a = signList(blob6a, pubSigningKeys1);
+
739
+
740 checkResult(
+
741 trustedKeys->applyLists(
+
742 manifest1,
+
743 version,
+
744 {{blob6a, sig6a, {}}, {blob6, sig6, {}}},
+
745 siteUri),
+
746 publisherPublic,
+
747 ListDisposition::pending,
+
748 ListDisposition::pending);
749
-
750 // do not re-apply lists with past or current sequence numbers
-
751 checkResult(
-
752 trustedKeys->applyLists(
-
753 manifest1,
-
754 version,
-
755 {{blob2, sig2, {}}, {blob3, sig3, {}}},
-
756 siteUri),
-
757 publisherPublic,
-
758 ListDisposition::stale,
-
759 ListDisposition::same_sequence);
-
760
-
761 // apply list with new publisher key updated by manifest. Also send some
-
762 // old lists along with the old manifest
-
763 auto const pubSigningKeys2 = randomKeyPair(KeyType::secp256k1);
-
764 auto manifest2 = base64_encode(makeManifestString(
-
765 publisherPublic,
-
766 publisherSecret,
-
767 pubSigningKeys2.first,
-
768 pubSigningKeys2.second,
-
769 2));
-
770
-
771 auto const sequence4 = 4;
-
772 auto const blob4 = makeList(
-
773 lists.at(4), sequence4, validUntil.time_since_epoch().count());
-
774 auto const sig4 = signList(blob4, pubSigningKeys2);
-
775
-
776 checkResult(
-
777 trustedKeys->applyLists(
-
778 manifest2,
-
779 version,
-
780 {{blob2, sig2, manifest1},
-
781 {blob3, sig3, manifest1},
-
782 {blob4, sig4, {}}},
-
783 siteUri),
-
784 publisherPublic,
-
785 ListDisposition::stale,
-
786 ListDisposition::accepted);
-
787
-
788 expectUntrusted(lists.at(2));
-
789 expectUntrusted(lists.at(3));
-
790 expectTrusted(lists.at(4));
-
791
-
792 checkAvailable(
-
793 trustedKeys,
-
794 hexPublic,
-
795 manifest2,
-
796 2,
-
797 {{blob4, sig4}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
+
750 expectUntrusted(lists.at(6));
+
751 expectTrusted(lists.at(2));
+
752
+
753 // Do not apply re-process lists known future sequence numbers
+
754
+
755 checkResult(
+
756 trustedKeys->applyLists(
+
757 manifest1,
+
758 version,
+
759 {{blob7, sig7, {}}, {blob6, sig6, {}}},
+
760 siteUri),
+
761 publisherPublic,
+
762 ListDisposition::known_sequence,
+
763 ListDisposition::known_sequence);
+
764
+
765 expectUntrusted(lists.at(6));
+
766 expectUntrusted(lists.at(7));
+
767 expectTrusted(lists.at(2));
+
768
+
769 // do not use list from untrusted publisher
+
770 auto const untrustedManifest = base64_encode(makeManifestString(
+
771 randomMasterKey(),
+
772 publisherSecret,
+
773 pubSigningKeys1.first,
+
774 pubSigningKeys1.second,
+
775 1));
+
776
+
777 checkResult(
+
778 trustedKeys->applyLists(
+
779 untrustedManifest, version, {{blob2, sig2, {}}}, siteUri),
+
780 publisherPublic,
+
781 ListDisposition::untrusted,
+
782 ListDisposition::untrusted);
+
783
+
784 // do not use list with unhandled version
+
785 auto const badVersion = 666;
+
786 checkResult(
+
787 trustedKeys->applyLists(
+
788 manifest1, badVersion, {{blob2, sig2, {}}}, siteUri),
+
789 publisherPublic,
+
790 ListDisposition::unsupported_version,
+
791 ListDisposition::unsupported_version);
+
792
+
793 // apply list with highest sequence number
+
794 auto const sequence3 = 3;
+
795 auto const blob3 = makeList(
+
796 lists.at(3), sequence3, validUntil.time_since_epoch().count());
+
797 auto const sig3 = signList(blob3, pubSigningKeys1);
798
-
799 auto const sequence5 = 5;
-
800 auto const blob5 = makeList(
-
801 lists.at(5), sequence5, validUntil.time_since_epoch().count());
-
802 auto const badSig = signList(blob5, pubSigningKeys1);
-
803 checkResult(
-
804 trustedKeys->applyLists(
-
805 manifest1, version, {{blob5, badSig, {}}}, siteUri),
-
806 publisherPublic,
-
807 ListDisposition::invalid,
-
808 ListDisposition::invalid);
+
799 checkResult(
+
800 trustedKeys->applyLists(
+
801 manifest1, version, {{blob3, sig3, {}}}, siteUri),
+
802 publisherPublic,
+
803 ListDisposition::accepted,
+
804 ListDisposition::accepted);
+
805
+
806 expectUntrusted(lists.at(1));
+
807 expectUntrusted(lists.at(2));
+
808 expectTrusted(lists.at(3));
809
-
810 expectUntrusted(lists.at(2));
-
811 expectUntrusted(lists.at(3));
-
812 expectTrusted(lists.at(4));
-
813 expectUntrusted(lists.at(5));
-
814
-
815 // Reprocess the pending list, but the signature is no longer valid
-
816 checkResult(
-
817 trustedKeys->applyLists(
-
818 manifest1,
-
819 version,
-
820 {{blob7, sig7, {}}, {blob8, sig8, {}}},
-
821 siteUri),
-
822 publisherPublic,
-
823 ListDisposition::invalid,
-
824 ListDisposition::invalid);
-
825
-
826 expectTrusted(lists.at(4));
-
827 expectUntrusted(lists.at(7));
-
828 expectUntrusted(lists.at(8));
+
810 // Note that blob6a is not present, because it was dropped during
+
811 // processing
+
812 checkAvailable(
+
813 trustedKeys,
+
814 hexPublic,
+
815 manifest1,
+
816 2,
+
817 {{blob3, sig3}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
+
818
+
819 // do not re-apply lists with past or current sequence numbers
+
820 checkResult(
+
821 trustedKeys->applyLists(
+
822 manifest1,
+
823 version,
+
824 {{blob2, sig2, {}}, {blob3, sig3, {}}},
+
825 siteUri),
+
826 publisherPublic,
+
827 ListDisposition::stale,
+
828 ListDisposition::same_sequence);
829
-
830 // Automatically rotate the first pending already processed list using
-
831 // updateTrusted. Note that the timekeeper is NOT moved, so the close
-
832 // time will be ahead of the test's wall clock
-
833 trustedKeys->updateTrusted(
-
834 {},
-
835 effective6 + 1s,
-
836 env.app().getOPs(),
-
837 env.app().overlay(),
-
838 env.app().getHashRouter());
+
830 // apply list with new publisher key updated by manifest. Also send some
+
831 // old lists along with the old manifest
+
832 auto const pubSigningKeys2 = randomKeyPair(KeyType::secp256k1);
+
833 auto manifest2 = base64_encode(makeManifestString(
+
834 publisherPublic,
+
835 publisherSecret,
+
836 pubSigningKeys2.first,
+
837 pubSigningKeys2.second,
+
838 2));
839
-
840 expectUntrusted(lists.at(3));
-
841 expectTrusted(lists.at(6));
-
842
-
843 checkAvailable(
-
844 trustedKeys,
-
845 hexPublic,
-
846 manifest2,
-
847 2,
-
848 {{blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
-
849
-
850 // Automatically rotate the LAST pending list using updateTrusted,
-
851 // bypassing blob7. Note that the timekeeper IS moved, so the provided
-
852 // close time will be behind the test's wall clock, and thus the wall
-
853 // clock is used.
-
854 env.timeKeeper().set(effective8);
-
855 trustedKeys->updateTrusted(
-
856 {},
-
857 effective8 + 1s,
-
858 env.app().getOPs(),
-
859 env.app().overlay(),
-
860 env.app().getHashRouter());
-
861
-
862 expectUntrusted(lists.at(6));
-
863 expectUntrusted(lists.at(7));
-
864 expectTrusted(lists.at(8));
-
865
-
866 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
+
840 auto const sequence4 = 4;
+
841 auto const blob4 = makeList(
+
842 lists.at(4), sequence4, validUntil.time_since_epoch().count());
+
843 auto const sig4 = signList(blob4, pubSigningKeys2);
+
844
+
845 checkResult(
+
846 trustedKeys->applyLists(
+
847 manifest2,
+
848 version,
+
849 {{blob2, sig2, manifest1},
+
850 {blob3, sig3, manifest1},
+
851 {blob4, sig4, {}}},
+
852 siteUri),
+
853 publisherPublic,
+
854 ListDisposition::stale,
+
855 ListDisposition::accepted);
+
856
+
857 expectUntrusted(lists.at(2));
+
858 expectUntrusted(lists.at(3));
+
859 expectTrusted(lists.at(4));
+
860
+
861 checkAvailable(
+
862 trustedKeys,
+
863 hexPublic,
+
864 manifest2,
+
865 2,
+
866 {{blob4, sig4}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
867
-
868 // resign the pending list with new key and validate it, but it's
-
869 // already valid Also try reprocessing the pending list with an
-
870 // explicit manifest
-
871 // - it is still invalid
-
872 auto const sig8_2 = signList(blob8, pubSigningKeys2);
-
873
-
874 checkResult(
-
875 trustedKeys->applyLists(
-
876 manifest2,
-
877 version,
-
878 {{blob8, sig8, manifest1}, {blob8, sig8_2, {}}},
-
879 siteUri),
-
880 publisherPublic,
-
881 ListDisposition::invalid,
-
882 ListDisposition::same_sequence);
+
868 auto const sequence5 = 5;
+
869 auto const blob5 = makeList(
+
870 lists.at(5), sequence5, validUntil.time_since_epoch().count());
+
871 auto const badSig = signList(blob5, pubSigningKeys1);
+
872 checkResult(
+
873 trustedKeys->applyLists(
+
874 manifest1, version, {{blob5, badSig, {}}}, siteUri),
+
875 publisherPublic,
+
876 ListDisposition::invalid,
+
877 ListDisposition::invalid);
+
878
+
879 expectUntrusted(lists.at(2));
+
880 expectUntrusted(lists.at(3));
+
881 expectTrusted(lists.at(4));
+
882 expectUntrusted(lists.at(5));
883
-
884 expectTrusted(lists.at(8));
-
885
-
886 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
-
887
-
888 // do not apply list with revoked publisher key
-
889 // applied list is removed due to revoked publisher key
-
890 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
-
891 auto maxManifest = base64_encode(
-
892 makeRevocationString(publisherPublic, publisherSecret));
-
893
-
894 auto const sequence9 = 9;
-
895 auto const blob9 = makeList(
-
896 lists.at(9), sequence9, validUntil.time_since_epoch().count());
-
897 auto const sig9 = signList(blob9, signingKeysMax);
+
884 // Reprocess the pending list, but the signature is no longer valid
+
885 checkResult(
+
886 trustedKeys->applyLists(
+
887 manifest1,
+
888 version,
+
889 {{blob7, sig7, {}}, {blob8, sig8, {}}},
+
890 siteUri),
+
891 publisherPublic,
+
892 ListDisposition::invalid,
+
893 ListDisposition::invalid);
+
894
+
895 expectTrusted(lists.at(4));
+
896 expectUntrusted(lists.at(7));
+
897 expectUntrusted(lists.at(8));
898
-
899 checkResult(
-
900 trustedKeys->applyLists(
-
901 maxManifest, version, {{blob9, sig9, {}}}, siteUri),
-
902 publisherPublic,
-
903 ListDisposition::untrusted,
-
904 ListDisposition::untrusted);
-
905
-
906 BEAST_EXPECT(!trustedKeys->trustedPublisher(publisherPublic));
-
907 for (auto const& [num, list] : lists)
-
908 {
-
909 (void)num;
-
910 expectUntrusted(list);
-
911 }
-
912
-
913 checkAvailable(trustedKeys, hexPublic, manifest2, 0, {});
-
914 }
-
915
-
916 void
-
917 testGetAvailable()
-
918 {
-
919 testcase("GetAvailable");
-
920 using namespace std::chrono_literals;
-
921
-
922 std::string const siteUri = "testApplyList.test";
-
923
-
924 ManifestCache manifests;
-
925 jtx::Env env(*this);
-
926 auto& app = env.app();
-
927 auto trustedKeys = std::make_unique<ValidatorList>(
-
928 manifests,
-
929 manifests,
-
930 env.app().timeKeeper(),
-
931 app.config().legacy("database_path"),
-
932 env.journal);
-
933
-
934 auto const publisherSecret = randomSecretKey();
-
935 auto const publisherPublic =
-
936 derivePublicKey(KeyType::ed25519, publisherSecret);
-
937 const auto hexPublic =
-
938 strHex(publisherPublic.begin(), publisherPublic.end());
-
939 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
-
940 auto const manifest = base64_encode(makeManifestString(
-
941 publisherPublic,
-
942 publisherSecret,
-
943 pubSigningKeys1.first,
-
944 pubSigningKeys1.second,
-
945 1));
-
946
-
947 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
-
948 std::vector<std::string> emptyCfgKeys;
-
949
-
950 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
-
951
-
952 std::vector<Validator> const list = []() {
-
953 auto constexpr listSize = 20;
-
954 std::vector<Validator> list;
-
955 list.reserve(listSize);
-
956 while (list.size() < listSize)
-
957 list.push_back(randomValidator());
-
958 return list;
-
959 }();
-
960
-
961 // Process a list
-
962 env.timeKeeper().set(env.timeKeeper().now() + 1s);
-
963 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
-
964 auto const blob =
-
965 makeList(list, 1, validUntil.time_since_epoch().count());
-
966 auto const sig = signList(blob, pubSigningKeys1);
+
899 // Automatically rotate the first pending already processed list using
+
900 // updateTrusted. Note that the timekeeper is NOT moved, so the close
+
901 // time will be ahead of the test's wall clock
+
902 trustedKeys->updateTrusted(
+
903 {},
+
904 effective6 + 1s,
+
905 env.app().getOPs(),
+
906 env.app().overlay(),
+
907 env.app().getHashRouter());
+
908
+
909 expectUntrusted(lists.at(3));
+
910 expectTrusted(lists.at(6));
+
911
+
912 checkAvailable(
+
913 trustedKeys,
+
914 hexPublic,
+
915 manifest2,
+
916 2,
+
917 {{blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
+
918
+
919 // Automatically rotate the LAST pending list using updateTrusted,
+
920 // bypassing blob7. Note that the timekeeper IS moved, so the provided
+
921 // close time will be behind the test's wall clock, and thus the wall
+
922 // clock is used.
+
923 env.timeKeeper().set(effective8);
+
924 trustedKeys->updateTrusted(
+
925 {},
+
926 effective8 + 1s,
+
927 env.app().getOPs(),
+
928 env.app().overlay(),
+
929 env.app().getHashRouter());
+
930
+
931 expectUntrusted(lists.at(6));
+
932 expectUntrusted(lists.at(7));
+
933 expectTrusted(lists.at(8));
+
934
+
935 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
+
936
+
937 // resign the pending list with new key and validate it, but it's
+
938 // already valid Also try reprocessing the pending list with an
+
939 // explicit manifest
+
940 // - it is still invalid
+
941 auto const sig8_2 = signList(blob8, pubSigningKeys2);
+
942
+
943 checkResult(
+
944 trustedKeys->applyLists(
+
945 manifest2,
+
946 version,
+
947 {{blob8, sig8, manifest1}, {blob8, sig8_2, {}}},
+
948 siteUri),
+
949 publisherPublic,
+
950 ListDisposition::invalid,
+
951 ListDisposition::same_sequence);
+
952
+
953 expectTrusted(lists.at(8));
+
954
+
955 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
+
956
+
957 // do not apply list with revoked publisher key
+
958 // applied list is removed due to revoked publisher key
+
959 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
+
960 auto maxManifest = base64_encode(
+
961 makeRevocationString(publisherPublic, publisherSecret));
+
962
+
963 auto const sequence9 = 9;
+
964 auto const blob9 = makeList(
+
965 lists.at(9), sequence9, validUntil.time_since_epoch().count());
+
966 auto const sig9 = signList(blob9, signingKeysMax);
967
-
968 {
-
969 // list unavailable
-
970 auto const available = trustedKeys->getAvailable(hexPublic);
-
971 BEAST_EXPECT(!available);
-
972 }
-
973
-
974 BEAST_EXPECT(
-
975 trustedKeys->applyLists(manifest, 1, {{blob, sig, {}}}, siteUri)
-
976 .bestDisposition() == ListDisposition::accepted);
-
977
-
978 {
-
979 // invalid public key
-
980 auto const available =
-
981 trustedKeys->getAvailable(hexPublic + "invalid", 1);
-
982 BEAST_EXPECT(!available);
-
983 }
+
968 checkResult(
+
969 trustedKeys->applyLists(
+
970 maxManifest, version, {{blob9, sig9, {}}}, siteUri),
+
971 publisherPublic,
+
972 ListDisposition::untrusted,
+
973 ListDisposition::untrusted);
+
974
+
975 BEAST_EXPECT(!trustedKeys->trustedPublisher(publisherPublic));
+
976 for (auto const& [num, list] : lists)
+
977 {
+
978 (void)num;
+
979 expectUntrusted(list);
+
980 }
+
981
+
982 checkAvailable(trustedKeys, hexPublic, manifest2, 0, {});
+
983 }
984
-
985 {
-
986 // unknown public key
-
987 auto const badSecret = randomSecretKey();
-
988 auto const badPublic = derivePublicKey(KeyType::ed25519, badSecret);
-
989 const auto hexBad = strHex(badPublic.begin(), badPublic.end());
+
985 void
+
986 testGetAvailable()
+
987 {
+
988 testcase("GetAvailable");
+
989 using namespace std::chrono_literals;
990
-
991 auto const available = trustedKeys->getAvailable(hexBad, 1);
-
992 BEAST_EXPECT(!available);
-
993 }
-
994 {
-
995 // bad version 0
-
996 auto const available = trustedKeys->getAvailable(hexPublic, 0);
-
997 if (BEAST_EXPECT(available))
-
998 {
-
999 auto const& a = *available;
-
1000 BEAST_EXPECT(!a);
-
1001 }
-
1002 }
-
1003 {
-
1004 // bad version 3
-
1005 auto const available = trustedKeys->getAvailable(hexPublic, 3);
-
1006 if (BEAST_EXPECT(available))
-
1007 {
-
1008 auto const& a = *available;
-
1009 BEAST_EXPECT(!a);
-
1010 }
-
1011 }
-
1012 {
-
1013 // version 1
-
1014 auto const available = trustedKeys->getAvailable(hexPublic, 1);
-
1015 if (BEAST_EXPECT(available))
-
1016 {
-
1017 auto const& a = *available;
-
1018 BEAST_EXPECT(a[jss::public_key] == hexPublic);
-
1019 BEAST_EXPECT(a[jss::manifest] == manifest);
-
1020 BEAST_EXPECT(a[jss::version] == 1);
-
1021
-
1022 BEAST_EXPECT(a[jss::blob] == blob);
-
1023 BEAST_EXPECT(a[jss::signature] == sig);
-
1024 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
-
1025 }
-
1026 }
-
1027
-
1028 {
-
1029 // version 2
-
1030 auto const available = trustedKeys->getAvailable(hexPublic, 2);
-
1031 if (BEAST_EXPECT(available))
-
1032 {
-
1033 auto const& a = *available;
-
1034 BEAST_EXPECT(a[jss::public_key] == hexPublic);
-
1035 BEAST_EXPECT(a[jss::manifest] == manifest);
-
1036 BEAST_EXPECT(a[jss::version] == 2);
-
1037
-
1038 if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
-
1039 {
-
1040 BEAST_EXPECT(!a.isMember(jss::blob));
-
1041 BEAST_EXPECT(!a.isMember(jss::signature));
-
1042 auto const& blobs_v2 = a[jss::blobs_v2];
-
1043 BEAST_EXPECT(blobs_v2.isArray() && blobs_v2.size() == 1);
-
1044
-
1045 BEAST_EXPECT(blobs_v2[0u][jss::blob] == blob);
-
1046 BEAST_EXPECT(blobs_v2[0u][jss::signature] == sig);
-
1047 }
-
1048 }
-
1049 }
-
1050 }
-
1051
-
1052 void
-
1053 testUpdateTrusted()
-
1054 {
-
1055 testcase("Update trusted");
-
1056
-
1057 std::string const siteUri = "testUpdateTrusted.test";
-
1058
-
1059 ManifestCache manifestsOuter;
-
1060 jtx::Env env(*this);
-
1061 auto& app = env.app();
-
1062 auto trustedKeysOuter = std::make_unique<ValidatorList>(
-
1063 manifestsOuter,
-
1064 manifestsOuter,
-
1065 env.timeKeeper(),
-
1066 app.config().legacy("database_path"),
-
1067 env.journal);
-
1068
-
1069 std::vector<std::string> cfgPublishersOuter;
-
1070 hash_set<NodeID> activeValidatorsOuter;
-
1071
-
1072 std::size_t const maxKeys = 40;
-
1073 {
-
1074 std::vector<std::string> cfgKeys;
-
1075 cfgKeys.reserve(maxKeys);
-
1076 hash_set<NodeID> unseenValidators;
-
1077
-
1078 while (cfgKeys.size() != maxKeys)
-
1079 {
-
1080 auto const valKey = randomNode();
-
1081 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
-
1082 if (cfgKeys.size() <= maxKeys - 5)
-
1083 activeValidatorsOuter.emplace(calcNodeID(valKey));
-
1084 else
-
1085 unseenValidators.emplace(calcNodeID(valKey));
-
1086 }
-
1087
-
1088 BEAST_EXPECT(
-
1089 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
+
991 std::string const siteUri = "testApplyList.test";
+
992
+
993 ManifestCache manifests;
+
994 jtx::Env env(*this);
+
995 auto& app = env.app();
+
996 auto trustedKeys = std::make_unique<ValidatorList>(
+
997 manifests,
+
998 manifests,
+
999 env.app().timeKeeper(),
+
1000 app.config().legacy("database_path"),
+
1001 env.journal);
+
1002
+
1003 auto const publisherSecret = randomSecretKey();
+
1004 auto const publisherPublic =
+
1005 derivePublicKey(KeyType::ed25519, publisherSecret);
+
1006 const auto hexPublic =
+
1007 strHex(publisherPublic.begin(), publisherPublic.end());
+
1008 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
+
1009 auto const manifest = base64_encode(makeManifestString(
+
1010 publisherPublic,
+
1011 publisherSecret,
+
1012 pubSigningKeys1.first,
+
1013 pubSigningKeys1.second,
+
1014 1));
+
1015
+
1016 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
+
1017 std::vector<std::string> emptyCfgKeys;
+
1018
+
1019 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
+
1020
+
1021 std::vector<Validator> const list = []() {
+
1022 auto constexpr listSize = 20;
+
1023 std::vector<Validator> list;
+
1024 list.reserve(listSize);
+
1025 while (list.size() < listSize)
+
1026 list.push_back(randomValidator());
+
1027 return list;
+
1028 }();
+
1029
+
1030 // Process a list
+
1031 env.timeKeeper().set(env.timeKeeper().now() + 1s);
+
1032 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
+
1033 auto const blob =
+
1034 makeList(list, 1, validUntil.time_since_epoch().count());
+
1035 auto const sig = signList(blob, pubSigningKeys1);
+
1036
+
1037 {
+
1038 // list unavailable
+
1039 auto const available = trustedKeys->getAvailable(hexPublic);
+
1040 BEAST_EXPECT(!available);
+
1041 }
+
1042
+
1043 BEAST_EXPECT(
+
1044 trustedKeys->applyLists(manifest, 1, {{blob, sig, {}}}, siteUri)
+
1045 .bestDisposition() == ListDisposition::accepted);
+
1046
+
1047 {
+
1048 // invalid public key
+
1049 auto const available =
+
1050 trustedKeys->getAvailable(hexPublic + "invalid", 1);
+
1051 BEAST_EXPECT(!available);
+
1052 }
+
1053
+
1054 {
+
1055 // unknown public key
+
1056 auto const badSecret = randomSecretKey();
+
1057 auto const badPublic = derivePublicKey(KeyType::ed25519, badSecret);
+
1058 const auto hexBad = strHex(badPublic.begin(), badPublic.end());
+
1059
+
1060 auto const available = trustedKeys->getAvailable(hexBad, 1);
+
1061 BEAST_EXPECT(!available);
+
1062 }
+
1063 {
+
1064 // bad version 0
+
1065 auto const available = trustedKeys->getAvailable(hexPublic, 0);
+
1066 if (BEAST_EXPECT(available))
+
1067 {
+
1068 auto const& a = *available;
+
1069 BEAST_EXPECT(!a);
+
1070 }
+
1071 }
+
1072 {
+
1073 // bad version 3
+
1074 auto const available = trustedKeys->getAvailable(hexPublic, 3);
+
1075 if (BEAST_EXPECT(available))
+
1076 {
+
1077 auto const& a = *available;
+
1078 BEAST_EXPECT(!a);
+
1079 }
+
1080 }
+
1081 {
+
1082 // version 1
+
1083 auto const available = trustedKeys->getAvailable(hexPublic, 1);
+
1084 if (BEAST_EXPECT(available))
+
1085 {
+
1086 auto const& a = *available;
+
1087 BEAST_EXPECT(a[jss::public_key] == hexPublic);
+
1088 BEAST_EXPECT(a[jss::manifest] == manifest);
+
1089 BEAST_EXPECT(a[jss::version] == 1);
1090
-
1091 // updateTrusted should make all configured validators trusted
-
1092 // even if they are not active/seen
-
1093 TrustChanges changes = trustedKeysOuter->updateTrusted(
-
1094 activeValidatorsOuter,
-
1095 env.timeKeeper().now(),
-
1096 env.app().getOPs(),
-
1097 env.app().overlay(),
-
1098 env.app().getHashRouter());
-
1099
-
1100 for (auto const& val : unseenValidators)
-
1101 activeValidatorsOuter.emplace(val);
-
1102
-
1103 BEAST_EXPECT(changes.added == activeValidatorsOuter);
-
1104 BEAST_EXPECT(changes.removed.empty());
-
1105 BEAST_EXPECT(
-
1106 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
-
1107 for (auto const& val : cfgKeys)
-
1108 {
-
1109 if (auto const valKey =
-
1110 parseBase58<PublicKey>(TokenType::NodePublic, val))
-
1111 {
-
1112 BEAST_EXPECT(trustedKeysOuter->listed(*valKey));
-
1113 BEAST_EXPECT(trustedKeysOuter->trusted(*valKey));
-
1114 }
-
1115 else
-
1116 fail();
+
1091 BEAST_EXPECT(a[jss::blob] == blob);
+
1092 BEAST_EXPECT(a[jss::signature] == sig);
+
1093 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
+
1094 }
+
1095 }
+
1096
+
1097 {
+
1098 // version 2
+
1099 auto const available = trustedKeys->getAvailable(hexPublic, 2);
+
1100 if (BEAST_EXPECT(available))
+
1101 {
+
1102 auto const& a = *available;
+
1103 BEAST_EXPECT(a[jss::public_key] == hexPublic);
+
1104 BEAST_EXPECT(a[jss::manifest] == manifest);
+
1105 BEAST_EXPECT(a[jss::version] == 2);
+
1106
+
1107 if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
+
1108 {
+
1109 BEAST_EXPECT(!a.isMember(jss::blob));
+
1110 BEAST_EXPECT(!a.isMember(jss::signature));
+
1111 auto const& blobs_v2 = a[jss::blobs_v2];
+
1112 BEAST_EXPECT(blobs_v2.isArray() && blobs_v2.size() == 1);
+
1113
+
1114 BEAST_EXPECT(blobs_v2[0u][jss::blob] == blob);
+
1115 BEAST_EXPECT(blobs_v2[0u][jss::signature] == sig);
+
1116 }
1117 }
-
1118
-
1119 changes = trustedKeysOuter->updateTrusted(
-
1120 activeValidatorsOuter,
-
1121 env.timeKeeper().now(),
-
1122 env.app().getOPs(),
-
1123 env.app().overlay(),
-
1124 env.app().getHashRouter());
-
1125 BEAST_EXPECT(changes.added.empty());
-
1126 BEAST_EXPECT(changes.removed.empty());
-
1127 BEAST_EXPECT(
-
1128 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
-
1129 }
-
1130 {
-
1131 // update with manifests
-
1132 auto const masterPrivate = randomSecretKey();
-
1133 auto const masterPublic =
-
1134 derivePublicKey(KeyType::ed25519, masterPrivate);
-
1135
-
1136 std::vector<std::string> cfgKeys(
-
1137 {toBase58(TokenType::NodePublic, masterPublic)});
-
1138
-
1139 BEAST_EXPECT(
-
1140 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
-
1141
-
1142 auto const signingKeys1 = randomKeyPair(KeyType::secp256k1);
-
1143 auto const signingPublic1 = signingKeys1.first;
-
1144 activeValidatorsOuter.emplace(calcNodeID(masterPublic));
-
1145
-
1146 // Should not trust ephemeral signing key if there is no manifest
-
1147 TrustChanges changes = trustedKeysOuter->updateTrusted(
-
1148 activeValidatorsOuter,
-
1149 env.timeKeeper().now(),
-
1150 env.app().getOPs(),
-
1151 env.app().overlay(),
-
1152 env.app().getHashRouter());
-
1153 BEAST_EXPECT(changes.added == asNodeIDs({masterPublic}));
-
1154 BEAST_EXPECT(changes.removed.empty());
-
1155 BEAST_EXPECT(
-
1156 trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f));
-
1157 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
-
1158 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
-
1159 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
-
1160 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
-
1161
-
1162 // Should trust the ephemeral signing key from the applied manifest
-
1163 auto m1 = deserializeManifest(makeManifestString(
-
1164 masterPublic,
-
1165 masterPrivate,
-
1166 signingPublic1,
-
1167 signingKeys1.second,
-
1168 1));
-
1169
-
1170 BEAST_EXPECT(
-
1171 manifestsOuter.applyManifest(std::move(*m1)) ==
-
1172 ManifestDisposition::accepted);
-
1173 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
-
1174 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
-
1175 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic1));
-
1176 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic1));
-
1177
-
1178 // Should only trust the ephemeral signing key
-
1179 // from the newest applied manifest
-
1180 auto const signingKeys2 = randomKeyPair(KeyType::secp256k1);
-
1181 auto const signingPublic2 = signingKeys2.first;
-
1182 auto m2 = deserializeManifest(makeManifestString(
-
1183 masterPublic,
-
1184 masterPrivate,
-
1185 signingPublic2,
-
1186 signingKeys2.second,
-
1187 2));
-
1188 BEAST_EXPECT(
-
1189 manifestsOuter.applyManifest(std::move(*m2)) ==
-
1190 ManifestDisposition::accepted);
-
1191 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
-
1192 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
-
1193 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic2));
-
1194 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic2));
-
1195 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
-
1196 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
-
1197
-
1198 // Should not trust keys from revoked master public key
-
1199 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
-
1200 auto const signingPublicMax = signingKeysMax.first;
-
1201 activeValidatorsOuter.emplace(calcNodeID(signingPublicMax));
-
1202 auto mMax = deserializeManifest(
-
1203 makeRevocationString(masterPublic, masterPrivate));
+
1118 }
+
1119 }
+
1120
+
1121 void
+
1122 testUpdateTrusted()
+
1123 {
+
1124 testcase("Update trusted");
+
1125
+
1126 std::string const siteUri = "testUpdateTrusted.test";
+
1127
+
1128 ManifestCache manifestsOuter;
+
1129 jtx::Env env(*this);
+
1130 auto& app = env.app();
+
1131 auto trustedKeysOuter = std::make_unique<ValidatorList>(
+
1132 manifestsOuter,
+
1133 manifestsOuter,
+
1134 env.timeKeeper(),
+
1135 app.config().legacy("database_path"),
+
1136 env.journal);
+
1137
+
1138 std::vector<std::string> cfgPublishersOuter;
+
1139 hash_set<NodeID> activeValidatorsOuter;
+
1140
+
1141 std::size_t const maxKeys = 40;
+
1142 {
+
1143 std::vector<std::string> cfgKeys;
+
1144 cfgKeys.reserve(maxKeys);
+
1145 hash_set<NodeID> unseenValidators;
+
1146
+
1147 while (cfgKeys.size() != maxKeys)
+
1148 {
+
1149 auto const valKey = randomNode();
+
1150 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
+
1151 if (cfgKeys.size() <= maxKeys - 5)
+
1152 activeValidatorsOuter.emplace(calcNodeID(valKey));
+
1153 else
+
1154 unseenValidators.emplace(calcNodeID(valKey));
+
1155 }
+
1156
+
1157 BEAST_EXPECT(
+
1158 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
+
1159
+
1160 // updateTrusted should make all configured validators trusted
+
1161 // even if they are not active/seen
+
1162 TrustChanges changes = trustedKeysOuter->updateTrusted(
+
1163 activeValidatorsOuter,
+
1164 env.timeKeeper().now(),
+
1165 env.app().getOPs(),
+
1166 env.app().overlay(),
+
1167 env.app().getHashRouter());
+
1168
+
1169 for (auto const& val : unseenValidators)
+
1170 activeValidatorsOuter.emplace(val);
+
1171
+
1172 BEAST_EXPECT(changes.added == activeValidatorsOuter);
+
1173 BEAST_EXPECT(changes.removed.empty());
+
1174 BEAST_EXPECT(
+
1175 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
+
1176 for (auto const& val : cfgKeys)
+
1177 {
+
1178 if (auto const valKey =
+
1179 parseBase58<PublicKey>(TokenType::NodePublic, val))
+
1180 {
+
1181 BEAST_EXPECT(trustedKeysOuter->listed(*valKey));
+
1182 BEAST_EXPECT(trustedKeysOuter->trusted(*valKey));
+
1183 }
+
1184 else
+
1185 fail();
+
1186 }
+
1187
+
1188 changes = trustedKeysOuter->updateTrusted(
+
1189 activeValidatorsOuter,
+
1190 env.timeKeeper().now(),
+
1191 env.app().getOPs(),
+
1192 env.app().overlay(),
+
1193 env.app().getHashRouter());
+
1194 BEAST_EXPECT(changes.added.empty());
+
1195 BEAST_EXPECT(changes.removed.empty());
+
1196 BEAST_EXPECT(
+
1197 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
+
1198 }
+
1199 {
+
1200 // update with manifests
+
1201 auto const masterPrivate = randomSecretKey();
+
1202 auto const masterPublic =
+
1203 derivePublicKey(KeyType::ed25519, masterPrivate);
1204
-
1205 BEAST_EXPECT(mMax->revoked());
-
1206 BEAST_EXPECT(
-
1207 manifestsOuter.applyManifest(std::move(*mMax)) ==
-
1208 ManifestDisposition::accepted);
-
1209 BEAST_EXPECT(
-
1210 manifestsOuter.getSigningKey(masterPublic) == masterPublic);
-
1211 BEAST_EXPECT(manifestsOuter.revoked(masterPublic));
-
1212
-
1213 // Revoked key remains trusted until list is updated
-
1214 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
-
1215 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
-
1216
-
1217 changes = trustedKeysOuter->updateTrusted(
-
1218 activeValidatorsOuter,
-
1219 env.timeKeeper().now(),
-
1220 env.app().getOPs(),
-
1221 env.app().overlay(),
-
1222 env.app().getHashRouter());
-
1223 BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic}));
-
1224 BEAST_EXPECT(changes.added.empty());
-
1225 BEAST_EXPECT(
-
1226 trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f));
-
1227 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
-
1228 BEAST_EXPECT(!trustedKeysOuter->trusted(masterPublic));
-
1229 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublicMax));
-
1230 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublicMax));
-
1231 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic2));
-
1232 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic2));
-
1233 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
-
1234 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
-
1235 }
-
1236 {
-
1237 // Make quorum unattainable if lists from any publishers are
-
1238 // unavailable
-
1239 auto trustedKeys = std::make_unique<ValidatorList>(
-
1240 manifestsOuter,
-
1241 manifestsOuter,
-
1242 env.timeKeeper(),
-
1243 app.config().legacy("database_path"),
-
1244 env.journal);
-
1245 auto const publisherSecret = randomSecretKey();
-
1246 auto const publisherPublic =
-
1247 derivePublicKey(KeyType::ed25519, publisherSecret);
-
1248
-
1249 std::vector<std::string> cfgPublishers({strHex(publisherPublic)});
-
1250 std::vector<std::string> emptyCfgKeys;
-
1251
-
1252 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
-
1253
-
1254 TrustChanges changes = trustedKeys->updateTrusted(
-
1255 activeValidatorsOuter,
-
1256 env.timeKeeper().now(),
-
1257 env.app().getOPs(),
-
1258 env.app().overlay(),
-
1259 env.app().getHashRouter());
-
1260 BEAST_EXPECT(changes.removed.empty());
-
1261 BEAST_EXPECT(changes.added.empty());
-
1262 BEAST_EXPECT(
-
1263 trustedKeys->quorum() ==
-
1264 std::numeric_limits<std::size_t>::max());
-
1265 }
-
1266 {
-
1267 // Should use custom minimum quorum
-
1268 std::size_t const minQuorum = 1;
-
1269 ManifestCache manifests;
-
1270 auto trustedKeys = std::make_unique<ValidatorList>(
-
1271 manifests,
-
1272 manifests,
-
1273 env.timeKeeper(),
-
1274 app.config().legacy("database_path"),
-
1275 env.journal,
-
1276 minQuorum);
-
1277
-
1278 std::size_t n = 10;
-
1279 std::vector<std::string> cfgKeys;
-
1280 cfgKeys.reserve(n);
-
1281 hash_set<NodeID> expectedTrusted;
-
1282 hash_set<NodeID> activeValidators;
-
1283 NodeID toBeSeen;
-
1284
-
1285 while (cfgKeys.size() < n)
-
1286 {
-
1287 auto const valKey = randomNode();
-
1288 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
-
1289 expectedTrusted.emplace(calcNodeID(valKey));
-
1290 if (cfgKeys.size() < std::ceil(n * 0.8f))
-
1291 activeValidators.emplace(calcNodeID(valKey));
-
1292 else if (cfgKeys.size() < std::ceil(n * 0.8f))
-
1293 toBeSeen = calcNodeID(valKey);
-
1294 }
-
1295
-
1296 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishersOuter));
-
1297
-
1298 TrustChanges changes = trustedKeys->updateTrusted(
-
1299 activeValidators,
-
1300 env.timeKeeper().now(),
-
1301 env.app().getOPs(),
-
1302 env.app().overlay(),
-
1303 env.app().getHashRouter());
-
1304 BEAST_EXPECT(changes.removed.empty());
-
1305 BEAST_EXPECT(changes.added == expectedTrusted);
-
1306 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
-
1307
-
1308 // Use configured quorum even when seen validators >= quorum
-
1309 activeValidators.emplace(toBeSeen);
-
1310 changes = trustedKeys->updateTrusted(
-
1311 activeValidators,
-
1312 env.timeKeeper().now(),
-
1313 env.app().getOPs(),
-
1314 env.app().overlay(),
-
1315 env.app().getHashRouter());
-
1316 BEAST_EXPECT(changes.removed.empty());
-
1317 BEAST_EXPECT(changes.added.empty());
-
1318 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
-
1319 }
-
1320 {
-
1321 // Remove expired published list
-
1322 auto trustedKeys = std::make_unique<ValidatorList>(
-
1323 manifestsOuter,
-
1324 manifestsOuter,
-
1325 env.app().timeKeeper(),
-
1326 app.config().legacy("database_path"),
-
1327 env.journal);
-
1328
-
1329 std::vector<std::string> emptyCfgKeys;
-
1330 auto const publisherKeys = randomKeyPair(KeyType::secp256k1);
-
1331 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
-
1332 auto const manifest = base64_encode(makeManifestString(
-
1333 publisherKeys.first,
-
1334 publisherKeys.second,
-
1335 pubSigningKeys.first,
-
1336 pubSigningKeys.second,
-
1337 1));
-
1338
-
1339 std::vector<std::string> cfgKeys({strHex(publisherKeys.first)});
-
1340
-
1341 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys));
-
1342
-
1343 std::vector<Validator> list({randomValidator(), randomValidator()});
-
1344 hash_set<NodeID> activeValidators(
-
1345 asNodeIDs({list[0].masterPublic, list[1].masterPublic}));
-
1346
-
1347 // do not apply expired list
-
1348 auto const version = 1;
-
1349 auto const sequence = 1;
-
1350 using namespace std::chrono_literals;
-
1351 NetClock::time_point const validUntil =
-
1352 env.timeKeeper().now() + 60s;
-
1353 auto const blob =
-
1354 makeList(list, sequence, validUntil.time_since_epoch().count());
-
1355 auto const sig = signList(blob, pubSigningKeys);
-
1356
-
1357 BEAST_EXPECT(
-
1358 ListDisposition::accepted ==
-
1359 trustedKeys
-
1360 ->applyLists(manifest, version, {{blob, sig, {}}}, siteUri)
-
1361 .bestDisposition());
-
1362
-
1363 TrustChanges changes = trustedKeys->updateTrusted(
-
1364 activeValidators,
-
1365 env.timeKeeper().now(),
-
1366 env.app().getOPs(),
-
1367 env.app().overlay(),
-
1368 env.app().getHashRouter());
-
1369 BEAST_EXPECT(changes.removed.empty());
-
1370 BEAST_EXPECT(changes.added == activeValidators);
-
1371 for (Validator const& val : list)
-
1372 {
-
1373 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
-
1374 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
-
1375 }
-
1376 BEAST_EXPECT(trustedKeys->quorum() == 2);
-
1377
-
1378 env.timeKeeper().set(validUntil);
-
1379 changes = trustedKeys->updateTrusted(
-
1380 activeValidators,
-
1381 env.timeKeeper().now(),
-
1382 env.app().getOPs(),
-
1383 env.app().overlay(),
-
1384 env.app().getHashRouter());
-
1385 BEAST_EXPECT(changes.removed == activeValidators);
-
1386 BEAST_EXPECT(changes.added.empty());
-
1387 BEAST_EXPECT(!trustedKeys->trusted(list[0].masterPublic));
-
1388 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
-
1389 BEAST_EXPECT(
-
1390 trustedKeys->quorum() ==
-
1391 std::numeric_limits<std::size_t>::max());
-
1392
-
1393 // (Re)trust validators from new valid list
-
1394 std::vector<Validator> list2({list[0], randomValidator()});
-
1395 activeValidators.insert(calcNodeID(list2[1].masterPublic));
-
1396 auto const sequence2 = 2;
-
1397 NetClock::time_point const expiration2 =
-
1398 env.timeKeeper().now() + 60s;
-
1399 auto const blob2 = makeList(
-
1400 list2, sequence2, expiration2.time_since_epoch().count());
-
1401 auto const sig2 = signList(blob2, pubSigningKeys);
+
1205 std::vector<std::string> cfgKeys(
+
1206 {toBase58(TokenType::NodePublic, masterPublic)});
+
1207
+
1208 BEAST_EXPECT(
+
1209 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
+
1210
+
1211 auto const signingKeys1 = randomKeyPair(KeyType::secp256k1);
+
1212 auto const signingPublic1 = signingKeys1.first;
+
1213 activeValidatorsOuter.emplace(calcNodeID(masterPublic));
+
1214
+
1215 // Should not trust ephemeral signing key if there is no manifest
+
1216 TrustChanges changes = trustedKeysOuter->updateTrusted(
+
1217 activeValidatorsOuter,
+
1218 env.timeKeeper().now(),
+
1219 env.app().getOPs(),
+
1220 env.app().overlay(),
+
1221 env.app().getHashRouter());
+
1222 BEAST_EXPECT(changes.added == asNodeIDs({masterPublic}));
+
1223 BEAST_EXPECT(changes.removed.empty());
+
1224 BEAST_EXPECT(
+
1225 trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f));
+
1226 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
+
1227 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
+
1228 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
+
1229 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
+
1230
+
1231 // Should trust the ephemeral signing key from the applied manifest
+
1232 auto m1 = deserializeManifest(makeManifestString(
+
1233 masterPublic,
+
1234 masterPrivate,
+
1235 signingPublic1,
+
1236 signingKeys1.second,
+
1237 1));
+
1238
+
1239 BEAST_EXPECT(
+
1240 manifestsOuter.applyManifest(std::move(*m1)) ==
+
1241 ManifestDisposition::accepted);
+
1242 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
+
1243 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
+
1244 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic1));
+
1245 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic1));
+
1246
+
1247 // Should only trust the ephemeral signing key
+
1248 // from the newest applied manifest
+
1249 auto const signingKeys2 = randomKeyPair(KeyType::secp256k1);
+
1250 auto const signingPublic2 = signingKeys2.first;
+
1251 auto m2 = deserializeManifest(makeManifestString(
+
1252 masterPublic,
+
1253 masterPrivate,
+
1254 signingPublic2,
+
1255 signingKeys2.second,
+
1256 2));
+
1257 BEAST_EXPECT(
+
1258 manifestsOuter.applyManifest(std::move(*m2)) ==
+
1259 ManifestDisposition::accepted);
+
1260 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
+
1261 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
+
1262 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic2));
+
1263 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic2));
+
1264 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
+
1265 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
+
1266
+
1267 // Should not trust keys from revoked master public key
+
1268 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
+
1269 auto const signingPublicMax = signingKeysMax.first;
+
1270 activeValidatorsOuter.emplace(calcNodeID(signingPublicMax));
+
1271 auto mMax = deserializeManifest(
+
1272 makeRevocationString(masterPublic, masterPrivate));
+
1273
+
1274 BEAST_EXPECT(mMax->revoked());
+
1275 BEAST_EXPECT(
+
1276 manifestsOuter.applyManifest(std::move(*mMax)) ==
+
1277 ManifestDisposition::accepted);
+
1278 BEAST_EXPECT(
+
1279 manifestsOuter.getSigningKey(masterPublic) == masterPublic);
+
1280 BEAST_EXPECT(manifestsOuter.revoked(masterPublic));
+
1281
+
1282 // Revoked key remains trusted until list is updated
+
1283 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
+
1284 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
+
1285
+
1286 changes = trustedKeysOuter->updateTrusted(
+
1287 activeValidatorsOuter,
+
1288 env.timeKeeper().now(),
+
1289 env.app().getOPs(),
+
1290 env.app().overlay(),
+
1291 env.app().getHashRouter());
+
1292 BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic}));
+
1293 BEAST_EXPECT(changes.added.empty());
+
1294 BEAST_EXPECT(
+
1295 trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f));
+
1296 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
+
1297 BEAST_EXPECT(!trustedKeysOuter->trusted(masterPublic));
+
1298 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublicMax));
+
1299 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublicMax));
+
1300 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic2));
+
1301 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic2));
+
1302 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
+
1303 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
+
1304 }
+
1305 {
+
1306 // Make quorum unattainable if lists from any publishers are
+
1307 // unavailable
+
1308 auto trustedKeys = std::make_unique<ValidatorList>(
+
1309 manifestsOuter,
+
1310 manifestsOuter,
+
1311 env.timeKeeper(),
+
1312 app.config().legacy("database_path"),
+
1313 env.journal);
+
1314 auto const publisherSecret = randomSecretKey();
+
1315 auto const publisherPublic =
+
1316 derivePublicKey(KeyType::ed25519, publisherSecret);
+
1317
+
1318 std::vector<std::string> cfgPublishers({strHex(publisherPublic)});
+
1319 std::vector<std::string> emptyCfgKeys;
+
1320
+
1321 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
+
1322
+
1323 TrustChanges changes = trustedKeys->updateTrusted(
+
1324 activeValidatorsOuter,
+
1325 env.timeKeeper().now(),
+
1326 env.app().getOPs(),
+
1327 env.app().overlay(),
+
1328 env.app().getHashRouter());
+
1329 BEAST_EXPECT(changes.removed.empty());
+
1330 BEAST_EXPECT(changes.added.empty());
+
1331 BEAST_EXPECT(
+
1332 trustedKeys->quorum() ==
+
1333 std::numeric_limits<std::size_t>::max());
+
1334 }
+
1335 {
+
1336 // Trust explicitly listed validators also when list threshold is
+
1337 // higher than 1
+
1338 auto trustedKeys = std::make_unique<ValidatorList>(
+
1339 manifestsOuter,
+
1340 manifestsOuter,
+
1341 env.timeKeeper(),
+
1342 app.config().legacy("database_path"),
+
1343 env.journal);
+
1344 auto const masterPrivate = randomSecretKey();
+
1345 auto const masterPublic =
+
1346 derivePublicKey(KeyType::ed25519, masterPrivate);
+
1347 std::vector<std::string> cfgKeys(
+
1348 {toBase58(TokenType::NodePublic, masterPublic)});
+
1349
+
1350 auto const publisher1Secret = randomSecretKey();
+
1351 auto const publisher1Public =
+
1352 derivePublicKey(KeyType::ed25519, publisher1Secret);
+
1353 auto const publisher2Secret = randomSecretKey();
+
1354 auto const publisher2Public =
+
1355 derivePublicKey(KeyType::ed25519, publisher2Secret);
+
1356 std::vector<std::string> cfgPublishers(
+
1357 {strHex(publisher1Public), strHex(publisher2Public)});
+
1358
+
1359 BEAST_EXPECT(
+
1360 trustedKeys->load({}, cfgKeys, cfgPublishers, std::size_t(2)));
+
1361
+
1362 TrustChanges changes = trustedKeys->updateTrusted(
+
1363 activeValidatorsOuter,
+
1364 env.timeKeeper().now(),
+
1365 env.app().getOPs(),
+
1366 env.app().overlay(),
+
1367 env.app().getHashRouter());
+
1368 BEAST_EXPECT(changes.removed.empty());
+
1369 BEAST_EXPECT(changes.added.size() == 1);
+
1370 BEAST_EXPECT(trustedKeys->listed(masterPublic));
+
1371 BEAST_EXPECT(trustedKeys->trusted(masterPublic));
+
1372 }
+
1373 {
+
1374 // Should use custom minimum quorum
+
1375 std::size_t const minQuorum = 1;
+
1376 ManifestCache manifests;
+
1377 auto trustedKeys = std::make_unique<ValidatorList>(
+
1378 manifests,
+
1379 manifests,
+
1380 env.timeKeeper(),
+
1381 app.config().legacy("database_path"),
+
1382 env.journal,
+
1383 minQuorum);
+
1384
+
1385 std::size_t n = 10;
+
1386 std::vector<std::string> cfgKeys;
+
1387 cfgKeys.reserve(n);
+
1388 hash_set<NodeID> expectedTrusted;
+
1389 hash_set<NodeID> activeValidators;
+
1390 NodeID toBeSeen;
+
1391
+
1392 while (cfgKeys.size() < n)
+
1393 {
+
1394 auto const valKey = randomNode();
+
1395 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
+
1396 expectedTrusted.emplace(calcNodeID(valKey));
+
1397 if (cfgKeys.size() < std::ceil(n * 0.8f))
+
1398 activeValidators.emplace(calcNodeID(valKey));
+
1399 else if (cfgKeys.size() < std::ceil(n * 0.8f))
+
1400 toBeSeen = calcNodeID(valKey);
+
1401 }
1402
-
1403 BEAST_EXPECT(
-
1404 ListDisposition::accepted ==
-
1405 trustedKeys
-
1406 ->applyLists(
-
1407 manifest, version, {{blob2, sig2, {}}}, siteUri)
-
1408 .bestDisposition());
-
1409
-
1410 changes = trustedKeys->updateTrusted(
-
1411 activeValidators,
-
1412 env.timeKeeper().now(),
-
1413 env.app().getOPs(),
-
1414 env.app().overlay(),
-
1415 env.app().getHashRouter());
-
1416 BEAST_EXPECT(changes.removed.empty());
-
1417 BEAST_EXPECT(
-
1418 changes.added ==
-
1419 asNodeIDs({list2[0].masterPublic, list2[1].masterPublic}));
-
1420 for (Validator const& val : list2)
-
1421 {
-
1422 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
-
1423 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
-
1424 }
-
1425 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
-
1426 BEAST_EXPECT(!trustedKeys->trusted(list[1].signingPublic));
-
1427 BEAST_EXPECT(trustedKeys->quorum() == 2);
-
1428 }
-
1429 {
-
1430 // Test 1-9 configured validators
-
1431 auto trustedKeys = std::make_unique<ValidatorList>(
-
1432 manifestsOuter,
-
1433 manifestsOuter,
-
1434 env.timeKeeper(),
-
1435 app.config().legacy("database_path"),
-
1436 env.journal);
-
1437
-
1438 std::vector<std::string> cfgPublishers;
-
1439 hash_set<NodeID> activeValidators;
-
1440 hash_set<PublicKey> activeKeys;
-
1441
-
1442 std::vector<std::string> cfgKeys;
-
1443 cfgKeys.reserve(9);
-
1444
-
1445 while (cfgKeys.size() < cfgKeys.capacity())
-
1446 {
-
1447 auto const valKey = randomNode();
-
1448 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
-
1449 activeValidators.emplace(calcNodeID(valKey));
-
1450 activeKeys.emplace(valKey);
-
1451 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishers));
-
1452 TrustChanges changes = trustedKeys->updateTrusted(
-
1453 activeValidators,
-
1454 env.timeKeeper().now(),
-
1455 env.app().getOPs(),
-
1456 env.app().overlay(),
-
1457 env.app().getHashRouter());
-
1458 BEAST_EXPECT(changes.removed.empty());
-
1459 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
-
1460 BEAST_EXPECT(
-
1461 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
-
1462 for (auto const& key : activeKeys)
-
1463 BEAST_EXPECT(trustedKeys->trusted(key));
-
1464 }
-
1465 }
-
1466 {
-
1467 // Test 2-9 configured validators as validator
-
1468 auto trustedKeys = std::make_unique<ValidatorList>(
-
1469 manifestsOuter,
-
1470 manifestsOuter,
-
1471 env.timeKeeper(),
-
1472 app.config().legacy("database_path"),
-
1473 env.journal);
-
1474
-
1475 auto const localKey = randomNode();
-
1476 std::vector<std::string> cfgPublishers;
-
1477 hash_set<NodeID> activeValidators;
-
1478 hash_set<PublicKey> activeKeys;
-
1479 std::vector<std::string> cfgKeys{
-
1480 toBase58(TokenType::NodePublic, localKey)};
-
1481 cfgKeys.reserve(9);
-
1482
-
1483 while (cfgKeys.size() < cfgKeys.capacity())
-
1484 {
-
1485 auto const valKey = randomNode();
-
1486 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
-
1487 activeValidators.emplace(calcNodeID(valKey));
-
1488 activeKeys.emplace(valKey);
-
1489
-
1490 BEAST_EXPECT(
-
1491 trustedKeys->load(localKey, cfgKeys, cfgPublishers));
-
1492 TrustChanges changes = trustedKeys->updateTrusted(
-
1493 activeValidators,
-
1494 env.timeKeeper().now(),
-
1495 env.app().getOPs(),
-
1496 env.app().overlay(),
-
1497 env.app().getHashRouter());
-
1498 BEAST_EXPECT(changes.removed.empty());
-
1499 if (cfgKeys.size() > 2)
-
1500 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
-
1501 else
-
1502 BEAST_EXPECT(
-
1503 changes.added == asNodeIDs({localKey, valKey}));
-
1504
-
1505 BEAST_EXPECT(
-
1506 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
-
1507
-
1508 for (auto const& key : activeKeys)
-
1509 BEAST_EXPECT(trustedKeys->trusted(key));
-
1510 }
-
1511 }
-
1512 {
-
1513 // Trusted set should include all validators from multiple lists
-
1514 ManifestCache manifests;
-
1515 auto trustedKeys = std::make_unique<ValidatorList>(
-
1516 manifests,
-
1517 manifests,
-
1518 env.timeKeeper(),
-
1519 app.config().legacy("database_path"),
-
1520 env.journal);
-
1521
-
1522 hash_set<NodeID> activeValidators;
-
1523 std::vector<Validator> valKeys;
-
1524 valKeys.reserve(maxKeys);
-
1525
-
1526 while (valKeys.size() != maxKeys)
-
1527 {
-
1528 valKeys.push_back(randomValidator());
-
1529 activeValidators.emplace(
-
1530 calcNodeID(valKeys.back().masterPublic));
+
1403 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishersOuter));
+
1404
+
1405 TrustChanges changes = trustedKeys->updateTrusted(
+
1406 activeValidators,
+
1407 env.timeKeeper().now(),
+
1408 env.app().getOPs(),
+
1409 env.app().overlay(),
+
1410 env.app().getHashRouter());
+
1411 BEAST_EXPECT(changes.removed.empty());
+
1412 BEAST_EXPECT(changes.added == expectedTrusted);
+
1413 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
+
1414
+
1415 // Use configured quorum even when seen validators >= quorum
+
1416 activeValidators.emplace(toBeSeen);
+
1417 changes = trustedKeys->updateTrusted(
+
1418 activeValidators,
+
1419 env.timeKeeper().now(),
+
1420 env.app().getOPs(),
+
1421 env.app().overlay(),
+
1422 env.app().getHashRouter());
+
1423 BEAST_EXPECT(changes.removed.empty());
+
1424 BEAST_EXPECT(changes.added.empty());
+
1425 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
+
1426 }
+
1427 {
+
1428 // Remove expired published list
+
1429 auto trustedKeys = std::make_unique<ValidatorList>(
+
1430 manifestsOuter,
+
1431 manifestsOuter,
+
1432 env.app().timeKeeper(),
+
1433 app.config().legacy("database_path"),
+
1434 env.journal);
+
1435
+
1436 std::vector<std::string> emptyCfgKeys;
+
1437 auto const publisherKeys = randomKeyPair(KeyType::secp256k1);
+
1438 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
+
1439 auto const manifest = base64_encode(makeManifestString(
+
1440 publisherKeys.first,
+
1441 publisherKeys.second,
+
1442 pubSigningKeys.first,
+
1443 pubSigningKeys.second,
+
1444 1));
+
1445
+
1446 std::vector<std::string> cfgKeys({strHex(publisherKeys.first)});
+
1447
+
1448 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys));
+
1449
+
1450 std::vector<Validator> list({randomValidator(), randomValidator()});
+
1451 hash_set<NodeID> activeValidators(
+
1452 asNodeIDs({list[0].masterPublic, list[1].masterPublic}));
+
1453
+
1454 // do not apply expired list
+
1455 auto const version = 1;
+
1456 auto const sequence = 1;
+
1457 using namespace std::chrono_literals;
+
1458 NetClock::time_point const validUntil =
+
1459 env.timeKeeper().now() + 60s;
+
1460 auto const blob =
+
1461 makeList(list, sequence, validUntil.time_since_epoch().count());
+
1462 auto const sig = signList(blob, pubSigningKeys);
+
1463
+
1464 BEAST_EXPECT(
+
1465 ListDisposition::accepted ==
+
1466 trustedKeys
+
1467 ->applyLists(manifest, version, {{blob, sig, {}}}, siteUri)
+
1468 .bestDisposition());
+
1469
+
1470 TrustChanges changes = trustedKeys->updateTrusted(
+
1471 activeValidators,
+
1472 env.timeKeeper().now(),
+
1473 env.app().getOPs(),
+
1474 env.app().overlay(),
+
1475 env.app().getHashRouter());
+
1476 BEAST_EXPECT(changes.removed.empty());
+
1477 BEAST_EXPECT(changes.added == activeValidators);
+
1478 for (Validator const& val : list)
+
1479 {
+
1480 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
1481 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
+
1482 }
+
1483 BEAST_EXPECT(trustedKeys->quorum() == 2);
+
1484
+
1485 env.timeKeeper().set(validUntil);
+
1486 changes = trustedKeys->updateTrusted(
+
1487 activeValidators,
+
1488 env.timeKeeper().now(),
+
1489 env.app().getOPs(),
+
1490 env.app().overlay(),
+
1491 env.app().getHashRouter());
+
1492 BEAST_EXPECT(changes.removed == activeValidators);
+
1493 BEAST_EXPECT(changes.added.empty());
+
1494 BEAST_EXPECT(!trustedKeys->trusted(list[0].masterPublic));
+
1495 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
+
1496 BEAST_EXPECT(
+
1497 trustedKeys->quorum() ==
+
1498 std::numeric_limits<std::size_t>::max());
+
1499
+
1500 // (Re)trust validators from new valid list
+
1501 std::vector<Validator> list2({list[0], randomValidator()});
+
1502 activeValidators.insert(calcNodeID(list2[1].masterPublic));
+
1503 auto const sequence2 = 2;
+
1504 NetClock::time_point const expiration2 =
+
1505 env.timeKeeper().now() + 60s;
+
1506 auto const blob2 = makeList(
+
1507 list2, sequence2, expiration2.time_since_epoch().count());
+
1508 auto const sig2 = signList(blob2, pubSigningKeys);
+
1509
+
1510 BEAST_EXPECT(
+
1511 ListDisposition::accepted ==
+
1512 trustedKeys
+
1513 ->applyLists(
+
1514 manifest, version, {{blob2, sig2, {}}}, siteUri)
+
1515 .bestDisposition());
+
1516
+
1517 changes = trustedKeys->updateTrusted(
+
1518 activeValidators,
+
1519 env.timeKeeper().now(),
+
1520 env.app().getOPs(),
+
1521 env.app().overlay(),
+
1522 env.app().getHashRouter());
+
1523 BEAST_EXPECT(changes.removed.empty());
+
1524 BEAST_EXPECT(
+
1525 changes.added ==
+
1526 asNodeIDs({list2[0].masterPublic, list2[1].masterPublic}));
+
1527 for (Validator const& val : list2)
+
1528 {
+
1529 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
1530 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
1531 }
-
1532
-
1533 auto addPublishedList = [this,
-
1534 &env,
-
1535 &trustedKeys,
-
1536 &valKeys,
-
1537 &siteUri]() {
-
1538 auto const publisherSecret = randomSecretKey();
-
1539 auto const publisherPublic =
-
1540 derivePublicKey(KeyType::ed25519, publisherSecret);
-
1541 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
-
1542 auto const manifest = base64_encode(makeManifestString(
-
1543 publisherPublic,
-
1544 publisherSecret,
-
1545 pubSigningKeys.first,
-
1546 pubSigningKeys.second,
-
1547 1));
+
1532 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
+
1533 BEAST_EXPECT(!trustedKeys->trusted(list[1].signingPublic));
+
1534 BEAST_EXPECT(trustedKeys->quorum() == 2);
+
1535 }
+
1536 {
+
1537 // Test 1-9 configured validators
+
1538 auto trustedKeys = std::make_unique<ValidatorList>(
+
1539 manifestsOuter,
+
1540 manifestsOuter,
+
1541 env.timeKeeper(),
+
1542 app.config().legacy("database_path"),
+
1543 env.journal);
+
1544
+
1545 std::vector<std::string> cfgPublishers;
+
1546 hash_set<NodeID> activeValidators;
+
1547 hash_set<PublicKey> activeKeys;
1548
-
1549 std::vector<std::string> cfgPublishers(
-
1550 {strHex(publisherPublic)});
-
1551 std::vector<std::string> emptyCfgKeys;
-
1552
-
1553 BEAST_EXPECT(
-
1554 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
-
1555
-
1556 auto const version = 1;
-
1557 auto const sequence = 1;
-
1558 using namespace std::chrono_literals;
-
1559 NetClock::time_point const validUntil =
-
1560 env.timeKeeper().now() + 3600s;
-
1561 auto const blob = makeList(
-
1562 valKeys, sequence, validUntil.time_since_epoch().count());
-
1563 auto const sig = signList(blob, pubSigningKeys);
-
1564
-
1565 BEAST_EXPECT(
-
1566 ListDisposition::accepted ==
-
1567 trustedKeys
-
1568 ->applyLists(
-
1569 manifest, version, {{blob, sig, {}}}, siteUri)
-
1570 .bestDisposition());
-
1571 };
-
1572
-
1573 // Apply multiple published lists
-
1574 for (auto i = 0; i < 3; ++i)
-
1575 addPublishedList();
-
1576
-
1577 TrustChanges changes = trustedKeys->updateTrusted(
-
1578 activeValidators,
-
1579 env.timeKeeper().now(),
-
1580 env.app().getOPs(),
-
1581 env.app().overlay(),
-
1582 env.app().getHashRouter());
-
1583
-
1584 BEAST_EXPECT(
-
1585 trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f));
-
1586
-
1587 hash_set<NodeID> added;
-
1588 for (auto const& val : valKeys)
-
1589 {
-
1590 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
-
1591 added.insert(calcNodeID(val.masterPublic));
-
1592 }
-
1593 BEAST_EXPECT(changes.added == added);
-
1594 BEAST_EXPECT(changes.removed.empty());
-
1595 }
-
1596 }
-
1597
-
1598 void
-
1599 testExpires()
-
1600 {
-
1601 testcase("Expires");
-
1602
-
1603 std::string const siteUri = "testExpires.test";
-
1604
-
1605 jtx::Env env(*this);
-
1606 auto& app = env.app();
-
1607
-
1608 auto toStr = [](PublicKey const& publicKey) {
-
1609 return toBase58(TokenType::NodePublic, publicKey);
-
1610 };
+
1549 std::vector<std::string> cfgKeys;
+
1550 cfgKeys.reserve(9);
+
1551
+
1552 while (cfgKeys.size() < cfgKeys.capacity())
+
1553 {
+
1554 auto const valKey = randomNode();
+
1555 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
+
1556 activeValidators.emplace(calcNodeID(valKey));
+
1557 activeKeys.emplace(valKey);
+
1558 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishers));
+
1559 TrustChanges changes = trustedKeys->updateTrusted(
+
1560 activeValidators,
+
1561 env.timeKeeper().now(),
+
1562 env.app().getOPs(),
+
1563 env.app().overlay(),
+
1564 env.app().getHashRouter());
+
1565 BEAST_EXPECT(changes.removed.empty());
+
1566 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
+
1567 BEAST_EXPECT(
+
1568 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
+
1569 for (auto const& key : activeKeys)
+
1570 BEAST_EXPECT(trustedKeys->trusted(key));
+
1571 }
+
1572 }
+
1573 {
+
1574 // Test 2-9 configured validators as validator
+
1575 auto trustedKeys = std::make_unique<ValidatorList>(
+
1576 manifestsOuter,
+
1577 manifestsOuter,
+
1578 env.timeKeeper(),
+
1579 app.config().legacy("database_path"),
+
1580 env.journal);
+
1581
+
1582 auto const localKey = randomNode();
+
1583 std::vector<std::string> cfgPublishers;
+
1584 hash_set<NodeID> activeValidators;
+
1585 hash_set<PublicKey> activeKeys;
+
1586 std::vector<std::string> cfgKeys{
+
1587 toBase58(TokenType::NodePublic, localKey)};
+
1588 cfgKeys.reserve(9);
+
1589
+
1590 while (cfgKeys.size() < cfgKeys.capacity())
+
1591 {
+
1592 auto const valKey = randomNode();
+
1593 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
+
1594 activeValidators.emplace(calcNodeID(valKey));
+
1595 activeKeys.emplace(valKey);
+
1596
+
1597 BEAST_EXPECT(
+
1598 trustedKeys->load(localKey, cfgKeys, cfgPublishers));
+
1599 TrustChanges changes = trustedKeys->updateTrusted(
+
1600 activeValidators,
+
1601 env.timeKeeper().now(),
+
1602 env.app().getOPs(),
+
1603 env.app().overlay(),
+
1604 env.app().getHashRouter());
+
1605 BEAST_EXPECT(changes.removed.empty());
+
1606 if (cfgKeys.size() > 2)
+
1607 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
+
1608 else
+
1609 BEAST_EXPECT(
+
1610 changes.added == asNodeIDs({localKey, valKey}));
1611
-
1612 // Config listed keys
-
1613 {
-
1614 ManifestCache manifests;
-
1615 auto trustedKeys = std::make_unique<ValidatorList>(
-
1616 manifests,
-
1617 manifests,
-
1618 env.timeKeeper(),
-
1619 app.config().legacy("database_path"),
-
1620 env.journal);
-
1621
-
1622 // Empty list has no expiration
-
1623 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
-
1624
-
1625 // Config listed keys have maximum expiry
-
1626 PublicKey localCfgListed = randomNode();
-
1627 trustedKeys->load({}, {toStr(localCfgListed)}, {});
-
1628 BEAST_EXPECT(
-
1629 trustedKeys->expires() &&
-
1630 trustedKeys->expires().value() == NetClock::time_point::max());
-
1631 BEAST_EXPECT(trustedKeys->listed(localCfgListed));
-
1632 }
-
1633
-
1634 // Published keys with expirations
-
1635 {
-
1636 ManifestCache manifests;
-
1637 auto trustedKeys = std::make_unique<ValidatorList>(
-
1638 manifests,
-
1639 manifests,
-
1640 env.app().timeKeeper(),
-
1641 app.config().legacy("database_path"),
-
1642 env.journal);
-
1643
-
1644 std::vector<Validator> validators = {randomValidator()};
-
1645 hash_set<NodeID> activeValidators;
-
1646 for (Validator const& val : validators)
-
1647 activeValidators.insert(calcNodeID(val.masterPublic));
-
1648 // Store prepared list data to control when it is applied
-
1649 struct PreparedList
-
1650 {
-
1651 PublicKey publisherPublic;
-
1652 std::string manifest;
-
1653 std::vector<ValidatorBlobInfo> blobs;
-
1654 int version;
-
1655 std::vector<NetClock::time_point> expirations;
-
1656 };
-
1657
-
1658 using namespace std::chrono_literals;
-
1659 auto addPublishedList = [this, &env, &trustedKeys, &validators]() {
-
1660 auto const publisherSecret = randomSecretKey();
-
1661 auto const publisherPublic =
-
1662 derivePublicKey(KeyType::ed25519, publisherSecret);
-
1663 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
-
1664 auto const manifest = base64_encode(makeManifestString(
-
1665 publisherPublic,
-
1666 publisherSecret,
-
1667 pubSigningKeys.first,
-
1668 pubSigningKeys.second,
-
1669 1));
+
1612 BEAST_EXPECT(
+
1613 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
+
1614
+
1615 for (auto const& key : activeKeys)
+
1616 BEAST_EXPECT(trustedKeys->trusted(key));
+
1617 }
+
1618 }
+
1619 {
+
1620 // Trusted set should include all validators from multiple lists
+
1621 ManifestCache manifests;
+
1622 auto trustedKeys = std::make_unique<ValidatorList>(
+
1623 manifests,
+
1624 manifests,
+
1625 env.timeKeeper(),
+
1626 app.config().legacy("database_path"),
+
1627 env.journal);
+
1628
+
1629 hash_set<NodeID> activeValidators;
+
1630 std::vector<Validator> valKeys;
+
1631 valKeys.reserve(maxKeys);
+
1632
+
1633 while (valKeys.size() != maxKeys)
+
1634 {
+
1635 valKeys.push_back(randomValidator());
+
1636 activeValidators.emplace(
+
1637 calcNodeID(valKeys.back().masterPublic));
+
1638 }
+
1639
+
1640 // locals[0]: from 0 to maxKeys - 4
+
1641 // locals[1]: from 1 to maxKeys - 2
+
1642 // locals[2]: from 2 to maxKeys
+
1643 constexpr static int publishers = 3;
+
1644 std::array<
+
1645 std::pair<
+
1646 decltype(valKeys)::const_iterator,
+
1647 decltype(valKeys)::const_iterator>,
+
1648 publishers>
+
1649 locals = {
+
1650 std::make_pair(valKeys.cbegin(), valKeys.cend() - 4),
+
1651 std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2),
+
1652 std::make_pair(valKeys.cbegin() + 2, valKeys.cend()),
+
1653 };
+
1654
+
1655 auto addPublishedList = [&, this](int i) {
+
1656 auto const publisherSecret = randomSecretKey();
+
1657 auto const publisherPublic =
+
1658 derivePublicKey(KeyType::ed25519, publisherSecret);
+
1659 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
+
1660 auto const manifest = base64_encode(makeManifestString(
+
1661 publisherPublic,
+
1662 publisherSecret,
+
1663 pubSigningKeys.first,
+
1664 pubSigningKeys.second,
+
1665 1));
+
1666
+
1667 std::vector<std::string> cfgPublishers(
+
1668 {strHex(publisherPublic)});
+
1669 std::vector<std::string> emptyCfgKeys;
1670
-
1671 std::vector<std::string> cfgPublishers(
-
1672 {strHex(publisherPublic)});
-
1673 std::vector<std::string> emptyCfgKeys;
+
1671 // Threshold of 1 will result in a union of all the lists
+
1672 BEAST_EXPECT(trustedKeys->load(
+
1673 {}, emptyCfgKeys, cfgPublishers, std::size_t(1)));
1674
-
1675 BEAST_EXPECT(
-
1676 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
-
1677
-
1678 auto const version = 2;
-
1679 auto const sequence1 = 1;
-
1680 NetClock::time_point const expiration1 =
-
1681 env.timeKeeper().now() + 1800s;
-
1682 auto const blob1 = makeList(
-
1683 validators,
-
1684 sequence1,
-
1685 expiration1.time_since_epoch().count());
-
1686 auto const sig1 = signList(blob1, pubSigningKeys);
-
1687
-
1688 NetClock::time_point const effective2 = expiration1 - 300s;
-
1689 NetClock::time_point const expiration2 = effective2 + 1800s;
-
1690 auto const sequence2 = 2;
-
1691 auto const blob2 = makeList(
-
1692 validators,
-
1693 sequence2,
-
1694 expiration2.time_since_epoch().count(),
-
1695 effective2.time_since_epoch().count());
-
1696 auto const sig2 = signList(blob2, pubSigningKeys);
-
1697
-
1698 return PreparedList{
-
1699 publisherPublic,
-
1700 manifest,
-
1701 {{blob1, sig1, {}}, {blob2, sig2, {}}},
-
1702 version,
-
1703 {expiration1, expiration2}};
-
1704 };
+
1675 auto const version = 1;
+
1676 auto const sequence = 1;
+
1677 using namespace std::chrono_literals;
+
1678 NetClock::time_point const validUntil =
+
1679 env.timeKeeper().now() + 3600s;
+
1680 std::vector<Validator> localKeys{
+
1681 locals[i].first, locals[i].second};
+
1682 auto const blob = makeList(
+
1683 localKeys, sequence, validUntil.time_since_epoch().count());
+
1684 auto const sig = signList(blob, pubSigningKeys);
+
1685
+
1686 BEAST_EXPECT(
+
1687 ListDisposition::accepted ==
+
1688 trustedKeys
+
1689 ->applyLists(
+
1690 manifest, version, {{blob, sig, {}}}, siteUri)
+
1691 .bestDisposition());
+
1692 };
+
1693
+
1694 // Apply multiple published lists
+
1695 for (auto i = 0; i < publishers; ++i)
+
1696 addPublishedList(i);
+
1697 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
1698
+
1699 TrustChanges changes = trustedKeys->updateTrusted(
+
1700 activeValidators,
+
1701 env.timeKeeper().now(),
+
1702 env.app().getOPs(),
+
1703 env.app().overlay(),
+
1704 env.app().getHashRouter());
1705
-
1706 // Configure two publishers and prepare 2 lists
-
1707 PreparedList prep1 = addPublishedList();
-
1708 env.timeKeeper().set(env.timeKeeper().now() + 200s);
-
1709 PreparedList prep2 = addPublishedList();
-
1710
-
1711 // Initially, no list has been published, so no known expiration
-
1712 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
-
1713
-
1714 // Apply first list
-
1715 checkResult(
-
1716 trustedKeys->applyLists(
-
1717 prep1.manifest, prep1.version, prep1.blobs, siteUri),
-
1718 prep1.publisherPublic,
-
1719 ListDisposition::pending,
-
1720 ListDisposition::accepted);
-
1721
-
1722 // One list still hasn't published, so expiration is still
-
1723 // unknown
-
1724 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
-
1725
-
1726 // Apply second list
-
1727 checkResult(
-
1728 trustedKeys->applyLists(
-
1729 prep2.manifest, prep2.version, prep2.blobs, siteUri),
-
1730 prep2.publisherPublic,
-
1731 ListDisposition::pending,
-
1732 ListDisposition::accepted);
-
1733 // We now have loaded both lists, so expiration is known
-
1734 BEAST_EXPECT(
-
1735 trustedKeys->expires() &&
-
1736 trustedKeys->expires().value() == prep1.expirations.back());
-
1737
-
1738 // Advance past the first list's LAST validFrom date. It remains
-
1739 // the earliest validUntil, while rotating in the second list
-
1740 {
-
1741 env.timeKeeper().set(prep1.expirations.front() - 1s);
-
1742 auto changes = trustedKeys->updateTrusted(
-
1743 activeValidators,
-
1744 env.timeKeeper().now(),
-
1745 env.app().getOPs(),
-
1746 env.app().overlay(),
-
1747 env.app().getHashRouter());
-
1748 BEAST_EXPECT(
-
1749 trustedKeys->expires() &&
-
1750 trustedKeys->expires().value() == prep1.expirations.back());
-
1751 BEAST_EXPECT(!changes.added.empty());
-
1752 BEAST_EXPECT(changes.removed.empty());
-
1753 }
-
1754
-
1755 // Advance past the first list's LAST validUntil, but it remains
-
1756 // the earliest validUntil, while being invalidated
-
1757 {
-
1758 env.timeKeeper().set(prep1.expirations.back() + 1s);
-
1759 auto changes = trustedKeys->updateTrusted(
-
1760 activeValidators,
-
1761 env.timeKeeper().now(),
-
1762 env.app().getOPs(),
-
1763 env.app().overlay(),
-
1764 env.app().getHashRouter());
-
1765 BEAST_EXPECT(
-
1766 trustedKeys->expires() &&
-
1767 trustedKeys->expires().value() == prep1.expirations.back());
-
1768 BEAST_EXPECT(changes.added.empty());
-
1769 BEAST_EXPECT(changes.removed.empty());
-
1770 }
-
1771 }
-
1772 }
-
1773
-
1774 void
-
1775 testNegativeUNL()
-
1776 {
-
1777 testcase("NegativeUNL");
-
1778 jtx::Env env(*this);
-
1779 ManifestCache manifests;
-
1780
-
1781 auto createValidatorList =
-
1782 [&](std::uint32_t vlSize,
-
1783 std::optional<std::size_t> minimumQuorum = {})
-
1784 -> std::shared_ptr<ValidatorList> {
-
1785 auto trustedKeys = std::make_shared<ValidatorList>(
-
1786 manifests,
-
1787 manifests,
-
1788 env.timeKeeper(),
-
1789 env.app().config().legacy("database_path"),
-
1790 env.journal,
-
1791 minimumQuorum);
-
1792
-
1793 std::vector<std::string> cfgPublishers;
-
1794 std::vector<std::string> cfgKeys;
-
1795 hash_set<NodeID> activeValidators;
-
1796 cfgKeys.reserve(vlSize);
-
1797 while (cfgKeys.size() < cfgKeys.capacity())
-
1798 {
-
1799 auto const valKey = randomNode();
-
1800 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
-
1801 activeValidators.emplace(calcNodeID(valKey));
-
1802 }
-
1803 if (trustedKeys->load({}, cfgKeys, cfgPublishers))
-
1804 {
-
1805 trustedKeys->updateTrusted(
-
1806 activeValidators,
-
1807 env.timeKeeper().now(),
-
1808 env.app().getOPs(),
-
1809 env.app().overlay(),
-
1810 env.app().getHashRouter());
-
1811 if (minimumQuorum == trustedKeys->quorum() ||
-
1812 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f))
-
1813 return trustedKeys;
-
1814 }
-
1815 return nullptr;
-
1816 };
+
1706 BEAST_EXPECT(
+
1707 trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f));
+
1708
+
1709 hash_set<NodeID> added;
+
1710 for (auto const& val : valKeys)
+
1711 {
+
1712 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
1713 added.insert(calcNodeID(val.masterPublic));
+
1714 }
+
1715 BEAST_EXPECT(changes.added == added);
+
1716 BEAST_EXPECT(changes.removed.empty());
+
1717 }
+
1718 {
+
1719 // Trusted set should include validators from intersection of lists
+
1720 ManifestCache manifests;
+
1721 auto trustedKeys = std::make_unique<ValidatorList>(
+
1722 manifests,
+
1723 manifests,
+
1724 env.timeKeeper(),
+
1725 app.config().legacy("database_path"),
+
1726 env.journal);
+
1727
+
1728 hash_set<NodeID> activeValidators;
+
1729 std::vector<Validator> valKeys;
+
1730 valKeys.reserve(maxKeys);
+
1731
+
1732 while (valKeys.size() != maxKeys)
+
1733 {
+
1734 valKeys.push_back(randomValidator());
+
1735 activeValidators.emplace(
+
1736 calcNodeID(valKeys.back().masterPublic));
+
1737 }
+
1738
+
1739 // locals[0]: from 0 to maxKeys - 4
+
1740 // locals[1]: from 1 to maxKeys - 2
+
1741 // locals[2]: from 2 to maxKeys
+
1742 // interesection of at least 2: same as locals[1]
+
1743 // intersection when 1 is dropped: from 2 to maxKeys - 4
+
1744 constexpr static int publishers = 3;
+
1745 std::array<
+
1746 std::pair<
+
1747 decltype(valKeys)::const_iterator,
+
1748 decltype(valKeys)::const_iterator>,
+
1749 publishers>
+
1750 locals = {
+
1751 std::make_pair(valKeys.cbegin(), valKeys.cend() - 4),
+
1752 std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2),
+
1753 std::make_pair(valKeys.cbegin() + 2, valKeys.cend()),
+
1754 };
+
1755
+
1756 auto addPublishedList = [&, this](
+
1757 int i,
+
1758 NetClock::time_point& validUntil1,
+
1759 NetClock::time_point& validUntil2) {
+
1760 auto const publisherSecret = randomSecretKey();
+
1761 auto const publisherPublic =
+
1762 derivePublicKey(KeyType::ed25519, publisherSecret);
+
1763 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
+
1764 auto const manifest = base64_encode(makeManifestString(
+
1765 publisherPublic,
+
1766 publisherSecret,
+
1767 pubSigningKeys.first,
+
1768 pubSigningKeys.second,
+
1769 1));
+
1770
+
1771 std::vector<std::string> cfgPublishers(
+
1772 {strHex(publisherPublic)});
+
1773 std::vector<std::string> emptyCfgKeys;
+
1774
+
1775 BEAST_EXPECT(
+
1776 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
+
1777
+
1778 auto const version = 1;
+
1779 auto const sequence = 1;
+
1780 using namespace std::chrono_literals;
+
1781 // Want to drop 1 sooner
+
1782 NetClock::time_point const validUntil = env.timeKeeper().now() +
+
1783 (i == 2 ? 120s
+
1784 : i == 1 ? 60s
+
1785 : 3600s);
+
1786 if (i == 1)
+
1787 validUntil1 = validUntil;
+
1788 else if (i == 2)
+
1789 validUntil2 = validUntil;
+
1790 std::vector<Validator> localKeys{
+
1791 locals[i].first, locals[i].second};
+
1792 auto const blob = makeList(
+
1793 localKeys, sequence, validUntil.time_since_epoch().count());
+
1794 auto const sig = signList(blob, pubSigningKeys);
+
1795
+
1796 BEAST_EXPECT(
+
1797 ListDisposition::accepted ==
+
1798 trustedKeys
+
1799 ->applyLists(
+
1800 manifest, version, {{blob, sig, {}}}, siteUri)
+
1801 .bestDisposition());
+
1802 };
+
1803
+
1804 // Apply multiple published lists
+
1805 // validUntil1 is expiration time for locals[1]
+
1806 NetClock::time_point validUntil1, validUntil2;
+
1807 for (auto i = 0; i < publishers; ++i)
+
1808 addPublishedList(i, validUntil1, validUntil2);
+
1809 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
1810
+
1811 TrustChanges changes = trustedKeys->updateTrusted(
+
1812 activeValidators,
+
1813 env.timeKeeper().now(),
+
1814 env.app().getOPs(),
+
1815 env.app().overlay(),
+
1816 env.app().getHashRouter());
1817
-
1818 /*
-
1819 * Test NegativeUNL
-
1820 * == Combinations ==
-
1821 * -- UNL size: 34, 35, 57
-
1822 * -- nUNL size: 0%, 20%, 30%, 50%
-
1823 *
-
1824 * == with UNL size 60
-
1825 * -- set == get,
-
1826 * -- check quorum, with nUNL size: 0, 12, 30, 18
-
1827 * -- nUNL overlap: |nUNL - UNL| = 5, with nUNL size: 18
-
1828 * -- with command line minimumQuorum = 50%,
-
1829 * seen_reliable affected by nUNL
-
1830 */
-
1831
-
1832 {
-
1833 hash_set<NodeID> activeValidators;
-
1834 //== Combinations ==
-
1835 std::array<std::uint32_t, 4> unlSizes = {34, 35, 39, 60};
-
1836 std::array<std::uint32_t, 4> nUnlPercent = {0, 20, 30, 50};
-
1837 for (auto us : unlSizes)
-
1838 {
-
1839 for (auto np : nUnlPercent)
-
1840 {
-
1841 auto validators = createValidatorList(us);
-
1842 BEAST_EXPECT(validators);
-
1843 if (validators)
-
1844 {
-
1845 std::uint32_t nUnlSize = us * np / 100;
-
1846 auto unl = validators->getTrustedMasterKeys();
-
1847 hash_set<PublicKey> nUnl;
-
1848 auto it = unl.begin();
-
1849 for (std::uint32_t i = 0; i < nUnlSize; ++i)
-
1850 {
-
1851 nUnl.insert(*it);
-
1852 ++it;
-
1853 }
-
1854 validators->setNegativeUNL(nUnl);
-
1855 validators->updateTrusted(
-
1856 activeValidators,
-
1857 env.timeKeeper().now(),
-
1858 env.app().getOPs(),
-
1859 env.app().overlay(),
-
1860 env.app().getHashRouter());
-
1861 BEAST_EXPECT(
-
1862 validators->quorum() ==
-
1863 static_cast<std::size_t>(std::ceil(
-
1864 std::max((us - nUnlSize) * 0.8f, us * 0.6f))));
-
1865 }
-
1866 }
-
1867 }
-
1868 }
+
1818 BEAST_EXPECT(
+
1819 trustedKeys->quorum() ==
+
1820 std::ceil((valKeys.size() - 3) * 0.8f));
+
1821
+
1822 for (auto const& val : valKeys)
+
1823 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
1824
+
1825 hash_set<NodeID> added;
+
1826 for (std::size_t i = 0; i < maxKeys; ++i)
+
1827 {
+
1828 auto const& val = valKeys[i];
+
1829 if (i >= 1 && i < maxKeys - 2)
+
1830 {
+
1831 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
1832 added.insert(calcNodeID(val.masterPublic));
+
1833 }
+
1834 else
+
1835 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
1836 }
+
1837 BEAST_EXPECT(changes.added == added);
+
1838 BEAST_EXPECT(changes.removed.empty());
+
1839
+
1840 // Expire locals[1]
+
1841 env.timeKeeper().set(validUntil1);
+
1842 changes = trustedKeys->updateTrusted(
+
1843 activeValidators,
+
1844 env.timeKeeper().now(),
+
1845 env.app().getOPs(),
+
1846 env.app().overlay(),
+
1847 env.app().getHashRouter());
+
1848
+
1849 BEAST_EXPECT(
+
1850 trustedKeys->quorum() ==
+
1851 std::ceil((valKeys.size() - 6) * 0.8f));
+
1852
+
1853 for (auto const& val : valKeys)
+
1854 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
1855
+
1856 hash_set<NodeID> removed;
+
1857 for (std::size_t i = 0; i < maxKeys; ++i)
+
1858 {
+
1859 auto const& val = valKeys[i];
+
1860 if (i >= 2 && i < maxKeys - 4)
+
1861 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
1862 else
+
1863 {
+
1864 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
1865 if (i >= 1 && i < maxKeys - 2)
+
1866 removed.insert(calcNodeID(val.masterPublic));
+
1867 }
+
1868 }
1869
-
1870 {
-
1871 //== with UNL size 60
-
1872 auto validators = createValidatorList(60);
-
1873 BEAST_EXPECT(validators);
-
1874 if (validators)
-
1875 {
-
1876 hash_set<NodeID> activeValidators;
-
1877 auto unl = validators->getTrustedMasterKeys();
-
1878 BEAST_EXPECT(unl.size() == 60);
-
1879 {
-
1880 //-- set == get,
-
1881 //-- check quorum, with nUNL size: 0, 30, 18, 12
-
1882 auto nUnlChange = [&](std::uint32_t nUnlSize,
-
1883 std::uint32_t quorum) -> bool {
-
1884 hash_set<PublicKey> nUnl;
-
1885 auto it = unl.begin();
-
1886 for (std::uint32_t i = 0; i < nUnlSize; ++i)
-
1887 {
-
1888 nUnl.insert(*it);
-
1889 ++it;
-
1890 }
-
1891 validators->setNegativeUNL(nUnl);
-
1892 auto nUnl_temp = validators->getNegativeUNL();
-
1893 if (nUnl_temp.size() == nUnl.size())
-
1894 {
-
1895 for (auto& n : nUnl_temp)
-
1896 {
-
1897 if (nUnl.find(n) == nUnl.end())
-
1898 return false;
-
1899 }
-
1900 validators->updateTrusted(
-
1901 activeValidators,
-
1902 env.timeKeeper().now(),
-
1903 env.app().getOPs(),
-
1904 env.app().overlay(),
-
1905 env.app().getHashRouter());
-
1906 return validators->quorum() == quorum;
-
1907 }
-
1908 return false;
-
1909 };
-
1910 BEAST_EXPECT(nUnlChange(0, 48));
-
1911 BEAST_EXPECT(nUnlChange(30, 36));
-
1912 BEAST_EXPECT(nUnlChange(18, 36));
-
1913 BEAST_EXPECT(nUnlChange(12, 39));
-
1914 }
-
1915
-
1916 {
-
1917 // nUNL overlap: |nUNL - UNL| = 5, with nUNL size:
-
1918 // 18
-
1919 auto nUnl = validators->getNegativeUNL();
-
1920 BEAST_EXPECT(nUnl.size() == 12);
-
1921 std::size_t ss = 33;
-
1922 std::vector<uint8_t> data(ss, 0);
-
1923 data[0] = 0xED;
-
1924 for (int i = 0; i < 6; ++i)
-
1925 {
-
1926 Slice s(data.data(), ss);
-
1927 data[1]++;
-
1928 nUnl.emplace(s);
-
1929 }
-
1930 validators->setNegativeUNL(nUnl);
-
1931 validators->updateTrusted(
-
1932 activeValidators,
-
1933 env.timeKeeper().now(),
-
1934 env.app().getOPs(),
-
1935 env.app().overlay(),
-
1936 env.app().getHashRouter());
-
1937 BEAST_EXPECT(validators->quorum() == 39);
-
1938 }
-
1939 }
-
1940 }
-
1941
+
1870 BEAST_EXPECT(changes.added.empty());
+
1871 BEAST_EXPECT(changes.removed == removed);
+
1872
+
1873 // Expire locals[2], which removes all validators
+
1874 env.timeKeeper().set(validUntil2);
+
1875 changes = trustedKeys->updateTrusted(
+
1876 activeValidators,
+
1877 env.timeKeeper().now(),
+
1878 env.app().getOPs(),
+
1879 env.app().overlay(),
+
1880 env.app().getHashRouter());
+
1881
+
1882 BEAST_EXPECT(
+
1883 trustedKeys->quorum() ==
+
1884 std::numeric_limits<std::size_t>::max());
+
1885
+
1886 removed.clear();
+
1887 for (std::size_t i = 0; i < maxKeys; ++i)
+
1888 {
+
1889 auto const& val = valKeys[i];
+
1890 if (i < maxKeys - 4)
+
1891 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
1892 else
+
1893 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
+
1894
+
1895 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
1896 if (i >= 2 && i < maxKeys - 4)
+
1897 removed.insert(calcNodeID(val.masterPublic));
+
1898 }
+
1899
+
1900 BEAST_EXPECT(changes.added.empty());
+
1901 BEAST_EXPECT(changes.removed == removed);
+
1902 }
+
1903 }
+
1904
+
1905 void
+
1906 testExpires()
+
1907 {
+
1908 testcase("Expires");
+
1909
+
1910 std::string const siteUri = "testExpires.test";
+
1911
+
1912 jtx::Env env(*this);
+
1913 auto& app = env.app();
+
1914
+
1915 auto toStr = [](PublicKey const& publicKey) {
+
1916 return toBase58(TokenType::NodePublic, publicKey);
+
1917 };
+
1918
+
1919 // Config listed keys
+
1920 {
+
1921 ManifestCache manifests;
+
1922 auto trustedKeys = std::make_unique<ValidatorList>(
+
1923 manifests,
+
1924 manifests,
+
1925 env.timeKeeper(),
+
1926 app.config().legacy("database_path"),
+
1927 env.journal);
+
1928
+
1929 // Empty list has no expiration
+
1930 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
+
1931
+
1932 // Config listed keys have maximum expiry
+
1933 PublicKey localCfgListed = randomNode();
+
1934 trustedKeys->load({}, {toStr(localCfgListed)}, {});
+
1935 BEAST_EXPECT(
+
1936 trustedKeys->expires() &&
+
1937 trustedKeys->expires().value() == NetClock::time_point::max());
+
1938 BEAST_EXPECT(trustedKeys->listed(localCfgListed));
+
1939 }
+
1940
+
1941 // Published keys with expirations
1942 {
-
1943 //== with UNL size 60
-
1944 //-- with command line minimumQuorum = 50%,
-
1945 // seen_reliable affected by nUNL
-
1946 auto validators = createValidatorList(60, 30);
-
1947 BEAST_EXPECT(validators);
-
1948 if (validators)
-
1949 {
-
1950 hash_set<NodeID> activeValidators;
-
1951 hash_set<PublicKey> unl = validators->getTrustedMasterKeys();
-
1952 auto it = unl.begin();
-
1953 for (std::uint32_t i = 0; i < 50; ++i)
-
1954 {
-
1955 activeValidators.insert(calcNodeID(*it));
-
1956 ++it;
-
1957 }
-
1958 validators->updateTrusted(
-
1959 activeValidators,
-
1960 env.timeKeeper().now(),
-
1961 env.app().getOPs(),
-
1962 env.app().overlay(),
-
1963 env.app().getHashRouter());
-
1964 BEAST_EXPECT(validators->quorum() == 30);
-
1965 hash_set<PublicKey> nUnl;
-
1966 it = unl.begin();
-
1967 for (std::uint32_t i = 0; i < 20; ++i)
-
1968 {
-
1969 nUnl.insert(*it);
-
1970 ++it;
-
1971 }
-
1972 validators->setNegativeUNL(nUnl);
-
1973 validators->updateTrusted(
-
1974 activeValidators,
-
1975 env.timeKeeper().now(),
-
1976 env.app().getOPs(),
-
1977 env.app().overlay(),
-
1978 env.app().getHashRouter());
-
1979 BEAST_EXPECT(validators->quorum() == 30);
-
1980 }
-
1981 }
-
1982 }
-
1983
-
1984 void
-
1985 testSha512Hash()
-
1986 {
-
1987 testcase("Sha512 hashing");
-
1988 // Tests that ValidatorList hash_append helpers with a single blob
-
1989 // returns the same result as ripple::Sha512Half used by the
-
1990 // TMValidatorList protocol message handler
-
1991 std::string const manifest = "This is not really a manifest";
-
1992 std::string const blob = "This is not really a blob";
-
1993 std::string const signature = "This is not really a signature";
-
1994 std::uint32_t const version = 1;
-
1995
-
1996 auto const global = sha512Half(manifest, blob, signature, version);
-
1997 BEAST_EXPECT(!!global);
-
1998
-
1999 std::vector<ValidatorBlobInfo> blobVector(1);
-
2000 blobVector[0].blob = blob;
-
2001 blobVector[0].signature = signature;
-
2002 BEAST_EXPECT(global == sha512Half(manifest, blobVector, version));
-
2003 BEAST_EXPECT(global != sha512Half(signature, blobVector, version));
+
1943 ManifestCache manifests;
+
1944 auto trustedKeys = std::make_unique<ValidatorList>(
+
1945 manifests,
+
1946 manifests,
+
1947 env.app().timeKeeper(),
+
1948 app.config().legacy("database_path"),
+
1949 env.journal);
+
1950
+
1951 std::vector<Validator> validators = {randomValidator()};
+
1952 hash_set<NodeID> activeValidators;
+
1953 for (Validator const& val : validators)
+
1954 activeValidators.insert(calcNodeID(val.masterPublic));
+
1955 // Store prepared list data to control when it is applied
+
1956 struct PreparedList
+
1957 {
+
1958 PublicKey publisherPublic;
+
1959 std::string manifest;
+
1960 std::vector<ValidatorBlobInfo> blobs;
+
1961 int version;
+
1962 std::vector<NetClock::time_point> expirations;
+
1963 };
+
1964
+
1965 using namespace std::chrono_literals;
+
1966 auto addPublishedList = [this, &env, &trustedKeys, &validators]() {
+
1967 auto const publisherSecret = randomSecretKey();
+
1968 auto const publisherPublic =
+
1969 derivePublicKey(KeyType::ed25519, publisherSecret);
+
1970 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
+
1971 auto const manifest = base64_encode(makeManifestString(
+
1972 publisherPublic,
+
1973 publisherSecret,
+
1974 pubSigningKeys.first,
+
1975 pubSigningKeys.second,
+
1976 1));
+
1977
+
1978 std::vector<std::string> cfgPublishers(
+
1979 {strHex(publisherPublic)});
+
1980 std::vector<std::string> emptyCfgKeys;
+
1981
+
1982 BEAST_EXPECT(
+
1983 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
+
1984
+
1985 auto const version = 2;
+
1986 auto const sequence1 = 1;
+
1987 NetClock::time_point const expiration1 =
+
1988 env.timeKeeper().now() + 1800s;
+
1989 auto const blob1 = makeList(
+
1990 validators,
+
1991 sequence1,
+
1992 expiration1.time_since_epoch().count());
+
1993 auto const sig1 = signList(blob1, pubSigningKeys);
+
1994
+
1995 NetClock::time_point const effective2 = expiration1 - 300s;
+
1996 NetClock::time_point const expiration2 = effective2 + 1800s;
+
1997 auto const sequence2 = 2;
+
1998 auto const blob2 = makeList(
+
1999 validators,
+
2000 sequence2,
+
2001 expiration2.time_since_epoch().count(),
+
2002 effective2.time_since_epoch().count());
+
2003 auto const sig2 = signList(blob2, pubSigningKeys);
2004
-
2005 {
-
2006 std::map<std::size_t, ValidatorBlobInfo> blobMap{
-
2007 {99, blobVector[0]}};
-
2008 BEAST_EXPECT(global == sha512Half(manifest, blobMap, version));
-
2009 BEAST_EXPECT(global != sha512Half(blob, blobMap, version));
-
2010 }
-
2011
-
2012 {
-
2013 protocol::TMValidatorList msg1;
-
2014 msg1.set_manifest(manifest);
-
2015 msg1.set_blob(blob);
-
2016 msg1.set_signature(signature);
-
2017 msg1.set_version(version);
-
2018 BEAST_EXPECT(global == sha512Half(msg1));
-
2019 msg1.set_signature(blob);
-
2020 BEAST_EXPECT(global != sha512Half(msg1));
-
2021 }
-
2022
-
2023 {
-
2024 protocol::TMValidatorListCollection msg2;
-
2025 msg2.set_manifest(manifest);
-
2026 msg2.set_version(version);
-
2027 auto& bi = *msg2.add_blobs();
-
2028 bi.set_blob(blob);
-
2029 bi.set_signature(signature);
-
2030 BEAST_EXPECT(global == sha512Half(msg2));
-
2031 bi.set_manifest(manifest);
-
2032 BEAST_EXPECT(global != sha512Half(msg2));
-
2033 }
-
2034 }
-
2035
-
2036 void
-
2037 testBuildMessages()
-
2038 {
-
2039 testcase("Build and split messages");
-
2040
-
2041 std::uint32_t const manifestCutoff = 7;
-
2042 auto extractHeader = [this](Message& message) {
-
2043 auto const& buffer =
-
2044 message.getBuffer(compression::Compressed::Off);
-
2045
-
2046 boost::beast::multi_buffer buffers;
-
2047
-
2048 // simulate multi-buffer
-
2049 auto start = buffer.begin();
-
2050 auto end = buffer.end();
-
2051 std::vector<std::uint8_t> slice(start, end);
-
2052 buffers.commit(boost::asio::buffer_copy(
-
2053 buffers.prepare(slice.size()), boost::asio::buffer(slice)));
-
2054
-
2055 boost::system::error_code ec;
-
2056 auto header =
-
2057 detail::parseMessageHeader(ec, buffers.data(), buffers.size());
-
2058 BEAST_EXPECT(!ec);
-
2059 return std::make_pair(header, buffers);
-
2060 };
-
2061 auto extractProtocolMessage1 = [this,
-
2062 &extractHeader](Message& message) {
-
2063 auto [header, buffers] = extractHeader(message);
-
2064 if (BEAST_EXPECT(header) &&
-
2065 BEAST_EXPECT(header->message_type == protocol::mtVALIDATORLIST))
-
2066 {
-
2067 auto const msg =
-
2068 detail::parseMessageContent<protocol::TMValidatorList>(
-
2069 *header, buffers.data());
-
2070 BEAST_EXPECT(msg);
-
2071 return msg;
-
2072 }
-
2073 return std::shared_ptr<protocol::TMValidatorList>();
-
2074 };
-
2075 auto extractProtocolMessage2 = [this,
-
2076 &extractHeader](Message& message) {
-
2077 auto [header, buffers] = extractHeader(message);
-
2078 if (BEAST_EXPECT(header) &&
-
2079 BEAST_EXPECT(
-
2080 header->message_type ==
-
2081 protocol::mtVALIDATORLISTCOLLECTION))
-
2082 {
-
2083 auto const msg = detail::parseMessageContent<
-
2084 protocol::TMValidatorListCollection>(
-
2085 *header, buffers.data());
-
2086 BEAST_EXPECT(msg);
-
2087 return msg;
-
2088 }
-
2089 return std::shared_ptr<protocol::TMValidatorListCollection>();
-
2090 };
-
2091 auto verifyMessage =
-
2092 [this,
-
2093 manifestCutoff,
-
2094 &extractProtocolMessage1,
-
2095 &extractProtocolMessage2](
-
2096 auto const version,
-
2097 auto const& manifest,
-
2098 auto const& blobInfos,
-
2099 auto const& messages,
-
2100 std::vector<std::pair<std::size_t, std::vector<std::uint32_t>>>
-
2101 expectedInfo) {
-
2102 BEAST_EXPECT(messages.size() == expectedInfo.size());
-
2103 auto msgIter = expectedInfo.begin();
-
2104 for (auto const& messageWithHash : messages)
-
2105 {
-
2106 if (!BEAST_EXPECT(msgIter != expectedInfo.end()))
-
2107 break;
-
2108 if (!BEAST_EXPECT(messageWithHash.message))
-
2109 continue;
-
2110 auto const& expectedSeqs = msgIter->second;
-
2111 auto seqIter = expectedSeqs.begin();
-
2112 auto const size =
-
2113 messageWithHash.message
-
2114 ->getBuffer(compression::Compressed::Off)
-
2115 .size();
-
2116 // This size is arbitrary, but shouldn't change
-
2117 BEAST_EXPECT(size == msgIter->first);
-
2118 if (expectedSeqs.size() == 1)
-
2119 {
-
2120 auto const msg =
-
2121 extractProtocolMessage1(*messageWithHash.message);
-
2122 auto const expectedVersion = 1;
-
2123 if (BEAST_EXPECT(msg))
-
2124 {
-
2125 BEAST_EXPECT(msg->version() == expectedVersion);
-
2126 if (!BEAST_EXPECT(seqIter != expectedSeqs.end()))
-
2127 continue;
-
2128 auto const& expectedBlob = blobInfos.at(*seqIter);
-
2129 BEAST_EXPECT(
-
2130 (*seqIter < manifestCutoff) ==
-
2131 !!expectedBlob.manifest);
-
2132 auto const expectedManifest =
-
2133 *seqIter < manifestCutoff &&
-
2134 expectedBlob.manifest
-
2135 ? *expectedBlob.manifest
-
2136 : manifest;
-
2137 BEAST_EXPECT(msg->manifest() == expectedManifest);
-
2138 BEAST_EXPECT(msg->blob() == expectedBlob.blob);
-
2139 BEAST_EXPECT(
-
2140 msg->signature() == expectedBlob.signature);
-
2141 ++seqIter;
-
2142 BEAST_EXPECT(seqIter == expectedSeqs.end());
-
2143
-
2144 BEAST_EXPECT(
-
2145 messageWithHash.hash ==
-
2146 sha512Half(
-
2147 expectedManifest,
-
2148 expectedBlob.blob,
-
2149 expectedBlob.signature,
-
2150 expectedVersion));
-
2151 }
-
2152 }
-
2153 else
-
2154 {
-
2155 std::vector<ValidatorBlobInfo> hashingBlobs;
-
2156 hashingBlobs.reserve(msgIter->second.size());
-
2157
-
2158 auto const msg =
-
2159 extractProtocolMessage2(*messageWithHash.message);
-
2160 if (BEAST_EXPECT(msg))
-
2161 {
-
2162 BEAST_EXPECT(msg->version() == version);
-
2163 BEAST_EXPECT(msg->manifest() == manifest);
-
2164 for (auto const& blobInfo : msg->blobs())
-
2165 {
-
2166 if (!BEAST_EXPECT(
-
2167 seqIter != expectedSeqs.end()))
-
2168 break;
-
2169 auto const& expectedBlob =
-
2170 blobInfos.at(*seqIter);
-
2171 hashingBlobs.push_back(expectedBlob);
-
2172 BEAST_EXPECT(
-
2173 blobInfo.has_manifest() ==
-
2174 !!expectedBlob.manifest);
-
2175 BEAST_EXPECT(
-
2176 blobInfo.has_manifest() ==
-
2177 (*seqIter < manifestCutoff));
-
2178
-
2179 if (*seqIter < manifestCutoff)
-
2180 BEAST_EXPECT(
-
2181 blobInfo.manifest() ==
-
2182 *expectedBlob.manifest);
-
2183 BEAST_EXPECT(
-
2184 blobInfo.blob() == expectedBlob.blob);
-
2185 BEAST_EXPECT(
-
2186 blobInfo.signature() ==
-
2187 expectedBlob.signature);
-
2188 ++seqIter;
-
2189 }
-
2190 BEAST_EXPECT(seqIter == expectedSeqs.end());
-
2191 }
-
2192 BEAST_EXPECT(
-
2193 messageWithHash.hash ==
-
2194 sha512Half(manifest, hashingBlobs, version));
-
2195 }
-
2196 ++msgIter;
-
2197 }
-
2198 BEAST_EXPECT(msgIter == expectedInfo.end());
-
2199 };
-
2200 auto verifyBuildMessages =
-
2201 [this](
-
2202 std::pair<std::size_t, std::size_t> const& result,
-
2203 std::size_t expectedSequence,
-
2204 std::size_t expectedSize) {
-
2205 BEAST_EXPECT(result.first == expectedSequence);
-
2206 BEAST_EXPECT(result.second == expectedSize);
-
2207 };
-
2208
-
2209 std::string const manifest = "This is not a manifest";
-
2210 std::uint32_t const version = 2;
-
2211 // Mutable so items can be removed in later tests.
-
2212 auto const blobInfos = [manifestCutoff = manifestCutoff]() {
-
2213 std::map<std::size_t, ValidatorBlobInfo> bis;
-
2214
-
2215 for (auto seq : {5, 6, 7, 10, 12})
-
2216 {
-
2217 auto& b = bis[seq];
-
2218 std::stringstream s;
-
2219 s << "This is not a blob with sequence " << seq;
-
2220 b.blob = s.str();
-
2221 s.str(std::string());
-
2222 s << "This is not a signature for sequence " << seq;
-
2223 b.signature = s.str();
-
2224 if (seq < manifestCutoff)
-
2225 {
-
2226 // add a manifest for the "early" blobs
-
2227 s.str(std::string());
-
2228 s << "This is not manifest " << seq;
-
2229 b.manifest = s.str();
-
2230 }
-
2231 }
-
2232 return bis;
-
2233 }();
-
2234 auto const maxSequence = blobInfos.rbegin()->first;
-
2235 BEAST_EXPECT(maxSequence == 12);
-
2236
-
2237 std::vector<ValidatorList::MessageWithHash> messages;
-
2238
-
2239 // Version 1
-
2240
-
2241 // This peer has a VL ahead of our "current"
-
2242 verifyBuildMessages(
-
2243 ValidatorList::buildValidatorListMessages(
-
2244 1, 8, maxSequence, version, manifest, blobInfos, messages),
-
2245 0,
-
2246 0);
-
2247 BEAST_EXPECT(messages.size() == 0);
+
2005 return PreparedList{
+
2006 publisherPublic,
+
2007 manifest,
+
2008 {{blob1, sig1, {}}, {blob2, sig2, {}}},
+
2009 version,
+
2010 {expiration1, expiration2}};
+
2011 };
+
2012
+
2013 // Configure two publishers and prepare 2 lists
+
2014 PreparedList prep1 = addPublishedList();
+
2015 env.timeKeeper().set(env.timeKeeper().now() + 200s);
+
2016 PreparedList prep2 = addPublishedList();
+
2017
+
2018 // Initially, no list has been published, so no known expiration
+
2019 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
+
2020
+
2021 // Apply first list
+
2022 checkResult(
+
2023 trustedKeys->applyLists(
+
2024 prep1.manifest, prep1.version, prep1.blobs, siteUri),
+
2025 prep1.publisherPublic,
+
2026 ListDisposition::pending,
+
2027 ListDisposition::accepted);
+
2028
+
2029 // One list still hasn't published, so expiration is still
+
2030 // unknown
+
2031 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
+
2032
+
2033 // Apply second list
+
2034 checkResult(
+
2035 trustedKeys->applyLists(
+
2036 prep2.manifest, prep2.version, prep2.blobs, siteUri),
+
2037 prep2.publisherPublic,
+
2038 ListDisposition::pending,
+
2039 ListDisposition::accepted);
+
2040 // We now have loaded both lists, so expiration is known
+
2041 BEAST_EXPECT(
+
2042 trustedKeys->expires() &&
+
2043 trustedKeys->expires().value() == prep1.expirations.back());
+
2044
+
2045 // Advance past the first list's LAST validFrom date. It remains
+
2046 // the earliest validUntil, while rotating in the second list
+
2047 {
+
2048 env.timeKeeper().set(prep1.expirations.front() - 1s);
+
2049 auto changes = trustedKeys->updateTrusted(
+
2050 activeValidators,
+
2051 env.timeKeeper().now(),
+
2052 env.app().getOPs(),
+
2053 env.app().overlay(),
+
2054 env.app().getHashRouter());
+
2055 BEAST_EXPECT(
+
2056 trustedKeys->expires() &&
+
2057 trustedKeys->expires().value() == prep1.expirations.back());
+
2058 BEAST_EXPECT(!changes.added.empty());
+
2059 BEAST_EXPECT(changes.removed.empty());
+
2060 }
+
2061
+
2062 // Advance past the first list's LAST validUntil, but it remains
+
2063 // the earliest validUntil, while being invalidated
+
2064 {
+
2065 env.timeKeeper().set(prep1.expirations.back() + 1s);
+
2066 auto changes = trustedKeys->updateTrusted(
+
2067 activeValidators,
+
2068 env.timeKeeper().now(),
+
2069 env.app().getOPs(),
+
2070 env.app().overlay(),
+
2071 env.app().getHashRouter());
+
2072 BEAST_EXPECT(
+
2073 trustedKeys->expires() &&
+
2074 trustedKeys->expires().value() == prep1.expirations.back());
+
2075 BEAST_EXPECT(changes.added.empty());
+
2076 BEAST_EXPECT(changes.removed.empty());
+
2077 }
+
2078 }
+
2079 }
+
2080
+
2081 void
+
2082 testNegativeUNL()
+
2083 {
+
2084 testcase("NegativeUNL");
+
2085 jtx::Env env(*this);
+
2086 ManifestCache manifests;
+
2087
+
2088 auto createValidatorList =
+
2089 [&](std::uint32_t vlSize,
+
2090 std::optional<std::size_t> minimumQuorum = {})
+
2091 -> std::shared_ptr<ValidatorList> {
+
2092 auto trustedKeys = std::make_shared<ValidatorList>(
+
2093 manifests,
+
2094 manifests,
+
2095 env.timeKeeper(),
+
2096 env.app().config().legacy("database_path"),
+
2097 env.journal,
+
2098 minimumQuorum);
+
2099
+
2100 std::vector<std::string> cfgPublishers;
+
2101 std::vector<std::string> cfgKeys;
+
2102 hash_set<NodeID> activeValidators;
+
2103 cfgKeys.reserve(vlSize);
+
2104 while (cfgKeys.size() < cfgKeys.capacity())
+
2105 {
+
2106 auto const valKey = randomNode();
+
2107 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
+
2108 activeValidators.emplace(calcNodeID(valKey));
+
2109 }
+
2110 if (trustedKeys->load({}, cfgKeys, cfgPublishers))
+
2111 {
+
2112 trustedKeys->updateTrusted(
+
2113 activeValidators,
+
2114 env.timeKeeper().now(),
+
2115 env.app().getOPs(),
+
2116 env.app().overlay(),
+
2117 env.app().getHashRouter());
+
2118 if (minimumQuorum == trustedKeys->quorum() ||
+
2119 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f))
+
2120 return trustedKeys;
+
2121 }
+
2122 return nullptr;
+
2123 };
+
2124
+
2125 /*
+
2126 * Test NegativeUNL
+
2127 * == Combinations ==
+
2128 * -- UNL size: 34, 35, 57
+
2129 * -- nUNL size: 0%, 20%, 30%, 50%
+
2130 *
+
2131 * == with UNL size 60
+
2132 * -- set == get,
+
2133 * -- check quorum, with nUNL size: 0, 12, 30, 18
+
2134 * -- nUNL overlap: |nUNL - UNL| = 5, with nUNL size: 18
+
2135 * -- with command line minimumQuorum = 50%,
+
2136 * seen_reliable affected by nUNL
+
2137 */
+
2138
+
2139 {
+
2140 hash_set<NodeID> activeValidators;
+
2141 //== Combinations ==
+
2142 std::array<std::uint32_t, 4> unlSizes = {34, 35, 39, 60};
+
2143 std::array<std::uint32_t, 4> nUnlPercent = {0, 20, 30, 50};
+
2144 for (auto us : unlSizes)
+
2145 {
+
2146 for (auto np : nUnlPercent)
+
2147 {
+
2148 auto validators = createValidatorList(us);
+
2149 BEAST_EXPECT(validators);
+
2150 if (validators)
+
2151 {
+
2152 std::uint32_t nUnlSize = us * np / 100;
+
2153 auto unl = validators->getTrustedMasterKeys();
+
2154 hash_set<PublicKey> nUnl;
+
2155 auto it = unl.begin();
+
2156 for (std::uint32_t i = 0; i < nUnlSize; ++i)
+
2157 {
+
2158 nUnl.insert(*it);
+
2159 ++it;
+
2160 }
+
2161 validators->setNegativeUNL(nUnl);
+
2162 validators->updateTrusted(
+
2163 activeValidators,
+
2164 env.timeKeeper().now(),
+
2165 env.app().getOPs(),
+
2166 env.app().overlay(),
+
2167 env.app().getHashRouter());
+
2168 BEAST_EXPECT(
+
2169 validators->quorum() ==
+
2170 static_cast<std::size_t>(std::ceil(
+
2171 std::max((us - nUnlSize) * 0.8f, us * 0.6f))));
+
2172 }
+
2173 }
+
2174 }
+
2175 }
+
2176
+
2177 {
+
2178 //== with UNL size 60
+
2179 auto validators = createValidatorList(60);
+
2180 BEAST_EXPECT(validators);
+
2181 if (validators)
+
2182 {
+
2183 hash_set<NodeID> activeValidators;
+
2184 auto unl = validators->getTrustedMasterKeys();
+
2185 BEAST_EXPECT(unl.size() == 60);
+
2186 {
+
2187 //-- set == get,
+
2188 //-- check quorum, with nUNL size: 0, 30, 18, 12
+
2189 auto nUnlChange = [&](std::uint32_t nUnlSize,
+
2190 std::uint32_t quorum) -> bool {
+
2191 hash_set<PublicKey> nUnl;
+
2192 auto it = unl.begin();
+
2193 for (std::uint32_t i = 0; i < nUnlSize; ++i)
+
2194 {
+
2195 nUnl.insert(*it);
+
2196 ++it;
+
2197 }
+
2198 validators->setNegativeUNL(nUnl);
+
2199 auto nUnl_temp = validators->getNegativeUNL();
+
2200 if (nUnl_temp.size() == nUnl.size())
+
2201 {
+
2202 for (auto& n : nUnl_temp)
+
2203 {
+
2204 if (nUnl.find(n) == nUnl.end())
+
2205 return false;
+
2206 }
+
2207 validators->updateTrusted(
+
2208 activeValidators,
+
2209 env.timeKeeper().now(),
+
2210 env.app().getOPs(),
+
2211 env.app().overlay(),
+
2212 env.app().getHashRouter());
+
2213 return validators->quorum() == quorum;
+
2214 }
+
2215 return false;
+
2216 };
+
2217 BEAST_EXPECT(nUnlChange(0, 48));
+
2218 BEAST_EXPECT(nUnlChange(30, 36));
+
2219 BEAST_EXPECT(nUnlChange(18, 36));
+
2220 BEAST_EXPECT(nUnlChange(12, 39));
+
2221 }
+
2222
+
2223 {
+
2224 // nUNL overlap: |nUNL - UNL| = 5, with nUNL size:
+
2225 // 18
+
2226 auto nUnl = validators->getNegativeUNL();
+
2227 BEAST_EXPECT(nUnl.size() == 12);
+
2228 std::size_t ss = 33;
+
2229 std::vector<uint8_t> data(ss, 0);
+
2230 data[0] = 0xED;
+
2231 for (int i = 0; i < 6; ++i)
+
2232 {
+
2233 Slice s(data.data(), ss);
+
2234 data[1]++;
+
2235 nUnl.emplace(s);
+
2236 }
+
2237 validators->setNegativeUNL(nUnl);
+
2238 validators->updateTrusted(
+
2239 activeValidators,
+
2240 env.timeKeeper().now(),
+
2241 env.app().getOPs(),
+
2242 env.app().overlay(),
+
2243 env.app().getHashRouter());
+
2244 BEAST_EXPECT(validators->quorum() == 39);
+
2245 }
+
2246 }
+
2247 }
2248
-
2249 // Don't repeat the work if messages is populated, even though the
-
2250 // peerSequence provided indicates it should. Note that this
-
2251 // situation is contrived for this test and should never happen in
-
2252 // real code.
-
2253 messages.emplace_back();
-
2254 verifyBuildMessages(
-
2255 ValidatorList::buildValidatorListMessages(
-
2256 1, 3, maxSequence, version, manifest, blobInfos, messages),
-
2257 5,
-
2258 0);
-
2259 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
-
2260
-
2261 // Generate a version 1 message
-
2262 messages.clear();
-
2263 verifyBuildMessages(
-
2264 ValidatorList::buildValidatorListMessages(
-
2265 1, 3, maxSequence, version, manifest, blobInfos, messages),
-
2266 5,
-
2267 1);
-
2268 if (BEAST_EXPECT(messages.size() == 1) &&
-
2269 BEAST_EXPECT(messages.front().message))
-
2270 {
-
2271 auto const& messageWithHash = messages.front();
-
2272 auto const msg = extractProtocolMessage1(*messageWithHash.message);
-
2273 auto const size =
-
2274 messageWithHash.message->getBuffer(compression::Compressed::Off)
-
2275 .size();
-
2276 // This size is arbitrary, but shouldn't change
-
2277 BEAST_EXPECT(size == 108);
-
2278 auto const& expected = blobInfos.at(5);
-
2279 if (BEAST_EXPECT(msg))
-
2280 {
-
2281 BEAST_EXPECT(msg->version() == 1);
-
2282 BEAST_EXPECT(msg->manifest() == *expected.manifest);
-
2283 BEAST_EXPECT(msg->blob() == expected.blob);
-
2284 BEAST_EXPECT(msg->signature() == expected.signature);
-
2285 }
-
2286 BEAST_EXPECT(
-
2287 messageWithHash.hash ==
-
2288 sha512Half(
-
2289 *expected.manifest, expected.blob, expected.signature, 1));
-
2290 }
-
2291
-
2292 // Version 2
-
2293
-
2294 messages.clear();
-
2295
-
2296 // This peer has a VL ahead of us.
-
2297 verifyBuildMessages(
-
2298 ValidatorList::buildValidatorListMessages(
-
2299 2,
-
2300 maxSequence * 2,
-
2301 maxSequence,
-
2302 version,
-
2303 manifest,
-
2304 blobInfos,
-
2305 messages),
-
2306 0,
-
2307 0);
-
2308 BEAST_EXPECT(messages.size() == 0);
-
2309
-
2310 // Don't repeat the work if messages is populated, even though the
-
2311 // peerSequence provided indicates it should. Note that this
-
2312 // situation is contrived for this test and should never happen in
-
2313 // real code.
-
2314 messages.emplace_back();
-
2315 verifyBuildMessages(
-
2316 ValidatorList::buildValidatorListMessages(
-
2317 2, 3, maxSequence, version, manifest, blobInfos, messages),
-
2318 maxSequence,
-
2319 0);
-
2320 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
-
2321
-
2322 // Generate a version 2 message. Don't send the current
-
2323 messages.clear();
-
2324 verifyBuildMessages(
-
2325 ValidatorList::buildValidatorListMessages(
-
2326 2, 5, maxSequence, version, manifest, blobInfos, messages),
-
2327 maxSequence,
-
2328 4);
-
2329 verifyMessage(
-
2330 version, manifest, blobInfos, messages, {{372, {6, 7, 10, 12}}});
-
2331
-
2332 // Test message splitting on size limits.
-
2333
-
2334 // Set a limit that should give two messages
-
2335 messages.clear();
-
2336 verifyBuildMessages(
-
2337 ValidatorList::buildValidatorListMessages(
-
2338 2, 5, maxSequence, version, manifest, blobInfos, messages, 300),
-
2339 maxSequence,
-
2340 4);
-
2341 verifyMessage(
-
2342 version,
-
2343 manifest,
-
2344 blobInfos,
-
2345 messages,
-
2346 {{212, {6, 7}}, {192, {10, 12}}});
+
2249 {
+
2250 //== with UNL size 60
+
2251 //-- with command line minimumQuorum = 50%,
+
2252 // seen_reliable affected by nUNL
+
2253 auto validators = createValidatorList(60, 30);
+
2254 BEAST_EXPECT(validators);
+
2255 if (validators)
+
2256 {
+
2257 hash_set<NodeID> activeValidators;
+
2258 hash_set<PublicKey> unl = validators->getTrustedMasterKeys();
+
2259 auto it = unl.begin();
+
2260 for (std::uint32_t i = 0; i < 50; ++i)
+
2261 {
+
2262 activeValidators.insert(calcNodeID(*it));
+
2263 ++it;
+
2264 }
+
2265 validators->updateTrusted(
+
2266 activeValidators,
+
2267 env.timeKeeper().now(),
+
2268 env.app().getOPs(),
+
2269 env.app().overlay(),
+
2270 env.app().getHashRouter());
+
2271 BEAST_EXPECT(validators->quorum() == 30);
+
2272 hash_set<PublicKey> nUnl;
+
2273 it = unl.begin();
+
2274 for (std::uint32_t i = 0; i < 20; ++i)
+
2275 {
+
2276 nUnl.insert(*it);
+
2277 ++it;
+
2278 }
+
2279 validators->setNegativeUNL(nUnl);
+
2280 validators->updateTrusted(
+
2281 activeValidators,
+
2282 env.timeKeeper().now(),
+
2283 env.app().getOPs(),
+
2284 env.app().overlay(),
+
2285 env.app().getHashRouter());
+
2286 BEAST_EXPECT(validators->quorum() == 30);
+
2287 }
+
2288 }
+
2289 }
+
2290
+
2291 void
+
2292 testSha512Hash()
+
2293 {
+
2294 testcase("Sha512 hashing");
+
2295 // Tests that ValidatorList hash_append helpers with a single blob
+
2296 // returns the same result as ripple::Sha512Half used by the
+
2297 // TMValidatorList protocol message handler
+
2298 std::string const manifest = "This is not really a manifest";
+
2299 std::string const blob = "This is not really a blob";
+
2300 std::string const signature = "This is not really a signature";
+
2301 std::uint32_t const version = 1;
+
2302
+
2303 auto const global = sha512Half(manifest, blob, signature, version);
+
2304 BEAST_EXPECT(!!global);
+
2305
+
2306 std::vector<ValidatorBlobInfo> blobVector(1);
+
2307 blobVector[0].blob = blob;
+
2308 blobVector[0].signature = signature;
+
2309 BEAST_EXPECT(global == sha512Half(manifest, blobVector, version));
+
2310 BEAST_EXPECT(global != sha512Half(signature, blobVector, version));
+
2311
+
2312 {
+
2313 std::map<std::size_t, ValidatorBlobInfo> blobMap{
+
2314 {99, blobVector[0]}};
+
2315 BEAST_EXPECT(global == sha512Half(manifest, blobMap, version));
+
2316 BEAST_EXPECT(global != sha512Half(blob, blobMap, version));
+
2317 }
+
2318
+
2319 {
+
2320 protocol::TMValidatorList msg1;
+
2321 msg1.set_manifest(manifest);
+
2322 msg1.set_blob(blob);
+
2323 msg1.set_signature(signature);
+
2324 msg1.set_version(version);
+
2325 BEAST_EXPECT(global == sha512Half(msg1));
+
2326 msg1.set_signature(blob);
+
2327 BEAST_EXPECT(global != sha512Half(msg1));
+
2328 }
+
2329
+
2330 {
+
2331 protocol::TMValidatorListCollection msg2;
+
2332 msg2.set_manifest(manifest);
+
2333 msg2.set_version(version);
+
2334 auto& bi = *msg2.add_blobs();
+
2335 bi.set_blob(blob);
+
2336 bi.set_signature(signature);
+
2337 BEAST_EXPECT(global == sha512Half(msg2));
+
2338 bi.set_manifest(manifest);
+
2339 BEAST_EXPECT(global != sha512Half(msg2));
+
2340 }
+
2341 }
+
2342
+
2343 void
+
2344 testBuildMessages()
+
2345 {
+
2346 testcase("Build and split messages");
2347
-
2348 // Set a limit between the size of the two earlier messages so one
-
2349 // will split and the other won't
-
2350 messages.clear();
-
2351 verifyBuildMessages(
-
2352 ValidatorList::buildValidatorListMessages(
-
2353 2, 5, maxSequence, version, manifest, blobInfos, messages, 200),
-
2354 maxSequence,
-
2355 4);
-
2356 verifyMessage(
-
2357 version,
-
2358 manifest,
-
2359 blobInfos,
-
2360 messages,
-
2361 {{108, {6}}, {108, {7}}, {192, {10, 12}}});
-
2362
-
2363 // Set a limit so that all the VLs are sent individually
-
2364 messages.clear();
-
2365 verifyBuildMessages(
-
2366 ValidatorList::buildValidatorListMessages(
-
2367 2, 5, maxSequence, version, manifest, blobInfos, messages, 150),
-
2368 maxSequence,
-
2369 4);
-
2370 verifyMessage(
-
2371 version,
-
2372 manifest,
-
2373 blobInfos,
-
2374 messages,
-
2375 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
-
2376
-
2377 // Set a limit smaller than some of the messages. Because single
-
2378 // messages send regardless, they will all still be sent
-
2379 messages.clear();
-
2380 verifyBuildMessages(
-
2381 ValidatorList::buildValidatorListMessages(
-
2382 2, 5, maxSequence, version, manifest, blobInfos, messages, 108),
-
2383 maxSequence,
-
2384 4);
-
2385 verifyMessage(
-
2386 version,
-
2387 manifest,
-
2388 blobInfos,
-
2389 messages,
-
2390 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
-
2391 }
-
2392
-
2393public:
-
2394 void
-
2395 run() override
-
2396 {
-
2397 testGenesisQuorum();
-
2398 testConfigLoad();
-
2399 testApplyLists();
-
2400 testGetAvailable();
-
2401 testUpdateTrusted();
-
2402 testExpires();
-
2403 testNegativeUNL();
-
2404 testSha512Hash();
-
2405 testBuildMessages();
-
2406 }
-
2407}; // namespace test
-
2408
-
2409BEAST_DEFINE_TESTSUITE(ValidatorList, app, ripple);
-
2410
-
2411} // namespace test
-
2412} // namespace ripple
+
2348 std::uint32_t const manifestCutoff = 7;
+
2349 auto extractHeader = [this](Message& message) {
+
2350 auto const& buffer =
+
2351 message.getBuffer(compression::Compressed::Off);
+
2352
+
2353 boost::beast::multi_buffer buffers;
+
2354
+
2355 // simulate multi-buffer
+
2356 auto start = buffer.begin();
+
2357 auto end = buffer.end();
+
2358 std::vector<std::uint8_t> slice(start, end);
+
2359 buffers.commit(boost::asio::buffer_copy(
+
2360 buffers.prepare(slice.size()), boost::asio::buffer(slice)));
+
2361
+
2362 boost::system::error_code ec;
+
2363 auto header =
+
2364 detail::parseMessageHeader(ec, buffers.data(), buffers.size());
+
2365 BEAST_EXPECT(!ec);
+
2366 return std::make_pair(header, buffers);
+
2367 };
+
2368 auto extractProtocolMessage1 = [this,
+
2369 &extractHeader](Message& message) {
+
2370 auto [header, buffers] = extractHeader(message);
+
2371 if (BEAST_EXPECT(header) &&
+
2372 BEAST_EXPECT(header->message_type == protocol::mtVALIDATORLIST))
+
2373 {
+
2374 auto const msg =
+
2375 detail::parseMessageContent<protocol::TMValidatorList>(
+
2376 *header, buffers.data());
+
2377 BEAST_EXPECT(msg);
+
2378 return msg;
+
2379 }
+
2380 return std::shared_ptr<protocol::TMValidatorList>();
+
2381 };
+
2382 auto extractProtocolMessage2 = [this,
+
2383 &extractHeader](Message& message) {
+
2384 auto [header, buffers] = extractHeader(message);
+
2385 if (BEAST_EXPECT(header) &&
+
2386 BEAST_EXPECT(
+
2387 header->message_type ==
+
2388 protocol::mtVALIDATORLISTCOLLECTION))
+
2389 {
+
2390 auto const msg = detail::parseMessageContent<
+
2391 protocol::TMValidatorListCollection>(
+
2392 *header, buffers.data());
+
2393 BEAST_EXPECT(msg);
+
2394 return msg;
+
2395 }
+
2396 return std::shared_ptr<protocol::TMValidatorListCollection>();
+
2397 };
+
2398 auto verifyMessage =
+
2399 [this,
+
2400 manifestCutoff,
+
2401 &extractProtocolMessage1,
+
2402 &extractProtocolMessage2](
+
2403 auto const version,
+
2404 auto const& manifest,
+
2405 auto const& blobInfos,
+
2406 auto const& messages,
+
2407 std::vector<std::pair<std::size_t, std::vector<std::uint32_t>>>
+
2408 expectedInfo) {
+
2409 BEAST_EXPECT(messages.size() == expectedInfo.size());
+
2410 auto msgIter = expectedInfo.begin();
+
2411 for (auto const& messageWithHash : messages)
+
2412 {
+
2413 if (!BEAST_EXPECT(msgIter != expectedInfo.end()))
+
2414 break;
+
2415 if (!BEAST_EXPECT(messageWithHash.message))
+
2416 continue;
+
2417 auto const& expectedSeqs = msgIter->second;
+
2418 auto seqIter = expectedSeqs.begin();
+
2419 auto const size =
+
2420 messageWithHash.message
+
2421 ->getBuffer(compression::Compressed::Off)
+
2422 .size();
+
2423 // This size is arbitrary, but shouldn't change
+
2424 BEAST_EXPECT(size == msgIter->first);
+
2425 if (expectedSeqs.size() == 1)
+
2426 {
+
2427 auto const msg =
+
2428 extractProtocolMessage1(*messageWithHash.message);
+
2429 auto const expectedVersion = 1;
+
2430 if (BEAST_EXPECT(msg))
+
2431 {
+
2432 BEAST_EXPECT(msg->version() == expectedVersion);
+
2433 if (!BEAST_EXPECT(seqIter != expectedSeqs.end()))
+
2434 continue;
+
2435 auto const& expectedBlob = blobInfos.at(*seqIter);
+
2436 BEAST_EXPECT(
+
2437 (*seqIter < manifestCutoff) ==
+
2438 !!expectedBlob.manifest);
+
2439 auto const expectedManifest =
+
2440 *seqIter < manifestCutoff &&
+
2441 expectedBlob.manifest
+
2442 ? *expectedBlob.manifest
+
2443 : manifest;
+
2444 BEAST_EXPECT(msg->manifest() == expectedManifest);
+
2445 BEAST_EXPECT(msg->blob() == expectedBlob.blob);
+
2446 BEAST_EXPECT(
+
2447 msg->signature() == expectedBlob.signature);
+
2448 ++seqIter;
+
2449 BEAST_EXPECT(seqIter == expectedSeqs.end());
+
2450
+
2451 BEAST_EXPECT(
+
2452 messageWithHash.hash ==
+
2453 sha512Half(
+
2454 expectedManifest,
+
2455 expectedBlob.blob,
+
2456 expectedBlob.signature,
+
2457 expectedVersion));
+
2458 }
+
2459 }
+
2460 else
+
2461 {
+
2462 std::vector<ValidatorBlobInfo> hashingBlobs;
+
2463 hashingBlobs.reserve(msgIter->second.size());
+
2464
+
2465 auto const msg =
+
2466 extractProtocolMessage2(*messageWithHash.message);
+
2467 if (BEAST_EXPECT(msg))
+
2468 {
+
2469 BEAST_EXPECT(msg->version() == version);
+
2470 BEAST_EXPECT(msg->manifest() == manifest);
+
2471 for (auto const& blobInfo : msg->blobs())
+
2472 {
+
2473 if (!BEAST_EXPECT(
+
2474 seqIter != expectedSeqs.end()))
+
2475 break;
+
2476 auto const& expectedBlob =
+
2477 blobInfos.at(*seqIter);
+
2478 hashingBlobs.push_back(expectedBlob);
+
2479 BEAST_EXPECT(
+
2480 blobInfo.has_manifest() ==
+
2481 !!expectedBlob.manifest);
+
2482 BEAST_EXPECT(
+
2483 blobInfo.has_manifest() ==
+
2484 (*seqIter < manifestCutoff));
+
2485
+
2486 if (*seqIter < manifestCutoff)
+
2487 BEAST_EXPECT(
+
2488 blobInfo.manifest() ==
+
2489 *expectedBlob.manifest);
+
2490 BEAST_EXPECT(
+
2491 blobInfo.blob() == expectedBlob.blob);
+
2492 BEAST_EXPECT(
+
2493 blobInfo.signature() ==
+
2494 expectedBlob.signature);
+
2495 ++seqIter;
+
2496 }
+
2497 BEAST_EXPECT(seqIter == expectedSeqs.end());
+
2498 }
+
2499 BEAST_EXPECT(
+
2500 messageWithHash.hash ==
+
2501 sha512Half(manifest, hashingBlobs, version));
+
2502 }
+
2503 ++msgIter;
+
2504 }
+
2505 BEAST_EXPECT(msgIter == expectedInfo.end());
+
2506 };
+
2507 auto verifyBuildMessages =
+
2508 [this](
+
2509 std::pair<std::size_t, std::size_t> const& result,
+
2510 std::size_t expectedSequence,
+
2511 std::size_t expectedSize) {
+
2512 BEAST_EXPECT(result.first == expectedSequence);
+
2513 BEAST_EXPECT(result.second == expectedSize);
+
2514 };
+
2515
+
2516 std::string const manifest = "This is not a manifest";
+
2517 std::uint32_t const version = 2;
+
2518 // Mutable so items can be removed in later tests.
+
2519 auto const blobInfos = [manifestCutoff = manifestCutoff]() {
+
2520 std::map<std::size_t, ValidatorBlobInfo> bis;
+
2521
+
2522 for (auto seq : {5, 6, 7, 10, 12})
+
2523 {
+
2524 auto& b = bis[seq];
+
2525 std::stringstream s;
+
2526 s << "This is not a blob with sequence " << seq;
+
2527 b.blob = s.str();
+
2528 s.str(std::string());
+
2529 s << "This is not a signature for sequence " << seq;
+
2530 b.signature = s.str();
+
2531 if (seq < manifestCutoff)
+
2532 {
+
2533 // add a manifest for the "early" blobs
+
2534 s.str(std::string());
+
2535 s << "This is not manifest " << seq;
+
2536 b.manifest = s.str();
+
2537 }
+
2538 }
+
2539 return bis;
+
2540 }();
+
2541 auto const maxSequence = blobInfos.rbegin()->first;
+
2542 BEAST_EXPECT(maxSequence == 12);
+
2543
+
2544 std::vector<ValidatorList::MessageWithHash> messages;
+
2545
+
2546 // Version 1
+
2547
+
2548 // This peer has a VL ahead of our "current"
+
2549 verifyBuildMessages(
+
2550 ValidatorList::buildValidatorListMessages(
+
2551 1, 8, maxSequence, version, manifest, blobInfos, messages),
+
2552 0,
+
2553 0);
+
2554 BEAST_EXPECT(messages.size() == 0);
+
2555
+
2556 // Don't repeat the work if messages is populated, even though the
+
2557 // peerSequence provided indicates it should. Note that this
+
2558 // situation is contrived for this test and should never happen in
+
2559 // real code.
+
2560 messages.emplace_back();
+
2561 verifyBuildMessages(
+
2562 ValidatorList::buildValidatorListMessages(
+
2563 1, 3, maxSequence, version, manifest, blobInfos, messages),
+
2564 5,
+
2565 0);
+
2566 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
+
2567
+
2568 // Generate a version 1 message
+
2569 messages.clear();
+
2570 verifyBuildMessages(
+
2571 ValidatorList::buildValidatorListMessages(
+
2572 1, 3, maxSequence, version, manifest, blobInfos, messages),
+
2573 5,
+
2574 1);
+
2575 if (BEAST_EXPECT(messages.size() == 1) &&
+
2576 BEAST_EXPECT(messages.front().message))
+
2577 {
+
2578 auto const& messageWithHash = messages.front();
+
2579 auto const msg = extractProtocolMessage1(*messageWithHash.message);
+
2580 auto const size =
+
2581 messageWithHash.message->getBuffer(compression::Compressed::Off)
+
2582 .size();
+
2583 // This size is arbitrary, but shouldn't change
+
2584 BEAST_EXPECT(size == 108);
+
2585 auto const& expected = blobInfos.at(5);
+
2586 if (BEAST_EXPECT(msg))
+
2587 {
+
2588 BEAST_EXPECT(msg->version() == 1);
+
2589 BEAST_EXPECT(msg->manifest() == *expected.manifest);
+
2590 BEAST_EXPECT(msg->blob() == expected.blob);
+
2591 BEAST_EXPECT(msg->signature() == expected.signature);
+
2592 }
+
2593 BEAST_EXPECT(
+
2594 messageWithHash.hash ==
+
2595 sha512Half(
+
2596 *expected.manifest, expected.blob, expected.signature, 1));
+
2597 }
+
2598
+
2599 // Version 2
+
2600
+
2601 messages.clear();
+
2602
+
2603 // This peer has a VL ahead of us.
+
2604 verifyBuildMessages(
+
2605 ValidatorList::buildValidatorListMessages(
+
2606 2,
+
2607 maxSequence * 2,
+
2608 maxSequence,
+
2609 version,
+
2610 manifest,
+
2611 blobInfos,
+
2612 messages),
+
2613 0,
+
2614 0);
+
2615 BEAST_EXPECT(messages.size() == 0);
+
2616
+
2617 // Don't repeat the work if messages is populated, even though the
+
2618 // peerSequence provided indicates it should. Note that this
+
2619 // situation is contrived for this test and should never happen in
+
2620 // real code.
+
2621 messages.emplace_back();
+
2622 verifyBuildMessages(
+
2623 ValidatorList::buildValidatorListMessages(
+
2624 2, 3, maxSequence, version, manifest, blobInfos, messages),
+
2625 maxSequence,
+
2626 0);
+
2627 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
+
2628
+
2629 // Generate a version 2 message. Don't send the current
+
2630 messages.clear();
+
2631 verifyBuildMessages(
+
2632 ValidatorList::buildValidatorListMessages(
+
2633 2, 5, maxSequence, version, manifest, blobInfos, messages),
+
2634 maxSequence,
+
2635 4);
+
2636 verifyMessage(
+
2637 version, manifest, blobInfos, messages, {{372, {6, 7, 10, 12}}});
+
2638
+
2639 // Test message splitting on size limits.
+
2640
+
2641 // Set a limit that should give two messages
+
2642 messages.clear();
+
2643 verifyBuildMessages(
+
2644 ValidatorList::buildValidatorListMessages(
+
2645 2, 5, maxSequence, version, manifest, blobInfos, messages, 300),
+
2646 maxSequence,
+
2647 4);
+
2648 verifyMessage(
+
2649 version,
+
2650 manifest,
+
2651 blobInfos,
+
2652 messages,
+
2653 {{212, {6, 7}}, {192, {10, 12}}});
+
2654
+
2655 // Set a limit between the size of the two earlier messages so one
+
2656 // will split and the other won't
+
2657 messages.clear();
+
2658 verifyBuildMessages(
+
2659 ValidatorList::buildValidatorListMessages(
+
2660 2, 5, maxSequence, version, manifest, blobInfos, messages, 200),
+
2661 maxSequence,
+
2662 4);
+
2663 verifyMessage(
+
2664 version,
+
2665 manifest,
+
2666 blobInfos,
+
2667 messages,
+
2668 {{108, {6}}, {108, {7}}, {192, {10, 12}}});
+
2669
+
2670 // Set a limit so that all the VLs are sent individually
+
2671 messages.clear();
+
2672 verifyBuildMessages(
+
2673 ValidatorList::buildValidatorListMessages(
+
2674 2, 5, maxSequence, version, manifest, blobInfos, messages, 150),
+
2675 maxSequence,
+
2676 4);
+
2677 verifyMessage(
+
2678 version,
+
2679 manifest,
+
2680 blobInfos,
+
2681 messages,
+
2682 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
+
2683
+
2684 // Set a limit smaller than some of the messages. Because single
+
2685 // messages send regardless, they will all still be sent
+
2686 messages.clear();
+
2687 verifyBuildMessages(
+
2688 ValidatorList::buildValidatorListMessages(
+
2689 2, 5, maxSequence, version, manifest, blobInfos, messages, 108),
+
2690 maxSequence,
+
2691 4);
+
2692 verifyMessage(
+
2693 version,
+
2694 manifest,
+
2695 blobInfos,
+
2696 messages,
+
2697 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
+
2698 }
+
2699
+
2700 void
+
2701 testQuorumDisabled()
+
2702 {
+
2703 testcase("Test quorum disabled");
+
2704
+
2705 std::string const siteUri = "testQuorumDisabled.test";
+
2706 jtx::Env env(*this);
+
2707 auto& app = env.app();
+
2708
+
2709 constexpr std::size_t maxKeys = 20;
+
2710 hash_set<NodeID> activeValidators;
+
2711 std::vector<Validator> valKeys;
+
2712 while (valKeys.size() != maxKeys)
+
2713 {
+
2714 valKeys.push_back(randomValidator());
+
2715 activeValidators.emplace(calcNodeID(valKeys.back().masterPublic));
+
2716 }
+
2717
+
2718 struct Publisher
+
2719 {
+
2720 bool revoked;
+
2721 PublicKey pubKey;
+
2722 std::pair<PublicKey, SecretKey> signingKeys;
+
2723 std::string manifest;
+
2724 NetClock::time_point expiry = {};
+
2725 };
+
2726
+
2727 // Create ValidatorList with a set of countTotal publishers, of which
+
2728 // first countRevoked are revoked and the last one expires early
+
2729 auto makeValidatorList = [&, this](
+
2730 std::size_t countTotal,
+
2731 std::size_t countRevoked,
+
2732 std::size_t listThreshold,
+
2733 ManifestCache& pubManifests,
+
2734 ManifestCache& valManifests,
+
2735 std::optional<Validator> self,
+
2736 std::vector<Publisher>& publishers // out
+
2737 ) -> std::unique_ptr<ValidatorList> {
+
2738 auto result = std::make_unique<ValidatorList>(
+
2739 valManifests,
+
2740 pubManifests,
+
2741 env.timeKeeper(),
+
2742 app.config().legacy("database_path"),
+
2743 env.journal);
+
2744
+
2745 std::vector<std::string> cfgPublishers;
+
2746 for (std::size_t i = 0; i < countTotal; ++i)
+
2747 {
+
2748 auto const publisherSecret = randomSecretKey();
+
2749 auto const publisherPublic =
+
2750 derivePublicKey(KeyType::ed25519, publisherSecret);
+
2751 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
+
2752 cfgPublishers.push_back(strHex(publisherPublic));
+
2753
+
2754 constexpr auto revoked =
+
2755 std::numeric_limits<std::uint32_t>::max();
+
2756 auto const manifest = base64_encode(makeManifestString(
+
2757 publisherPublic,
+
2758 publisherSecret,
+
2759 pubSigningKeys.first,
+
2760 pubSigningKeys.second,
+
2761 i < countRevoked ? revoked : 1));
+
2762 publishers.push_back(Publisher{
+
2763 i < countRevoked,
+
2764 publisherPublic,
+
2765 pubSigningKeys,
+
2766 manifest});
+
2767 }
+
2768
+
2769 std::vector<std::string> const emptyCfgKeys;
+
2770 auto threshold =
+
2771 listThreshold > 0 ? std::optional(listThreshold) : std::nullopt;
+
2772 if (self)
+
2773 {
+
2774 valManifests.applyManifest(
+
2775 *deserializeManifest(base64_decode(self->manifest)));
+
2776 BEAST_EXPECT(result->load(
+
2777 self->signingPublic,
+
2778 emptyCfgKeys,
+
2779 cfgPublishers,
+
2780 threshold));
+
2781 }
+
2782 else
+
2783 {
+
2784 BEAST_EXPECT(
+
2785 result->load({}, emptyCfgKeys, cfgPublishers, threshold));
+
2786 }
+
2787
+
2788 for (std::size_t i = 0; i < countTotal; ++i)
+
2789 {
+
2790 using namespace std::chrono_literals;
+
2791 publishers[i].expiry = env.timeKeeper().now() +
+
2792 (i == countTotal - 1 ? 60s : 3600s);
+
2793 auto const blob = makeList(
+
2794 valKeys,
+
2795 1,
+
2796 publishers[i].expiry.time_since_epoch().count());
+
2797 auto const sig = signList(blob, publishers[i].signingKeys);
+
2798
+
2799 BEAST_EXPECT(
+
2800 result
+
2801 ->applyLists(
+
2802 publishers[i].manifest,
+
2803 1,
+
2804 {{blob, sig, {}}},
+
2805 siteUri)
+
2806 .bestDisposition() ==
+
2807 (publishers[i].revoked ? ListDisposition::untrusted
+
2808 : ListDisposition::accepted));
+
2809 }
+
2810
+
2811 return result;
+
2812 };
+
2813
+
2814 // Test cases use 5 publishers.
+
2815 constexpr auto quorumDisabled = std::numeric_limits<std::size_t>::max();
+
2816 {
+
2817 // List threshold = 5 (same as number of trusted publishers)
+
2818 ManifestCache pubManifests;
+
2819 ManifestCache valManifests;
+
2820 std::vector<Publisher> publishers;
+
2821 // Self is a random validator
+
2822 auto const self = randomValidator();
+
2823 auto const keysTotal = valKeys.size() + 1;
+
2824 auto trustedKeys = makeValidatorList(
+
2825 5, //
+
2826 0,
+
2827 5,
+
2828 pubManifests,
+
2829 valManifests,
+
2830 self,
+
2831 publishers);
+
2832 BEAST_EXPECT(trustedKeys->getListThreshold() == 5);
+
2833 for (auto const& p : publishers)
+
2834 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
2835
+
2836 TrustChanges changes = trustedKeys->updateTrusted(
+
2837 activeValidators,
+
2838 env.timeKeeper().now(),
+
2839 env.app().getOPs(),
+
2840 env.app().overlay(),
+
2841 env.app().getHashRouter());
+
2842 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
2843 BEAST_EXPECT(
+
2844 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
2845
+
2846 hash_set<NodeID> added;
+
2847 added.insert(calcNodeID(self.masterPublic));
+
2848 for (auto const& val : valKeys)
+
2849 {
+
2850 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
2851 added.insert(calcNodeID(val.masterPublic));
+
2852 }
+
2853 BEAST_EXPECT(changes.added == added);
+
2854 BEAST_EXPECT(changes.removed.empty());
+
2855
+
2856 // Expire one publisher - only trusted validator is self
+
2857 env.timeKeeper().set(publishers.back().expiry);
+
2858 changes = trustedKeys->updateTrusted(
+
2859 activeValidators,
+
2860 env.timeKeeper().now(),
+
2861 env.app().getOPs(),
+
2862 env.app().overlay(),
+
2863 env.app().getHashRouter());
+
2864 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
2865 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
2866
+
2867 hash_set<NodeID> removed;
+
2868 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
2869 for (auto const& val : valKeys)
+
2870 {
+
2871 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
2872 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
2873 removed.insert(calcNodeID(val.masterPublic));
+
2874 }
+
2875 BEAST_EXPECT(changes.added.empty());
+
2876 BEAST_EXPECT(changes.removed == removed);
+
2877 }
+
2878 {
+
2879 // List threshold = 5 (same as number of trusted publishers)
+
2880 ManifestCache pubManifests;
+
2881 ManifestCache valManifests;
+
2882 std::vector<Publisher> publishers;
+
2883 auto const keysTotal = valKeys.size();
+
2884 auto trustedKeys = makeValidatorList(
+
2885 5, //
+
2886 0,
+
2887 5,
+
2888 pubManifests,
+
2889 valManifests,
+
2890 {},
+
2891 publishers);
+
2892 BEAST_EXPECT(trustedKeys->getListThreshold() == 5);
+
2893 for (auto const& p : publishers)
+
2894 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
2895
+
2896 TrustChanges changes = trustedKeys->updateTrusted(
+
2897 activeValidators,
+
2898 env.timeKeeper().now(),
+
2899 env.app().getOPs(),
+
2900 env.app().overlay(),
+
2901 env.app().getHashRouter());
+
2902 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
2903 BEAST_EXPECT(
+
2904 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
2905
+
2906 hash_set<NodeID> added;
+
2907 for (auto const& val : valKeys)
+
2908 {
+
2909 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
2910 added.insert(calcNodeID(val.masterPublic));
+
2911 }
+
2912 BEAST_EXPECT(changes.added == added);
+
2913 BEAST_EXPECT(changes.removed.empty());
+
2914
+
2915 // Expire one publisher - no trusted validators
+
2916 env.timeKeeper().set(publishers.back().expiry);
+
2917 changes = trustedKeys->updateTrusted(
+
2918 activeValidators,
+
2919 env.timeKeeper().now(),
+
2920 env.app().getOPs(),
+
2921 env.app().overlay(),
+
2922 env.app().getHashRouter());
+
2923 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
2924 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
+
2925
+
2926 hash_set<NodeID> removed;
+
2927 for (auto const& val : valKeys)
+
2928 {
+
2929 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
2930 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
2931 removed.insert(calcNodeID(val.masterPublic));
+
2932 }
+
2933 BEAST_EXPECT(changes.added.empty());
+
2934 BEAST_EXPECT(changes.removed == removed);
+
2935 }
+
2936 {
+
2937 // List threshold = 4, 1 publisher is revoked
+
2938 ManifestCache pubManifests;
+
2939 ManifestCache valManifests;
+
2940 std::vector<Publisher> publishers;
+
2941 // Self is in UNL
+
2942 auto const self = valKeys[1];
+
2943 auto const keysTotal = valKeys.size();
+
2944 auto trustedKeys = makeValidatorList(
+
2945 5, //
+
2946 1,
+
2947 4,
+
2948 pubManifests,
+
2949 valManifests,
+
2950 self,
+
2951 publishers);
+
2952 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
+
2953 int untrustedCount = 0;
+
2954 for (auto const& p : publishers)
+
2955 {
+
2956 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
2957 BEAST_EXPECT(p.revoked ^ trusted);
+
2958 untrustedCount += trusted ? 0 : 1;
+
2959 }
+
2960 BEAST_EXPECT(untrustedCount == 1);
+
2961
+
2962 TrustChanges changes = trustedKeys->updateTrusted(
+
2963 activeValidators,
+
2964 env.timeKeeper().now(),
+
2965 env.app().getOPs(),
+
2966 env.app().overlay(),
+
2967 env.app().getHashRouter());
+
2968 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
2969 BEAST_EXPECT(
+
2970 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
2971
+
2972 hash_set<NodeID> added;
+
2973 for (auto const& val : valKeys)
+
2974 {
+
2975 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
2976 added.insert(calcNodeID(val.masterPublic));
+
2977 }
+
2978 BEAST_EXPECT(changes.added == added);
+
2979 BEAST_EXPECT(changes.removed.empty());
+
2980
+
2981 // Expire one publisher - only trusted validator is self
+
2982 env.timeKeeper().set(publishers.back().expiry);
+
2983 changes = trustedKeys->updateTrusted(
+
2984 activeValidators,
+
2985 env.timeKeeper().now(),
+
2986 env.app().getOPs(),
+
2987 env.app().overlay(),
+
2988 env.app().getHashRouter());
+
2989 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
2990 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
2991
+
2992 hash_set<NodeID> removed;
+
2993 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
2994 for (auto const& val : valKeys)
+
2995 {
+
2996 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
2997 if (val.masterPublic != self.masterPublic)
+
2998 {
+
2999 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3000 removed.insert(calcNodeID(val.masterPublic));
+
3001 }
+
3002 }
+
3003 BEAST_EXPECT(changes.added.empty());
+
3004 BEAST_EXPECT(changes.removed == removed);
+
3005 }
+
3006 {
+
3007 // List threshold = 3 (default), 2 publishers are revoked
+
3008 ManifestCache pubManifests;
+
3009 ManifestCache valManifests;
+
3010 std::vector<Publisher> publishers;
+
3011 // Self is a random validator
+
3012 auto const self = randomValidator();
+
3013 auto const keysTotal = valKeys.size() + 1;
+
3014 auto trustedKeys = makeValidatorList(
+
3015 5, //
+
3016 2,
+
3017 0,
+
3018 pubManifests,
+
3019 valManifests,
+
3020 self,
+
3021 publishers);
+
3022 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
+
3023 int untrustedCount = 0;
+
3024 for (auto const& p : publishers)
+
3025 {
+
3026 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
3027 BEAST_EXPECT(p.revoked ^ trusted);
+
3028 untrustedCount += trusted ? 0 : 1;
+
3029 }
+
3030 BEAST_EXPECT(untrustedCount == 2);
+
3031
+
3032 TrustChanges changes = trustedKeys->updateTrusted(
+
3033 activeValidators,
+
3034 env.timeKeeper().now(),
+
3035 env.app().getOPs(),
+
3036 env.app().overlay(),
+
3037 env.app().getHashRouter());
+
3038 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3039 BEAST_EXPECT(
+
3040 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3041
+
3042 hash_set<NodeID> added;
+
3043 added.insert(calcNodeID(self.masterPublic));
+
3044 for (auto const& val : valKeys)
+
3045 {
+
3046 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3047 added.insert(calcNodeID(val.masterPublic));
+
3048 }
+
3049 BEAST_EXPECT(changes.added == added);
+
3050 BEAST_EXPECT(changes.removed.empty());
+
3051
+
3052 // Expire one publisher - no quorum, only trusted validator is self
+
3053 env.timeKeeper().set(publishers.back().expiry);
+
3054 changes = trustedKeys->updateTrusted(
+
3055 activeValidators,
+
3056 env.timeKeeper().now(),
+
3057 env.app().getOPs(),
+
3058 env.app().overlay(),
+
3059 env.app().getHashRouter());
+
3060 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3061 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
3062
+
3063 hash_set<NodeID> removed;
+
3064 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3065 for (auto const& val : valKeys)
+
3066 {
+
3067 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3068 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3069 removed.insert(calcNodeID(val.masterPublic));
+
3070 }
+
3071 BEAST_EXPECT(changes.added.empty());
+
3072 BEAST_EXPECT(changes.removed == removed);
+
3073 }
+
3074 {
+
3075 // List threshold = 3 (default), 2 publishers are revoked
+
3076 ManifestCache pubManifests;
+
3077 ManifestCache valManifests;
+
3078 std::vector<Publisher> publishers;
+
3079 // Self is in UNL
+
3080 auto const self = valKeys[5];
+
3081 auto const keysTotal = valKeys.size();
+
3082 auto trustedKeys = makeValidatorList(
+
3083 5, //
+
3084 2,
+
3085 0,
+
3086 pubManifests,
+
3087 valManifests,
+
3088 self,
+
3089 publishers);
+
3090 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
+
3091 int untrustedCount = 0;
+
3092 for (auto const& p : publishers)
+
3093 {
+
3094 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
3095 BEAST_EXPECT(p.revoked ^ trusted);
+
3096 untrustedCount += trusted ? 0 : 1;
+
3097 }
+
3098 BEAST_EXPECT(untrustedCount == 2);
+
3099
+
3100 TrustChanges changes = trustedKeys->updateTrusted(
+
3101 activeValidators,
+
3102 env.timeKeeper().now(),
+
3103 env.app().getOPs(),
+
3104 env.app().overlay(),
+
3105 env.app().getHashRouter());
+
3106 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3107 BEAST_EXPECT(
+
3108 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3109
+
3110 hash_set<NodeID> added;
+
3111 for (auto const& val : valKeys)
+
3112 {
+
3113 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3114 added.insert(calcNodeID(val.masterPublic));
+
3115 }
+
3116 BEAST_EXPECT(changes.added == added);
+
3117 BEAST_EXPECT(changes.removed.empty());
+
3118
+
3119 // Expire one publisher - no quorum, only trusted validator is self
+
3120 env.timeKeeper().set(publishers.back().expiry);
+
3121 changes = trustedKeys->updateTrusted(
+
3122 activeValidators,
+
3123 env.timeKeeper().now(),
+
3124 env.app().getOPs(),
+
3125 env.app().overlay(),
+
3126 env.app().getHashRouter());
+
3127 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3128 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
3129
+
3130 hash_set<NodeID> removed;
+
3131 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3132 for (auto const& val : valKeys)
+
3133 {
+
3134 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3135 if (val.masterPublic != self.masterPublic)
+
3136 {
+
3137 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3138 removed.insert(calcNodeID(val.masterPublic));
+
3139 }
+
3140 }
+
3141 BEAST_EXPECT(changes.added.empty());
+
3142 BEAST_EXPECT(changes.removed == removed);
+
3143 }
+
3144 {
+
3145 // List threshold = 3 (default), 2 publishers are revoked
+
3146 ManifestCache pubManifests;
+
3147 ManifestCache valManifests;
+
3148 std::vector<Publisher> publishers;
+
3149 auto const keysTotal = valKeys.size();
+
3150 auto trustedKeys = makeValidatorList(
+
3151 5, //
+
3152 2,
+
3153 0,
+
3154 pubManifests,
+
3155 valManifests,
+
3156 {},
+
3157 publishers);
+
3158 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
+
3159 int untrustedCount = 0;
+
3160 for (auto const& p : publishers)
+
3161 {
+
3162 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
3163 BEAST_EXPECT(p.revoked ^ trusted);
+
3164 untrustedCount += trusted ? 0 : 1;
+
3165 }
+
3166 BEAST_EXPECT(untrustedCount == 2);
+
3167
+
3168 TrustChanges changes = trustedKeys->updateTrusted(
+
3169 activeValidators,
+
3170 env.timeKeeper().now(),
+
3171 env.app().getOPs(),
+
3172 env.app().overlay(),
+
3173 env.app().getHashRouter());
+
3174 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3175 BEAST_EXPECT(
+
3176 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3177
+
3178 hash_set<NodeID> added;
+
3179 for (auto const& val : valKeys)
+
3180 {
+
3181 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3182 added.insert(calcNodeID(val.masterPublic));
+
3183 }
+
3184 BEAST_EXPECT(changes.added == added);
+
3185 BEAST_EXPECT(changes.removed.empty());
+
3186
+
3187 // Expire one publisher - no quorum, no trusted validators
+
3188 env.timeKeeper().set(publishers.back().expiry);
+
3189 changes = trustedKeys->updateTrusted(
+
3190 activeValidators,
+
3191 env.timeKeeper().now(),
+
3192 env.app().getOPs(),
+
3193 env.app().overlay(),
+
3194 env.app().getHashRouter());
+
3195 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3196 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
+
3197
+
3198 hash_set<NodeID> removed;
+
3199 for (auto const& val : valKeys)
+
3200 {
+
3201 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3202 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3203 removed.insert(calcNodeID(val.masterPublic));
+
3204 }
+
3205 BEAST_EXPECT(changes.added.empty());
+
3206 BEAST_EXPECT(changes.removed == removed);
+
3207 }
+
3208 {
+
3209 // List threshold = 2, 1 publisher is revoked
+
3210 ManifestCache pubManifests;
+
3211 ManifestCache valManifests;
+
3212 std::vector<Publisher> publishers;
+
3213 // Self is a random validator
+
3214 auto const self = randomValidator();
+
3215 auto const keysTotal = valKeys.size() + 1;
+
3216 auto trustedKeys = makeValidatorList(
+
3217 5, //
+
3218 1,
+
3219 2,
+
3220 pubManifests,
+
3221 valManifests,
+
3222 self,
+
3223 publishers);
+
3224 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
3225 int untrustedCount = 0;
+
3226 for (auto const& p : publishers)
+
3227 {
+
3228 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
3229 BEAST_EXPECT(p.revoked ^ trusted);
+
3230 untrustedCount += trusted ? 0 : 1;
+
3231 }
+
3232 BEAST_EXPECT(untrustedCount == 1);
+
3233
+
3234 TrustChanges changes = trustedKeys->updateTrusted(
+
3235 activeValidators,
+
3236 env.timeKeeper().now(),
+
3237 env.app().getOPs(),
+
3238 env.app().overlay(),
+
3239 env.app().getHashRouter());
+
3240 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3241 BEAST_EXPECT(
+
3242 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3243
+
3244 hash_set<NodeID> added;
+
3245 added.insert(calcNodeID(self.masterPublic));
+
3246 for (auto const& val : valKeys)
+
3247 {
+
3248 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3249 added.insert(calcNodeID(val.masterPublic));
+
3250 }
+
3251 BEAST_EXPECT(changes.added == added);
+
3252 BEAST_EXPECT(changes.removed.empty());
+
3253
+
3254 // Expire one publisher - no quorum
+
3255 env.timeKeeper().set(publishers.back().expiry);
+
3256 changes = trustedKeys->updateTrusted(
+
3257 activeValidators,
+
3258 env.timeKeeper().now(),
+
3259 env.app().getOPs(),
+
3260 env.app().overlay(),
+
3261 env.app().getHashRouter());
+
3262 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3263 BEAST_EXPECT(
+
3264 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3265
+
3266 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3267 for (auto const& val : valKeys)
+
3268 {
+
3269 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3270 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3271 }
+
3272 BEAST_EXPECT(changes.added.empty());
+
3273 BEAST_EXPECT(changes.removed.empty());
+
3274 }
+
3275 {
+
3276 // List threshold = 1
+
3277 ManifestCache pubManifests;
+
3278 ManifestCache valManifests;
+
3279 std::vector<Publisher> publishers;
+
3280 // Self is a random validator
+
3281 auto const self = randomValidator();
+
3282 auto const keysTotal = valKeys.size() + 1;
+
3283 auto trustedKeys = makeValidatorList(
+
3284 5, //
+
3285 0,
+
3286 1,
+
3287 pubManifests,
+
3288 valManifests,
+
3289 self,
+
3290 publishers);
+
3291 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
3292 for (auto const& p : publishers)
+
3293 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3294
+
3295 TrustChanges changes = trustedKeys->updateTrusted(
+
3296 activeValidators,
+
3297 env.timeKeeper().now(),
+
3298 env.app().getOPs(),
+
3299 env.app().overlay(),
+
3300 env.app().getHashRouter());
+
3301 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3302 BEAST_EXPECT(
+
3303 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3304
+
3305 hash_set<NodeID> added;
+
3306 added.insert(calcNodeID(self.masterPublic));
+
3307 for (auto const& val : valKeys)
+
3308 {
+
3309 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3310 added.insert(calcNodeID(val.masterPublic));
+
3311 }
+
3312 BEAST_EXPECT(changes.added == added);
+
3313 BEAST_EXPECT(changes.removed.empty());
+
3314
+
3315 // Expire one publisher - no quorum
+
3316 env.timeKeeper().set(publishers.back().expiry);
+
3317 changes = trustedKeys->updateTrusted(
+
3318 activeValidators,
+
3319 env.timeKeeper().now(),
+
3320 env.app().getOPs(),
+
3321 env.app().overlay(),
+
3322 env.app().getHashRouter());
+
3323 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3324 BEAST_EXPECT(
+
3325 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3326
+
3327 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3328 for (auto const& val : valKeys)
+
3329 {
+
3330 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3331 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3332 }
+
3333 BEAST_EXPECT(changes.added.empty());
+
3334 BEAST_EXPECT(changes.removed.empty());
+
3335 }
+
3336 {
+
3337 // List threshold = 1
+
3338 ManifestCache pubManifests;
+
3339 ManifestCache valManifests;
+
3340 std::vector<Publisher> publishers;
+
3341 // Self is in UNL
+
3342 auto const self = valKeys[7];
+
3343 auto const keysTotal = valKeys.size();
+
3344 auto trustedKeys = makeValidatorList(
+
3345 5, //
+
3346 0,
+
3347 1,
+
3348 pubManifests,
+
3349 valManifests,
+
3350 self,
+
3351 publishers);
+
3352 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
3353 for (auto const& p : publishers)
+
3354 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3355
+
3356 TrustChanges changes = trustedKeys->updateTrusted(
+
3357 activeValidators,
+
3358 env.timeKeeper().now(),
+
3359 env.app().getOPs(),
+
3360 env.app().overlay(),
+
3361 env.app().getHashRouter());
+
3362 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3363 BEAST_EXPECT(
+
3364 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3365
+
3366 hash_set<NodeID> added;
+
3367 for (auto const& val : valKeys)
+
3368 {
+
3369 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3370 added.insert(calcNodeID(val.masterPublic));
+
3371 }
+
3372 BEAST_EXPECT(changes.added == added);
+
3373 BEAST_EXPECT(changes.removed.empty());
+
3374
+
3375 // Expire one publisher - no quorum
+
3376 env.timeKeeper().set(publishers.back().expiry);
+
3377 changes = trustedKeys->updateTrusted(
+
3378 activeValidators,
+
3379 env.timeKeeper().now(),
+
3380 env.app().getOPs(),
+
3381 env.app().overlay(),
+
3382 env.app().getHashRouter());
+
3383 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3384 BEAST_EXPECT(
+
3385 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3386
+
3387 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3388 for (auto const& val : valKeys)
+
3389 {
+
3390 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3391 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3392 }
+
3393 BEAST_EXPECT(changes.added.empty());
+
3394 BEAST_EXPECT(changes.removed.empty());
+
3395 }
+
3396 {
+
3397 // List threshold = 1
+
3398 ManifestCache pubManifests;
+
3399 ManifestCache valManifests;
+
3400 std::vector<Publisher> publishers;
+
3401 auto const keysTotal = valKeys.size();
+
3402 auto trustedKeys = makeValidatorList(
+
3403 5, //
+
3404 0,
+
3405 1,
+
3406 pubManifests,
+
3407 valManifests,
+
3408 {},
+
3409 publishers);
+
3410 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
3411 for (auto const& p : publishers)
+
3412 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3413
+
3414 TrustChanges changes = trustedKeys->updateTrusted(
+
3415 activeValidators,
+
3416 env.timeKeeper().now(),
+
3417 env.app().getOPs(),
+
3418 env.app().overlay(),
+
3419 env.app().getHashRouter());
+
3420 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3421 BEAST_EXPECT(
+
3422 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3423
+
3424 hash_set<NodeID> added;
+
3425 for (auto const& val : valKeys)
+
3426 {
+
3427 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3428 added.insert(calcNodeID(val.masterPublic));
+
3429 }
+
3430 BEAST_EXPECT(changes.added == added);
+
3431 BEAST_EXPECT(changes.removed.empty());
+
3432
+
3433 // Expire one publisher - no quorum
+
3434 env.timeKeeper().set(publishers.back().expiry);
+
3435 changes = trustedKeys->updateTrusted(
+
3436 activeValidators,
+
3437 env.timeKeeper().now(),
+
3438 env.app().getOPs(),
+
3439 env.app().overlay(),
+
3440 env.app().getHashRouter());
+
3441 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3442 BEAST_EXPECT(
+
3443 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3444
+
3445 for (auto const& val : valKeys)
+
3446 {
+
3447 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3448 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3449 }
+
3450 BEAST_EXPECT(changes.added.empty());
+
3451 BEAST_EXPECT(changes.removed.empty());
+
3452 }
+
3453
+
3454 // Test cases use 2 publishers
+
3455 {
+
3456 // List threshold = 1, 1 publisher revoked
+
3457 ManifestCache pubManifests;
+
3458 ManifestCache valManifests;
+
3459 std::vector<Publisher> publishers;
+
3460 // Self is a random validator
+
3461 auto const self = randomValidator();
+
3462 auto const keysTotal = valKeys.size() + 1;
+
3463 auto trustedKeys = makeValidatorList(
+
3464 2, //
+
3465 1,
+
3466 1,
+
3467 pubManifests,
+
3468 valManifests,
+
3469 self,
+
3470 publishers);
+
3471 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
3472 int untrustedCount = 0;
+
3473 for (auto const& p : publishers)
+
3474 {
+
3475 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
3476 BEAST_EXPECT(p.revoked ^ trusted);
+
3477 untrustedCount += trusted ? 0 : 1;
+
3478 }
+
3479 BEAST_EXPECT(untrustedCount == 1);
+
3480
+
3481 TrustChanges changes = trustedKeys->updateTrusted(
+
3482 activeValidators,
+
3483 env.timeKeeper().now(),
+
3484 env.app().getOPs(),
+
3485 env.app().overlay(),
+
3486 env.app().getHashRouter());
+
3487 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3488 BEAST_EXPECT(
+
3489 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3490
+
3491 hash_set<NodeID> added;
+
3492 added.insert(calcNodeID(self.masterPublic));
+
3493 for (auto const& val : valKeys)
+
3494 {
+
3495 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3496 added.insert(calcNodeID(val.masterPublic));
+
3497 }
+
3498 BEAST_EXPECT(changes.added == added);
+
3499 BEAST_EXPECT(changes.removed.empty());
+
3500
+
3501 // Expire one publisher - no quorum, only trusted validator is self
+
3502 env.timeKeeper().set(publishers.back().expiry);
+
3503 changes = trustedKeys->updateTrusted(
+
3504 activeValidators,
+
3505 env.timeKeeper().now(),
+
3506 env.app().getOPs(),
+
3507 env.app().overlay(),
+
3508 env.app().getHashRouter());
+
3509 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3510 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
3511
+
3512 hash_set<NodeID> removed;
+
3513 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3514 for (auto const& val : valKeys)
+
3515 {
+
3516 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
+
3517 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3518 removed.insert(calcNodeID(val.masterPublic));
+
3519 }
+
3520 BEAST_EXPECT(changes.added.empty());
+
3521 BEAST_EXPECT(changes.removed == removed);
+
3522 }
+
3523 {
+
3524 // List threshold = 1, 1 publisher revoked
+
3525 ManifestCache pubManifests;
+
3526 ManifestCache valManifests;
+
3527 std::vector<Publisher> publishers;
+
3528 // Self is in UNL
+
3529 auto const self = valKeys[5];
+
3530 auto const keysTotal = valKeys.size();
+
3531 auto trustedKeys = makeValidatorList(
+
3532 2, //
+
3533 1,
+
3534 1,
+
3535 pubManifests,
+
3536 valManifests,
+
3537 self,
+
3538 publishers);
+
3539 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
3540 int untrustedCount = 0;
+
3541 for (auto const& p : publishers)
+
3542 {
+
3543 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
3544 BEAST_EXPECT(p.revoked ^ trusted);
+
3545 untrustedCount += trusted ? 0 : 1;
+
3546 }
+
3547 BEAST_EXPECT(untrustedCount == 1);
+
3548
+
3549 TrustChanges changes = trustedKeys->updateTrusted(
+
3550 activeValidators,
+
3551 env.timeKeeper().now(),
+
3552 env.app().getOPs(),
+
3553 env.app().overlay(),
+
3554 env.app().getHashRouter());
+
3555 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3556 BEAST_EXPECT(
+
3557 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3558
+
3559 hash_set<NodeID> added;
+
3560 for (auto const& val : valKeys)
+
3561 {
+
3562 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3563 added.insert(calcNodeID(val.masterPublic));
+
3564 }
+
3565 BEAST_EXPECT(changes.added == added);
+
3566 BEAST_EXPECT(changes.removed.empty());
+
3567
+
3568 // Expire one publisher - no quorum, only trusted validator is self
+
3569 env.timeKeeper().set(publishers.back().expiry);
+
3570 changes = trustedKeys->updateTrusted(
+
3571 activeValidators,
+
3572 env.timeKeeper().now(),
+
3573 env.app().getOPs(),
+
3574 env.app().overlay(),
+
3575 env.app().getHashRouter());
+
3576 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3577 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
3578
+
3579 hash_set<NodeID> removed;
+
3580 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3581 for (auto const& val : valKeys)
+
3582 {
+
3583 if (val.masterPublic != self.masterPublic)
+
3584 {
+
3585 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
+
3586 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3587 removed.insert(calcNodeID(val.masterPublic));
+
3588 }
+
3589 }
+
3590 BEAST_EXPECT(changes.added.empty());
+
3591 BEAST_EXPECT(changes.removed == removed);
+
3592 }
+
3593 {
+
3594 // List threshold = 1, 1 publisher revoked
+
3595 ManifestCache pubManifests;
+
3596 ManifestCache valManifests;
+
3597 std::vector<Publisher> publishers;
+
3598 auto const keysTotal = valKeys.size();
+
3599 auto trustedKeys = makeValidatorList(
+
3600 2, //
+
3601 1,
+
3602 1,
+
3603 pubManifests,
+
3604 valManifests,
+
3605 {},
+
3606 publishers);
+
3607 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
3608 int untrustedCount = 0;
+
3609 for (auto const& p : publishers)
+
3610 {
+
3611 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
3612 BEAST_EXPECT(p.revoked ^ trusted);
+
3613 untrustedCount += trusted ? 0 : 1;
+
3614 }
+
3615 BEAST_EXPECT(untrustedCount == 1);
+
3616
+
3617 TrustChanges changes = trustedKeys->updateTrusted(
+
3618 activeValidators,
+
3619 env.timeKeeper().now(),
+
3620 env.app().getOPs(),
+
3621 env.app().overlay(),
+
3622 env.app().getHashRouter());
+
3623 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3624 BEAST_EXPECT(
+
3625 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3626
+
3627 hash_set<NodeID> added;
+
3628 for (auto const& val : valKeys)
+
3629 {
+
3630 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3631 added.insert(calcNodeID(val.masterPublic));
+
3632 }
+
3633 BEAST_EXPECT(changes.added == added);
+
3634 BEAST_EXPECT(changes.removed.empty());
+
3635
+
3636 // Expire one publisher - no quorum, no trusted validators
+
3637 env.timeKeeper().set(publishers.back().expiry);
+
3638 changes = trustedKeys->updateTrusted(
+
3639 activeValidators,
+
3640 env.timeKeeper().now(),
+
3641 env.app().getOPs(),
+
3642 env.app().overlay(),
+
3643 env.app().getHashRouter());
+
3644 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3645 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
+
3646
+
3647 hash_set<NodeID> removed;
+
3648 for (auto const& val : valKeys)
+
3649 {
+
3650 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
+
3651 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3652 removed.insert(calcNodeID(val.masterPublic));
+
3653 }
+
3654 BEAST_EXPECT(changes.added.empty());
+
3655 BEAST_EXPECT(changes.removed == removed);
+
3656 }
+
3657 {
+
3658 // List threshold = 2 (same as number of trusted publishers)
+
3659 ManifestCache pubManifests;
+
3660 ManifestCache valManifests;
+
3661 std::vector<Publisher> publishers;
+
3662 // Self is a random validator
+
3663 auto const self = randomValidator();
+
3664 auto const keysTotal = valKeys.size() + 1;
+
3665 auto trustedKeys = makeValidatorList(
+
3666 2, //
+
3667 0,
+
3668 2,
+
3669 pubManifests,
+
3670 valManifests,
+
3671 self,
+
3672 publishers);
+
3673 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
3674 for (auto const& p : publishers)
+
3675 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3676
+
3677 TrustChanges changes = trustedKeys->updateTrusted(
+
3678 activeValidators,
+
3679 env.timeKeeper().now(),
+
3680 env.app().getOPs(),
+
3681 env.app().overlay(),
+
3682 env.app().getHashRouter());
+
3683 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3684 BEAST_EXPECT(
+
3685 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3686
+
3687 hash_set<NodeID> added;
+
3688 added.insert(calcNodeID(self.masterPublic));
+
3689 for (auto const& val : valKeys)
+
3690 {
+
3691 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3692 added.insert(calcNodeID(val.masterPublic));
+
3693 }
+
3694 BEAST_EXPECT(changes.added == added);
+
3695 BEAST_EXPECT(changes.removed.empty());
+
3696
+
3697 // Expire one publisher - only trusted validator is self
+
3698 env.timeKeeper().set(publishers.back().expiry);
+
3699 changes = trustedKeys->updateTrusted(
+
3700 activeValidators,
+
3701 env.timeKeeper().now(),
+
3702 env.app().getOPs(),
+
3703 env.app().overlay(),
+
3704 env.app().getHashRouter());
+
3705 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3706 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
3707
+
3708 hash_set<NodeID> removed;
+
3709 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3710 for (auto const& val : valKeys)
+
3711 {
+
3712 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3713 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3714 removed.insert(calcNodeID(val.masterPublic));
+
3715 }
+
3716 BEAST_EXPECT(changes.added.empty());
+
3717 BEAST_EXPECT(changes.removed == removed);
+
3718 }
+
3719 {
+
3720 // List threshold = 2 (same as number of trusted publishers)
+
3721 ManifestCache pubManifests;
+
3722 ManifestCache valManifests;
+
3723 std::vector<Publisher> publishers;
+
3724 // Self is in UNL
+
3725 auto const self = valKeys[5];
+
3726 auto const keysTotal = valKeys.size();
+
3727 auto trustedKeys = makeValidatorList(
+
3728 2, //
+
3729 0,
+
3730 2,
+
3731 pubManifests,
+
3732 valManifests,
+
3733 self,
+
3734 publishers);
+
3735 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
3736 for (auto const& p : publishers)
+
3737 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3738
+
3739 TrustChanges changes = trustedKeys->updateTrusted(
+
3740 activeValidators,
+
3741 env.timeKeeper().now(),
+
3742 env.app().getOPs(),
+
3743 env.app().overlay(),
+
3744 env.app().getHashRouter());
+
3745 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3746 BEAST_EXPECT(
+
3747 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3748
+
3749 hash_set<NodeID> added;
+
3750 added.insert(calcNodeID(self.masterPublic));
+
3751 for (auto const& val : valKeys)
+
3752 {
+
3753 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3754 added.insert(calcNodeID(val.masterPublic));
+
3755 }
+
3756 BEAST_EXPECT(changes.added == added);
+
3757 BEAST_EXPECT(changes.removed.empty());
+
3758
+
3759 // Expire one publisher - only trusted validator is self
+
3760 env.timeKeeper().set(publishers.back().expiry);
+
3761 changes = trustedKeys->updateTrusted(
+
3762 activeValidators,
+
3763 env.timeKeeper().now(),
+
3764 env.app().getOPs(),
+
3765 env.app().overlay(),
+
3766 env.app().getHashRouter());
+
3767 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3768 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
3769
+
3770 hash_set<NodeID> removed;
+
3771 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3772 for (auto const& val : valKeys)
+
3773 {
+
3774 if (val.masterPublic != self.masterPublic)
+
3775 {
+
3776 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3777 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3778 removed.insert(calcNodeID(val.masterPublic));
+
3779 }
+
3780 }
+
3781 BEAST_EXPECT(changes.added.empty());
+
3782 BEAST_EXPECT(changes.removed == removed);
+
3783 }
+
3784 {
+
3785 // List threshold = 2 (same as number of trusted publishers)
+
3786 ManifestCache pubManifests;
+
3787 ManifestCache valManifests;
+
3788 std::vector<Publisher> publishers;
+
3789 auto const keysTotal = valKeys.size();
+
3790 auto trustedKeys = makeValidatorList(
+
3791 2, //
+
3792 0,
+
3793 2,
+
3794 pubManifests,
+
3795 valManifests,
+
3796 {},
+
3797 publishers);
+
3798 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
3799 for (auto const& p : publishers)
+
3800 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3801
+
3802 TrustChanges changes = trustedKeys->updateTrusted(
+
3803 activeValidators,
+
3804 env.timeKeeper().now(),
+
3805 env.app().getOPs(),
+
3806 env.app().overlay(),
+
3807 env.app().getHashRouter());
+
3808 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3809 BEAST_EXPECT(
+
3810 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3811
+
3812 hash_set<NodeID> added;
+
3813 for (auto const& val : valKeys)
+
3814 {
+
3815 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3816 added.insert(calcNodeID(val.masterPublic));
+
3817 }
+
3818 BEAST_EXPECT(changes.added == added);
+
3819 BEAST_EXPECT(changes.removed.empty());
+
3820
+
3821 // Expire one publisher - no trusted validators
+
3822 env.timeKeeper().set(publishers.back().expiry);
+
3823 changes = trustedKeys->updateTrusted(
+
3824 activeValidators,
+
3825 env.timeKeeper().now(),
+
3826 env.app().getOPs(),
+
3827 env.app().overlay(),
+
3828 env.app().getHashRouter());
+
3829 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3830 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
+
3831
+
3832 hash_set<NodeID> removed;
+
3833 for (auto const& val : valKeys)
+
3834 {
+
3835 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
3836 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3837 removed.insert(calcNodeID(val.masterPublic));
+
3838 }
+
3839 BEAST_EXPECT(changes.added.empty());
+
3840 BEAST_EXPECT(changes.removed == removed);
+
3841 }
+
3842
+
3843 // Test case for 1 publisher
+
3844 {
+
3845 // List threshold = 1 (default), no publisher revoked
+
3846 ManifestCache pubManifests;
+
3847 ManifestCache valManifests;
+
3848 std::vector<Publisher> publishers;
+
3849 // Self is a random validator
+
3850 auto const self = randomValidator();
+
3851 auto const keysTotal = valKeys.size() + 1;
+
3852 auto trustedKeys = makeValidatorList(
+
3853 1, //
+
3854 0,
+
3855 0,
+
3856 pubManifests,
+
3857 valManifests,
+
3858 self,
+
3859 publishers);
+
3860 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
+
3861 for (auto const& p : publishers)
+
3862 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3863
+
3864 TrustChanges changes = trustedKeys->updateTrusted(
+
3865 activeValidators,
+
3866 env.timeKeeper().now(),
+
3867 env.app().getOPs(),
+
3868 env.app().overlay(),
+
3869 env.app().getHashRouter());
+
3870 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3871 BEAST_EXPECT(
+
3872 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3873
+
3874 hash_set<NodeID> added;
+
3875 added.insert(calcNodeID(self.masterPublic));
+
3876 for (auto const& val : valKeys)
+
3877 {
+
3878 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3879 added.insert(calcNodeID(val.masterPublic));
+
3880 }
+
3881 BEAST_EXPECT(changes.added == added);
+
3882 BEAST_EXPECT(changes.removed.empty());
+
3883
+
3884 // Expire one publisher - no quorum, only trusted validator is self
+
3885 env.timeKeeper().set(publishers.back().expiry);
+
3886 changes = trustedKeys->updateTrusted(
+
3887 activeValidators,
+
3888 env.timeKeeper().now(),
+
3889 env.app().getOPs(),
+
3890 env.app().overlay(),
+
3891 env.app().getHashRouter());
+
3892 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
3893 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
3894
+
3895 hash_set<NodeID> removed;
+
3896 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
3897 for (auto const& val : valKeys)
+
3898 {
+
3899 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
+
3900 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
3901 removed.insert(calcNodeID(val.masterPublic));
+
3902 }
+
3903 BEAST_EXPECT(changes.added.empty());
+
3904 BEAST_EXPECT(changes.removed == removed);
+
3905 }
+
3906
+
3907 // Test case for 3 publishers (for 2 is a block above)
+
3908 {
+
3909 // List threshold = 2 (default), no publisher revoked
+
3910 ManifestCache pubManifests;
+
3911 ManifestCache valManifests;
+
3912 std::vector<Publisher> publishers;
+
3913 // Self is in UNL
+
3914 auto const self = valKeys[2];
+
3915 auto const keysTotal = valKeys.size();
+
3916 auto trustedKeys = makeValidatorList(
+
3917 3, //
+
3918 0,
+
3919 0,
+
3920 pubManifests,
+
3921 valManifests,
+
3922 self,
+
3923 publishers);
+
3924 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
+
3925 for (auto const& p : publishers)
+
3926 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3927
+
3928 TrustChanges changes = trustedKeys->updateTrusted(
+
3929 activeValidators,
+
3930 env.timeKeeper().now(),
+
3931 env.app().getOPs(),
+
3932 env.app().overlay(),
+
3933 env.app().getHashRouter());
+
3934 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3935 BEAST_EXPECT(
+
3936 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3937
+
3938 hash_set<NodeID> added;
+
3939 for (auto const& val : valKeys)
+
3940 {
+
3941 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3942 added.insert(calcNodeID(val.masterPublic));
+
3943 }
+
3944 BEAST_EXPECT(changes.added == added);
+
3945 BEAST_EXPECT(changes.removed.empty());
+
3946 }
+
3947
+
3948 // Test case for 4 publishers
+
3949 {
+
3950 // List threshold = 3 (default), no publisher revoked
+
3951 ManifestCache pubManifests;
+
3952 ManifestCache valManifests;
+
3953 std::vector<Publisher> publishers;
+
3954 auto const keysTotal = valKeys.size();
+
3955 auto trustedKeys = makeValidatorList(
+
3956 4, //
+
3957 0,
+
3958 0,
+
3959 pubManifests,
+
3960 valManifests,
+
3961 {},
+
3962 publishers);
+
3963 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
+
3964 for (auto const& p : publishers)
+
3965 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
+
3966
+
3967 TrustChanges changes = trustedKeys->updateTrusted(
+
3968 activeValidators,
+
3969 env.timeKeeper().now(),
+
3970 env.app().getOPs(),
+
3971 env.app().overlay(),
+
3972 env.app().getHashRouter());
+
3973 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
3974 BEAST_EXPECT(
+
3975 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
3976
+
3977 hash_set<NodeID> added;
+
3978 for (auto const& val : valKeys)
+
3979 {
+
3980 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
3981 added.insert(calcNodeID(val.masterPublic));
+
3982 }
+
3983 BEAST_EXPECT(changes.added == added);
+
3984 BEAST_EXPECT(changes.removed.empty());
+
3985 }
+
3986
+
3987 // Test case for 6 publishers (for 5 is a large block above)
+
3988 {
+
3989 // List threshold = 4 (default), 2 publishers revoked
+
3990 ManifestCache pubManifests;
+
3991 ManifestCache valManifests;
+
3992 std::vector<Publisher> publishers;
+
3993 // Self is a random validator
+
3994 auto const self = randomValidator();
+
3995 auto const keysTotal = valKeys.size() + 1;
+
3996 auto trustedKeys = makeValidatorList(
+
3997 6, //
+
3998 2,
+
3999 0,
+
4000 pubManifests,
+
4001 valManifests,
+
4002 self,
+
4003 publishers);
+
4004 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
+
4005 int untrustedCount = 0;
+
4006 for (auto const& p : publishers)
+
4007 {
+
4008 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
4009 BEAST_EXPECT(p.revoked ^ trusted);
+
4010 untrustedCount += trusted ? 0 : 1;
+
4011 }
+
4012 BEAST_EXPECT(untrustedCount == 2);
+
4013
+
4014 TrustChanges changes = trustedKeys->updateTrusted(
+
4015 activeValidators,
+
4016 env.timeKeeper().now(),
+
4017 env.app().getOPs(),
+
4018 env.app().overlay(),
+
4019 env.app().getHashRouter());
+
4020 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
4021 BEAST_EXPECT(
+
4022 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
4023
+
4024 hash_set<NodeID> added;
+
4025 added.insert(calcNodeID(self.masterPublic));
+
4026 for (auto const& val : valKeys)
+
4027 {
+
4028 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
4029 added.insert(calcNodeID(val.masterPublic));
+
4030 }
+
4031 BEAST_EXPECT(changes.added == added);
+
4032 BEAST_EXPECT(changes.removed.empty());
+
4033
+
4034 // Expire one publisher - no quorum, only trusted validator is self
+
4035 env.timeKeeper().set(publishers.back().expiry);
+
4036 changes = trustedKeys->updateTrusted(
+
4037 activeValidators,
+
4038 env.timeKeeper().now(),
+
4039 env.app().getOPs(),
+
4040 env.app().overlay(),
+
4041 env.app().getHashRouter());
+
4042 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
4043 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
4044
+
4045 hash_set<NodeID> removed;
+
4046 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
4047 for (auto const& val : valKeys)
+
4048 {
+
4049 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
4050 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
4051 removed.insert(calcNodeID(val.masterPublic));
+
4052 }
+
4053 BEAST_EXPECT(changes.added.empty());
+
4054 BEAST_EXPECT(changes.removed == removed);
+
4055 }
+
4056
+
4057 // Test case for 7 publishers
+
4058 {
+
4059 // List threshold = 4 (default), 3 publishers revoked
+
4060 ManifestCache pubManifests;
+
4061 ManifestCache valManifests;
+
4062 std::vector<Publisher> publishers;
+
4063 // Self is in UNL
+
4064 auto const self = valKeys[2];
+
4065 auto const keysTotal = valKeys.size();
+
4066 auto trustedKeys = makeValidatorList(
+
4067 7, //
+
4068 3,
+
4069 0,
+
4070 pubManifests,
+
4071 valManifests,
+
4072 self,
+
4073 publishers);
+
4074 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
+
4075 int untrustedCount = 0;
+
4076 for (auto const& p : publishers)
+
4077 {
+
4078 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
+
4079 BEAST_EXPECT(p.revoked ^ trusted);
+
4080 untrustedCount += trusted ? 0 : 1;
+
4081 }
+
4082 BEAST_EXPECT(untrustedCount == 3);
+
4083
+
4084 TrustChanges changes = trustedKeys->updateTrusted(
+
4085 activeValidators,
+
4086 env.timeKeeper().now(),
+
4087 env.app().getOPs(),
+
4088 env.app().overlay(),
+
4089 env.app().getHashRouter());
+
4090 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
+
4091 BEAST_EXPECT(
+
4092 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
+
4093
+
4094 hash_set<NodeID> added;
+
4095 for (auto const& val : valKeys)
+
4096 {
+
4097 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
+
4098 added.insert(calcNodeID(val.masterPublic));
+
4099 }
+
4100 BEAST_EXPECT(changes.added == added);
+
4101 BEAST_EXPECT(changes.removed.empty());
+
4102
+
4103 // Expire one publisher - only trusted validator is self
+
4104 env.timeKeeper().set(publishers.back().expiry);
+
4105 changes = trustedKeys->updateTrusted(
+
4106 activeValidators,
+
4107 env.timeKeeper().now(),
+
4108 env.app().getOPs(),
+
4109 env.app().overlay(),
+
4110 env.app().getHashRouter());
+
4111 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
+
4112 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
+
4113
+
4114 hash_set<NodeID> removed;
+
4115 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
+
4116 for (auto const& val : valKeys)
+
4117 {
+
4118 if (val.masterPublic != self.masterPublic)
+
4119 {
+
4120 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
+
4121 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
+
4122 removed.insert(calcNodeID(val.masterPublic));
+
4123 }
+
4124 }
+
4125 BEAST_EXPECT(changes.added.empty());
+
4126 BEAST_EXPECT(changes.removed == removed);
+
4127 }
+
4128 }
+
4129
+
4130public:
+
4131 void
+
4132 run() override
+
4133 {
+
4134 testGenesisQuorum();
+
4135 testConfigLoad();
+
4136 testApplyLists();
+
4137 testGetAvailable();
+
4138 testUpdateTrusted();
+
4139 testExpires();
+
4140 testNegativeUNL();
+
4141 testSha512Hash();
+
4142 testBuildMessages();
+
4143 testQuorumDisabled();
+
4144 }
+
4145}; // namespace test
+
4146
+
4147BEAST_DEFINE_TESTSUITE(ValidatorList, app, ripple);
+
4148
+
4149} // namespace test
+
4150} // namespace ripple
std::array
std::map::at
T at(T... args)
std::vector::back
T back(T... args)
std::string
std::stringstream
-
std::unordered_set::begin
T begin(T... args)
+
std::vector::cbegin
T cbegin(T... args)
std::vector::capacity
T capacity(T... args)
std::ceil
T ceil(T... args)
beast::unit_test::suite
A testsuite class.
Definition: suite.h:53
@@ -2504,6 +4242,7 @@ $(function() {
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::BasicConfig::legacy
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Definition: BasicConfig.cpp:164
+
ripple::Dir::const_iterator
Definition: Dir.h:62
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:256
ripple::ManifestCache::getSigningKey
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition: app/misc/detail/Manifest.cpp:310
ripple::ManifestCache::revoked
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Definition: app/misc/detail/Manifest.cpp:370
@@ -2522,16 +4261,17 @@ $(function() {
ripple::test::ManualTimeKeeper::now
time_point now() const override
Returns the current time.
Definition: ManualTimeKeeper.h:38
ripple::test::ManualTimeKeeper::set
void set(time_point now)
Definition: ManualTimeKeeper.h:44
ripple::test::ValidatorList_test
Definition: ValidatorList_test.cpp:40
-
ripple::test::ValidatorList_test::testUpdateTrusted
void testUpdateTrusted()
Definition: ValidatorList_test.cpp:1053
-
ripple::test::ValidatorList_test::testNegativeUNL
void testNegativeUNL()
Definition: ValidatorList_test.cpp:1775
-
ripple::test::ValidatorList_test::run
void run() override
Runs the suite.
Definition: ValidatorList_test.cpp:2395
-
ripple::test::ValidatorList_test::testExpires
void testExpires()
Definition: ValidatorList_test.cpp:1599
+
ripple::test::ValidatorList_test::testUpdateTrusted
void testUpdateTrusted()
Definition: ValidatorList_test.cpp:1122
+
ripple::test::ValidatorList_test::testNegativeUNL
void testNegativeUNL()
Definition: ValidatorList_test.cpp:2082
+
ripple::test::ValidatorList_test::run
void run() override
Runs the suite.
Definition: ValidatorList_test.cpp:4132
+
ripple::test::ValidatorList_test::testExpires
void testExpires()
Definition: ValidatorList_test.cpp:1906
ripple::test::ValidatorList_test::randomMasterKey
static PublicKey randomMasterKey()
Definition: ValidatorList_test.cpp:56
-
ripple::test::ValidatorList_test::testBuildMessages
void testBuildMessages()
Definition: ValidatorList_test.cpp:2037
+
ripple::test::ValidatorList_test::testQuorumDisabled
void testQuorumDisabled()
Definition: ValidatorList_test.cpp:2701
+
ripple::test::ValidatorList_test::testBuildMessages
void testBuildMessages()
Definition: ValidatorList_test.cpp:2344
ripple::test::ValidatorList_test::asNodeIDs
static hash_set< NodeID > asNodeIDs(std::initializer_list< PublicKey > const &pks)
Definition: ValidatorList_test.cpp:163
-
ripple::test::ValidatorList_test::testSha512Hash
void testSha512Hash()
Definition: ValidatorList_test.cpp:1985
+
ripple::test::ValidatorList_test::testSha512Hash
void testSha512Hash()
Definition: ValidatorList_test.cpp:2292
ripple::test::ValidatorList_test::checkResult
void checkResult(ValidatorList::PublisherListStats const &result, PublicKey pubKey, ListDisposition expectedWorst, ListDisposition expectedBest)
Definition: ValidatorList_test.cpp:173
-
ripple::test::ValidatorList_test::testApplyLists
void testApplyLists()
Definition: ValidatorList_test.cpp:468
+
ripple::test::ValidatorList_test::testApplyLists
void testApplyLists()
Definition: ValidatorList_test.cpp:537
ripple::test::ValidatorList_test::makeRevocationString
static std::string makeRevocationString(PublicKey const &pk, SecretKey const &sk)
Definition: ValidatorList_test.cpp:93
ripple::test::ValidatorList_test::makeList
std::string makeList(std::vector< Validator > const &validators, std::size_t sequence, std::size_t validUntil, std::optional< std::size_t > validFrom={})
Definition: ValidatorList_test.cpp:130
ripple::test::ValidatorList_test::testGenesisQuorum
void testGenesisQuorum()
Definition: ValidatorList_test.cpp:187
@@ -2539,7 +4279,7 @@ $(function() {
ripple::test::ValidatorList_test::makeManifestString
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
Definition: ValidatorList_test.cpp:62
ripple::test::ValidatorList_test::randomNode
static PublicKey randomNode()
Definition: ValidatorList_test.cpp:50
ripple::test::ValidatorList_test::signList
std::string signList(std::string const &blob, std::pair< PublicKey, SecretKey > const &keys)
Definition: ValidatorList_test.cpp:154
-
ripple::test::ValidatorList_test::testGetAvailable
void testGetAvailable()
Definition: ValidatorList_test.cpp:917
+
ripple::test::ValidatorList_test::testGetAvailable
void testGetAvailable()
Definition: ValidatorList_test.cpp:986
ripple::test::ValidatorList_test::randomValidator
static Validator randomValidator()
Definition: ValidatorList_test.cpp:113
ripple::test::Validator
Simulate Validator.
Definition: reduce_relay_test.cpp:316
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
@@ -2549,7 +4289,7 @@ $(function() {
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:35
std::vector::clear
T clear(T... args)
std::unordered_set::emplace
T emplace(T... args)
-
std::unordered_set::end
T end(T... args)
+
std::vector::cend
T cend(T... args)
std::unordered_set::find
T find(T... args)
std::initializer_list
std::unordered_set::insert
T insert(T... args)
@@ -2579,6 +4319,7 @@ $(function() {
ripple::KeyType::secp256k1
@ secp256k1
ripple::base64_encode
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:236
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
+
ripple::PublisherStatus::revoked
@ revoked
ripple::PublisherStatus::available
@ available
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::HashPrefix::manifest
@ manifest
Manifest.
@@ -2596,10 +4337,10 @@ $(function() {
ripple::TrustChanges
Changes in trusted nodes after updating validator list.
Definition: ValidatorList.h:108
ripple::TrustChanges::added
hash_set< NodeID > added
Definition: ValidatorList.h:111
ripple::TrustChanges::removed
hash_set< NodeID > removed
Definition: ValidatorList.h:112
-
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:289
+
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:292
ripple::ValidatorList::PublisherListStats::bestDisposition
ListDisposition bestDisposition() const
Definition: ValidatorList.cpp:85
ripple::ValidatorList::PublisherListStats::worstDisposition
ListDisposition worstDisposition() const
Definition: ValidatorList.cpp:92
-
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:308
+
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:311
ripple::test::ValidatorList_test::Validator
Definition: ValidatorList_test.cpp:43
ripple::test::ValidatorList_test::Validator::masterPublic
PublicKey masterPublic
Definition: ValidatorList_test.cpp:44
ripple::test::ValidatorList_test::Validator::signingPublic
PublicKey signingPublic
Definition: ValidatorList_test.cpp:45
@@ -2608,6 +4349,7 @@ $(function() {
std::chrono::time_point
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
std::to_string
T to_string(T... args)
+
std::unique_ptr
std::unordered_set
std::vector
diff --git a/ValidatorSite_8cpp_source.html b/ValidatorSite_8cpp_source.html index 575400b201..2032e09c3e 100644 --- a/ValidatorSite_8cpp_source.html +++ b/ValidatorSite_8cpp_source.html @@ -808,9 +808,9 @@ $(function() {
ripple::Application::validators
virtual ValidatorList & validators()=0
ripple::Application::getIOService
virtual boost::asio::io_service & getIOService()=0
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
-
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1267
-
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:906
-
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:366
+
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1299
+
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:938
+
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:398
ripple::ValidatorSite::start
void start()
Start fetching lists from sites.
Definition: ValidatorSite.cpp:167
ripple::ValidatorSite::cv_
std::condition_variable cv_
Definition: ValidatorSite.h:125
ripple::ValidatorSite::j_
beast::Journal const j_
Definition: ValidatorSite.h:118
diff --git a/Validators_8cpp_source.html b/Validators_8cpp_source.html index 573f0d4c2e..0c9a9727e6 100644 --- a/Validators_8cpp_source.html +++ b/Validators_8cpp_source.html @@ -112,7 +112,7 @@ $(function() {
34} // namespace ripple
Json::Value
Represents a JSON value.
Definition: json_value.h:147
ripple::Application::validators
virtual ValidatorList & validators()=0
-
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1583
+
ripple::ValidatorList::getJson
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Definition: ValidatorList.cpp:1615
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::doValidators
Json::Value doValidators(RPC::JsonContext &)
Definition: Validators.cpp:29
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
diff --git a/classripple_1_1Application.html b/classripple_1_1Application.html index 8d42d4d689..671f985002 100644 --- a/classripple_1_1Application.html +++ b/classripple_1_1Application.html @@ -341,7 +341,7 @@ Private Attributes
-

Definition at line 2175 of file Application.cpp.

+

Definition at line 2176 of file Application.cpp.

diff --git a/classripple_1_1ApplicationImp.html b/classripple_1_1ApplicationImp.html index 25029352f4..117ca867f3 100644 --- a/classripple_1_1ApplicationImp.html +++ b/classripple_1_1ApplicationImp.html @@ -655,7 +655,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 1523 of file Application.cpp.

+

Definition at line 1524 of file Application.cpp.

@@ -684,7 +684,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 1546 of file Application.cpp.

+

Definition at line 1547 of file Application.cpp.

@@ -714,7 +714,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 1641 of file Application.cpp.

+

Definition at line 1642 of file Application.cpp.

@@ -743,7 +743,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 1655 of file Application.cpp.

+

Definition at line 1656 of file Application.cpp.

@@ -773,7 +773,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 1661 of file Application.cpp.

+

Definition at line 1662 of file Application.cpp.

@@ -802,7 +802,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 1667 of file Application.cpp.

+

Definition at line 1668 of file Application.cpp.

@@ -831,7 +831,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 1673 of file Application.cpp.

+

Definition at line 1674 of file Application.cpp.

@@ -2258,7 +2258,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 2109 of file Application.cpp.

+

Definition at line 2110 of file Application.cpp.

@@ -2288,7 +2288,7 @@ Private Attributes

Implements ripple::Application.

-

Definition at line 2157 of file Application.cpp.

+

Definition at line 2158 of file Application.cpp.

@@ -2503,7 +2503,7 @@ Private Attributes
-

Definition at line 1698 of file Application.cpp.

+

Definition at line 1699 of file Application.cpp.

@@ -2530,7 +2530,7 @@ Private Attributes
-

Definition at line 1722 of file Application.cpp.

+

Definition at line 1723 of file Application.cpp.

@@ -2558,7 +2558,7 @@ Private Attributes
-

Definition at line 1766 of file Application.cpp.

+

Definition at line 1767 of file Application.cpp.

@@ -2608,7 +2608,7 @@ Private Attributes
-

Definition at line 1905 of file Application.cpp.

+

Definition at line 1906 of file Application.cpp.

@@ -2635,7 +2635,7 @@ Private Attributes
-

Definition at line 2163 of file Application.cpp.

+

Definition at line 2164 of file Application.cpp.

diff --git a/classripple_1_1Config-members.html b/classripple_1_1Config-members.html index 669085a0e6..833434cd39 100644 --- a/classripple_1_1Config-members.html +++ b/classripple_1_1Config-members.html @@ -141,8 +141,8 @@ $(function() { PEERS_MAXripple::Config PEERS_OUT_MAXripple::Config PREFETCH_WORKERSripple::Config - QUIETripple::Configprivate - quiet() constripple::Config + quiet() constripple::Config + QUIETripple::Configprivate ramSize_ripple::Configprivate RELAY_UNTRUSTED_PROPOSALSripple::Config RELAY_UNTRUSTED_VALIDATIONSripple::Config @@ -155,8 +155,8 @@ $(function() { setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)ripple::Config setupControl(bool bQuiet, bool bSilent, bool bStandalone)ripple::Config signingEnabled_ripple::Configprivate - silent() constripple::Config - SILENTripple::Configprivate + SILENTripple::Configprivate + silent() constripple::Config SSL_VERIFYripple::Config SSL_VERIFY_DIRripple::Config SSL_VERIFY_FILEripple::Config @@ -174,10 +174,11 @@ $(function() { USE_TX_TABLESripple::Configprivate useTxTables() constripple::Config VALIDATION_QUORUMripple::Config - validatorsFileNameripple::Configstatic - VP_REDUCE_RELAY_ENABLEripple::Config - VP_REDUCE_RELAY_SQUELCHripple::Config - WORKERSripple::Config + VALIDATOR_LIST_THRESHOLDripple::Config + validatorsFileNameripple::Configstatic + VP_REDUCE_RELAY_ENABLEripple::Config + VP_REDUCE_RELAY_SQUELCHripple::Config + WORKERSripple::Config