From 6ba58f42f0c58f6f72e6f0b0a8d9ee5b445dbf4c Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Fri, 20 Feb 2026 15:56:03 +0000 Subject: [PATCH] style: Set clang-format width 100 (#2953) --- .clang-format | 2 +- benchmarks/rpc/WorkQueueBenchmarks.cpp | 18 +- benchmarks/util/log/LoggerBenchmark.cpp | 15 +- src/app/CliArgs.cpp | 23 +- src/app/CliArgs.hpp | 3 +- src/app/ClioApplication.cpp | 35 +- src/app/Stopper.hpp | 3 +- src/app/VerifyConfig.hpp | 3 +- src/app/WebHandlers.cpp | 19 +- src/app/WebHandlers.hpp | 20 +- src/cluster/Backend.cpp | 4 +- src/cluster/Backend.hpp | 7 +- src/cluster/ClioNode.cpp | 10 +- src/cluster/ClioNode.hpp | 16 +- src/cluster/ClusterCommunicationService.hpp | 6 +- src/cluster/Metrics.hpp | 6 +- src/cluster/WriterDecider.cpp | 18 +- src/cluster/WriterDecider.hpp | 8 +- src/cluster/impl/RepeatedTask.hpp | 3 +- src/data/AmendmentCenter.cpp | 46 +- src/data/AmendmentCenter.hpp | 12 +- src/data/AmendmentCenterInterface.hpp | 6 +- src/data/BackendCounters.cpp | 13 +- src/data/BackendCounters.hpp | 4 +- src/data/BackendInterface.cpp | 33 +- src/data/BackendInterface.hpp | 96 +++- src/data/CassandraBackend.hpp | 33 +- src/data/DBHelpers.hpp | 44 +- src/data/KeyspaceBackend.hpp | 46 +- src/data/LedgerCache.cpp | 7 +- src/data/LedgerCache.hpp | 47 +- src/data/LedgerCacheInterface.hpp | 12 +- src/data/LedgerCacheSaver.cpp | 14 +- src/data/LedgerCacheSaver.hpp | 5 +- src/data/Types.hpp | 42 +- src/data/cassandra/CassandraBackendFamily.hpp | 232 +++++--- src/data/cassandra/Concepts.hpp | 15 +- src/data/cassandra/Error.hpp | 6 +- src/data/cassandra/Handle.cpp | 21 +- src/data/cassandra/Handle.hpp | 12 +- src/data/cassandra/Schema.hpp | 12 +- src/data/cassandra/SettingsProvider.cpp | 21 +- src/data/cassandra/impl/AsyncExecutor.hpp | 12 +- src/data/cassandra/impl/Batch.cpp | 3 +- src/data/cassandra/impl/Cluster.cpp | 55 +- src/data/cassandra/impl/Cluster.hpp | 21 +- src/data/cassandra/impl/ExecutionStrategy.hpp | 49 +- src/data/cassandra/impl/Future.cpp | 4 +- src/data/cassandra/impl/Result.hpp | 4 +- src/data/cassandra/impl/RetryPolicy.hpp | 8 +- src/data/cassandra/impl/SslContext.cpp | 7 +- src/data/cassandra/impl/Statement.hpp | 20 +- src/data/cassandra/impl/Tuple.cpp | 3 +- src/data/cassandra/impl/Tuple.hpp | 4 +- src/data/impl/LedgerCacheFile.cpp | 35 +- src/etl/CacheLoader.hpp | 15 +- src/etl/CacheLoaderSettings.cpp | 3 +- src/etl/CacheLoaderSettings.hpp | 17 +- src/etl/CorruptionDetector.hpp | 4 +- src/etl/ETLHelpers.hpp | 11 +- src/etl/ETLService.cpp | 31 +- src/etl/ETLService.hpp | 20 +- src/etl/ETLServiceInterface.hpp | 4 +- src/etl/ETLState.cpp | 3 +- src/etl/ETLState.hpp | 22 +- src/etl/LedgerFetcherInterface.hpp | 14 +- src/etl/LoadBalancer.cpp | 48 +- src/etl/LoadBalancer.hpp | 41 +- src/etl/LoadBalancerInterface.hpp | 10 +- src/etl/MPTHelpers.cpp | 16 +- src/etl/Models.hpp | 4 +- src/etl/MonitorInterface.hpp | 7 +- src/etl/NFTHelpers.cpp | 104 ++-- src/etl/NFTHelpers.hpp | 3 +- src/etl/NetworkValidatedLedgers.cpp | 5 +- src/etl/NetworkValidatedLedgers.hpp | 24 +- src/etl/NetworkValidatedLedgersInterface.hpp | 13 +- src/etl/RegistryInterface.hpp | 19 +- src/etl/Source.cpp | 7 +- src/etl/Source.hpp | 17 +- src/etl/SystemState.hpp | 17 +- src/etl/WriterState.hpp | 3 +- src/etl/impl/AmendmentBlockHandler.cpp | 14 +- src/etl/impl/AsyncGrpcCall.cpp | 12 +- src/etl/impl/AsyncGrpcCall.hpp | 11 +- src/etl/impl/CacheLoader.hpp | 24 +- src/etl/impl/CursorFromAccountProvider.hpp | 6 +- src/etl/impl/CursorFromDiffProvider.hpp | 5 +- src/etl/impl/CursorFromFixDiffNumProvider.hpp | 4 +- src/etl/impl/Extraction.cpp | 30 +- src/etl/impl/ForwardingSource.cpp | 6 +- src/etl/impl/GrpcSource.cpp | 22 +- src/etl/impl/GrpcSource.hpp | 18 +- src/etl/impl/LedgerFetcher.hpp | 22 +- src/etl/impl/LedgerPublisher.hpp | 76 ++- src/etl/impl/Loading.cpp | 39 +- src/etl/impl/Monitor.cpp | 37 +- src/etl/impl/Monitor.hpp | 3 +- src/etl/impl/MonitorProvider.hpp | 6 +- src/etl/impl/Registry.hpp | 36 +- src/etl/impl/Scheduling.hpp | 13 +- src/etl/impl/SourceImpl.hpp | 22 +- src/etl/impl/SubscriptionSource.cpp | 107 ++-- src/etl/impl/SubscriptionSource.hpp | 13 +- src/etl/impl/TaskManager.cpp | 28 +- src/etl/impl/TaskQueue.hpp | 24 +- src/etl/impl/ext/Cache.cpp | 9 +- src/etl/impl/ext/Cache.hpp | 9 +- src/etl/impl/ext/Core.cpp | 3 +- src/etl/impl/ext/MPT.cpp | 3 +- src/etl/impl/ext/NFT.cpp | 3 +- src/etl/impl/ext/Successor.cpp | 28 +- src/etl/impl/ext/Successor.hpp | 6 +- src/feed/SubscriptionManager.cpp | 40 +- src/feed/SubscriptionManager.hpp | 30 +- src/feed/SubscriptionManagerInterface.hpp | 19 +- src/feed/impl/BookChangesFeed.hpp | 13 +- src/feed/impl/LedgerFeed.cpp | 9 +- src/feed/impl/LedgerFeed.hpp | 9 +- src/feed/impl/ProposedTransactionFeed.cpp | 43 +- src/feed/impl/ProposedTransactionFeed.hpp | 7 +- src/feed/impl/SingleFeedBase.cpp | 15 +- src/feed/impl/TrackableSignal.hpp | 43 +- src/feed/impl/TrackableSignalMap.hpp | 27 +- src/feed/impl/TransactionFeed.cpp | 65 ++- src/feed/impl/TransactionFeed.hpp | 20 +- src/migration/MigrationApplication.cpp | 18 +- src/migration/MigrationInspectorFactory.hpp | 3 +- src/migration/MigrationInspectorInterface.hpp | 7 +- src/migration/MigrationManagerInterface.hpp | 6 +- src/migration/MigratiorStatus.hpp | 3 +- .../cassandra/CassandraMigrationBackend.hpp | 17 +- .../cassandra/CassandraMigrationManager.hpp | 7 +- .../impl/CassandraMigrationSchema.hpp | 14 +- .../cassandra/impl/FullTableScanner.hpp | 26 +- .../impl/FullTableScannerAdapterBase.hpp | 16 +- .../cassandra/impl/ObjectsAdapter.hpp | 12 +- .../cassandra/impl/TransactionsAdapter.hpp | 15 +- src/migration/impl/MigrationInspectorBase.hpp | 18 +- src/migration/impl/MigrationManagerBase.hpp | 7 +- .../impl/MigrationManagerFactory.cpp | 9 +- .../impl/MigrationManagerFactory.hpp | 12 +- src/migration/impl/MigratorsRegister.hpp | 30 +- src/migration/impl/Spec.hpp | 21 +- src/rpc/AMMHelpers.cpp | 21 +- src/rpc/BookChangesHelper.hpp | 25 +- src/rpc/Counters.cpp | 4 +- src/rpc/CredentialHelpers.cpp | 29 +- src/rpc/CredentialHelpers.hpp | 3 +- src/rpc/Errors.cpp | 67 ++- src/rpc/Errors.hpp | 7 +- src/rpc/Factories.cpp | 26 +- src/rpc/Factories.hpp | 9 +- src/rpc/RPCEngine.hpp | 14 +- src/rpc/RPCHelpers.cpp | 244 +++++--- src/rpc/RPCHelpers.hpp | 33 +- src/rpc/WorkQueue.cpp | 13 +- src/rpc/WorkQueue.hpp | 12 +- src/rpc/common/APIVersion.hpp | 4 +- src/rpc/common/AnyHandler.hpp | 8 +- src/rpc/common/Checkers.hpp | 10 +- src/rpc/common/Concepts.hpp | 4 +- src/rpc/common/MetaProcessors.hpp | 38 +- src/rpc/common/Modifiers.hpp | 6 +- src/rpc/common/Specs.hpp | 11 +- src/rpc/common/ValidationHelpers.hpp | 9 +- src/rpc/common/Validators.cpp | 92 ++- src/rpc/common/Validators.hpp | 65 ++- src/rpc/common/impl/APIVersionParser.cpp | 8 +- src/rpc/common/impl/Factories.hpp | 17 +- src/rpc/common/impl/ForwardingProxy.hpp | 12 +- src/rpc/common/impl/HandlerProvider.cpp | 23 +- src/rpc/common/impl/Processors.hpp | 13 +- src/rpc/handlers/AMMInfo.cpp | 77 ++- src/rpc/handlers/AccountChannels.cpp | 46 +- src/rpc/handlers/AccountChannels.hpp | 8 +- src/rpc/handlers/AccountCurrencies.cpp | 16 +- src/rpc/handlers/AccountCurrencies.hpp | 4 +- src/rpc/handlers/AccountInfo.cpp | 32 +- src/rpc/handlers/AccountInfo.hpp | 6 +- src/rpc/handlers/AccountLines.cpp | 40 +- src/rpc/handlers/AccountLines.hpp | 13 +- src/rpc/handlers/AccountMPTokenIssuances.cpp | 29 +- src/rpc/handlers/AccountMPTokenIssuances.hpp | 13 +- src/rpc/handlers/AccountMPTokens.cpp | 30 +- src/rpc/handlers/AccountMPTokens.hpp | 6 +- src/rpc/handlers/AccountNFTs.cpp | 34 +- src/rpc/handlers/AccountNFTs.hpp | 3 +- src/rpc/handlers/AccountObjects.cpp | 30 +- src/rpc/handlers/AccountObjects.hpp | 7 +- src/rpc/handlers/AccountOffers.cpp | 25 +- src/rpc/handlers/AccountTx.cpp | 63 +- src/rpc/handlers/AccountTx.hpp | 7 +- src/rpc/handlers/BookChanges.cpp | 14 +- src/rpc/handlers/BookChanges.hpp | 3 +- src/rpc/handlers/BookOffers.cpp | 24 +- src/rpc/handlers/BookOffers.hpp | 22 +- src/rpc/handlers/DepositAuthorized.cpp | 32 +- src/rpc/handlers/DepositAuthorized.hpp | 13 +- src/rpc/handlers/Feature.cpp | 40 +- src/rpc/handlers/Feature.hpp | 8 +- src/rpc/handlers/GatewayBalances.cpp | 59 +- src/rpc/handlers/GatewayBalances.hpp | 27 +- src/rpc/handlers/GetAggregatePrice.cpp | 46 +- src/rpc/handlers/GetAggregatePrice.hpp | 39 +- src/rpc/handlers/Ledger.cpp | 10 +- src/rpc/handlers/LedgerData.cpp | 36 +- src/rpc/handlers/LedgerData.hpp | 11 +- src/rpc/handlers/LedgerEntry.cpp | 247 +++++--- src/rpc/handlers/LedgerEntry.hpp | 273 ++++++--- src/rpc/handlers/LedgerIndex.cpp | 17 +- src/rpc/handlers/LedgerIndex.hpp | 7 +- src/rpc/handlers/LedgerRange.cpp | 6 +- src/rpc/handlers/LedgerRange.hpp | 6 +- src/rpc/handlers/MPTHolders.cpp | 28 +- src/rpc/handlers/MPTHolders.hpp | 10 +- src/rpc/handlers/NFTHistory.cpp | 35 +- src/rpc/handlers/NFTHistory.hpp | 13 +- src/rpc/handlers/NFTInfo.cpp | 6 +- src/rpc/handlers/NFTInfo.hpp | 7 +- src/rpc/handlers/NFTOffersCommon.cpp | 21 +- src/rpc/handlers/NFTOffersCommon.hpp | 4 +- src/rpc/handlers/NFTsByIssuer.cpp | 16 +- src/rpc/handlers/NFTsByIssuer.hpp | 3 +- src/rpc/handlers/NoRippleCheck.cpp | 36 +- src/rpc/handlers/NoRippleCheck.hpp | 7 +- src/rpc/handlers/Ping.hpp | 3 +- src/rpc/handlers/Random.hpp | 4 +- src/rpc/handlers/ServerInfo.hpp | 30 +- src/rpc/handlers/Subscribe.cpp | 59 +- src/rpc/handlers/Subscribe.hpp | 8 +- src/rpc/handlers/TransactionEntry.cpp | 18 +- src/rpc/handlers/TransactionEntry.hpp | 7 +- src/rpc/handlers/Tx.hpp | 40 +- src/rpc/handlers/Unsubscribe.cpp | 22 +- src/rpc/handlers/Unsubscribe.hpp | 19 +- src/rpc/handlers/VaultInfo.cpp | 23 +- src/rpc/handlers/VaultInfo.hpp | 8 +- src/util/AccountUtils.hpp | 18 +- src/util/Assert.hpp | 6 +- src/util/Atomic.hpp | 3 +- src/util/BlockingCache.hpp | 17 +- src/util/Channel.hpp | 94 +-- src/util/Coroutine.cpp | 5 +- src/util/Coroutine.hpp | 37 +- src/util/CoroutineGroup.cpp | 22 +- src/util/CoroutineGroup.hpp | 28 +- src/util/JsonUtils.hpp | 3 +- src/util/LedgerUtils.cpp | 38 +- src/util/LedgerUtils.hpp | 59 +- src/util/MoveTracker.hpp | 3 +- src/util/ObservableValue.hpp | 22 +- src/util/Profiler.hpp | 7 +- src/util/Random.cpp | 3 +- src/util/Repeat.hpp | 55 +- src/util/Retry.cpp | 8 +- src/util/Retry.hpp | 26 +- src/util/SignalsHandler.cpp | 19 +- src/util/Spawn.hpp | 14 +- src/util/StopHelper.cpp | 4 +- src/util/Taggable.hpp | 13 +- src/util/TerminationHandler.cpp | 3 +- src/util/TimeUtils.cpp | 4 +- src/util/WithTimeout.hpp | 13 +- src/util/async/AnyExecutionContext.hpp | 93 +-- src/util/async/AnyOperation.hpp | 18 +- src/util/async/AnyStrand.hpp | 33 +- src/util/async/Concepts.hpp | 6 +- src/util/async/Operation.hpp | 22 +- .../async/context/BasicExecutionContext.hpp | 96 +++- .../async/context/SyncExecutionContext.hpp | 9 +- .../async/context/SystemExecutionContext.hpp | 4 +- src/util/async/context/impl/Execution.hpp | 18 +- src/util/async/context/impl/Strand.hpp | 29 +- src/util/async/context/impl/Utils.hpp | 9 +- src/util/async/impl/ErasedOperation.hpp | 12 +- src/util/async/impl/ErrorHandling.hpp | 37 +- src/util/build/Build.cpp | 3 +- src/util/config/Array.cpp | 5 +- src/util/config/Array.hpp | 6 +- src/util/config/ArrayView.cpp | 6 +- src/util/config/ArrayView.hpp | 3 +- src/util/config/ConfigConstraints.hpp | 56 +- src/util/config/ConfigDefinition.cpp | 211 ++++--- src/util/config/ConfigDefinition.hpp | 7 +- src/util/config/ConfigDescription.hpp | 234 +++++--- src/util/config/ConfigFileJson.cpp | 33 +- src/util/config/ConfigValue.hpp | 9 +- src/util/config/ObjectView.cpp | 14 +- src/util/config/ObjectView.hpp | 14 +- src/util/config/ValueView.hpp | 5 +- src/util/log/Logger.cpp | 45 +- src/util/log/Logger.hpp | 29 +- src/util/prometheus/Gauge.hpp | 3 +- src/util/prometheus/Histogram.hpp | 29 +- src/util/prometheus/Http.hpp | 5 +- src/util/prometheus/Label.hpp | 6 +- src/util/prometheus/MetricBase.hpp | 13 +- src/util/prometheus/MetricBuilder.cpp | 13 +- src/util/prometheus/MetricBuilder.hpp | 20 +- src/util/prometheus/MetricsFamily.cpp | 8 +- src/util/prometheus/MetricsFamily.hpp | 9 +- src/util/prometheus/OStream.cpp | 4 +- src/util/prometheus/Prometheus.cpp | 78 ++- src/util/prometheus/Prometheus.hpp | 49 +- src/util/prometheus/impl/HistogramImpl.hpp | 19 +- src/util/requests/RequestBuilder.cpp | 12 +- src/util/requests/RequestBuilder.hpp | 48 +- src/util/requests/Types.cpp | 6 +- src/util/requests/WsConnection.cpp | 13 +- src/util/requests/WsConnection.hpp | 16 +- src/util/requests/impl/SslContext.cpp | 10 +- src/util/requests/impl/StreamData.hpp | 10 +- src/util/requests/impl/WsConnectionImpl.hpp | 11 +- src/web/AdminVerificationStrategy.cpp | 7 +- src/web/AdminVerificationStrategy.hpp | 4 +- src/web/Context.hpp | 3 +- src/web/PlainWsSession.hpp | 7 +- src/web/ProxyIpResolver.cpp | 8 +- src/web/ProxyIpResolver.hpp | 9 +- src/web/RPCServerHandler.hpp | 45 +- src/web/Server.hpp | 58 +- src/web/SslHttpSession.hpp | 8 +- src/web/SslWsSession.hpp | 7 +- src/web/SubscriptionContext.hpp | 10 +- src/web/SubscriptionContextInterface.hpp | 4 +- src/web/dosguard/DOSGuard.cpp | 3 +- src/web/dosguard/IntervalSweepHandler.cpp | 4 +- src/web/dosguard/Weights.cpp | 7 +- src/web/dosguard/Weights.hpp | 3 +- src/web/dosguard/WhitelistHandler.cpp | 10 +- src/web/dosguard/WhitelistHandler.hpp | 12 +- src/web/impl/ErrorHandling.hpp | 36 +- src/web/impl/HttpBase.hpp | 44 +- src/web/impl/WsBase.hpp | 58 +- src/web/interface/Concepts.hpp | 14 +- src/web/ng/Connection.cpp | 5 +- src/web/ng/Connection.hpp | 16 +- src/web/ng/MessageHandler.hpp | 8 +- src/web/ng/RPCServerHandler.hpp | 72 ++- src/web/ng/Request.cpp | 6 +- src/web/ng/Request.hpp | 13 +- src/web/ng/Response.cpp | 50 +- src/web/ng/Response.hpp | 33 +- src/web/ng/Server.cpp | 79 ++- src/web/ng/Server.hpp | 18 +- src/web/ng/SubscriptionContext.cpp | 17 +- src/web/ng/SubscriptionContext.hpp | 18 +- src/web/ng/impl/Concepts.hpp | 3 +- src/web/ng/impl/ConnectionHandler.cpp | 80 ++- src/web/ng/impl/ConnectionHandler.hpp | 8 +- src/web/ng/impl/ErrorHandling.cpp | 40 +- src/web/ng/impl/ErrorHandling.hpp | 5 +- src/web/ng/impl/HttpConnection.hpp | 19 +- src/web/ng/impl/SendingQueue.hpp | 3 +- src/web/ng/impl/ServerSslContext.cpp | 4 +- src/web/ng/impl/WsConnection.hpp | 25 +- tests/common/etl/FakeDiffProvider.hpp | 36 +- tests/common/rpc/FakesAndMocks.hpp | 4 +- tests/common/util/AsioContextTestFixture.hpp | 14 +- tests/common/util/BinaryTestObject.cpp | 63 +- tests/common/util/BinaryTestObject.hpp | 11 +- tests/common/util/CallWithTimeout.cpp | 4 +- tests/common/util/CallWithTimeout.hpp | 3 +- tests/common/util/HandlerBaseTestFixture.hpp | 9 +- tests/common/util/LoggerFixtures.cpp | 8 +- tests/common/util/LoggerFixtures.hpp | 4 +- tests/common/util/MockAmendmentCenter.hpp | 21 +- tests/common/util/MockAssert.hpp | 49 +- tests/common/util/MockBackend.hpp | 38 +- tests/common/util/MockBackendTestFixture.hpp | 7 +- .../common/util/MockETLServiceTestFixture.hpp | 8 +- tests/common/util/MockExecutionContext.hpp | 3 +- tests/common/util/MockHandlerProvider.hpp | 7 +- tests/common/util/MockLedgerCache.hpp | 21 +- tests/common/util/MockLedgerPublisher.hpp | 14 +- tests/common/util/MockLoadBalancer.hpp | 5 +- .../util/MockMigrationBackendFixture.hpp | 7 +- .../util/MockNetworkValidatedLedgers.hpp | 3 +- tests/common/util/MockPrometheus.hpp | 114 ++-- tests/common/util/MockRPCEngine.hpp | 15 +- tests/common/util/MockSource.hpp | 23 +- tests/common/util/MockStrand.hpp | 3 +- tests/common/util/MockSubscriptionManager.hpp | 45 +- tests/common/util/MockWsBase.hpp | 3 +- tests/common/util/TestHttpClient.cpp | 19 +- tests/common/util/TestHttpClient.hpp | 4 +- tests/common/util/TestHttpServer.cpp | 3 +- tests/common/util/TestHttpServer.hpp | 7 +- tests/common/util/TestObject.cpp | 134 ++++- tests/common/util/TestObject.hpp | 38 +- tests/common/util/TestWebSocketClient.cpp | 59 +- tests/common/util/TestWebSocketClient.hpp | 16 +- tests/common/util/TestWsServer.cpp | 5 +- tests/common/util/TestWsServer.hpp | 4 +- tests/common/util/config/FakeConfigData.hpp | 18 +- tests/common/web/dosguard/DOSGuardMock.hpp | 7 +- .../common/web/ng/impl/MockHttpConnection.hpp | 7 +- tests/common/web/ng/impl/MockWsConnection.hpp | 7 +- .../integration/data/BackendFactoryTests.cpp | 36 +- .../data/cassandra/BackendTests.cpp | 253 +++++--- .../integration/data/cassandra/BaseTests.cpp | 16 +- .../CassandraMigrationManagerTests.cpp | 114 ++-- .../CassandraMigrationTestBackend.hpp | 26 +- .../migration/cassandra/DBRawData.cpp | 210 ++----- .../cassandra/ExampleDropTableMigrator.cpp | 5 +- .../cassandra/ExampleDropTableMigrator.hpp | 4 +- .../cassandra/ExampleLedgerMigrator.cpp | 10 +- .../cassandra/ExampleLedgerMigrator.hpp | 8 +- .../cassandra/ExampleObjectsMigrator.cpp | 27 +- .../cassandra/ExampleObjectsMigrator.hpp | 4 +- .../cassandra/ExampleTransactionsMigrator.cpp | 18 +- .../cassandra/ExampleTransactionsMigrator.hpp | 5 +- tests/integration/util/CassandraDBHelper.cpp | 35 +- tests/integration/util/CassandraDBHelper.hpp | 18 +- tests/unit/JsonUtilTests.cpp | 6 +- tests/unit/app/CliArgsTests.cpp | 38 +- tests/unit/app/StopperTests.cpp | 20 +- tests/unit/app/WebHandlersTests.cpp | 13 +- tests/unit/cluster/BackendTests.cpp | 169 ++++-- tests/unit/cluster/ClioNodeTests.cpp | 15 +- .../ClusterCommunicationServiceTests.cpp | 73 ++- tests/unit/cluster/MetricsTests.cpp | 36 +- tests/unit/cluster/RepeatedTaskTests.cpp | 40 +- tests/unit/cluster/WriterDeciderTests.cpp | 23 +- tests/unit/data/AmendmentCenterTests.cpp | 41 +- tests/unit/data/BackendCountersTests.cpp | 68 ++- tests/unit/data/BackendInterfaceTests.cpp | 32 +- tests/unit/data/LedgerCacheSaverTests.cpp | 24 +- .../data/cassandra/AsyncExecutorTests.cpp | 40 +- .../data/cassandra/ExecutionStrategyTests.cpp | 130 ++++- .../data/cassandra/LedgerHeaderCacheTests.cpp | 3 +- .../unit/data/cassandra/RetryPolicyTests.cpp | 12 +- .../data/cassandra/SettingsProviderTests.cpp | 22 +- tests/unit/data/impl/LedgerCacheFileTests.cpp | 88 ++- tests/unit/etl/AmendmentBlockHandlerTests.cpp | 7 +- tests/unit/etl/CacheLoaderSettingsTests.cpp | 12 +- tests/unit/etl/CacheLoaderTests.cpp | 56 +- .../etl/CursorFromAccountProviderTests.cpp | 3 +- .../unit/etl/CursorFromDiffProviderTests.cpp | 68 ++- tests/unit/etl/ETLServiceTests.cpp | 231 +++++--- tests/unit/etl/ETLStateTests.cpp | 3 +- tests/unit/etl/ExtractionTests.cpp | 28 +- tests/unit/etl/ForwardingSourceTests.cpp | 38 +- tests/unit/etl/GrpcSourceTests.cpp | 47 +- tests/unit/etl/LedgerPublisherTests.cpp | 90 ++- tests/unit/etl/LoadBalancerTests.cpp | 249 +++++--- tests/unit/etl/LoadingTests.cpp | 36 +- tests/unit/etl/MonitorTests.cpp | 14 +- tests/unit/etl/NFTHelpersTests.cpp | 145 +++-- .../unit/etl/NetworkValidatedLedgersTests.cpp | 4 +- tests/unit/etl/RegistryTests.cpp | 79 ++- tests/unit/etl/SchedulingTests.cpp | 13 +- tests/unit/etl/SourceImplTests.cpp | 33 +- tests/unit/etl/SubscriptionSourceTests.cpp | 117 ++-- tests/unit/etl/SystemStateTests.cpp | 6 +- tests/unit/etl/TaskManagerTests.cpp | 22 +- tests/unit/etl/ext/CacheTests.cpp | 6 +- tests/unit/etl/ext/CoreTests.cpp | 3 +- tests/unit/etl/ext/MPTTests.cpp | 47 +- tests/unit/etl/ext/NFTTests.cpp | 540 ++++++++++++------ tests/unit/etl/ext/SuccessorTests.cpp | 262 ++++++--- tests/unit/feed/BookChangesFeedTests.cpp | 3 +- tests/unit/feed/ForwardFeedTests.cpp | 3 +- .../feed/ProposedTransactionFeedTests.cpp | 23 +- tests/unit/feed/SingleFeedBaseTests.cpp | 6 +- tests/unit/feed/SubscriptionManagerTests.cpp | 22 +- tests/unit/feed/TrackableSignalTests.cpp | 6 +- tests/unit/feed/TransactionFeedTests.cpp | 118 ++-- .../migration/MigrationInspectorBaseTests.cpp | 52 +- .../MigrationInspectorFactoryTests.cpp | 9 +- .../migration/MigrationManagerBaseTests.cpp | 53 +- .../MigrationManagerFactoryTests.cpp | 3 +- .../unit/migration/MigratorRegisterTests.cpp | 98 +++- tests/unit/migration/MigratorStatusTests.cpp | 16 +- .../cassandra/FullTableScannerTests.cpp | 35 +- tests/unit/rpc/APIVersionTests.cpp | 6 +- tests/unit/rpc/BaseTests.cpp | 92 +-- tests/unit/rpc/CountersTests.cpp | 161 ++++-- tests/unit/rpc/ErrorTests.cpp | 46 +- tests/unit/rpc/ForwardingProxyTests.cpp | 23 +- tests/unit/rpc/JsonBoolTests.cpp | 48 +- tests/unit/rpc/RPCEngineTests.cpp | 53 +- tests/unit/rpc/RPCHelpersTests.cpp | 296 +++++++--- tests/unit/rpc/WorkQueueTests.cpp | 48 +- tests/unit/rpc/common/SpecsTests.cpp | 11 +- tests/unit/rpc/common/TypesTests.cpp | 9 +- .../rpc/common/impl/HandlerProviderTests.cpp | 12 +- tests/unit/rpc/handlers/AMMInfoTests.cpp | 205 +++++-- .../rpc/handlers/AccountChannelsTests.cpp | 70 ++- .../rpc/handlers/AccountCurrenciesTests.cpp | 45 +- tests/unit/rpc/handlers/AccountInfoTests.cpp | 127 ++-- tests/unit/rpc/handlers/AccountLinesTests.cpp | 117 ++-- .../handlers/AccountMPTokenIssuancesTests.cpp | 155 +++-- .../rpc/handlers/AccountMPTokensTests.cpp | 150 +++-- tests/unit/rpc/handlers/AccountNFTsTests.cpp | 37 +- .../unit/rpc/handlers/AccountObjectsTests.cpp | 335 +++++++---- .../unit/rpc/handlers/AccountOffersTests.cpp | 58 +- tests/unit/rpc/handlers/AccountTxTests.cpp | 198 +++++-- tests/unit/rpc/handlers/AllHandlerTests.cpp | 30 +- tests/unit/rpc/handlers/BookChangesTests.cpp | 15 +- tests/unit/rpc/handlers/BookOffersTests.cpp | 255 ++++++--- .../rpc/handlers/CredentialHelpersTests.cpp | 27 +- .../rpc/handlers/DepositAuthorizedTests.cpp | 219 +++++-- tests/unit/rpc/handlers/FeatureTests.cpp | 66 ++- .../rpc/handlers/GatewayBalancesTests.cpp | 103 +++- .../rpc/handlers/GetAggregatePriceTests.cpp | 54 +- tests/unit/rpc/handlers/LedgerDataTests.cpp | 137 +++-- tests/unit/rpc/handlers/LedgerEntryTests.cpp | 287 +++++++--- tests/unit/rpc/handlers/LedgerIndexTests.cpp | 20 +- tests/unit/rpc/handlers/LedgerTests.cpp | 225 +++++--- tests/unit/rpc/handlers/MPTHoldersTests.cpp | 72 ++- tests/unit/rpc/handlers/NFTBuyOffersTests.cpp | 31 +- tests/unit/rpc/handlers/NFTHistoryTests.cpp | 112 +++- tests/unit/rpc/handlers/NFTInfoTests.cpp | 20 +- .../unit/rpc/handlers/NFTSellOffersTests.cpp | 21 +- tests/unit/rpc/handlers/NFTsByIssuerTest.cpp | 92 ++- .../unit/rpc/handlers/NoRippleCheckTests.cpp | 140 +++-- tests/unit/rpc/handlers/ServerInfoTests.cpp | 89 ++- tests/unit/rpc/handlers/SubscribeTests.cpp | 235 ++++++-- .../rpc/handlers/TransactionEntryTests.cpp | 33 +- tests/unit/rpc/handlers/TxTests.cpp | 111 ++-- tests/unit/rpc/handlers/UnsubscribeTests.cpp | 40 +- tests/unit/rpc/handlers/VaultInfoTests.cpp | 37 +- tests/unit/util/BlockingCacheTests.cpp | 70 ++- tests/unit/util/ChannelTests.cpp | 294 ++++++---- tests/unit/util/CoroutineGroupTests.cpp | 8 +- tests/unit/util/CoroutineTest.cpp | 19 +- tests/unit/util/LedgerUtilsTests.cpp | 26 +- tests/unit/util/MoveTrackerTests.cpp | 8 +- tests/unit/util/ObservableValueTest.cpp | 33 +- tests/unit/util/RepeatTests.cpp | 16 +- tests/unit/util/ShasumTests.cpp | 6 +- tests/unit/util/SignalsHandlerTests.cpp | 22 +- tests/unit/util/SpawnTests.cpp | 8 +- tests/unit/util/TxUtilTests.cpp | 11 +- tests/unit/util/WithTimeout.cpp | 9 +- .../util/async/AnyExecutionContextTests.cpp | 41 +- tests/unit/util/async/AnyOperationTests.cpp | 12 +- tests/unit/util/async/AnyStopTokenTests.cpp | 12 +- tests/unit/util/async/AnyStrandTests.cpp | 20 +- .../util/async/AsyncExecutionContextTests.cpp | 58 +- tests/unit/util/config/ArrayViewTests.cpp | 4 +- .../util/config/ClioConfigDefinitionTests.cpp | 26 +- .../unit/util/config/ConfigFileJsonTests.cpp | 21 +- tests/unit/util/config/ConfigValueTests.cpp | 54 +- tests/unit/util/config/ObjectViewTests.cpp | 9 +- tests/unit/util/config/ValueViewTests.cpp | 3 +- tests/unit/util/log/LogServiceInitTests.cpp | 33 +- tests/unit/util/log/LoggerTests.cpp | 9 +- tests/unit/util/log/PrettyPathTests.cpp | 3 +- tests/unit/util/prometheus/GaugeTests.cpp | 6 +- tests/unit/util/prometheus/HistogramTests.cpp | 7 +- tests/unit/util/prometheus/HttpTests.cpp | 24 +- .../util/prometheus/MetricBuilderTests.cpp | 4 +- .../util/prometheus/MetricsFamilyTests.cpp | 18 +- .../util/requests/RequestBuilderTests.cpp | 31 +- .../unit/util/requests/WsConnectionTests.cpp | 45 +- tests/unit/web/AdminVerificationTests.cpp | 6 +- tests/unit/web/ProxyIpResolverTests.cpp | 3 +- tests/unit/web/RPCServerHandlerTests.cpp | 96 +++- tests/unit/web/ServerTests.cpp | 92 ++- .../dosguard/IntervalSweepHandlerTests.cpp | 4 +- tests/unit/web/dosguard/WeightsTests.cpp | 79 ++- .../web/dosguard/WhitelistHandlerTests.cpp | 19 +- tests/unit/web/impl/ErrorHandlingTests.cpp | 17 +- tests/unit/web/ng/RPCServerHandlerTests.cpp | 169 ++++-- tests/unit/web/ng/ResponseTests.cpp | 42 +- tests/unit/web/ng/ServerTests.cpp | 190 +++--- .../unit/web/ng/SubscriptionContextTests.cpp | 40 +- .../web/ng/impl/ConnectionHandlerTests.cpp | 483 ++++++++++------ tests/unit/web/ng/impl/ErrorHandlingTests.cpp | 20 +- .../unit/web/ng/impl/HttpConnectionTests.cpp | 116 ++-- .../web/ng/impl/ServerSslContextTests.cpp | 16 +- tests/unit/web/ng/impl/WsConnectionTests.cpp | 111 ++-- 575 files changed, 14315 insertions(+), 6552 deletions(-) diff --git a/.clang-format b/.clang-format index 921e91798..13b8c58a5 100644 --- a/.clang-format +++ b/.clang-format @@ -22,7 +22,7 @@ BreakBeforeBinaryOperators: false BreakBeforeBraces: WebKit BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: true -ColumnLimit: 120 +ColumnLimit: 100 CommentPragmas: "^ IWYU pragma:" ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 diff --git a/benchmarks/rpc/WorkQueueBenchmarks.cpp b/benchmarks/rpc/WorkQueueBenchmarks.cpp index f50dd0868..f33bf2ad9 100644 --- a/benchmarks/rpc/WorkQueueBenchmarks.cpp +++ b/benchmarks/rpc/WorkQueueBenchmarks.cpp @@ -51,12 +51,15 @@ auto const kCONFIG = ClioConfigDefinition{ {"log.channels.[].channel", Array{ConfigValue{ConfigType::String}}}, {"log.channels.[].level", Array{ConfigValue{ConfigType::String}}}, {"log.level", ConfigValue{ConfigType::String}.defaultValue("info")}, - {"log.format", ConfigValue{ConfigType::String}.defaultValue(R"(%Y-%m-%d %H:%M:%S.%f %^%3!l:%n%$ - %v)")}, + {"log.format", + ConfigValue{ConfigType::String}.defaultValue(R"(%Y-%m-%d %H:%M:%S.%f %^%3!l:%n%$ - %v)")}, {"log.is_async", ConfigValue{ConfigType::Boolean}.defaultValue(false)}, {"log.enable_console", ConfigValue{ConfigType::Boolean}.defaultValue(false)}, {"log.directory", ConfigValue{ConfigType::String}.optional()}, - {"log.rotation_size", ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(gValidateUint32)}, - {"log.directory_max_files", ConfigValue{ConfigType::Integer}.defaultValue(25).withConstraint(gValidateUint32)}, + {"log.rotation_size", + ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(gValidateUint32)}, + {"log.directory_max_files", + ConfigValue{ConfigType::Integer}.defaultValue(25).withConstraint(gValidateUint32)}, {"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("none")}, }; @@ -124,9 +127,14 @@ benchmarkWorkQueue(benchmark::State& state) ASSERT(totalQueued <= itemsPerClient * clientThreads, "Queued more than requested"); if (maxQueueSize == 0) { - ASSERT(totalQueued == itemsPerClient * clientThreads, "Queued exactly the expected amount"); + ASSERT( + totalQueued == itemsPerClient * clientThreads, "Queued exactly the expected amount" + ); } else { - ASSERT(totalQueued >= std::min(maxQueueSize, itemsPerClient * clientThreads), "Queued less than expected"); + ASSERT( + totalQueued >= std::min(maxQueueSize, itemsPerClient * clientThreads), + "Queued less than expected" + ); } } } diff --git a/benchmarks/util/log/LoggerBenchmark.cpp b/benchmarks/util/log/LoggerBenchmark.cpp index 0b7467e35..86c0ef772 100644 --- a/benchmarks/util/log/LoggerBenchmark.cpp +++ b/benchmarks/util/log/LoggerBenchmark.cpp @@ -62,8 +62,9 @@ uniqueLogDir() { auto const epochTime = std::chrono::high_resolution_clock::now().time_since_epoch(); auto const tmpDir = std::filesystem::temp_directory_path(); - std::string const dirName = - fmt::format("logs_{}", std::chrono::duration_cast(epochTime).count()); + std::string const dirName = fmt::format( + "logs_{}", std::chrono::duration_cast(epochTime).count() + ); return tmpDir / "clio_benchmark" / dirName; } @@ -108,7 +109,8 @@ benchmarkConcurrentFileLogging(benchmark::State& state) channel, fileSink, spdlog::thread_pool(), spdlog::async_overflow_policy::block ); spdlog::register_logger(logger); - Logger const threadLogger = BenchmarkLoggingInitializer::getLogger(std::move(logger)); + Logger const threadLogger = + BenchmarkLoggingInitializer::getLogger(std::move(logger)); barrier.arrive_and_wait(); @@ -124,13 +126,16 @@ benchmarkConcurrentFileLogging(benchmark::State& state) spdlog::shutdown(); auto const end = std::chrono::high_resolution_clock::now(); - state.SetIterationTime(std::chrono::duration_cast>(end - start).count()); + state.SetIterationTime( + std::chrono::duration_cast>(end - start).count() + ); std::filesystem::remove_all(logDir); } auto const totalMessages = numThreads * messagesPerThread; - state.counters["TotalMessagesRate"] = benchmark::Counter(totalMessages, benchmark::Counter::kIsRate); + state.counters["TotalMessagesRate"] = + benchmark::Counter(totalMessages, benchmark::Counter::kIsRate); state.counters["Threads"] = numThreads; state.counters["MessagesPerThread"] = messagesPerThread; } diff --git a/src/app/CliArgs.cpp b/src/app/CliArgs.cpp index 45ae42404..0db6b04fe 100644 --- a/src/app/CliArgs.cpp +++ b/src/app/CliArgs.cpp @@ -58,12 +58,16 @@ CliArgs::parse(int argc, char const* argv[]) positional.add("conf", 1); auto const printHelp = [&description]() { - std::cout << "Clio server " << util::build::getClioFullVersionString() << "\n\n" << description; + std::cout << "Clio server " << util::build::getClioFullVersionString() << "\n\n" + << description; }; po::variables_map parsed; try { - po::store(po::command_line_parser(argc, argv).options(description).positional(positional).run(), parsed); + po::store( + po::command_line_parser(argc, argv).options(description).positional(positional).run(), + parsed + ); po::notify(parsed); } catch (po::error const& e) { std::cerr << "Error: " << e.what() << std::endl << std::endl; @@ -87,7 +91,8 @@ CliArgs::parse(int argc, char const* argv[]) if (parsed.contains("config-description")) { std::filesystem::path const filePath = parsed["config-description"].as(); - auto const res = util::config::ClioConfigDescription::generateConfigDescriptionToFile(filePath); + auto const res = + util::config::ClioConfigDescription::generateConfigDescriptionToFile(filePath); if (res.has_value()) return Action{Action::Exit{EXIT_SUCCESS}}; @@ -100,14 +105,20 @@ CliArgs::parse(int argc, char const* argv[]) if (parsed.contains("migrate")) { auto const opt = parsed["migrate"].as(); if (opt == "status") - return Action{Action::Migrate{.configPath = std::move(configPath), .subCmd = MigrateSubCmd::status()}}; - return Action{Action::Migrate{.configPath = std::move(configPath), .subCmd = MigrateSubCmd::migration(opt)}}; + return Action{Action::Migrate{ + .configPath = std::move(configPath), .subCmd = MigrateSubCmd::status() + }}; + return Action{Action::Migrate{ + .configPath = std::move(configPath), .subCmd = MigrateSubCmd::migration(opt) + }}; } if (parsed.contains("verify")) return Action{Action::VerifyConfig{.configPath = std::move(configPath)}}; - return Action{Action::Run{.configPath = std::move(configPath), .useNgWebServer = parsed.contains("ng-web-server")}}; + return Action{Action::Run{ + .configPath = std::move(configPath), .useNgWebServer = parsed.contains("ng-web-server") + }}; } } // namespace app diff --git a/src/app/CliArgs.hpp b/src/app/CliArgs.hpp index 8f2a8c359..7d8b2aa2f 100644 --- a/src/app/CliArgs.hpp +++ b/src/app/CliArgs.hpp @@ -79,7 +79,8 @@ public: /** * @brief Apply a function to the action. * - * @tparam Processors Action processors types. Must be callable with the action type and return int. + * @tparam Processors Action processors types. Must be callable with the action type and + * return int. * @param processors Action processors. * @return Exit code. */ diff --git a/src/app/ClioApplication.cpp b/src/app/ClioApplication.cpp index 436813d14..efa136263 100644 --- a/src/app/ClioApplication.cpp +++ b/src/app/ClioApplication.cpp @@ -136,14 +136,15 @@ ClioApplication::run(bool const useNgWebServer) auto const migrationInspector = migration::makeMigrationInspector(config_, backend); // Check if any migration is blocking Clio server starting. if (migrationInspector->isBlockingClio() and backend->hardFetchLedgerRangeNoThrow()) { - LOG(util::LogService::error()) - << "Existing Migration is blocking Clio, Please complete the database migration first."; + LOG(util::LogService::error()) << "Existing Migration is blocking Clio, Please " + "complete the database migration first."; return EXIT_FAILURE; } } // Manages clients subscribed to streams - auto subscriptions = feed::SubscriptionManager::makeSubscriptionManager(config_, backend, amendmentCenter); + auto subscriptions = + feed::SubscriptionManager::makeSubscriptionManager(config_, backend, amendmentCenter); // Tracks which ledgers have been validated by the network auto ledgers = etl::NetworkValidatedLedgers::makeValidatedLedgers(); @@ -156,7 +157,8 @@ ClioApplication::run(bool const useNgWebServer) config_, ioc, backend, subscriptions, std::make_unique(), ledgers ); - // ETL is responsible for writing and publishing to streams. In read-only mode, ETL only publishes + // ETL is responsible for writing and publishing to streams. In read-only mode, ETL only + // publishes auto etl = etl::ETLService::makeETLService( config_, std::move(systemState), ctx, backend, subscriptions, balancer, ledgers ); @@ -169,15 +171,19 @@ ClioApplication::run(bool const useNgWebServer) ); using RPCEngineType = rpc::RPCEngine; - auto const rpcEngine = - RPCEngineType::makeRPCEngine(config_, backend, balancer, dosGuard, workQueue, counters, handlerProvider); + auto const rpcEngine = RPCEngineType::makeRPCEngine( + config_, backend, balancer, dosGuard, workQueue, counters, handlerProvider + ); if (useNgWebServer or config_.get("server.__ng_web_server")) { - web::ng::RPCServerHandler handler{config_, backend, rpcEngine, etl, dosGuard}; + web::ng::RPCServerHandler handler{ + config_, backend, rpcEngine, etl, dosGuard + }; auto expectedAdminVerifier = web::makeAdminVerificationStrategy(config_); if (not expectedAdminVerifier.has_value()) { - LOG(util::LogService::error()) << "Error creating admin verifier: " << expectedAdminVerifier.error(); + LOG(util::LogService::error()) + << "Error creating admin verifier: " << expectedAdminVerifier.error(); return EXIT_FAILURE; } auto const adminVerifier = std::move(expectedAdminVerifier).value(); @@ -226,12 +232,21 @@ ClioApplication::run(bool const useNgWebServer) } // Init the web server - auto handler = std::make_shared>(config_, backend, rpcEngine, etl, dosGuard); + auto handler = std::make_shared>( + config_, backend, rpcEngine, etl, dosGuard + ); auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler, cache); appStopper_.setOnStop( Stopper::makeOnStopCallback( - *httpServer, *balancer, *etl, *subscriptions, *backend, cacheSaver, clusterCommunicationService, ioc + *httpServer, + *balancer, + *etl, + *subscriptions, + *backend, + cacheSaver, + clusterCommunicationService, + ioc ) ); diff --git a/src/app/Stopper.hpp b/src/app/Stopper.hpp index b21ffc487..1846e979e 100644 --- a/src/app/Stopper.hpp +++ b/src/app/Stopper.hpp @@ -39,7 +39,8 @@ namespace app { /** - * @brief Application stopper class. On stop it will create a new thread to run all the shutdown tasks. + * @brief Application stopper class. On stop it will create a new thread to run all the shutdown + * tasks. */ class Stopper { boost::asio::io_context ctx_; diff --git a/src/app/VerifyConfig.hpp b/src/app/VerifyConfig.hpp index c0af108d2..ff538e7bc 100644 --- a/src/app/VerifyConfig.hpp +++ b/src/app/VerifyConfig.hpp @@ -41,7 +41,8 @@ parseConfig(std::string_view configPath) auto const json = ConfigFileJson::makeConfigFileJson(configPath); if (!json.has_value()) { - std::cerr << "Error parsing json from config: " << configPath << "\n" << json.error().error << std::endl; + std::cerr << "Error parsing json from config: " << configPath << "\n" + << json.error().error << std::endl; return false; } auto const errors = getClioConfig().parse(json.value()); diff --git a/src/app/WebHandlers.cpp b/src/app/WebHandlers.cpp index a84fd97be..738595af7 100644 --- a/src/app/WebHandlers.cpp +++ b/src/app/WebHandlers.cpp @@ -51,9 +51,9 @@ OnConnectCheck::operator()(web::ng::Connection const& connection) { dosguard_.get().increment(connection.ip()); if (not dosguard_.get().isOk(connection.ip())) { - return std::unexpected{ - web::ng::Response{boost::beast::http::status::too_many_requests, "Too many requests", connection} - }; + return std::unexpected{web::ng::Response{ + boost::beast::http::status::too_many_requests, "Too many requests", connection + }}; } return {}; @@ -80,7 +80,10 @@ DisconnectHook::operator()(web::ng::Connection const& connection) dosguard_.get().decrement(connection.ip()); } -MetricsHandler::MetricsHandler(std::shared_ptr adminVerifier, rpc::WorkQueue& workQueue) +MetricsHandler::MetricsHandler( + std::shared_ptr adminVerifier, + rpc::WorkQueue& workQueue +) : adminVerifier_{std::move(adminVerifier)}, workQueue_{std::ref(workQueue)} { } @@ -120,7 +123,9 @@ MetricsHandler::operator()( if (!postSuccessful) { return web::ng::Response{ - boost::beast::http::status::too_many_requests, rpc::makeError(rpc::RippledError::rpcTOO_BUSY), request + boost::beast::http::status::too_many_requests, + rpc::makeError(rpc::RippledError::rpcTOO_BUSY), + request }; } @@ -177,7 +182,9 @@ CacheStateHandler::operator()( if (cache_.get().isFull()) return web::ng::Response{boost::beast::http::status::ok, kCACHE_CHECK_LOADED_HTML, request}; - return web::ng::Response{boost::beast::http::status::service_unavailable, kCACHE_CHECK_NOT_LOADED_HTML, request}; + return web::ng::Response{ + boost::beast::http::status::service_unavailable, kCACHE_CHECK_NOT_LOADED_HTML, request + }; } } // namespace app diff --git a/src/app/WebHandlers.hpp b/src/app/WebHandlers.hpp index cd5880cea..7c256fd97 100644 --- a/src/app/WebHandlers.hpp +++ b/src/app/WebHandlers.hpp @@ -68,8 +68,8 @@ public: }; /** - * @brief A function object that is called when the IP of a connection changes (usually if proxy detected). - * This is used to update the DOS guard. + * @brief A function object that is called when the IP of a connection changes (usually if proxy + * detected). This is used to update the DOS guard. */ class IpChangeHook { std::reference_wrapper dosguard_; @@ -126,10 +126,14 @@ public: /** * @brief Construct a new MetricsHandler object * - * @param adminVerifier The AdminVerificationStrategy to use for verifying the connection for admin access. + * @param adminVerifier The AdminVerificationStrategy to use for verifying the connection for + * admin access. * @param workQueue The WorkQueue to use for handling the request. */ - MetricsHandler(std::shared_ptr adminVerifier, rpc::WorkQueue& workQueue); + MetricsHandler( + std::shared_ptr adminVerifier, + rpc::WorkQueue& workQueue + ); /** * @brief The call of the function object. @@ -214,10 +218,14 @@ public: /** * @brief Construct a new RequestHandler object * - * @param adminVerifier The AdminVerificationStrategy to use for verifying the connection for admin access. + * @param adminVerifier The AdminVerificationStrategy to use for verifying the connection for + * admin access. * @param rpcHandler The RPC handler to use for handling the request. */ - RequestHandler(std::shared_ptr adminVerifier, RpcHandlerType& rpcHandler) + RequestHandler( + std::shared_ptr adminVerifier, + RpcHandlerType& rpcHandler + ) : adminVerifier_(std::move(adminVerifier)), rpcHandler_(rpcHandler) { } diff --git a/src/cluster/Backend.cpp b/src/cluster/Backend.cpp index b4a88240a..9a44df18d 100644 --- a/src/cluster/Backend.cpp +++ b/src/cluster/Backend.cpp @@ -113,7 +113,9 @@ Backend::doRead(boost::asio::yield_context yield) auto expectedNodeData = boost::json::try_value_to(json); if (expectedNodeData.has_error()) { - return std::unexpected{fmt::format("Error converting json to ClioNode: {}", nodeDataStr)}; + return std::unexpected{ + fmt::format("Error converting json to ClioNode: {}", nodeDataStr) + }; } *expectedNodeData->uuid = uuid; otherNodesData.push_back(std::move(expectedNodeData).value()); diff --git a/src/cluster/Backend.hpp b/src/cluster/Backend.hpp index 41ea73f83..9dc6196b9 100644 --- a/src/cluster/Backend.hpp +++ b/src/cluster/Backend.hpp @@ -49,12 +49,13 @@ namespace cluster { * @brief Backend communication handler for cluster state synchronization. * * This class manages reading and writing cluster state information to/from the backend database. - * It periodically reads the state of other nodes in the cluster and writes the current node's state, - * enabling cluster-wide coordination and awareness. + * It periodically reads the state of other nodes in the cluster and writes the current node's + * state, enabling cluster-wide coordination and awareness. */ class Backend { public: - /** @brief Type representing cluster data result - either a vector of nodes or an error message */ + /** @brief Type representing cluster data result - either a vector of nodes or an error message + */ using ClusterData = std::expected, std::string>; private: diff --git a/src/cluster/ClioNode.cpp b/src/cluster/ClioNode.cpp index a9dc528e6..1ea7d3b4b 100644 --- a/src/cluster/ClioNode.cpp +++ b/src/cluster/ClioNode.cpp @@ -62,7 +62,9 @@ ClioNode::from(ClioNode::Uuid uuid, etl::WriterStateInterface const& writerState return writerState.isWriting() ? ClioNode::DbRole::Writer : ClioNode::DbRole::NotWriter; }(); - return ClioNode{.uuid = std::move(uuid), .updateTime = std::chrono::system_clock::now(), .dbRole = dbRole}; + return ClioNode{ + .uuid = std::move(uuid), .updateTime = std::chrono::system_clock::now(), .dbRole = dbRole + }; } void @@ -78,7 +80,8 @@ ClioNode tag_invoke(boost::json::value_to_tag, boost::json::value const& jv) { auto const& updateTimeStr = jv.as_object().at(JsonFields::kUPDATE_TIME).as_string(); - auto const updateTime = util::systemTpFromUtcStr(std::string(updateTimeStr), ClioNode::kTIME_FORMAT); + auto const updateTime = + util::systemTpFromUtcStr(std::string(updateTimeStr), ClioNode::kTIME_FORMAT); if (!updateTime.has_value()) { throw std::runtime_error("Failed to parse update time"); } @@ -88,7 +91,8 @@ tag_invoke(boost::json::value_to_tag, boost::json::value const& jv) throw std::runtime_error("Invalid db_role value"); return ClioNode{ - // Json data doesn't contain uuid so leaving it empty here. It will be filled outside of this parsing + // Json data doesn't contain uuid so leaving it empty here. It will be filled outside of + // this parsing .uuid = std::make_shared(), .updateTime = updateTime.value(), .dbRole = static_cast(dbRoleValue) diff --git a/src/cluster/ClioNode.hpp b/src/cluster/ClioNode.hpp index ea2a83e97..9bccf7007 100644 --- a/src/cluster/ClioNode.hpp +++ b/src/cluster/ClioNode.hpp @@ -52,14 +52,22 @@ struct ClioNode { * from the cluster communication mechanism to the slower but more reliable * database-based conflict detection mechanism. */ - enum class DbRole { ReadOnly = 0, LoadingCache = 1, NotWriter = 2, Writer = 3, Fallback = 4, MAX = 4 }; + enum class DbRole { + ReadOnly = 0, + LoadingCache = 1, + NotWriter = 2, + Writer = 3, + Fallback = 4, + MAX = 4 + }; using Uuid = std::shared_ptr; using CUuid = std::shared_ptr; - Uuid uuid; ///< The UUID of the node. - std::chrono::system_clock::time_point updateTime; ///< The time the data about the node was last updated. - DbRole dbRole; ///< The database role of the node + Uuid uuid; ///< The UUID of the node. + std::chrono::system_clock::time_point + updateTime; ///< The time the data about the node was last updated. + DbRole dbRole; ///< The database role of the node /** * @brief Create a ClioNode from writer state. diff --git a/src/cluster/ClusterCommunicationService.hpp b/src/cluster/ClusterCommunicationService.hpp index f73a7cd32..d598a7336 100644 --- a/src/cluster/ClusterCommunicationService.hpp +++ b/src/cluster/ClusterCommunicationService.hpp @@ -38,10 +38,12 @@ namespace cluster { /** - * @brief Service to post and read messages to/from the cluster. It uses a backend to communicate with the cluster. + * @brief Service to post and read messages to/from the cluster. It uses a backend to communicate + * with the cluster. */ class ClusterCommunicationService : public ClusterCommunicationServiceTag { - // TODO: Use util::async::CoroExecutionContext after https://github.com/XRPLF/clio/issues/1973 is implemented + // TODO: Use util::async::CoroExecutionContext after https://github.com/XRPLF/clio/issues/1973 + // is implemented boost::asio::thread_pool ctx_{1}; Backend backend_; Metrics metrics_; diff --git a/src/cluster/Metrics.hpp b/src/cluster/Metrics.hpp index affea41e7..814c1b6e6 100644 --- a/src/cluster/Metrics.hpp +++ b/src/cluster/Metrics.hpp @@ -48,7 +48,8 @@ class Metrics { util::prometheus::Bool isHealthy_ = PrometheusService::boolMetric( "cluster_communication_is_healthy", {}, - "Whether cluster communication service is operating healthy (1 - healthy, 0 - we have a problem)" + "Whether cluster communication service is operating healthy (1 - healthy, 0 - we have a " + "problem)" ); public: @@ -67,7 +68,8 @@ public: * - Node count to reflect the current cluster size * * @param uuid The UUID of the node (unused in current implementation) - * @param clusterData Shared pointer to the current cluster data; may be empty if communication failed + * @param clusterData Shared pointer to the current cluster data; may be empty if communication + * failed */ void onNewState(ClioNode::CUuid uuid, std::shared_ptr clusterData); diff --git a/src/cluster/WriterDecider.cpp b/src/cluster/WriterDecider.cpp index 4713ca807..de11d2f4b 100644 --- a/src/cluster/WriterDecider.cpp +++ b/src/cluster/WriterDecider.cpp @@ -34,13 +34,19 @@ namespace cluster { -WriterDecider::WriterDecider(boost::asio::thread_pool& ctx, std::unique_ptr writerState) +WriterDecider::WriterDecider( + boost::asio::thread_pool& ctx, + std::unique_ptr writerState +) : ctx_(ctx), writerState_(std::move(writerState)) { } void -WriterDecider::onNewState(ClioNode::CUuid selfId, std::shared_ptr clusterData) +WriterDecider::onNewState( + ClioNode::CUuid selfId, + std::shared_ptr clusterData +) { if (not clusterData->has_value()) return; @@ -50,8 +56,9 @@ WriterDecider::onNewState(ClioNode::CUuid selfId, std::shared_ptrclone(), selfId = std::move(selfId), clusterData = clusterData->value()](auto&&) mutable { - auto const selfData = - std::ranges::find_if(clusterData, [&selfId](ClioNode const& node) { return node.uuid == selfId; }); + auto const selfData = std::ranges::find_if( + clusterData, [&selfId](ClioNode const& node) { return node.uuid == selfId; } + ); ASSERT(selfData != clusterData.end(), "Self data should always be in the cluster data"); if (selfData->dbRole == ClioNode::DbRole::Fallback) { @@ -78,7 +85,8 @@ WriterDecider::onNewState(ClioNode::CUuid selfId, std::shared_ptr writerState); + WriterDecider( + boost::asio::thread_pool& ctx, + std::unique_ptr writerState + ); /** * @brief Handles cluster state changes and decides whether this node should be the writer. @@ -66,7 +69,8 @@ public: * - Logs a warning if no nodes in the cluster are allowed to write * * @param selfId The UUID of the current node - * @param clusterData Shared pointer to current cluster data; may be empty if communication failed + * @param clusterData Shared pointer to current cluster data; may be empty if communication + * failed */ void onNewState(ClioNode::CUuid selfId, std::shared_ptr clusterData); diff --git a/src/cluster/impl/RepeatedTask.hpp b/src/cluster/impl/RepeatedTask.hpp index 8e4ef8ea5..9e43c6894 100644 --- a/src/cluster/impl/RepeatedTask.hpp +++ b/src/cluster/impl/RepeatedTask.hpp @@ -92,7 +92,8 @@ public: void stop() { - if (auto expected = State::Running; not state_.compare_exchange_strong(expected, State::Stopped)) + if (auto expected = State::Running; + not state_.compare_exchange_strong(expected, State::Stopped)) return; // Already stopped or not started std::binary_semaphore cancelSemaphore{0}; diff --git a/src/data/AmendmentCenter.cpp b/src/data/AmendmentCenter.cpp index 4863ff0e5..9c43521c4 100644 --- a/src/data/AmendmentCenter.cpp +++ b/src/data/AmendmentCenter.cpp @@ -57,10 +57,15 @@ supportedAmendments() } bool -lookupAmendment(auto const& allAmendments, std::vector const& ledgerAmendments, std::string_view name) +lookupAmendment( + auto const& allAmendments, + std::vector const& ledgerAmendments, + std::string_view name +) { namespace rg = std::ranges; - if (auto const am = rg::find(allAmendments, name, &data::Amendment::name); am != rg::end(allAmendments)) + if (auto const am = rg::find(allAmendments, name, &data::Amendment::name); + am != rg::end(allAmendments)) return rg::find(ledgerAmendments, am->feature) != rg::end(ledgerAmendments); return false; } @@ -70,9 +75,12 @@ lookupAmendment(auto const& allAmendments, std::vector const& l namespace data { namespace impl { -WritingAmendmentKey::WritingAmendmentKey(std::string amendmentName) : AmendmentKey{std::move(amendmentName)} +WritingAmendmentKey::WritingAmendmentKey(std::string amendmentName) + : AmendmentKey{std::move(amendmentName)} { - ASSERT(not supportedAmendments().contains(name), "Attempt to register the same amendment twice"); + ASSERT( + not supportedAmendments().contains(name), "Attempt to register the same amendment twice" + ); supportedAmendments().insert(name); } @@ -96,7 +104,8 @@ operator ripple::uint256() const return Amendment::getAmendmentId(name); } -AmendmentCenter::AmendmentCenter(std::shared_ptr const& backend) : backend_{backend} +AmendmentCenter::AmendmentCenter(std::shared_ptr const& backend) + : backend_{backend} { namespace rg = std::ranges; namespace vs = std::views; @@ -108,7 +117,8 @@ AmendmentCenter::AmendmentCenter(std::shared_ptr const& .name = name, .feature = Amendment::getAmendmentId(name), .isSupportedByXRPL = support != ripple::AmendmentSupport::Unsupported, - .isSupportedByClio = rg::find(supportedAmendments(), name) != rg::end(supportedAmendments()), + .isSupportedByClio = + rg::find(supportedAmendments(), name) != rg::end(supportedAmendments()), .isRetired = support == ripple::AmendmentSupport::Retired }; }), @@ -144,19 +154,28 @@ AmendmentCenter::isEnabled(AmendmentKey const& key, uint32_t seq) const } bool -AmendmentCenter::isEnabled(boost::asio::yield_context yield, AmendmentKey const& key, uint32_t seq) const +AmendmentCenter::isEnabled( + boost::asio::yield_context yield, + AmendmentKey const& key, + uint32_t seq +) const { try { if (auto const listAmendments = fetchAmendmentsList(yield, seq); listAmendments) return lookupAmendment(all_, *listAmendments, key); } catch (std::runtime_error const&) { - return false; // Some old ledger does not contain Amendments ledger object so do best we can for now + return false; // Some old ledger does not contain Amendments ledger object so do best we + // can for now } return false; } std::vector -AmendmentCenter::isEnabled(boost::asio::yield_context yield, std::vector const& keys, uint32_t seq) const +AmendmentCenter::isEnabled( + boost::asio::yield_context yield, + std::vector const& keys, + uint32_t seq +) const { namespace rg = std::ranges; @@ -181,7 +200,11 @@ AmendmentCenter::isEnabled(boost::asio::yield_context yield, std::vector> AmendmentCenter::fetchAmendmentsList(boost::asio::yield_context yield, uint32_t seq) const { // the amendments should always be present on the ledger - auto const amendments = backend_->fetchLedgerObject(ripple::keylet::amendments().key, seq, yield); + auto const amendments = + backend_->fetchLedgerObject(ripple::keylet::amendments().key, seq, yield); if (not amendments.has_value()) throw std::runtime_error("Amendments ledger object must be present in the database"); diff --git a/src/data/AmendmentCenter.hpp b/src/data/AmendmentCenter.hpp index 1da72373c..fb5b7a2cc 100644 --- a/src/data/AmendmentCenter.hpp +++ b/src/data/AmendmentCenter.hpp @@ -62,9 +62,9 @@ struct WritingAmendmentKey : AmendmentKey { */ struct Amendments { // NOTE: if Clio wants to report it supports an Amendment it should be listed here. - // Whether an amendment is obsolete and/or supported by libxrpl is extracted directly from libxrpl. - // If an amendment is in the list below it just means Clio did whatever changes needed to support it. - // Most of the time it's going to be no changes at all. + // Whether an amendment is obsolete and/or supported by libxrpl is extracted directly from + // libxrpl. If an amendment is in the list below it just means Clio did whatever changes needed + // to support it. Most of the time it's going to be no changes at all. /** @cond */ // NOLINTBEGIN(readability-identifier-naming) @@ -256,7 +256,11 @@ public: * @return A vector of bools representing enabled state for each of the given keys */ [[nodiscard]] std::vector - isEnabled(boost::asio::yield_context yield, std::vector const& keys, uint32_t seq) const final; + isEnabled( + boost::asio::yield_context yield, + std::vector const& keys, + uint32_t seq + ) const final; /** * @brief Get an amendment diff --git a/src/data/AmendmentCenterInterface.hpp b/src/data/AmendmentCenterInterface.hpp index d77994a29..aacb99fbe 100644 --- a/src/data/AmendmentCenterInterface.hpp +++ b/src/data/AmendmentCenterInterface.hpp @@ -92,7 +92,11 @@ public: * @return A vector of bools representing enabled state for each of the given keys */ [[nodiscard]] virtual std::vector - isEnabled(boost::asio::yield_context yield, std::vector const& keys, uint32_t seq) const = 0; + isEnabled( + boost::asio::yield_context yield, + std::vector const& keys, + uint32_t seq + ) const = 0; /** * @brief Get an amendment diff --git a/src/data/BackendCounters.cpp b/src/data/BackendCounters.cpp index 819ea7e60..aa9e519c1 100644 --- a/src/data/BackendCounters.cpp +++ b/src/data/BackendCounters.cpp @@ -41,7 +41,10 @@ std::vector const kHISTOGRAM_BUCKETS{1, 2, 5, 10, 20, 50, 100, 200 std::int64_t durationInMillisecondsSince(std::chrono::steady_clock::time_point const startTime) { - return std::chrono::duration_cast(std::chrono::steady_clock::now() - startTime).count(); + return std::chrono::duration_cast( + std::chrono::steady_clock::now() - startTime + ) + .count(); } } // namespace @@ -144,7 +147,10 @@ BackendCounters::registerReadStarted(std::uint64_t const count) } void -BackendCounters::registerReadFinished(std::chrono::steady_clock::time_point const startTime, std::uint64_t const count) +BackendCounters::registerReadFinished( + std::chrono::steady_clock::time_point const startTime, + std::uint64_t const count +) { asyncReadCounters_.registerFinished(count); auto const duration = durationInMillisecondsSince(startTime); @@ -238,7 +244,8 @@ void BackendCounters::AsyncOperationCounters::registerError(std::uint64_t count) { ASSERT( - pendingCounter_.get().value() >= static_cast(count), "Error operations can't be more than pending" + pendingCounter_.get().value() >= static_cast(count), + "Error operations can't be more than pending" ); pendingCounter_.get() -= count; errorCounter_.get() += count; diff --git a/src/data/BackendCounters.hpp b/src/data/BackendCounters.hpp index ab24b2968..4a01edf5e 100644 --- a/src/data/BackendCounters.hpp +++ b/src/data/BackendCounters.hpp @@ -46,7 +46,9 @@ concept SomeBackendCounters = requires(T a) { { a.registerWriteFinished(std::chrono::steady_clock::time_point{}) } -> std::same_as; { a.registerWriteRetry() } -> std::same_as; { a.registerReadStarted(std::uint64_t{}) } -> std::same_as; - { a.registerReadFinished(std::chrono::steady_clock::time_point{}, std::uint64_t{}) } -> std::same_as; + { + a.registerReadFinished(std::chrono::steady_clock::time_point{}, std::uint64_t{}) + } -> std::same_as; { a.registerReadRetry(std::uint64_t{}) } -> std::same_as; { a.registerReadError(std::uint64_t{}) } -> std::same_as; { a.report() } -> std::same_as; diff --git a/src/data/BackendInterface.cpp b/src/data/BackendInterface.cpp index 2a8978fad..8dd5b84f7 100644 --- a/src/data/BackendInterface.cpp +++ b/src/data/BackendInterface.cpp @@ -128,7 +128,8 @@ BackendInterface::fetchLedgerObjects( misses.push_back(keys[i]); } } - LOG(log_.trace()) << "Cache hits = " << keys.size() - misses.size() << " - cache misses = " << misses.size(); + LOG(log_.trace()) << "Cache hits = " << keys.size() - misses.size() + << " - cache misses = " << misses.size(); if (!misses.empty()) { auto objs = doFetchLedgerObjects(misses, sequence, yield); @@ -192,7 +193,9 @@ BackendInterface::fetchBookOffers( ripple::uint256 const bookEnd = ripple::getQualityNext(book); ripple::uint256 uTipIndex = book; std::vector keys; - auto getMillis = [](auto diff) { return std::chrono::duration_cast(diff).count(); }; + auto getMillis = [](auto diff) { + return std::chrono::duration_cast(diff).count(); + }; auto begin = std::chrono::system_clock::now(); std::uint32_t numSucc = 0; std::uint32_t numPages = 0; @@ -233,20 +236,23 @@ BackendInterface::fetchBookOffers( auto mid = std::chrono::system_clock::now(); auto objs = fetchLedgerObjects(keys, ledgerSequence, yield); for (size_t i = 0; i < keys.size() && i < limit; ++i) { - LOG(log_.trace()) << "Key = " << ripple::strHex(keys[i]) << " blob = " << ripple::strHex(objs[i]) + LOG(log_.trace()) << "Key = " << ripple::strHex(keys[i]) + << " blob = " << ripple::strHex(objs[i]) << " ledgerSequence = " << ledgerSequence; ASSERT(!objs[i].empty(), "Ledger object can't be empty"); page.offers.push_back({keys[i], objs[i]}); } auto end = std::chrono::system_clock::now(); LOG(log_.debug()) << "Fetching " << std::to_string(keys.size()) << " offers took " - << std::to_string(getMillis(mid - begin)) << " milliseconds. Fetching next dir took " - << std::to_string(succMillis) << " milliseconds. Fetched next dir " << std::to_string(numSucc) - << " times" - << " Fetching next page of dir took " << std::to_string(pageMillis) << " milliseconds" - << ". num pages = " << std::to_string(numPages) << ". Fetching all objects took " - << std::to_string(getMillis(end - mid)) - << " milliseconds. total time = " << std::to_string(getMillis(end - begin)) << " milliseconds" + << std::to_string(getMillis(mid - begin)) + << " milliseconds. Fetching next dir took " << std::to_string(succMillis) + << " milliseconds. Fetched next dir " << std::to_string(numSucc) << " times" + << " Fetching next page of dir took " << std::to_string(pageMillis) + << " milliseconds" + << ". num pages = " << std::to_string(numPages) + << ". Fetching all objects took " << std::to_string(getMillis(end - mid)) + << " milliseconds. total time = " << std::to_string(getMillis(end - begin)) + << " milliseconds" << " book = " << ripple::strHex(book); return page; @@ -273,7 +279,8 @@ BackendInterface::updateRange(uint32_t newMax) if (range_.has_value() and newMax < range_->maxSequence) { ASSERT( false, - "Range shouldn't exist yet or newMax should be at least range->maxSequence. newMax = {}, " + "Range shouldn't exist yet or newMax should be at least range->maxSequence. newMax = " + "{}, " "range->maxSequence = {}", newMax, range_->maxSequence @@ -339,8 +346,8 @@ BackendInterface::fetchLedgerPage( if (!objects[i].empty()) { page.objects.push_back({keys[i], std::move(objects[i])}); } else if (!outOfOrder) { - LOG(log_.error()) << "Deleted or non-existent object in successor table. key = " << ripple::strHex(keys[i]) - << " - seq = " << ledgerSequence; + LOG(log_.error()) << "Deleted or non-existent object in successor table. key = " + << ripple::strHex(keys[i]) << " - seq = " << ledgerSequence; std::stringstream msg; for (size_t j = 0; j < objects.size(); ++j) { msg << " - " << ripple::strHex(keys[j]); diff --git a/src/data/BackendInterface.hpp b/src/data/BackendInterface.hpp index 7a823c76a..d13a18357 100644 --- a/src/data/BackendInterface.hpp +++ b/src/data/BackendInterface.hpp @@ -109,18 +109,23 @@ synchronous(FnType&& func) using R = typename boost::result_of::type; if constexpr (!std::is_same_v) { R res; - util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) { res = func(yield); }); + util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) { + res = func(yield); + }); ctx.run(); return res; } else { - util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) { func(yield); }); + util::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) { + func(yield); + }); ctx.run(); } } /** - * @brief Synchronously execute the given function object and retry until no DatabaseTimeout is thrown. + * @brief Synchronously execute the given function object and retry until no DatabaseTimeout is + * thrown. * * @tparam FnType The type of function object to execute * @param func The function object to execute @@ -225,7 +230,8 @@ public: fetchLedgerRange() const; /** - * @brief Fetch the specified number of account root object indexes by page, the accounts need to exist for seq. + * @brief Fetch the specified number of account root object indexes by page, the accounts need + * to exist for seq. * * @param number The number of accounts to fetch * @param pageSize The maximum number of accounts per page @@ -296,7 +302,10 @@ public: * @return A vector of TransactionAndMetadata matching the given hashes */ virtual std::vector - fetchTransactions(std::vector const& hashes, boost::asio::yield_context yield) const = 0; + fetchTransactions( + std::vector const& hashes, + boost::asio::yield_context yield + ) const = 0; /** * @brief Fetches all transactions for a specific account. @@ -325,7 +334,10 @@ public: * @return Results as a vector of TransactionAndMetadata */ virtual std::vector - fetchAllTransactionsInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0; + fetchAllTransactionsInLedger( + std::uint32_t ledgerSequence, + boost::asio::yield_context yield + ) const = 0; /** * @brief Fetches all transaction hashes from a specific ledger. @@ -335,7 +347,10 @@ public: * @return Hashes as ripple::uint256 in a vector */ virtual std::vector - fetchAllTransactionHashesInLedger(std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0; + fetchAllTransactionHashesInLedger( + std::uint32_t ledgerSequence, + boost::asio::yield_context yield + ) const = 0; /** * @brief Fetches a specific NFT. @@ -346,7 +361,11 @@ public: * @return NFT object on success; nullopt otherwise */ virtual std::optional - fetchNFT(ripple::uint256 const& tokenID, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0; + fetchNFT( + ripple::uint256 const& tokenID, + std::uint32_t ledgerSequence, + boost::asio::yield_context yield + ) const = 0; /** * @brief Fetches all transactions for a specific NFT. @@ -376,7 +395,8 @@ public: * @param limit Paging limit. * @param cursorIn Optional cursor to allow us to pick up from where we last left off. * @param yield Currently executing coroutine. - * @return NFTs issued by this account, or this issuer/taxon combination if taxon is passed and an optional marker + * @return NFTs issued by this account, or this issuer/taxon combination if taxon is passed and + * an optional marker */ virtual NFTsAndCursor fetchNFTsByIssuer( @@ -410,8 +430,8 @@ public: /** * @brief Fetches a specific ledger object. * - * Currently the real fetch happens in doFetchLedgerObject and fetchLedgerObject attempts to fetch from Cache first - * and only calls out to the real DB if a cache miss occurred. + * Currently the real fetch happens in doFetchLedgerObject and fetchLedgerObject attempts to + * fetch from Cache first and only calls out to the real DB if a cache miss occurred. * * @param key The key of the object * @param sequence The ledger sequence to fetch for @@ -419,7 +439,11 @@ public: * @return The object as a Blob on success; nullopt otherwise */ std::optional - fetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const; + fetchLedgerObject( + ripple::uint256 const& key, + std::uint32_t sequence, + boost::asio::yield_context yield + ) const; /** * @brief Fetches a specific ledger object sequence. @@ -432,13 +456,18 @@ public: * @return The sequence in unit32_t on success; nullopt otherwise */ std::optional - fetchLedgerObjectSeq(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const; + fetchLedgerObjectSeq( + ripple::uint256 const& key, + std::uint32_t sequence, + boost::asio::yield_context yield + ) const; /** * @brief Fetches all ledger objects by their keys. * - * Currently the real fetch happens in doFetchLedgerObjects and fetchLedgerObjects attempts to fetch from Cache - * first and only calls out to the real DB for each of the keys that was not found in the cache. + * Currently the real fetch happens in doFetchLedgerObjects and fetchLedgerObjects attempts to + * fetch from Cache first and only calls out to the real DB for each of the keys that was not + * found in the cache. * * @param keys A vector with the keys of the objects to fetch * @param sequence The ledger sequence to fetch for @@ -461,7 +490,11 @@ public: * @return The object as a Blob on success; nullopt otherwise */ virtual std::optional - doFetchLedgerObject(ripple::uint256 const& key, std::uint32_t sequence, boost::asio::yield_context yield) const = 0; + doFetchLedgerObject( + ripple::uint256 const& key, + std::uint32_t sequence, + boost::asio::yield_context yield + ) const = 0; /** * @brief The database-specific implementation for fetching a ledger object sequence. @@ -531,13 +564,18 @@ public: * @return The successor on success; nullopt otherwise */ std::optional - fetchSuccessorObject(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const; + fetchSuccessorObject( + ripple::uint256 key, + std::uint32_t ledgerSequence, + boost::asio::yield_context yield + ) const; /** * @brief Fetches the successor key. * - * Thea real fetch happens in doFetchSuccessorKey. This function will attempt to lookup the successor in the cache - * first and only if it's not found in the cache will it fetch from the actual DB. + * Thea real fetch happens in doFetchSuccessorKey. This function will attempt to lookup the + * successor in the cache first and only if it's not found in the cache will it fetch from the + * actual DB. * * @param key The key to fetch for * @param ledgerSequence The ledger sequence to fetch for @@ -545,7 +583,11 @@ public: * @return The successor key on success; nullopt otherwise */ std::optional - fetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const; + fetchSuccessorKey( + ripple::uint256 key, + std::uint32_t ledgerSequence, + boost::asio::yield_context yield + ) const; /** * @brief Database-specific implementation of fetching the successor key @@ -556,7 +598,11 @@ public: * @return The successor on success; nullopt otherwise */ virtual std::optional - doFetchSuccessorKey(ripple::uint256 key, std::uint32_t ledgerSequence, boost::asio::yield_context yield) const = 0; + doFetchSuccessorKey( + ripple::uint256 key, + std::uint32_t ledgerSequence, + boost::asio::yield_context yield + ) const = 0; /** * @brief Fetches book offers. @@ -583,7 +629,10 @@ public: * @return The status of the migrator if found; nullopt otherwise */ virtual std::optional - fetchMigratorStatus(std::string const& migratorName, boost::asio::yield_context yield) const = 0; + fetchMigratorStatus( + std::string const& migratorName, + boost::asio::yield_context yield + ) const = 0; /** @brief Return type for fetchClioNodesData() method */ using ClioNodesDataFetchResult = @@ -601,7 +650,8 @@ public: /** * @brief Synchronously fetches the ledger range from DB. * - * This function just wraps hardFetchLedgerRange(boost::asio::yield_context) using synchronous(FnType&&). + * This function just wraps hardFetchLedgerRange(boost::asio::yield_context) using + * synchronous(FnType&&). * * @return The ledger range if available; nullopt otherwise */ diff --git a/src/data/CassandraBackend.hpp b/src/data/CassandraBackend.hpp index e9b716b6d..672bfac59 100644 --- a/src/data/CassandraBackend.hpp +++ b/src/data/CassandraBackend.hpp @@ -102,10 +102,14 @@ public: this->waitForWritesToFinish(); if (!range_) { - executor_.writeSync(schema_->updateLedgerRange, ledgerSequence_, false, ledgerSequence_); + executor_.writeSync( + schema_->updateLedgerRange, ledgerSequence_, false, ledgerSequence_ + ); } - if (not this->executeSyncUpdate(schema_->updateLedgerRange.bind(ledgerSequence_, true, ledgerSequence_ - 1))) { + if (not this->executeSyncUpdate( + schema_->updateLedgerRange.bind(ledgerSequence_, true, ledgerSequence_ - 1) + )) { LOG(log_.warn()) << "Update failed for ledger " << ledgerSequence_; return false; } @@ -139,7 +143,8 @@ public: r.bindAt( 1, std::make_tuple( - cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0, + cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) + : 0, cursorIn.value_or(ripple::uint256(0)) ) ); @@ -170,9 +175,10 @@ public: selectNFTStatements.reserve(nftIDs.size()); std::transform( - std::cbegin(nftIDs), std::cend(nftIDs), std::back_inserter(selectNFTStatements), [&](auto const& nftID) { - return schema_->selectNFT.bind(nftID, ledgerSequence); - } + std::cbegin(nftIDs), + std::cend(nftIDs), + std::back_inserter(selectNFTStatements), + [&](auto const& nftID) { return schema_->selectNFT.bind(nftID, ledgerSequence); } ); auto const nftInfos = executor_.readEach(yield, selectNFTStatements); @@ -181,9 +187,10 @@ public: selectNFTURIStatements.reserve(nftIDs.size()); std::transform( - std::cbegin(nftIDs), std::cend(nftIDs), std::back_inserter(selectNFTURIStatements), [&](auto const& nftID) { - return schema_->selectNFTURI.bind(nftID, ledgerSequence); - } + std::cbegin(nftIDs), + std::cend(nftIDs), + std::back_inserter(selectNFTURIStatements), + [&](auto const& nftID) { return schema_->selectNFTURI.bind(nftID, ledgerSequence); } ); auto const nftUris = executor_.readEach(yield, selectNFTURIStatements); @@ -193,7 +200,8 @@ public: maybeRow.has_value()) { auto [seq, owner, isBurned] = *maybeRow; NFT nft(nftIDs[i], seq, owner, isBurned); - if (auto const maybeUri = nftUris[i].template get(); maybeUri.has_value()) + if (auto const maybeUri = nftUris[i].template get(); + maybeUri.has_value()) nft.uri = *maybeUri; ret.nfts.push_back(nft); } @@ -213,8 +221,9 @@ public: std::optional lastItem; while (liveAccounts.size() < number) { - Statement const statement = lastItem ? schema_->selectAccountFromToken.bind(*lastItem, Limit{pageSize}) - : schema_->selectAccountFromBeginning.bind(Limit{pageSize}); + Statement const statement = lastItem + ? schema_->selectAccountFromToken.bind(*lastItem, Limit{pageSize}) + : schema_->selectAccountFromBeginning.bind(Limit{pageSize}); auto const res = executor_.read(yield, statement); if (res) { diff --git a/src/data/DBHelpers.hpp b/src/data/DBHelpers.hpp index 589e79061..31b0d9cf2 100644 --- a/src/data/DBHelpers.hpp +++ b/src/data/DBHelpers.hpp @@ -83,8 +83,15 @@ struct NFTTransactionsData { * @param meta The transaction metadata * @param txHash The transaction hash */ - NFTTransactionsData(ripple::uint256 const& tokenID, ripple::TxMeta const& meta, ripple::uint256 const& txHash) - : tokenID(tokenID), ledgerSequence(meta.getLgrSeq()), transactionIndex(meta.getIndex()), txHash(txHash) + NFTTransactionsData( + ripple::uint256 const& tokenID, + ripple::TxMeta const& meta, + ripple::uint256 const& txHash + ) + : tokenID(tokenID) + , ledgerSequence(meta.getLgrSeq()) + , transactionIndex(meta.getIndex()) + , txHash(txHash) { } }; @@ -94,11 +101,13 @@ struct NFTTransactionsData { * * Gets written to nf_tokens table and the like. * - * The transaction index is only stored because we want to store only the final state of an NFT per ledger. - * Since we pull this from transactions we keep track of which tx index created this so we can de-duplicate, as it is - * possible for one ledger to have multiple txs that change the state of the same NFT. + * The transaction index is only stored because we want to store only the final state of an NFT per + * ledger. Since we pull this from transactions we keep track of which tx index created this so we + * can de-duplicate, as it is possible for one ledger to have multiple txs that change the state of + * the same NFT. * - * We only set the uri if this is a mint tx, or if we are loading initial state from NFTokenPage objects. + * We only set the uri if this is a mint tx, or if we are loading initial state from NFTokenPage + * objects. */ struct NFTsData { ripple::uint256 tokenID; @@ -113,8 +122,9 @@ struct NFTsData { * @brief Construct a new NFTsData object * * @note This constructor is used when parsing an NFTokenMint tx - * Unfortunately because of the extreme edge case of being able to re-mint an NFT with the same ID, we must - * explicitly record a null URI. For this reason, we _always_ write this field as a result of this tx. + * Unfortunately because of the extreme edge case of being able to re-mint an NFT with the same + * ID, we must explicitly record a null URI. For this reason, we _always_ write this field as a + * result of this tx. * * @param tokenID The token ID * @param owner The owner @@ -127,7 +137,11 @@ struct NFTsData { ripple::Blob const& uri, ripple::TxMeta const& meta ) - : tokenID(tokenID), ledgerSequence(meta.getLgrSeq()), transactionIndex(meta.getIndex()), owner(owner), uri(uri) + : tokenID(tokenID) + , ledgerSequence(meta.getLgrSeq()) + , transactionIndex(meta.getIndex()) + , owner(owner) + , uri(uri) { } @@ -141,7 +155,12 @@ struct NFTsData { * @param meta The transaction metadata * @param isBurned Whether the NFT is burned */ - NFTsData(ripple::uint256 const& tokenID, ripple::AccountID const& owner, ripple::TxMeta const& meta, bool isBurned) + NFTsData( + ripple::uint256 const& tokenID, + ripple::AccountID const& owner, + ripple::TxMeta const& meta, + bool isBurned + ) : tokenID(tokenID) , ledgerSequence(meta.getLgrSeq()) , transactionIndex(meta.getIndex()) @@ -154,8 +173,9 @@ struct NFTsData { * @brief Construct a new NFTsData object * * @note This constructor is used when parsing an NFTokenPage directly from ledger state. - * Unfortunately because of the extreme edge case of being able to re-mint an NFT with the same ID, we must - * explicitly record a null URI. For this reason, we _always_ write this field as a result of this tx. + * Unfortunately because of the extreme edge case of being able to re-mint an NFT with the same + * ID, we must explicitly record a null URI. For this reason, we _always_ write this field as a + * result of this tx. * * @param tokenID The token ID * @param ledgerSequence The ledger sequence diff --git a/src/data/KeyspaceBackend.hpp b/src/data/KeyspaceBackend.hpp index eaf74dd96..887faba64 100644 --- a/src/data/KeyspaceBackend.hpp +++ b/src/data/KeyspaceBackend.hpp @@ -102,11 +102,17 @@ public: // This would be the first write to the table. // In this case, insert both min_sequence/max_sequence range into the table. if (not range_.has_value()) { - executor_.writeSync(schema_->insertLedgerRange, /* isLatestLedger =*/false, ledgerSequence_); - executor_.writeSync(schema_->insertLedgerRange, /* isLatestLedger =*/true, ledgerSequence_); + executor_.writeSync( + schema_->insertLedgerRange, /* isLatestLedger =*/false, ledgerSequence_ + ); + executor_.writeSync( + schema_->insertLedgerRange, /* isLatestLedger =*/true, ledgerSequence_ + ); } - if (not this->executeSyncUpdate(schema_->updateLedgerRange.bind(ledgerSequence_, true, ledgerSequence_ - 1))) { + if (not this->executeSyncUpdate( + schema_->updateLedgerRange.bind(ledgerSequence_, true, ledgerSequence_ - 1) + )) { log_.warn() << "Update failed for ledger " << ledgerSequence_; return false; } @@ -131,7 +137,8 @@ public: nftIDs = fetchNFTIDsByTaxon(issuer, *taxon, limit, cursorIn, yield); } else { // Amazon Keyspaces Workflow for non-taxon queries - auto const startTaxon = cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0; + auto const startTaxon = + cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0; auto const startTokenID = cursorIn.value_or(ripple::uint256(0)); Statement const firstQuery = schema_->selectNFTIDsByIssuerTaxon.bind(issuer); @@ -163,10 +170,10 @@ public: /** * @brief (Unsupported in Keyspaces) Fetches account root object indexes by page. - * @note Loading the cache by enumerating all accounts is currently unsupported by the AWS Keyspaces backend. - * This function's logic relies on "PER PARTITION LIMIT 1", which Keyspaces does not support, and there is - * no efficient alternative. This is acceptable as the cache is primarily loaded via diffs. Calling this - * function will throw an exception. + * @note Loading the cache by enumerating all accounts is currently unsupported by the AWS + * Keyspaces backend. This function's logic relies on "PER PARTITION LIMIT 1", which Keyspaces + * does not support, and there is no efficient alternative. This is acceptable as the cache is + * primarily loaded via diffs. Calling this function will throw an exception. * * @param number The total number of accounts to fetch. * @param pageSize The maximum number of accounts per page. @@ -220,7 +227,8 @@ private: { std::vector nftIDs; - auto const startTaxon = cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0; + auto const startTaxon = + cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0; auto const startTokenID = cursorIn.value_or(ripple::uint256(0)); Statement firstQuery = schema_->selectNFTIDsByIssuerTaxon.bind(issuer); @@ -250,7 +258,8 @@ private: } /** - * @brief Takes a list of NFT IDs, fetches their full data, and assembles the final result with a cursor. + * @brief Takes a list of NFT IDs, fetches their full data, and assembles the final result with + * a cursor. */ NFTsAndCursor populateNFTsAndCreateCursor( @@ -273,17 +282,19 @@ private: std::vector selectNFTStatements; selectNFTStatements.reserve(nftIDs.size()); std::transform( - std::cbegin(nftIDs), std::cend(nftIDs), std::back_inserter(selectNFTStatements), [&](auto const& nftID) { - return schema_->selectNFT.bind(nftID, ledgerSequence); - } + std::cbegin(nftIDs), + std::cend(nftIDs), + std::back_inserter(selectNFTStatements), + [&](auto const& nftID) { return schema_->selectNFT.bind(nftID, ledgerSequence); } ); std::vector selectNFTURIStatements; selectNFTURIStatements.reserve(nftIDs.size()); std::transform( - std::cbegin(nftIDs), std::cend(nftIDs), std::back_inserter(selectNFTURIStatements), [&](auto const& nftID) { - return schema_->selectNFTURI.bind(nftID, ledgerSequence); - } + std::cbegin(nftIDs), + std::cend(nftIDs), + std::back_inserter(selectNFTURIStatements), + [&](auto const& nftID) { return schema_->selectNFTURI.bind(nftID, ledgerSequence); } ); auto const nftInfos = executor_.readEach(yield, selectNFTStatements); @@ -295,7 +306,8 @@ private: maybeRow.has_value()) { auto [seq, owner, isBurned] = *maybeRow; NFT nft(nftIDs[i], seq, owner, isBurned); - if (auto const maybeUri = nftUris[i].template get(); maybeUri.has_value()) + if (auto const maybeUri = nftUris[i].template get(); + maybeUri.has_value()) nft.uri = *maybeUri; ret.nfts.push_back(nft); } diff --git a/src/data/LedgerCache.cpp b/src/data/LedgerCache.cpp index b48748620..c4549199d 100644 --- a/src/data/LedgerCache.cpp +++ b/src/data/LedgerCache.cpp @@ -254,7 +254,8 @@ LedgerCache::getSuccessorHitRate() const { if (successorReqCounter_.get().value() == 0u) return 1; - return static_cast(successorHitCounter_.get().value()) / successorReqCounter_.get().value(); + return static_cast(successorHitCounter_.get().value()) / + successorReqCounter_.get().value(); } std::expected @@ -266,7 +267,9 @@ LedgerCache::saveToFile(std::string const& path) const impl::LedgerCacheFile file{path}; std::shared_lock const lock{mtx_}; - impl::LedgerCacheFile::DataView const data{.latestSeq = latestSeq_, .map = map_, .deleted = deleted_}; + impl::LedgerCacheFile::DataView const data{ + .latestSeq = latestSeq_, .map = map_, .deleted = deleted_ + }; return file.write(data); } diff --git a/src/data/LedgerCache.hpp b/src/data/LedgerCache.hpp index b6346f47a..d4194cfd9 100644 --- a/src/data/LedgerCache.hpp +++ b/src/data/LedgerCache.hpp @@ -58,26 +58,34 @@ public: private: // counters for fetchLedgerObject(s) hit rate - std::reference_wrapper objectReqCounter_{PrometheusService::counterInt( - "ledger_cache_counter_total_number", - util::prometheus::Labels({{"type", "request"}, {"fetch", "ledger_objects"}}), - "LedgerCache statistics" - )}; - std::reference_wrapper objectHitCounter_{PrometheusService::counterInt( - "ledger_cache_counter_total_number", - util::prometheus::Labels({{"type", "cache_hit"}, {"fetch", "ledger_objects"}}) - )}; + std::reference_wrapper objectReqCounter_{ + PrometheusService::counterInt( + "ledger_cache_counter_total_number", + util::prometheus::Labels({{"type", "request"}, {"fetch", "ledger_objects"}}), + "LedgerCache statistics" + ) + }; + std::reference_wrapper objectHitCounter_{ + PrometheusService::counterInt( + "ledger_cache_counter_total_number", + util::prometheus::Labels({{"type", "cache_hit"}, {"fetch", "ledger_objects"}}) + ) + }; // counters for fetchSuccessorKey hit rate - std::reference_wrapper successorReqCounter_{PrometheusService::counterInt( - "ledger_cache_counter_total_number", - util::prometheus::Labels({{"type", "request"}, {"fetch", "successor_key"}}), - "ledgerCache" - )}; - std::reference_wrapper successorHitCounter_{PrometheusService::counterInt( - "ledger_cache_counter_total_number", - util::prometheus::Labels({{"type", "cache_hit"}, {"fetch", "successor_key"}}) - )}; + std::reference_wrapper successorReqCounter_{ + PrometheusService::counterInt( + "ledger_cache_counter_total_number", + util::prometheus::Labels({{"type", "request"}, {"fetch", "successor_key"}}), + "ledgerCache" + ) + }; + std::reference_wrapper successorHitCounter_{ + PrometheusService::counterInt( + "ledger_cache_counter_total_number", + util::prometheus::Labels({{"type", "cache_hit"}, {"fetch", "successor_key"}}) + ) + }; CacheMap map_; CacheMap deleted_; @@ -96,7 +104,8 @@ private: "Whether ledger cache is disabled or not" )}; - // temporary set to prevent background thread from writing already deleted data. not used when cache is full + // temporary set to prevent background thread from writing already deleted data. not used when + // cache is full std::unordered_set> deletes_; public: diff --git a/src/data/LedgerCacheInterface.hpp b/src/data/LedgerCacheInterface.hpp index d2ff7e488..ec4cd67a1 100644 --- a/src/data/LedgerCacheInterface.hpp +++ b/src/data/LedgerCacheInterface.hpp @@ -126,9 +126,9 @@ public: /** * @brief Sets the full flag to true. * - * This is used when cache loaded in its entirety at startup of the application. This can be either loaded from DB, - * populated together with initial ledger download (on first run) or downloaded from a peer node (specified in - * config). + * This is used when cache loaded in its entirety at startup of the application. This can be + * either loaded from DB, populated together with initial ledger download (on first run) or + * downloaded from a peer node (specified in config). */ virtual void setFull() = 0; @@ -152,13 +152,15 @@ public: size() const = 0; /** - * @return A number representing the success rate of hitting an object in the cache versus missing it. + * @return A number representing the success rate of hitting an object in the cache versus + * missing it. */ virtual float getObjectHitRate() const = 0; /** - * @return A number representing the success rate of hitting a successor in the cache versus missing it. + * @return A number representing the success rate of hitting a successor in the cache versus + * missing it. */ virtual float getSuccessorHitRate() const = 0; diff --git a/src/data/LedgerCacheSaver.cpp b/src/data/LedgerCacheSaver.cpp index 3d4d27e42..66348f7d0 100644 --- a/src/data/LedgerCacheSaver.cpp +++ b/src/data/LedgerCacheSaver.cpp @@ -29,7 +29,10 @@ namespace data { -LedgerCacheSaver::LedgerCacheSaver(util::config::ClioConfigDefinition const& config, LedgerCacheInterface const& cache) +LedgerCacheSaver::LedgerCacheSaver( + util::config::ClioConfigDefinition const& config, + LedgerCacheInterface const& cache +) : cacheFilePath_(config.maybeValue("cache.file.path")) , cache_(cache) , isAsync_(config.get("cache.file.async_save")) @@ -51,11 +54,14 @@ LedgerCacheSaver::save() } LOG(util::LogService::info()) << "Saving ledger cache to " << *cacheFilePath_; - if (auto const [success, durationMs] = util::timed([&]() { return cache_.get().saveToFile(*cacheFilePath_); }); + if (auto const [success, durationMs] = + util::timed([&]() { return cache_.get().saveToFile(*cacheFilePath_); }); success.has_value()) { - LOG(util::LogService::info()) << "Successfully saved ledger cache in " << durationMs << " ms"; + LOG(util::LogService::info()) + << "Successfully saved ledger cache in " << durationMs << " ms"; } else { - LOG(util::LogService::error()) << "Error saving LedgerCache to file: " << success.error(); + LOG(util::LogService::error()) + << "Error saving LedgerCache to file: " << success.error(); } }); if (not isAsync_) { diff --git a/src/data/LedgerCacheSaver.hpp b/src/data/LedgerCacheSaver.hpp index 9d21ea4a8..5db403322 100644 --- a/src/data/LedgerCacheSaver.hpp +++ b/src/data/LedgerCacheSaver.hpp @@ -62,7 +62,10 @@ public: * @param config The configuration object containing the cache file path setting * @param cache Reference to the ledger cache interface to be saved */ - LedgerCacheSaver(util::config::ClioConfigDefinition const& config, LedgerCacheInterface const& cache); + LedgerCacheSaver( + util::config::ClioConfigDefinition const& config, + LedgerCacheInterface const& cache + ); /** * @brief Destructor that ensures the saving thread is properly joined. diff --git a/src/data/Types.hpp b/src/data/Types.hpp index 175583efa..b8cf6598e 100644 --- a/src/data/Types.hpp +++ b/src/data/Types.hpp @@ -81,8 +81,16 @@ struct TransactionAndMetadata { * @param ledgerSequence The ledger sequence * @param date The date */ - TransactionAndMetadata(Blob transaction, Blob metadata, std::uint32_t ledgerSequence, std::uint32_t date) - : transaction{std::move(transaction)}, metadata{std::move(metadata)}, ledgerSequence{ledgerSequence}, date{date} + TransactionAndMetadata( + Blob transaction, + Blob metadata, + std::uint32_t ledgerSequence, + std::uint32_t date + ) + : transaction{std::move(transaction)} + , metadata{std::move(metadata)} + , ledgerSequence{ledgerSequence} + , date{date} { } @@ -192,7 +200,11 @@ struct NFT { ripple::AccountID const& owner, Blob uri, bool isBurned) - : tokenID{tokenID}, ledgerSequence{ledgerSequence}, owner{owner}, uri{std::move(uri)}, isBurned{isBurned} + : tokenID{tokenID} + , ledgerSequence{ledgerSequence} + , owner{owner} + , uri{std::move(uri)} + , isBurned{isBurned} { } @@ -204,7 +216,10 @@ struct NFT { * @param owner The owner * @param isBurned Whether the token is burned */ - NFT(ripple::uint256 const& tokenID, std::uint32_t ledgerSequence, ripple::AccountID const& owner, bool isBurned) + NFT(ripple::uint256 const& tokenID, + std::uint32_t ledgerSequence, + ripple::AccountID const& owner, + bool isBurned) : NFT(tokenID, ledgerSequence, owner, {}, isBurned) { } @@ -212,8 +227,8 @@ struct NFT { /** * @brief Check if the NFT is the same as another * - * Clearly two tokens are the same if they have the same ID, but this struct stores the state of a given - * token at a given ledger sequence, so we also need to compare with ledgerSequence. + * Clearly two tokens are the same if they have the same ID, but this struct stores the state of + * a given token at a given ledger sequence, so we also need to compare with ledgerSequence. * * @param other The other NFT * @return true if they are the same; false otherwise @@ -293,7 +308,8 @@ struct AmendmentKey { * @brief Construct a new AmendmentKey * @param val Anything convertible to a string */ - AmendmentKey(std::convertible_to auto&& val) : name{std::forward(val)} + AmendmentKey(std::convertible_to auto&& val) + : name{std::forward(val)} { } @@ -315,8 +331,14 @@ struct AmendmentKey { operator<=>(AmendmentKey const& other) const = default; }; -constexpr ripple::uint256 kFIRST_KEY{"0000000000000000000000000000000000000000000000000000000000000000"}; -constexpr ripple::uint256 kLAST_KEY{"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"}; -constexpr ripple::uint256 kHI192{"0000000000000000000000000000000000000000000000001111111111111111"}; +constexpr ripple::uint256 kFIRST_KEY{ + "0000000000000000000000000000000000000000000000000000000000000000" +}; +constexpr ripple::uint256 kLAST_KEY{ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; +constexpr ripple::uint256 kHI192{ + "0000000000000000000000000000000000000000000000001111111111111111" +}; } // namespace data diff --git a/src/data/cassandra/CassandraBackendFamily.hpp b/src/data/cassandra/CassandraBackendFamily.hpp index ad917e129..96a459984 100644 --- a/src/data/cassandra/CassandraBackendFamily.hpp +++ b/src/data/cassandra/CassandraBackendFamily.hpp @@ -104,7 +104,11 @@ public: * @param cache The ledger cache * @param readOnly Whether the database should be in readonly mode */ - CassandraBackendFamily(SettingsProviderType settingsProvider, data::LedgerCacheInterface& cache, bool readOnly) + CassandraBackendFamily( + SettingsProviderType settingsProvider, + data::LedgerCacheInterface& cache, + bool readOnly + ) : BackendInterface(cache) , settingsProvider_{std::move(settingsProvider)} , schema_{settingsProvider_} @@ -116,8 +120,8 @@ public: if (not readOnly) { if (auto const res = handle_.execute(schema_.createKeyspace); not res.has_value()) { - // on datastax, creation of keyspaces can be configured to only be done thru the admin - // interface. this does not mean that the keyspace does not already exist tho. + // on datastax, creation of keyspaces can be configured to only be done thru the + // admin interface. this does not mean that the keyspace does not already exist tho. if (res.error().code() != CASS_ERROR_SERVER_UNAUTHORIZED) throw std::runtime_error("Could not create keyspace: " + res.error()); } @@ -130,7 +134,8 @@ public: schema_.prepareStatements(handle_); } catch (std::runtime_error const& ex) { auto const error = fmt::format( - "Failed to prepare the statements: {}; readOnly: {}. ReadOnly should be turned off or another Clio " + "Failed to prepare the statements: {}; readOnly: {}. ReadOnly should be turned off " + "or another Clio " "node with write access to DB should be started first.", ex.what(), readOnly @@ -169,8 +174,8 @@ public: auto cursor = txnCursor; if (cursor) { statement.bindAt(1, cursor->asTuple()); - LOG(log_.debug()) << "account = " << ripple::strHex(account) << " tuple = " << cursor->ledgerSequence - << cursor->transactionIndex; + LOG(log_.debug()) << "account = " << ripple::strHex(account) + << " tuple = " << cursor->ledgerSequence << cursor->transactionIndex; } else { auto const seq = forward ? rng->minSequence : rng->maxSequence; auto const placeHolder = forward ? 0u : std::numeric_limits::max(); @@ -195,7 +200,8 @@ public: auto numRows = results.numRows(); LOG(log_.info()) << "num_rows = " << numRows; - for (auto [hash, data] : extract>(results)) { + for (auto [hash, data] : + extract>(results)) { hashes.push_back(hash); if (--numRows == 0) { LOG(log_.debug()) << "Setting cursor"; @@ -251,7 +257,10 @@ public: } std::optional - fetchLedgerBySequence(std::uint32_t const sequence, boost::asio::yield_context yield) const override + fetchLedgerBySequence( + std::uint32_t const sequence, + boost::asio::yield_context yield + ) const override { if (auto const lock = ledgerCache_.get(); lock.has_value() && lock->seq == sequence) return lock->ledger; @@ -259,7 +268,8 @@ public: auto const res = executor_.read(yield, schema_->selectLedgerBySeq, sequence); if (res) { if (auto const& result = res.value(); result) { - if (auto const maybeValue = result.template get>(); maybeValue) { + if (auto const maybeValue = result.template get>(); + maybeValue) { auto const header = util::deserializeHeader(ripple::makeSlice(*maybeValue)); ledgerCache_.put(FetchLedgerCache::CacheEntry{header, sequence}); return header; @@ -336,7 +346,10 @@ public: } std::vector - fetchAllTransactionsInLedger(std::uint32_t const ledgerSequence, boost::asio::yield_context yield) const override + fetchAllTransactionsInLedger( + std::uint32_t const ledgerSequence, + boost::asio::yield_context yield + ) const override { auto hashes = fetchAllTransactionHashesInLedger(ledgerSequence, yield); return fetchTransactions(hashes, yield); @@ -349,7 +362,8 @@ public: ) const override { auto start = std::chrono::system_clock::now(); - auto const res = executor_.read(yield, schema_->selectAllTransactionHashesInLedger, ledgerSequence); + auto const res = + executor_.read(yield, schema_->selectAllTransactionHashesInLedger, ledgerSequence); if (not res) { LOG(log_.error()) << "Could not fetch all transaction hashes: " << res.error(); @@ -368,9 +382,12 @@ public: hashes.push_back(std::move(hash)); auto end = std::chrono::system_clock::now(); - LOG(log_.debug()) << "Fetched " << hashes.size() << " transaction hashes from database in " - << std::chrono::duration_cast(end - start).count() - << " milliseconds"; + LOG( + log_.debug() + ) << "Fetched " + << hashes.size() << " transaction hashes from database in " + << std::chrono::duration_cast(end - start).count() + << " milliseconds"; return hashes; } @@ -386,7 +403,8 @@ public: if (not res) return std::nullopt; - if (auto const maybeRow = res->template get(); maybeRow) { + if (auto const maybeRow = res->template get(); + maybeRow) { auto [seq, owner, isBurned] = *maybeRow; auto result = std::make_optional(tokenID, seq, owner, isBurned); @@ -437,8 +455,8 @@ public: auto cursor = cursorIn; if (cursor) { statement.bindAt(1, cursor->asTuple()); - LOG(log_.debug()) << "token_id = " << ripple::strHex(tokenID) << " tuple = " << cursor->ledgerSequence - << cursor->transactionIndex; + LOG(log_.debug()) << "token_id = " << ripple::strHex(tokenID) + << " tuple = " << cursor->ledgerSequence << cursor->transactionIndex; } else { auto const seq = forward ? rng->minSequence : rng->maxSequence; auto const placeHolder = forward ? 0 : std::numeric_limits::max(); @@ -461,7 +479,8 @@ public: auto numRows = results.numRows(); LOG(log_.info()) << "num_rows = " << numRows; - for (auto [hash, data] : extract>(results)) { + for (auto [hash, data] : + extract>(results)) { hashes.push_back(hash); if (--numRows == 0) { LOG(log_.debug()) << "Setting cursor"; @@ -495,7 +514,11 @@ public: ) const override { auto const holderEntries = executor_.read( - yield, schema_->selectMPTHolders, mptID, cursorIn.value_or(ripple::AccountID(0)), Limit{limit} + yield, + schema_->selectMPTHolders, + mptID, + cursorIn.value_or(ripple::AccountID(0)), + Limit{limit} ); auto const& holderResults = holderEntries.value(); @@ -513,7 +536,9 @@ public: auto mptObjects = doFetchLedgerObjects(mptKeys, ledgerSequence, yield); - auto it = std::remove_if(mptObjects.begin(), mptObjects.end(), [](Blob const& mpt) { return mpt.empty(); }); + auto it = std::remove_if(mptObjects.begin(), mptObjects.end(), [](Blob const& mpt) { + return mpt.empty(); + }); mptObjects.erase(it, mptObjects.end()); @@ -531,7 +556,8 @@ public: boost::asio::yield_context yield ) const override { - LOG(log_.debug()) << "Fetching ledger object for seq " << sequence << ", key = " << ripple::to_string(key); + LOG(log_.debug()) << "Fetching ledger object for seq " << sequence + << ", key = " << ripple::to_string(key); if (auto const res = executor_.read(yield, schema_->selectObject, key, sequence); res) { if (auto const result = res->template get(); result) { if (result->size()) @@ -553,7 +579,8 @@ public: boost::asio::yield_context yield ) const override { - LOG(log_.debug()) << "Fetching ledger object for seq " << sequence << ", key = " << ripple::to_string(key); + LOG(log_.debug()) << "Fetching ledger object for seq " << sequence + << ", key = " << ripple::to_string(key); if (auto const res = executor_.read(yield, schema_->selectObject, key, sequence); res) { if (auto const result = res->template get(); result) { auto [_, seq] = result.value(); @@ -571,7 +598,8 @@ public: fetchTransaction(ripple::uint256 const& hash, boost::asio::yield_context yield) const override { if (auto const res = executor_.read(yield, schema_->selectTransaction, hash); res) { - if (auto const maybeValue = res->template get(); maybeValue) { + if (auto const maybeValue = res->template get(); + maybeValue) { auto [transaction, meta, seq, date] = *maybeValue; return std::make_optional(transaction, meta, seq, date); } @@ -591,7 +619,8 @@ public: boost::asio::yield_context yield ) const override { - if (auto const res = executor_.read(yield, schema_->selectSuccessor, key, ledgerSequence); res) { + if (auto const res = executor_.read(yield, schema_->selectSuccessor, key, ledgerSequence); + res) { if (auto const result = res->template get(); result) { if (*result == kLAST_KEY) return std::nullopt; @@ -607,7 +636,10 @@ public: } std::vector - fetchTransactions(std::vector const& hashes, boost::asio::yield_context yield) const override + fetchTransactions( + std::vector const& hashes, + boost::asio::yield_context yield + ) const override { if (hashes.empty()) return {}; @@ -622,9 +654,10 @@ public: auto const timeDiff = util::timed([this, yield, &results, &hashes, &statements]() { // TODO: seems like a job for "hash IN (list of hashes)" instead? std::transform( - std::cbegin(hashes), std::cend(hashes), std::back_inserter(statements), [this](auto const& hash) { - return schema_->selectTransaction.bind(hash); - } + std::cbegin(hashes), + std::cend(hashes), + std::back_inserter(statements), + [this](auto const& hash) { return schema_->selectTransaction.bind(hash); } ); auto const entries = executor_.readEach(yield, statements); @@ -633,7 +666,8 @@ public: std::cend(entries), std::back_inserter(results), [](auto const& res) -> TransactionAndMetadata { - if (auto const maybeRow = res.template get(); maybeRow) + if (auto const maybeRow = res.template get(); + maybeRow) return *maybeRow; return {}; @@ -642,8 +676,8 @@ public: }); ASSERT(numHashes == results.size(), "Number of hashes and results must match"); - LOG(log_.debug()) << "Fetched " << numHashes << " transactions from database in " << timeDiff - << " milliseconds"; + LOG(log_.debug()) << "Fetched " << numHashes << " transactions from database in " + << timeDiff << " milliseconds"; return results; } @@ -668,14 +702,18 @@ public: // TODO: seems like a job for "key IN (list of keys)" instead? std::transform( - std::cbegin(keys), std::cend(keys), std::back_inserter(statements), [this, &sequence](auto const& key) { - return schema_->selectObject.bind(key, sequence); - } + std::cbegin(keys), + std::cend(keys), + std::back_inserter(statements), + [this, &sequence](auto const& key) { return schema_->selectObject.bind(key, sequence); } ); auto const entries = executor_.readEach(yield, statements); std::transform( - std::cbegin(entries), std::cend(entries), std::back_inserter(results), [](auto const& res) -> Blob { + std::cbegin(entries), + std::cend(entries), + std::back_inserter(results), + [](auto const& res) -> Blob { if (auto const maybeValue = res.template get(); maybeValue) return *maybeValue; @@ -688,34 +726,40 @@ public: } std::vector - fetchLedgerDiff(std::uint32_t const ledgerSequence, boost::asio::yield_context yield) const override + fetchLedgerDiff( + std::uint32_t const ledgerSequence, + boost::asio::yield_context yield + ) const override { - auto const [keys, timeDiff] = util::timed([this, &ledgerSequence, yield]() -> std::vector { - auto const res = executor_.read(yield, schema_->selectDiff, ledgerSequence); - if (not res) { - LOG(log_.error()) << "Could not fetch ledger diff: " << res.error() << "; ledger = " << ledgerSequence; - return {}; - } + auto const [keys, timeDiff] = + util::timed([this, &ledgerSequence, yield]() -> std::vector { + auto const res = executor_.read(yield, schema_->selectDiff, ledgerSequence); + if (not res) { + LOG(log_.error()) << "Could not fetch ledger diff: " << res.error() + << "; ledger = " << ledgerSequence; + return {}; + } - auto const& results = res.value(); - if (not results) { - LOG(log_.error()) << "Could not fetch ledger diff - no rows; ledger = " << ledgerSequence; - return {}; - } + auto const& results = res.value(); + if (not results) { + LOG(log_.error()) + << "Could not fetch ledger diff - no rows; ledger = " << ledgerSequence; + return {}; + } - std::vector resultKeys; - for (auto [key] : extract(results)) - resultKeys.push_back(key); + std::vector resultKeys; + for (auto [key] : extract(results)) + resultKeys.push_back(key); - return resultKeys; - }); + return resultKeys; + }); // one of the above errors must have happened if (keys.empty()) return {}; - LOG(log_.debug()) << "Fetched " << keys.size() << " diff hashes from database in " << timeDiff - << " milliseconds"; + LOG(log_.debug()) << "Fetched " << keys.size() << " diff hashes from database in " + << timeDiff << " milliseconds"; auto const objs = fetchLedgerObjects(keys, ledgerSequence, yield); std::vector results; @@ -733,7 +777,10 @@ public: } std::optional - fetchMigratorStatus(std::string const& migratorName, boost::asio::yield_context yield) const override + fetchMigratorStatus( + std::string const& migratorName, + boost::asio::yield_context yield + ) const override { auto const res = executor_.read(yield, schema_->selectMigratorStatus, Text(migratorName)); if (not res) { @@ -771,7 +818,8 @@ public: void doWriteLedgerObject(std::string&& key, std::uint32_t const seq, std::string&& blob) override { - LOG(log_.trace()) << " Writing ledger object " << key.size() << ":" << seq << " [" << blob.size() << " bytes]"; + LOG(log_.trace()) << " Writing ledger object " << key.size() << ":" << seq << " [" + << blob.size() << " bytes]"; if (range_) executor_.write(schema_->insertDiff, seq, key); @@ -783,7 +831,8 @@ public: writeSuccessor(std::string&& key, std::uint32_t const seq, std::string&& successor) override { LOG(log_.trace()) << "Writing successor. key = " << key.size() << " bytes. " - << " seq = " << std::to_string(seq) << " successor = " << successor.size() << " bytes."; + << " seq = " << std::to_string(seq) << " successor = " << successor.size() + << " bytes."; ASSERT(!key.empty(), "Key must not be empty"); ASSERT(!successor.empty(), "Successor must not be empty"); @@ -797,13 +846,15 @@ public: statements.reserve(data.size() * 10); // assume 10 transactions avg for (auto& record : data) { - std::ranges::transform(record.accounts, std::back_inserter(statements), [this, &record](auto&& account) { - return schema_->insertAccountTx.bind( - std::forward(account), - std::make_tuple(record.ledgerSequence, record.transactionIndex), - record.txHash - ); - }); + std::ranges::transform( + record.accounts, std::back_inserter(statements), [this, &record](auto&& account) { + return schema_->insertAccountTx.bind( + std::forward(account), + std::make_tuple(record.ledgerSequence, record.transactionIndex), + record.txHash + ); + } + ); } executor_.write(std::move(statements)); @@ -815,13 +866,15 @@ public: std::vector statements; statements.reserve(record.accounts.size()); - std::ranges::transform(record.accounts, std::back_inserter(statements), [this, &record](auto&& account) { - return schema_->insertAccountTx.bind( - std::forward(account), - std::make_tuple(record.ledgerSequence, record.transactionIndex), - record.txHash - ); - }); + std::ranges::transform( + record.accounts, std::back_inserter(statements), [this, &record](auto&& account) { + return schema_->insertAccountTx.bind( + std::forward(account), + std::make_tuple(record.ledgerSequence, record.transactionIndex), + record.txHash + ); + } + ); executor_.write(std::move(statements)); } @@ -834,7 +887,9 @@ public: std::ranges::transform(data, std::back_inserter(statements), [this](auto const& record) { return schema_->insertNFTTx.bind( - record.tokenID, std::make_tuple(record.ledgerSequence, record.transactionIndex), record.txHash + record.tokenID, + std::make_tuple(record.ledgerSequence, record.transactionIndex), + record.txHash ); }); @@ -854,7 +909,12 @@ public: executor_.write(schema_->insertLedgerTransaction, seq, hash); executor_.write( - schema_->insertTransaction, std::move(hash), seq, date, std::move(transaction), std::move(metadata) + schema_->insertTransaction, + std::move(hash), + seq, + date, + std::move(transaction), + std::move(metadata) ); } @@ -866,9 +926,9 @@ public: for (NFTsData const& record : data) { if (!record.onlyUriChanged) { - statements.push_back( - schema_->insertNFT.bind(record.tokenID, record.ledgerSequence, record.owner, record.isBurned) - ); + statements.push_back(schema_->insertNFT.bind( + record.tokenID, record.ledgerSequence, record.owner, record.isBurned + )); // If `uri` is set (and it can be set to an empty uri), we know this // is a net-new NFT. That is, this NFT has not been seen before by @@ -881,15 +941,15 @@ public: static_cast(ripple::nft::getTaxon(record.tokenID)), record.tokenID )); - statements.push_back( - schema_->insertNFTURI.bind(record.tokenID, record.ledgerSequence, record.uri.value()) - ); + statements.push_back(schema_->insertNFTURI.bind( + record.tokenID, record.ledgerSequence, record.uri.value() + )); } } else { // only uri changed, we update the uri table only - statements.push_back( - schema_->insertNFTURI.bind(record.tokenID, record.ledgerSequence, record.uri.value()) - ); + statements.push_back(schema_->insertNFTURI.bind( + record.tokenID, record.ledgerSequence, record.uri.value() + )); } } @@ -918,14 +978,18 @@ public: writeMigratorStatus(std::string const& migratorName, std::string const& status) override { executor_.writeSync( - schema_->insertMigratorStatus, data::cassandra::Text{migratorName}, data::cassandra::Text(status) + schema_->insertMigratorStatus, + data::cassandra::Text{migratorName}, + data::cassandra::Text(status) ); } void writeNodeMessage(boost::uuids::uuid const& uuid, std::string message) override { - executor_.writeSync(schema_->updateClioNodeMessage, data::cassandra::Text{std::move(message)}, uuid); + executor_.writeSync( + schema_->updateClioNodeMessage, data::cassandra::Text{std::move(message)}, uuid + ); } bool diff --git a/src/data/cassandra/Concepts.hpp b/src/data/cassandra/Concepts.hpp index 7ede90cdc..4e33b88a0 100644 --- a/src/data/cassandra/Concepts.hpp +++ b/src/data/cassandra/Concepts.hpp @@ -78,12 +78,13 @@ concept SomeExecutionStrategy = requires( * @brief The requirements of a retry policy. */ template -concept SomeRetryPolicy = requires(T a, boost::asio::io_context ioc, CassandraError err, uint32_t attempt) { - { T(ioc) }; - { a.shouldRetry(err) } -> std::same_as; - { - a.retry([]() {}) - } -> std::same_as; -}; +concept SomeRetryPolicy = + requires(T a, boost::asio::io_context ioc, CassandraError err, uint32_t attempt) { + { T(ioc) }; + { a.shouldRetry(err) } -> std::same_as; + { + a.retry([]() {}) + } -> std::same_as; + }; } // namespace data::cassandra diff --git a/src/data/cassandra/Error.hpp b/src/data/cassandra/Error.hpp index e4e9adc9e..895265f68 100644 --- a/src/data/cassandra/Error.hpp +++ b/src/data/cassandra/Error.hpp @@ -105,9 +105,9 @@ public: bool isTimeout() const { - return code_ == CASS_ERROR_LIB_NO_HOSTS_AVAILABLE or code_ == CASS_ERROR_LIB_REQUEST_TIMED_OUT or - code_ == CASS_ERROR_SERVER_UNAVAILABLE or code_ == CASS_ERROR_SERVER_OVERLOADED or - code_ == CASS_ERROR_SERVER_READ_TIMEOUT; + return code_ == CASS_ERROR_LIB_NO_HOSTS_AVAILABLE or + code_ == CASS_ERROR_LIB_REQUEST_TIMED_OUT or code_ == CASS_ERROR_SERVER_UNAVAILABLE or + code_ == CASS_ERROR_SERVER_OVERLOADED or code_ == CASS_ERROR_SERVER_READ_TIMEOUT; } /** diff --git a/src/data/cassandra/Handle.cpp b/src/data/cassandra/Handle.cpp index d01e055f3..7bd8ed915 100644 --- a/src/data/cassandra/Handle.cpp +++ b/src/data/cassandra/Handle.cpp @@ -36,7 +36,8 @@ Handle::Handle(Settings clusterSettings) : cluster_{clusterSettings} { } -Handle::Handle(std::string_view contactPoints) : Handle{Settings::defaultSettings().withContactPoints(contactPoints)} +Handle::Handle(std::string_view contactPoints) + : Handle{Settings::defaultSettings().withContactPoints(contactPoints)} { } @@ -85,7 +86,9 @@ Handle::FutureType Handle::asyncReconnect(std::string_view keyspace) const { if (auto rc = asyncDisconnect().await(); not rc) // sync - throw std::logic_error("Reconnect to keyspace '" + std::string{keyspace} + "' failed: " + rc.error()); + throw std::logic_error( + "Reconnect to keyspace '" + std::string{keyspace} + "' failed: " + rc.error() + ); return asyncConnect(keyspace); } @@ -123,7 +126,10 @@ Handle::asyncExecute(StatementType const& statement) const } Handle::FutureWithCallbackType -Handle::asyncExecute(StatementType const& statement, std::function&& cb) const +Handle::asyncExecute( + StatementType const& statement, + std::function&& cb +) const { return Handle::FutureWithCallbackType{cass_session_execute(session_, statement), std::move(cb)}; } @@ -147,9 +153,14 @@ Handle::execute(std::vector const& statements) const } Handle::FutureWithCallbackType -Handle::asyncExecute(std::vector const& statements, std::function&& cb) const +Handle::asyncExecute( + std::vector const& statements, + std::function&& cb +) const { - return Handle::FutureWithCallbackType{cass_session_execute_batch(session_, Batch{statements}), std::move(cb)}; + return Handle::FutureWithCallbackType{ + cass_session_execute_batch(session_, Batch{statements}), std::move(cb) + }; } Handle::PreparedStatementType diff --git a/src/data/cassandra/Handle.hpp b/src/data/cassandra/Handle.hpp index 27eeddfc5..d7852c13a 100644 --- a/src/data/cassandra/Handle.hpp +++ b/src/data/cassandra/Handle.hpp @@ -293,14 +293,18 @@ public: execute(std::vector const& statements) const; /** - * @brief Execute a batch of (bound or simple) statements asynchronously with a completion callback. + * @brief Execute a batch of (bound or simple) statements asynchronously with a completion + * callback. * * @param statements The statements to execute * @param cb The callback to execute when data is ready * @return A future that holds onto the callback provided */ [[nodiscard]] FutureWithCallbackType - asyncExecute(std::vector const& statements, std::function&& cb) const; + asyncExecute( + std::vector const& statements, + std::function&& cb + ) const; /** * @brief Prepare a statement. @@ -314,8 +318,8 @@ public: }; /** - * @brief Extracts the results into series of std::tuple by creating a simple wrapper with an STL input - * iterator inside. + * @brief Extracts the results into series of std::tuple by creating a simple wrapper with + * an STL input iterator inside. * * You can call .begin() and .end() in order to iterate as usual. * This also means that you can use it in a range-based for or with some algorithms. diff --git a/src/data/cassandra/Schema.hpp b/src/data/cassandra/Schema.hpp index d89952c42..83bc49498 100644 --- a/src/data/cassandra/Schema.hpp +++ b/src/data/cassandra/Schema.hpp @@ -43,9 +43,14 @@ namespace data::cassandra { * @return The qualified table name */ template -[[nodiscard]] std::string inline qualifiedTableName(SettingsProviderType const& provider, std::string_view name) +[[nodiscard]] std::string inline qualifiedTableName( + SettingsProviderType const& provider, + std::string_view name +) { - return fmt::format("{}.{}{}", provider.getKeyspace(), provider.getTablePrefix().value_or(""), name); + return fmt::format( + "{}.{}{}", provider.getKeyspace(), provider.getTablePrefix().value_or(""), name + ); } /** @@ -65,7 +70,8 @@ public: * * @param settingsProvider The settings provider */ - explicit Schema(SettingsProviderType const& settingsProvider) : settingsProvider_{std::cref(settingsProvider)} + explicit Schema(SettingsProviderType const& settingsProvider) + : settingsProvider_{std::cref(settingsProvider)} { } diff --git a/src/data/cassandra/SettingsProvider.cpp b/src/data/cassandra/SettingsProvider.cpp index 4ce67c7fc..afcb2a6c1 100644 --- a/src/data/cassandra/SettingsProvider.cpp +++ b/src/data/cassandra/SettingsProvider.cpp @@ -61,12 +61,18 @@ SettingsProvider::parseOptionalCertificate() const auto const path = std::filesystem::path(certPath.asString()); std::ifstream fileStream(path.string(), std::ios::in); if (!fileStream) { - throw std::system_error(errno, std::generic_category(), "Opening certificate " + path.string()); + throw std::system_error( + errno, std::generic_category(), "Opening certificate " + path.string() + ); } - std::string contents(std::istreambuf_iterator{fileStream}, std::istreambuf_iterator{}); + std::string contents( + std::istreambuf_iterator{fileStream}, std::istreambuf_iterator{} + ); if (fileStream.bad()) { - throw std::system_error(errno, std::generic_category(), "Reading certificate " + path.string()); + throw std::system_error( + errno, std::generic_category(), "Reading certificate " + path.string() + ); } return contents; @@ -82,7 +88,8 @@ SettingsProvider::parseSettings() const // all config values used in settings is under "database.cassandra" prefix if (config_.getValueView("secure_connect_bundle").hasValue()) { - auto const bundle = Settings::SecureConnectionBundle{(config_.get("secure_connect_bundle"))}; + auto const bundle = + Settings::SecureConnectionBundle{(config_.get("secure_connect_bundle"))}; settings.connectionInfo = bundle; } else { Settings::ContactPoints out; @@ -101,12 +108,14 @@ SettingsProvider::parseSettings() const if (config_.getValueView("connect_timeout").hasValue()) { auto const connectTimeoutSecond = config_.get("connect_timeout"); - settings.connectionTimeout = std::chrono::milliseconds{connectTimeoutSecond * util::kMILLISECONDS_PER_SECOND}; + settings.connectionTimeout = + std::chrono::milliseconds{connectTimeoutSecond * util::kMILLISECONDS_PER_SECOND}; } if (config_.getValueView("request_timeout").hasValue()) { auto const requestTimeoutSecond = config_.get("request_timeout"); - settings.requestTimeout = std::chrono::milliseconds{requestTimeoutSecond * util::kMILLISECONDS_PER_SECOND}; + settings.requestTimeout = + std::chrono::milliseconds{requestTimeoutSecond * util::kMILLISECONDS_PER_SECOND}; } settings.certificate = parseOptionalCertificate(); diff --git a/src/data/cassandra/impl/AsyncExecutor.hpp b/src/data/cassandra/impl/AsyncExecutor.hpp index 0ac1051d2..e582a0135 100644 --- a/src/data/cassandra/impl/AsyncExecutor.hpp +++ b/src/data/cassandra/impl/AsyncExecutor.hpp @@ -52,7 +52,8 @@ template < typename StatementType, typename HandleType = Handle, SomeRetryPolicy RetryPolicyType = ExponentialBackoffRetryPolicy> -class AsyncExecutor : public std::enable_shared_from_this> { +class AsyncExecutor : public std::enable_shared_from_this< + AsyncExecutor> { using FutureWithCallbackType = typename HandleType::FutureWithCallbackType; using CallbackType = std::function; using RetryCallbackType = std::function; @@ -92,7 +93,9 @@ public: } }; - auto ptr = std::make_shared(ioc, std::move(data), std::move(onComplete), std::move(onRetry)); + auto ptr = std::make_shared( + ioc, std::move(data), std::move(onComplete), std::move(onRetry) + ); ptr->execute(handle); } @@ -103,7 +106,10 @@ private: CallbackType&& onComplete, RetryCallbackType&& onRetry ) - : data_{std::move(data)}, retryPolicy_{ioc}, onComplete_{std::move(onComplete)}, onRetry_{std::move(onRetry)} + : data_{std::move(data)} + , retryPolicy_{ioc} + , onComplete_{std::move(onComplete)} + , onRetry_{std::move(onRetry)} { } diff --git a/src/data/cassandra/impl/Batch.cpp b/src/data/cassandra/impl/Batch.cpp index 48841a278..439b27c69 100644 --- a/src/data/cassandra/impl/Batch.cpp +++ b/src/data/cassandra/impl/Batch.cpp @@ -44,7 +44,8 @@ namespace data::cassandra::impl { * UNLOGGED: For performance. Sends many separate updates in one network trip to be fast. * Use this for bulk-loading unrelated data, but know there's NO all-or-nothing guarantee. * - * More info here: https://docs.datastax.com/en/developer/cpp-driver-dse/1.10/features/basics/batches/index.html + * More info here: + * https://docs.datastax.com/en/developer/cpp-driver-dse/1.10/features/basics/batches/index.html */ Batch::Batch(std::vector const& statements) : ManagedObject{cass_batch_new(CASS_BATCH_TYPE_UNLOGGED), kBATCH_DELETER} diff --git a/src/data/cassandra/impl/Cluster.cpp b/src/data/cassandra/impl/Cluster.cpp index 5664e7c10..d992fd42a 100644 --- a/src/data/cassandra/impl/Cluster.cpp +++ b/src/data/cassandra/impl/Cluster.cpp @@ -44,7 +44,8 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), k using std::to_string; cass_cluster_set_token_aware_routing(*this, cass_true); - if (auto const rc = cass_cluster_set_protocol_version(*this, CASS_PROTOCOL_VERSION_V4); rc != CASS_OK) { + if (auto const rc = cass_cluster_set_protocol_version(*this, CASS_PROTOCOL_VERSION_V4); + rc != CASS_OK) { throw std::runtime_error( fmt::format("Error setting cassandra protocol version to v4: {}", cass_error_desc(rc)) ); @@ -52,7 +53,11 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), k if (auto const rc = cass_cluster_set_num_threads_io(*this, settings.threads); rc != CASS_OK) { throw std::runtime_error( - fmt::format("Error setting cassandra io threads to {}: {}", settings.threads, cass_error_desc(rc)) + fmt::format( + "Error setting cassandra io threads to {}: {}", + settings.threads, + cass_error_desc(rc) + ) ); } @@ -62,24 +67,36 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), k // TODO: AWS keyspace reads should be local_one to save cost if (settings.provider == cassandra::impl::Provider::Keyspace) { - if (auto const rc = cass_cluster_set_consistency(*this, CASS_CONSISTENCY_LOCAL_QUORUM); rc != CASS_OK) { - throw std::runtime_error(fmt::format("Error setting keyspace consistency: {}", cass_error_desc(rc))); + if (auto const rc = cass_cluster_set_consistency(*this, CASS_CONSISTENCY_LOCAL_QUORUM); + rc != CASS_OK) { + throw std::runtime_error( + fmt::format("Error setting keyspace consistency: {}", cass_error_desc(rc)) + ); } } else { - if (auto const rc = cass_cluster_set_consistency(*this, CASS_CONSISTENCY_QUORUM); rc != CASS_OK) { - throw std::runtime_error(fmt::format("Error setting cassandra consistency: {}", cass_error_desc(rc))); + if (auto const rc = cass_cluster_set_consistency(*this, CASS_CONSISTENCY_QUORUM); + rc != CASS_OK) { + throw std::runtime_error( + fmt::format("Error setting cassandra consistency: {}", cass_error_desc(rc)) + ); } } - if (auto const rc = cass_cluster_set_core_connections_per_host(*this, settings.coreConnectionsPerHost); + if (auto const rc = + cass_cluster_set_core_connections_per_host(*this, settings.coreConnectionsPerHost); rc != CASS_OK) { - throw std::runtime_error(fmt::format("Could not set core connections per host: {}", cass_error_desc(rc))); + throw std::runtime_error( + fmt::format("Could not set core connections per host: {}", cass_error_desc(rc)) + ); } - auto const queueSize = - settings.queueSizeIO.value_or(settings.maxWriteRequestsOutstanding + settings.maxReadRequestsOutstanding); + auto const queueSize = settings.queueSizeIO.value_or( + settings.maxWriteRequestsOutstanding + settings.maxReadRequestsOutstanding + ); if (auto const rc = cass_cluster_set_queue_size_io(*this, queueSize); rc != CASS_OK) { - throw std::runtime_error(fmt::format("Could not set queue size for IO per host: {}", cass_error_desc(rc))); + throw std::runtime_error( + fmt::format("Could not set queue size for IO per host: {}", cass_error_desc(rc)) + ); } setupConnection(settings); @@ -111,7 +128,9 @@ Cluster::setupContactPoints(Settings::ContactPoints const& points) auto throwErrorIfNeeded = [](CassError rc, std::string const& label, std::string const& value) { if (rc != CASS_OK) { throw std::runtime_error( - fmt::format("Cassandra: Error setting {} [{}]: {}", label, value, cass_error_desc(rc)) + fmt::format( + "Cassandra: Error setting {} [{}]: {}", label, value, cass_error_desc(rc) + ) ); } }; @@ -132,8 +151,12 @@ void Cluster::setupSecureBundle(Settings::SecureConnectionBundle const& bundle) { LOG(log_.debug()) << "Attempt connection using secure bundle"; - if (auto const rc = cass_cluster_set_cloud_secure_connection_bundle(*this, bundle.bundle.data()); rc != CASS_OK) { - throw std::runtime_error("Failed to connect using secure connection bundle " + bundle.bundle); + if (auto const rc = + cass_cluster_set_cloud_secure_connection_bundle(*this, bundle.bundle.data()); + rc != CASS_OK) { + throw std::runtime_error( + "Failed to connect using secure connection bundle " + bundle.bundle + ); } } @@ -155,7 +178,9 @@ Cluster::setupCredentials(Settings const& settings) return; LOG(log_.debug()) << "Set credentials; username: " << settings.username.value(); - cass_cluster_set_credentials(*this, settings.username.value().c_str(), settings.password.value().c_str()); + cass_cluster_set_credentials( + *this, settings.username.value().c_str(), settings.password.value().c_str() + ); } } // namespace data::cassandra::impl diff --git a/src/data/cassandra/impl/Cluster.hpp b/src/data/cassandra/impl/Cluster.hpp index 3af21df98..5ea4c980c 100644 --- a/src/data/cassandra/impl/Cluster.hpp +++ b/src/data/cassandra/impl/Cluster.hpp @@ -79,7 +79,8 @@ struct Settings { bool enableLog = false; /** @brief Connect timeout specified in milliseconds */ - std::chrono::milliseconds connectionTimeout = std::chrono::milliseconds{kDEFAULT_CONNECTION_TIMEOUT}; + std::chrono::milliseconds connectionTimeout = + std::chrono::milliseconds{kDEFAULT_CONNECTION_TIMEOUT}; /** @brief Request timeout specified in milliseconds */ std::chrono::milliseconds requestTimeout = std::chrono::milliseconds{0}; // no timeout at all @@ -106,25 +107,31 @@ struct Settings { Provider provider = kDEFAULT_PROVIDER; /** @brief Size of the IO queue */ - std::optional queueSizeIO = std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional queueSizeIO = + std::nullopt; // NOLINT(readability-redundant-member-init) /** @brief SSL certificate */ - std::optional certificate = std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional certificate = + std::nullopt; // NOLINT(readability-redundant-member-init) /** @brief Username/login */ - std::optional username = std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional username = + std::nullopt; // NOLINT(readability-redundant-member-init) /** @brief Password to match the `username` */ - std::optional password = std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional password = + std::nullopt; // NOLINT(readability-redundant-member-init) /** - * @brief Creates a new Settings object as a copy of the current one with overridden contact points. + * @brief Creates a new Settings object as a copy of the current one with overridden contact + * points. */ Settings withContactPoints(std::string_view contactPoints) { auto tmp = *this; - tmp.connectionInfo = ContactPoints{.contactPoints = std::string{contactPoints}, .port = std::nullopt}; + tmp.connectionInfo = + ContactPoints{.contactPoints = std::string{contactPoints}, .port = std::nullopt}; return tmp; } diff --git a/src/data/cassandra/impl/ExecutionStrategy.hpp b/src/data/cassandra/impl/ExecutionStrategy.hpp index ea5a14eb6..c74e1beed 100644 --- a/src/data/cassandra/impl/ExecutionStrategy.hpp +++ b/src/data/cassandra/impl/ExecutionStrategy.hpp @@ -267,8 +267,8 @@ public: } /** - * @brief Non-blocking query execution used for writing data. Contrast with write, this method does not execute - * the statements in a batch. + * @brief Non-blocking query execution used for writing data. Contrast with write, this method + * does not execute the statements in a batch. * * Retries forever with retry policy specified by @ref AsyncExecutor. * @@ -278,7 +278,9 @@ public: void writeEach(std::vector&& statements) { - std::ranges::for_each(std::move(statements), [this](auto& statement) { this->write(std::move(statement)); }); + std::ranges::for_each(std::move(statements), [this](auto& statement) { + this->write(std::move(statement)); + }); } /** @@ -328,7 +330,9 @@ public: future.emplace(handle_.get().asyncExecute(statements, [sself](auto&& res) mutable { boost::asio::post( boost::asio::get_associated_executor(*sself), - [sself, res = std::forward(res)]() mutable { sself->complete(std::move(res)); } + [sself, res = std::forward(res)]() mutable { + sself->complete(std::move(res)); + } ); })); }; @@ -381,7 +385,9 @@ public: future.emplace(handle_.get().asyncExecute(statement, [sself](auto&& res) mutable { boost::asio::post( boost::asio::get_associated_executor(*sself), - [sself, res = std::forward(res)]() mutable { sself->complete(std::move(res)); } + [sself, res = std::forward(res)]() mutable { + sself->complete(std::move(res)); + } ); })); }; @@ -431,19 +437,23 @@ public: futures.reserve(numOutstanding); counters_->registerReadStarted(statements.size()); - auto init = [this, &statements, &futures, &errorsCount, &numOutstanding](Self& self) { + auto init = [this, &statements, &futures, &errorsCount, &numOutstanding]( + Self& self + ) { auto sself = std::make_shared(std::move(self)); - auto executionHandler = [&errorsCount, &numOutstanding, sself](auto const& res) mutable { - if (not res) - ++errorsCount; + auto executionHandler = + [&errorsCount, &numOutstanding, sself](auto const& res) mutable { + if (not res) + ++errorsCount; - // when all async operations complete unblock the result - if (--numOutstanding == 0) { - boost::asio::post(boost::asio::get_associated_executor(*sself), [sself]() mutable { - sself->complete(); - }); - } - }; + // when all async operations complete unblock the result + if (--numOutstanding == 0) { + boost::asio::post( + boost::asio::get_associated_executor(*sself), + [sself]() mutable { sself->complete(); } + ); + } + }; std::transform( std::cbegin(statements), @@ -461,7 +471,9 @@ public: numReadRequestsOutstanding_ -= statements.size(); if (errorsCount > 0) { - ASSERT(errorsCount <= statements.size(), "Errors number cannot exceed statements number"); + ASSERT( + errorsCount <= statements.size(), "Errors number cannot exceed statements number" + ); counters_->registerReadError(errorsCount); counters_->registerReadFinished(startTime, statements.size() - errorsCount); throw DatabaseTimeout{}; @@ -471,7 +483,8 @@ public: std::vector results; results.reserve(futures.size()); - // it's safe to call blocking get on futures here as we already waited for the coroutine to resume above. + // it's safe to call blocking get on futures here as we already waited for the coroutine to + // resume above. std::transform( std::make_move_iterator(std::begin(futures)), std::make_move_iterator(std::end(futures)), diff --git a/src/data/cassandra/impl/Future.cpp b/src/data/cassandra/impl/Future.cpp index 8389e32f9..5d970f1e4 100644 --- a/src/data/cassandra/impl/Future.cpp +++ b/src/data/cassandra/impl/Future.cpp @@ -76,8 +76,8 @@ void invokeHelper(CassFuture* ptr, void* cbPtr) { // Note: can't use Future{ptr}.get() because double free will occur :/ - // Note2: we are moving/copying it locally as a workaround for an issue we are seeing from asio recently. - // stackoverflow.com/questions/77004137/boost-asio-async-compose-gets-stuck-under-load + // Note2: we are moving/copying it locally as a workaround for an issue we are seeing from asio + // recently. stackoverflow.com/questions/77004137/boost-asio-async-compose-gets-stuck-under-load auto* cb = static_cast(cbPtr); auto local = std::make_unique(std::move(*cb)); if (auto const rc = cass_future_error_code(ptr); rc) { diff --git a/src/data/cassandra/impl/Result.hpp b/src/data/cassandra/impl/Result.hpp index 1926deb20..31864acd9 100644 --- a/src/data/cassandra/impl/Result.hpp +++ b/src/data/cassandra/impl/Result.hpp @@ -139,7 +139,9 @@ struct Result : public ManagedObject { std::size_t idx = 0; auto advanceId = [&idx]() { return idx++; }; - return std::make_optional>({extractColumn(row, advanceId())...}); + return std::make_optional>( + {extractColumn(row, advanceId())...} + ); } template diff --git a/src/data/cassandra/impl/RetryPolicy.hpp b/src/data/cassandra/impl/RetryPolicy.hpp index 8ad1fa564..b22def6a1 100644 --- a/src/data/cassandra/impl/RetryPolicy.hpp +++ b/src/data/cassandra/impl/RetryPolicy.hpp @@ -63,9 +63,11 @@ public: [[nodiscard]] bool shouldRetry([[maybe_unused]] CassandraError err) { - auto const delayMs = std::chrono::duration_cast(retry_.delayValue()).count(); - LOG(log_.error()) << "Cassandra write error: " << err << ", current retries " << retry_.attemptNumber() - << ", retrying in " << delayMs << " milliseconds"; + auto const delayMs = + std::chrono::duration_cast(retry_.delayValue()).count(); + LOG(log_.error()) << "Cassandra write error: " << err << ", current retries " + << retry_.attemptNumber() << ", retrying in " << delayMs + << " milliseconds"; return true; // keep retrying forever } diff --git a/src/data/cassandra/impl/SslContext.cpp b/src/data/cassandra/impl/SslContext.cpp index cf6b1ac20..ebfbc3138 100644 --- a/src/data/cassandra/impl/SslContext.cpp +++ b/src/data/cassandra/impl/SslContext.cpp @@ -32,11 +32,14 @@ constexpr auto kCONTEXT_DELETER = [](CassSsl* ptr) { cass_ssl_free(ptr); }; namespace data::cassandra::impl { -SslContext::SslContext(std::string const& certificate) : ManagedObject{cass_ssl_new(), kCONTEXT_DELETER} +SslContext::SslContext(std::string const& certificate) + : ManagedObject{cass_ssl_new(), kCONTEXT_DELETER} { cass_ssl_set_verify_flags(*this, CASS_SSL_VERIFY_NONE); if (auto const rc = cass_ssl_add_trusted_cert(*this, certificate.c_str()); rc != CASS_OK) { - throw std::runtime_error(std::string{"Error setting Cassandra SSL Context: "} + cass_error_desc(rc)); + throw std::runtime_error( + std::string{"Error setting Cassandra SSL Context: "} + cass_error_desc(rc) + ); } } diff --git a/src/data/cassandra/impl/Statement.hpp b/src/data/cassandra/impl/Statement.hpp index 6998c741c..96f986945 100644 --- a/src/data/cassandra/impl/Statement.hpp +++ b/src/data/cassandra/impl/Statement.hpp @@ -97,11 +97,15 @@ public: using std::to_string; auto throwErrorIfNeeded = [idx](CassError rc, std::string_view label) { if (rc != CASS_OK) - throw std::logic_error(fmt::format("[{}] at idx {}: {}", label, idx, cass_error_desc(rc))); + throw std::logic_error( + fmt::format("[{}] at idx {}: {}", label, idx, cass_error_desc(rc)) + ); }; auto bindBytes = [this, idx](auto const* data, size_t size) { - return cass_statement_bind_bytes(*this, idx, static_cast(data), size); + return cass_statement_bind_bytes( + *this, idx, static_cast(data), size + ); }; using DecayedType = std::decay_t; @@ -110,7 +114,8 @@ public: using UintByteTupleType = std::tuple; using ByteVectorType = std::vector; - if constexpr (std::is_same_v || std::is_same_v) { + if constexpr (std::is_same_v || + std::is_same_v) { auto const rc = bindBytes(value.data(), value.size()); throwErrorIfNeeded(rc, "Bind ripple::base_uint"); } else if constexpr (std::is_same_v) { @@ -121,17 +126,20 @@ public: throwErrorIfNeeded(rc, "Bind vector"); } else if constexpr (std::is_convertible_v) { // reinterpret_cast is needed here :'( - auto const rc = bindBytes(reinterpret_cast(value.data()), value.size()); + auto const rc = + bindBytes(reinterpret_cast(value.data()), value.size()); throwErrorIfNeeded(rc, "Bind string (as bytes)"); } else if constexpr (std::is_convertible_v) { - auto const rc = cass_statement_bind_string_n(*this, idx, value.text.c_str(), value.text.size()); + auto const rc = + cass_statement_bind_string_n(*this, idx, value.text.c_str(), value.text.size()); throwErrorIfNeeded(rc, "Bind string (as TEXT)"); } else if constexpr (std::is_same_v || std::is_same_v) { auto const rc = cass_statement_bind_tuple(*this, idx, Tuple{std::forward(value)}); throwErrorIfNeeded(rc, "Bind tuple or "); } else if constexpr (std::is_same_v) { - auto const rc = cass_statement_bind_collection(*this, idx, Collection{std::forward(value)}); + auto const rc = + cass_statement_bind_collection(*this, idx, Collection{std::forward(value)}); throwErrorIfNeeded(rc, "Bind collection"); } else if constexpr (std::is_same_v) { auto const rc = cass_statement_bind_bool(*this, idx, value ? cass_true : cass_false); diff --git a/src/data/cassandra/impl/Tuple.cpp b/src/data/cassandra/impl/Tuple.cpp index b11308ed1..d8df1b119 100644 --- a/src/data/cassandra/impl/Tuple.cpp +++ b/src/data/cassandra/impl/Tuple.cpp @@ -34,7 +34,8 @@ namespace data::cassandra::impl { { } -/* implicit */ TupleIterator::TupleIterator(CassIterator* ptr) : ManagedObject{ptr, kTUPLE_ITERATOR_DELETER} +/* implicit */ TupleIterator::TupleIterator(CassIterator* ptr) + : ManagedObject{ptr, kTUPLE_ITERATOR_DELETER} { } diff --git a/src/data/cassandra/impl/Tuple.hpp b/src/data/cassandra/impl/Tuple.hpp index d498b924a..008213036 100644 --- a/src/data/cassandra/impl/Tuple.hpp +++ b/src/data/cassandra/impl/Tuple.hpp @@ -65,7 +65,9 @@ public: auto throwErrorIfNeeded = [idx](CassError rc, std::string_view label) { if (rc != CASS_OK) { auto const tag = '[' + std::string{label} + ']'; - throw std::logic_error(tag + " at idx " + to_string(idx) + ": " + cass_error_desc(rc)); + throw std::logic_error( + tag + " at idx " + to_string(idx) + ": " + cass_error_desc(rc) + ); } }; diff --git a/src/data/impl/LedgerCacheFile.cpp b/src/data/impl/LedgerCacheFile.cpp index a171e791b..81ff3379d 100644 --- a/src/data/impl/LedgerCacheFile.cpp +++ b/src/data/impl/LedgerCacheFile.cpp @@ -92,7 +92,9 @@ LedgerCacheFile::write(DataView dataView) } Header const header{ - .latestSeq = dataView.latestSeq, .mapSize = dataView.map.size(), .deletedSize = dataView.deleted.size() + .latestSeq = dataView.latestSeq, + .mapSize = dataView.map.size(), + .deletedSize = dataView.deleted.size() }; file.write(header); file.write(kSEPARATOR); @@ -123,7 +125,9 @@ LedgerCacheFile::write(DataView dataView) try { std::filesystem::rename(newFilePath, path_); } catch (std::exception const& e) { - return std::unexpected{fmt::format("Error moving cache file from {} to {}: {}", newFilePath, path_, e.what())}; + return std::unexpected{ + fmt::format("Error moving cache file from {} to {}: {}", newFilePath, path_, e.what()) + }; } return {}; @@ -145,12 +149,14 @@ LedgerCacheFile::read(uint32_t minLatestSequence) return std::unexpected{"Error reading cache header"}; } if (header.version != kVERSION) { - return std::unexpected{ - fmt::format("Cache has wrong version: expected {} found {}", kVERSION, header.version) - }; + return std::unexpected{fmt::format( + "Cache has wrong version: expected {} found {}", kVERSION, header.version + )}; } if (header.latestSeq < minLatestSequence) { - return std::unexpected{fmt::format("Latest sequence ({}) in the cache file is too low.", header.latestSeq)}; + return std::unexpected{ + fmt::format("Latest sequence ({}) in the cache file is too low.", header.latestSeq) + }; } result.latestSeq = header.latestSeq; @@ -158,7 +164,8 @@ LedgerCacheFile::read(uint32_t minLatestSequence) if (not file.readRaw(separator.data(), separator.size())) { return std::unexpected{"Error reading cache header"}; } - if (auto verificationResult = verifySeparator(separator); not verificationResult.has_value()) { + if (auto verificationResult = verifySeparator(separator); + not verificationResult.has_value()) { return std::unexpected{std::move(verificationResult).error()}; } @@ -167,15 +174,16 @@ LedgerCacheFile::read(uint32_t minLatestSequence) if (not cacheEntryExpected.has_value()) { return std::unexpected{std::move(cacheEntryExpected).error()}; } - // Using insert with hint here to decrease insert operation complexity to the amortized constant instead of - // logN + // Using insert with hint here to decrease insert operation complexity to the amortized + // constant instead of logN result.map.insert(result.map.end(), std::move(cacheEntryExpected).value()); } if (not file.readRaw(separator.data(), separator.size())) { return std::unexpected{"Error reading separator"}; } - if (auto verificationResult = verifySeparator(separator); not verificationResult.has_value()) { + if (auto verificationResult = verifySeparator(separator); + not verificationResult.has_value()) { return std::unexpected{std::move(verificationResult).error()}; } @@ -190,13 +198,16 @@ LedgerCacheFile::read(uint32_t minLatestSequence) if (not file.readRaw(separator.data(), separator.size())) { return std::unexpected{"Error reading separator"}; } - if (auto verificationResult = verifySeparator(separator); not verificationResult.has_value()) { + if (auto verificationResult = verifySeparator(separator); + not verificationResult.has_value()) { return std::unexpected{std::move(verificationResult).error()}; } auto const dataHash = file.hash(); ripple::uint256 hashFromFile{}; - if (not file.readRaw(reinterpret_cast(hashFromFile.data()), decltype(hashFromFile)::bytes)) { + if (not file.readRaw( + reinterpret_cast(hashFromFile.data()), decltype(hashFromFile)::bytes + )) { return std::unexpected{"Error reading hash"}; } diff --git a/src/etl/CacheLoader.hpp b/src/etl/CacheLoader.hpp index 92743fa80..147efd2dd 100644 --- a/src/etl/CacheLoader.hpp +++ b/src/etl/CacheLoader.hpp @@ -110,7 +110,9 @@ public: if (settings_.numCacheCursorsFromDiff != 0) { LOG(log_.info()) << "Loading cache with cursor from num_cursors_from_diff=" << settings_.numCacheCursorsFromDiff; - provider = std::make_shared(backend_, settings_.numCacheCursorsFromDiff); + provider = std::make_shared( + backend_, settings_.numCacheCursorsFromDiff + ); } else if (settings_.numCacheCursorsFromAccount != 0) { LOG(log_.info()) << "Loading cache with cursor from num_cursors_from_account=" << settings_.numCacheCursorsFromAccount; @@ -118,8 +120,11 @@ public: backend_, settings_.numCacheCursorsFromAccount, settings_.cachePageFetchSize ); } else { - LOG(log_.info()) << "Loading cache with cursor from num_diffs=" << settings_.numCacheDiffs; - provider = std::make_shared(backend_, settings_.numCacheDiffs); + LOG(log_.info()) << "Loading cache with cursor from num_diffs=" + << settings_.numCacheDiffs; + provider = std::make_shared( + backend_, settings_.numCacheDiffs + ); } loader_ = std::make_unique( @@ -169,7 +174,9 @@ private: auto const minLatestSequence = backend_->fetchLedgerRange() .transform([this](data::LedgerRange const& range) { - return std::max(range.maxSequence - settings_.cacheFileSettings->maxAge, range.minSequence); + return std::max( + range.maxSequence - settings_.cacheFileSettings->maxAge, range.minSequence + ); }) .value_or(0); diff --git a/src/etl/CacheLoaderSettings.cpp b/src/etl/CacheLoaderSettings.cpp index 7332bd455..c0cee5a85 100644 --- a/src/etl/CacheLoaderSettings.cpp +++ b/src/etl/CacheLoaderSettings.cpp @@ -66,7 +66,8 @@ makeCacheLoaderSettings(util::config::ClioConfigDefinition const& config) if (auto filePath = cache.maybeValue("file.path"); filePath.has_value()) { settings.cacheFileSettings = CacheLoaderSettings::CacheFileSettings{ - .path = std::move(filePath).value(), .maxAge = cache.get("file.max_sequence_age") + .path = std::move(filePath).value(), + .maxAge = cache.get("file.max_sequence_age") }; } diff --git a/src/etl/CacheLoaderSettings.hpp b/src/etl/CacheLoaderSettings.hpp index 2f4c284de..97805d3f9 100644 --- a/src/etl/CacheLoaderSettings.hpp +++ b/src/etl/CacheLoaderSettings.hpp @@ -37,22 +37,25 @@ struct CacheLoaderSettings { /** @brief Settings for cache file operations */ struct CacheFileSettings { - std::string path; /**< path to the file to load cache from on start and save cache to on shutdown */ + std::string + path; /**< path to the file to load cache from on start and save cache to on shutdown */ uint32_t maxAge = 5000; /**< max difference between latest sequence in cache file and DB */ auto operator<=>(CacheFileSettings const&) const = default; }; - size_t numCacheDiffs = 32; /**< number of diffs to use to generate cursors */ - size_t numCacheMarkers = 48; /**< number of markers to use at one time to traverse the ledger */ - size_t cachePageFetchSize = 512; /**< number of ledger objects to fetch concurrently per marker */ - size_t numThreads = 2; /**< number of threads to use for loading cache */ + size_t numCacheDiffs = 32; /**< number of diffs to use to generate cursors */ + size_t numCacheMarkers = 48; /**< number of markers to use at one time to traverse the ledger */ + size_t cachePageFetchSize = + 512; /**< number of ledger objects to fetch concurrently per marker */ + size_t numThreads = 2; /**< number of threads to use for loading cache */ size_t numCacheCursorsFromDiff = 0; /**< number of cursors to fetch from diff */ size_t numCacheCursorsFromAccount = 0; /**< number of cursors to fetch from account_tx */ - LoadStyle loadStyle = LoadStyle::ASYNC; /**< how to load the cache */ - std::optional cacheFileSettings; /**< optional settings for cache file operations */ + LoadStyle loadStyle = LoadStyle::ASYNC; /**< how to load the cache */ + std::optional + cacheFileSettings; /**< optional settings for cache file operations */ auto operator<=>(CacheLoaderSettings const&) const = default; diff --git a/src/etl/CorruptionDetector.hpp b/src/etl/CorruptionDetector.hpp index e8deba09b..bd20acb6d 100644 --- a/src/etl/CorruptionDetector.hpp +++ b/src/etl/CorruptionDetector.hpp @@ -59,7 +59,9 @@ public: if (not state_.get().isCorruptionDetected) { state_.get().isCorruptionDetected = true; - LOG(log_.error()) << "Disabling the cache to avoid corrupting the DB further. Please investigate."; + LOG( + log_.error() + ) << "Disabling the cache to avoid corrupting the DB further. Please investigate."; cache_.get().setDisabled(); } } diff --git a/src/etl/ETLHelpers.hpp b/src/etl/ETLHelpers.hpp index 5152292b9..a19852be0 100644 --- a/src/etl/ETLHelpers.hpp +++ b/src/etl/ETLHelpers.hpp @@ -33,12 +33,13 @@ namespace etl { -// TODO: does the note make sense? lockfree queues provide the same blocking behaviour just without mutex, don't they? +// TODO: does the note make sense? lockfree queues provide the same blocking behaviour just without +// mutex, don't they? /** * @brief Generic thread-safe queue with a max capacity. * - * @note (original note) We can't use a lockfree queue here, since we need the ability to wait for an element to be - * added or removed from the queue. These waits are blocking calls. + * @note (original note) We can't use a lockfree queue here, since we need the ability to wait for + * an element to be added or removed from the queue. These waits are blocking calls. */ template class ThreadSafeQueue { @@ -52,8 +53,8 @@ public: /** * @brief Create an instance of the queue. * - * @param maxSize maximum size of the queue. Calls that would cause the queue to exceed this size will block until - * free space is available. + * @param maxSize maximum size of the queue. Calls that would cause the queue to exceed this + * size will block until free space is available. */ ThreadSafeQueue(uint32_t maxSize) : maxSize_(maxSize) { diff --git a/src/etl/ETLService.cpp b/src/etl/ETLService.cpp index 433721c28..b43b146c2 100644 --- a/src/etl/ETLService.cpp +++ b/src/etl/ETLService.cpp @@ -112,7 +112,8 @@ ETLService::makeETLService( state ); - auto taskManagerProvider = std::make_shared(*ledgers, extractor, loader); + auto taskManagerProvider = + std::make_shared(*ledgers, extractor, loader); ret = std::make_shared( ctx, @@ -131,7 +132,8 @@ ETLService::makeETLService( state ); - // inject networkID into subscriptions, as transaction feed require it to inject CTID in response + // inject networkID into subscriptions, as transaction feed require it to inject CTID in + // response if (auto const etlState = ret->getETLState(); etlState) subscriptions->setNetworkID(etlState->networkID); @@ -181,7 +183,8 @@ ETLService::ETLService( if (finishSequence_.has_value()) LOG(log_.info()) << "Finish sequence: " << *finishSequence_; - LOG(log_.info()) << "Starting in " << (state_->isStrictReadonly ? "STRICT READONLY MODE" : "WRITE MODE"); + LOG(log_.info()) << "Starting in " + << (state_->isStrictReadonly ? "STRICT READONLY MODE" : "WRITE MODE"); } ETLService::~ETLService() @@ -213,7 +216,8 @@ ETLService::run() } auto const nextSequence = syncCacheWithDb(); - LOG(log_.debug()) << "Database is populated. Starting monitor loop. sequence = " << nextSequence; + LOG(log_.debug()) << "Database is populated. Starting monitor loop. sequence = " + << nextSequence; startMonitor(nextSequence); @@ -290,7 +294,8 @@ ETLService::loadInitialLedgerIfNeeded() if (not rng.has_value()) { ASSERT( not state_->isStrictReadonly, - "Database is empty but this node is in strict readonly mode. Can't write initial ledger." + "Database is empty but this node is in strict readonly mode. Can't write initial " + "ledger." ); LOG(log_.info()) << "Database is empty. Will download a ledger from the network."; @@ -309,9 +314,11 @@ ETLService::loadInitialLedgerIfNeeded() auto [ledger, timeDiff] = ::util::timed>([this, seq]() { return extractor_->extractLedgerOnly(seq).and_then( [this, seq](auto&& data) -> std::optional { - // TODO: loadInitialLedger in balancer should be called fetchEdgeKeys or similar + // TODO: loadInitialLedger in balancer should be called fetchEdgeKeys or + // similar auto res = balancer_->loadInitialLedger(seq, *initialLoadObserver_); - if (not res.has_value() and res.error() == InitialLedgerLoadError::Cancelled) { + if (not res.has_value() and + res.error() == InitialLedgerLoadError::Cancelled) { LOG(log_.debug()) << "Initial ledger load got cancelled"; return std::nullopt; } @@ -330,7 +337,8 @@ ETLService::loadInitialLedgerIfNeeded() } LOG(log_.debug()) << "Time to download and store ledger = " << timeDiff; - LOG(log_.info()) << "Finished loadInitialLedger. cache size = " << backend_->cache().size(); + LOG(log_.info()) << "Finished loadInitialLedger. cache size = " + << backend_->cache().size(); return backend_->hardFetchLedgerRangeNoThrow(); } @@ -353,7 +361,8 @@ ETLService::syncCacheWithDb() { auto rng = backend_->hardFetchLedgerRangeNoThrow(); - while (not backend_->cache().isDisabled() and rng->maxSequence > backend_->cache().latestLedgerSequence()) { + while (not backend_->cache().isDisabled() and + rng->maxSequence > backend_->cache().latestLedgerSequence()) { LOG(log_.info()) << "Syncing cache with DB. DB latest seq: " << rng->maxSequence << ". Cache latest seq: " << backend_->cache().latestLedgerSequence(); for (auto seq = backend_->cache().latestLedgerSequence(); seq <= rng->maxSequence; ++seq) { @@ -443,8 +452,8 @@ ETLService::attemptTakeoverWriter() if (backend_->cache().latestLedgerSequence() != rng->maxSequence) { LOG(log_.info()) << "Wanted to take over the ETL writer seat but LedgerCache is outdated"; - // Give ETL time to update LedgerCache. This method will be called because ClusterCommunication will likely to - // continue sending StartWriting signal every 1 second + // Give ETL time to update LedgerCache. This method will be called because + // ClusterCommunication will likely to continue sending StartWriting signal every 1 second return; } diff --git a/src/etl/ETLService.hpp b/src/etl/ETLService.hpp index 5effa8eec..6260c0f44 100644 --- a/src/etl/ETLService.hpp +++ b/src/etl/ETLService.hpp @@ -80,17 +80,19 @@ namespace etl { /** - * @brief This class is responsible for continuously extracting data from a p2p node, and writing that data to the - * databases. + * @brief This class is responsible for continuously extracting data from a p2p node, and writing + * that data to the databases. * - * Usually, multiple different processes share access to the same network accessible databases, in which case only one - * such process is performing ETL and writing to the database. The other processes simply monitor the database for new - * ledgers, and publish those ledgers to the various subscription streams. If a monitoring process determines that the - * ETL writer has failed (no new ledgers written for some time), the process will attempt to become the ETL writer. + * Usually, multiple different processes share access to the same network accessible databases, in + * which case only one such process is performing ETL and writing to the database. The other + * processes simply monitor the database for new ledgers, and publish those ledgers to the various + * subscription streams. If a monitoring process determines that the ETL writer has failed (no new + * ledgers written for some time), the process will attempt to become the ETL writer. * - * If there are multiple monitoring processes that try to become the ETL writer at the same time, one will win out, and - * the others will fall back to monitoring/publishing. In this sense, this class dynamically transitions from monitoring - * to writing and from writing to monitoring, based on the activity of other processes running on different machines. + * If there are multiple monitoring processes that try to become the ETL writer at the same time, + * one will win out, and the others will fall back to monitoring/publishing. In this sense, this + * class dynamically transitions from monitoring to writing and from writing to monitoring, based on + * the activity of other processes running on different machines. */ class ETLService : public ETLServiceInterface { util::Logger log_{"ETL"}; diff --git a/src/etl/ETLServiceInterface.hpp b/src/etl/ETLServiceInterface.hpp index 300720e8f..e142d5aee 100644 --- a/src/etl/ETLServiceInterface.hpp +++ b/src/etl/ETLServiceInterface.hpp @@ -30,8 +30,8 @@ namespace etl { /** * @brief This is a base class for any ETL service implementations. - * @note A ETL service is responsible for continuously extracting data from a p2p node, and writing that data to the - * databases. + * @note A ETL service is responsible for continuously extracting data from a p2p node, and writing + * that data to the databases. */ struct ETLServiceInterface { virtual ~ETLServiceInterface() = default; diff --git a/src/etl/ETLState.cpp b/src/etl/ETLState.cpp index 5b7f4ba6e..a06ad8e24 100644 --- a/src/etl/ETLState.cpp +++ b/src/etl/ETLState.cpp @@ -36,7 +36,8 @@ tag_invoke(boost::json::value_to_tag, boost::json::value const& jv) ETLState state; auto const& jsonObject = jv.as_object(); - if (jsonObject.contains(JS(result)) && jsonObject.at(JS(result)).as_object().contains(JS(info))) { + if (jsonObject.contains(JS(result)) && + jsonObject.at(JS(result)).as_object().contains(JS(info))) { auto const rippledInfo = jsonObject.at(JS(result)).as_object().at(JS(info)).as_object(); if (rippledInfo.contains(JS(network_id))) state.networkID = boost::json::value_to(rippledInfo.at(JS(network_id))); diff --git a/src/etl/ETLState.hpp b/src/etl/ETLState.hpp index 3b447d985..aafc9336f 100644 --- a/src/etl/ETLState.hpp +++ b/src/etl/ETLState.hpp @@ -35,13 +35,14 @@ namespace etl { /** - * @brief This class is responsible for fetching and storing the state of the ETL information, such as the network id + * @brief This class is responsible for fetching and storing the state of the ETL information, such + * as the network id */ struct ETLState { /* * NOTE: Rippled NetworkID: Mainnet = 0; Testnet = 1; Devnet = 2 - * However, if rippled is running on neither of these (ie. standalone mode) rippled will default to 0, but - * is not included in the stateOpt response. Must manually add it here. + * However, if rippled is running on neither of these (ie. standalone mode) rippled will default + * to 0, but is not included in the stateOpt response. Must manually add it here. */ uint32_t networkID{0}; @@ -54,12 +55,15 @@ struct ETLState { static std::optional fetchETLStateFromSource(Forward& source) noexcept { - auto const serverInfoRippled = data::synchronous([&source](auto yield) -> std::optional { - if (auto result = source.forwardToRippled({{"command", "server_info"}}, std::nullopt, {}, yield)) { - return std::move(result).value(); - } - return std::nullopt; - }); + auto const serverInfoRippled = + data::synchronous([&source](auto yield) -> std::optional { + if (auto result = source.forwardToRippled( + {{"command", "server_info"}}, std::nullopt, {}, yield + )) { + return std::move(result).value(); + } + return std::nullopt; + }); if (serverInfoRippled && not serverInfoRippled->contains(JS(error))) { return boost::json::value_to(boost::json::value(*serverInfoRippled)); diff --git a/src/etl/LedgerFetcherInterface.hpp b/src/etl/LedgerFetcherInterface.hpp index bdab1efd0..125d86822 100644 --- a/src/etl/LedgerFetcherInterface.hpp +++ b/src/etl/LedgerFetcherInterface.hpp @@ -40,11 +40,12 @@ struct LedgerFetcherInterface { /** * @brief Extract data for a particular ledger from an ETL source * - * This function continuously tries to extract the specified ledger (using all available ETL sources) until the - * extraction succeeds, or the server shuts down. + * This function continuously tries to extract the specified ledger (using all available ETL + * sources) until the extraction succeeds, or the server shuts down. * * @param seq sequence of the ledger to extract - * @return Ledger header and transaction+metadata blobs; Empty optional if the server is shutting down + * @return Ledger header and transaction+metadata blobs; Empty optional if the server is + * shutting down */ [[nodiscard]] virtual OptionalGetLedgerResponseType fetchData(uint32_t seq) = 0; @@ -52,11 +53,12 @@ struct LedgerFetcherInterface { /** * @brief Extract diff data for a particular ledger from an ETL source. * - * This function continuously tries to extract the specified ledger (using all available ETL sources) until the - * extraction succeeds, or the server shuts down. + * This function continuously tries to extract the specified ledger (using all available ETL + * sources) until the extraction succeeds, or the server shuts down. * * @param seq sequence of the ledger to extract - * @return Ledger data diff between sequance and parent; Empty optional if the server is shutting down + * @return Ledger data diff between sequance and parent; Empty optional if the server is + * shutting down */ [[nodiscard]] virtual OptionalGetLedgerResponseType fetchDataAndDiff(uint32_t seq) = 0; diff --git a/src/etl/LoadBalancer.cpp b/src/etl/LoadBalancer.cpp index 46893aacb..0919a06c4 100644 --- a/src/etl/LoadBalancer.cpp +++ b/src/etl/LoadBalancer.cpp @@ -111,7 +111,8 @@ LoadBalancer::LoadBalancer( .retries = PrometheusService::counterInt( "forwarding_retries_counter", Labels(), - "The number of retries before a forwarded request was successful. Initial attempt excluded" + "The number of retries before a forwarded request was successful. Initial attempt " + "excluded" ), .cacheHit = PrometheusService::counterInt( "forwarding_cache_hit_counter", @@ -147,7 +148,9 @@ LoadBalancer::LoadBalancer( LOG(log_.warn()) << log; if (!allowNoEtl) { - LOG(log_.error()) << "Set allow_no_etl as true in config to allow clio run without valid ETL sources."; + LOG( + log_.error() + ) << "Set allow_no_etl as true in config to allow clio run without valid ETL sources."; throw std::logic_error("ETL configuration error."); } }; @@ -185,7 +188,8 @@ LoadBalancer::LoadBalancer( } else if (etlState_ && etlState_->networkID != stateOpt->networkID) { checkOnETLFailure( fmt::format( - "ETL sources must be on the same network. Source network id = {} does not match others network id " + "ETL sources must be on the same network. Source network id = {} does not " + "match others network id " "= {}", stateOpt->networkID, etlState_->networkID @@ -200,7 +204,9 @@ LoadBalancer::LoadBalancer( } if (!etlState_) - checkOnETLFailure("Failed to fetch ETL state from any source. Please check the configuration and network"); + checkOnETLFailure( + "Failed to fetch ETL state from any source. Please check the configuration and network" + ); if (sources_.empty()) checkOnETLFailure("No ETL sources configured. Please check the configuration"); @@ -227,7 +233,8 @@ LoadBalancer::loadInitialLedger( if (not res.has_value() and res.error() == InitialLedgerLoadError::Errored) { LOG(log_.error()) << "Failed to download initial ledger." - << " Sequence = " << sequence << " source = " << source->toString(); + << " Sequence = " << sequence + << " source = " << source->toString(); return false; // should retry on error } @@ -252,7 +259,8 @@ LoadBalancer::fetchLedger( GetLedgerResponseType response; execute( [&response, ledgerSequence, getObjects, getObjectNeighbors, log = log_](auto& source) { - auto [status, data] = source->fetchLedger(ledgerSequence, getObjects, getObjectNeighbors); + auto [status, data] = + source->fetchLedger(ledgerSequence, getObjects, getObjectNeighbors); response = std::move(data); if (status.ok() && response.validated()) { LOG(log.info()) << "Successfully fetched ledger = " << ledgerSequence @@ -260,8 +268,10 @@ LoadBalancer::fetchLedger( return true; } - LOG(log.warn()) << "Could not fetch ledger " << ledgerSequence << ", Reply: " << response.DebugString() - << ", error_code: " << status.error_code() << ", error_msg: " << status.error_message() + LOG(log.warn()) << "Could not fetch ledger " << ledgerSequence + << ", Reply: " << response.DebugString() + << ", error_code: " << status.error_code() + << ", error_msg: " << status.error_message() << ", source = " << source->toString(); return false; }, @@ -301,8 +311,9 @@ LoadBalancer::forwardToRippled( std::optional response; rpc::ClioError error = rpc::ClioError::EtlConnectionError; while (numAttempts < sources_.size()) { - auto [res, duration] = - util::timed([&]() { return sources_[sourceIdx]->forwardToRippled(request, clientIp, xUserValue, yield); }); + auto [res, duration] = util::timed([&]() { + return sources_[sourceIdx]->forwardToRippled(request, clientIp, xUserValue, yield); + }); if (res) { forwardingCounters_.successDuration.get() += duration; response = std::move(res).value(); @@ -337,7 +348,11 @@ LoadBalancer::toJson() const template void -LoadBalancer::execute(Func f, uint32_t ledgerSequence, std::chrono::steady_clock::duration retryAfter) +LoadBalancer::execute( + Func f, + uint32_t ledgerSequence, + std::chrono::steady_clock::duration retryAfter +) { ASSERT(not sources_.empty(), "ETL sources must be configured to execute functions."); size_t sourceIdx = randomGenerator_->uniform(0ul, sources_.size() - 1); @@ -370,8 +385,11 @@ LoadBalancer::execute(Func f, uint32_t ledgerSequence, std::chrono::steady_clock sourceIdx = (sourceIdx + 1) % sources_.size(); numAttempts++; if (numAttempts % sources_.size() == 0) { - LOG(log_.info()) << "Ledger sequence " << ledgerSequence - << " is not yet available from any configured sources. Sleeping and trying again"; + LOG( + log_.info() + ) << "Ledger sequence " + << ledgerSequence + << " is not yet available from any configured sources. Sleeping and trying again"; std::this_thread::sleep_for(retryAfter); } } @@ -392,7 +410,9 @@ LoadBalancer::stop(boost::asio::yield_context yield) { util::CoroutineGroup group{yield}; std::ranges::for_each(sources_, [&group, yield](auto& source) { - group.spawn(yield, [&source](boost::asio::yield_context innerYield) { source->stop(innerYield); }); + group.spawn(yield, [&source](boost::asio::yield_context innerYield) { + source->stop(innerYield); + }); }); group.asyncWait(yield); } diff --git a/src/etl/LoadBalancer.hpp b/src/etl/LoadBalancer.hpp index 784a473e8..aa12e717c 100644 --- a/src/etl/LoadBalancer.hpp +++ b/src/etl/LoadBalancer.hpp @@ -70,9 +70,10 @@ concept SomeLoadBalancer = std::derived_from; /** * @brief This class is used to manage connections to transaction processing processes. * - * This class spawns a listener for each etl source, which listens to messages on the ledgers stream (to keep track of - * which ledgers have been validated by the network, and the range of ledgers each etl source has). This class also - * allows requests for ledger data to be load balanced across all possible ETL sources. + * This class spawns a listener for each etl source, which listens to messages on the ledgers stream + * (to keep track of which ledgers have been validated by the network, and the range of ledgers each + * etl source has). This class also allows requests for ledger data to be load balanced across all + * possible ETL sources. */ class LoadBalancer : public LoadBalancerInterface, LoadBalancerTag { public: @@ -84,7 +85,8 @@ private: static constexpr std::uint32_t kDEFAULT_DOWNLOAD_RANGES = 16; util::Logger log_{"ETL"}; - // Forwarding cache must be destroyed after sources because sources have a callback to invalidate cache + // Forwarding cache must be destroyed after sources because sources have a callback to + // invalidate cache std::optional forwardingCache_; std::optional forwardingXUserValue_; @@ -92,8 +94,8 @@ private: std::vector sources_; std::optional etlState_; - std::uint32_t downloadRanges_ = - kDEFAULT_DOWNLOAD_RANGES; /*< The number of markers to use when downloading initial ledger */ + std::uint32_t downloadRanges_ = kDEFAULT_DOWNLOAD_RANGES; /*< The number of markers to use when + downloading initial ledger */ struct ForwardingCounters { std::reference_wrapper successDuration; @@ -104,7 +106,8 @@ private: } forwardingCounters_; // Using mutex instead of atomic_bool because choosing a new source to - // forward messages should be done with a mutual exclusion otherwise there will be a race condition + // forward messages should be done with a mutual exclusion otherwise there will be a race + // condition util::Mutex hasForwardingSource_{false}; public: @@ -164,12 +167,14 @@ public: /** * @brief Load the initial ledger, writing data to the queue. - * @note This function will retry indefinitely until the ledger is downloaded or the download is cancelled. + * @note This function will retry indefinitely until the ledger is downloaded or the download is + * cancelled. * * @param sequence Sequence of ledger to download * @param observer The observer to notify of progress * @param retryAfter Time to wait between retries (2 seconds by default) - * @return A std::expected with ledger edge keys on success, or InitialLedgerLoadError on failure + * @return A std::expected with ledger edge keys on success, or InitialLedgerLoadError on + * failure */ InitialLedgerLoadResult loadInitialLedger( @@ -181,8 +186,8 @@ public: /** * @brief Fetch data for a specific ledger. * - * This function will continuously try to fetch data for the specified ledger until the fetch succeeds, the ledger - * is found in the database, or the server is shutting down. + * This function will continuously try to fetch data for the specified ledger until the fetch + * succeeds, the ledger is found in the database, or the server is shutting down. * * @param ledgerSequence Sequence of the ledger to fetch * @param getObjects Whether to get the account state diff between this ledger and the prior one @@ -245,17 +250,23 @@ private: * @brief Execute a function on a randomly selected source. * * @note f is a function that takes an Source as an argument and returns a bool. - * Attempt to execute f for one randomly chosen Source that has the specified ledger. If f returns false, another - * randomly chosen Source is used. The process repeats until f returns true. + * Attempt to execute f for one randomly chosen Source that has the specified ledger. If f + * returns false, another randomly chosen Source is used. The process repeats until f returns + * true. * - * @param f Function to execute. This function takes the ETL source as an argument, and returns a bool + * @param f Function to execute. This function takes the ETL source as an argument, and returns + * a bool * @param ledgerSequence f is executed for each Source that has this ledger * @param retryAfter Time to wait between retries (2 seconds by default) * server is shutting down */ template void - execute(Func f, uint32_t ledgerSequence, std::chrono::steady_clock::duration retryAfter = std::chrono::seconds{2}); + execute( + Func f, + uint32_t ledgerSequence, + std::chrono::steady_clock::duration retryAfter = std::chrono::seconds{2} + ); /** * @brief Choose a new source to forward requests diff --git a/src/etl/LoadBalancerInterface.hpp b/src/etl/LoadBalancerInterface.hpp index 5bb15cdc0..292f2a830 100644 --- a/src/etl/LoadBalancerInterface.hpp +++ b/src/etl/LoadBalancerInterface.hpp @@ -66,12 +66,14 @@ public: /** * @brief Load the initial ledger, writing data to the queue. - * @note This function will retry indefinitely until the ledger is downloaded or the download is cancelled. + * @note This function will retry indefinitely until the ledger is downloaded or the download is + * cancelled. * * @param sequence Sequence of ledger to download * @param loader InitialLoadObserverInterface implementation * @param retryAfter Time to wait between retries (2 seconds by default) - * @return A std::expected with ledger edge keys on success, or InitialLedgerLoadError on failure + * @return A std::expected with ledger edge keys on success, or InitialLedgerLoadError on + * failure */ [[nodiscard]] virtual InitialLedgerLoadResult loadInitialLedger( @@ -83,8 +85,8 @@ public: /** * @brief Fetch data for a specific ledger. * - * This function will continuously try to fetch data for the specified ledger until the fetch succeeds, the ledger - * is found in the database, or the server is shutting down. + * This function will continuously try to fetch data for the specified ledger until the fetch + * succeeds, the ledger is found in the database, or the server is shutting down. * * @param ledgerSequence Sequence of the ledger to fetch * @param getObjects Whether to get the account state diff between this ledger and the prior one diff --git a/src/etl/MPTHelpers.cpp b/src/etl/MPTHelpers.cpp index 23767cbe8..b31763a14 100644 --- a/src/etl/MPTHelpers.cpp +++ b/src/etl/MPTHelpers.cpp @@ -53,7 +53,8 @@ getMPTokenAuthorize(ripple::TxMeta const& txMeta) if (node.getFName() == ripple::sfCreatedNode) { auto const& newMPT = node.peekAtField(ripple::sfNewFields).downcast(); return MPTHolderData{ - .mptID = newMPT[ripple::sfMPTokenIssuanceID], .holder = newMPT.getAccountID(ripple::sfAccount) + .mptID = newMPT[ripple::sfMPTokenIssuanceID], + .holder = newMPT.getAccountID(ripple::sfAccount) }; } } @@ -63,7 +64,8 @@ getMPTokenAuthorize(ripple::TxMeta const& txMeta) std::optional getMPTHolderFromTx(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) { - if (txMeta.getResultTER() != ripple::tesSUCCESS || sttx.getTxnType() != ripple::TxType::ttMPTOKEN_AUTHORIZE) + if (txMeta.getResultTER() != ripple::tesSUCCESS || + sttx.getTxnType() != ripple::TxType::ttMPTOKEN_AUTHORIZE) return {}; return getMPTokenAuthorize(txMeta); @@ -73,10 +75,14 @@ std::optional getMPTHolderFromObj(std::string const& key, std::string const& blob) { // https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0033-multi-purpose-tokens#2121-mptoken-ledger-identifier - ASSERT(key.size() == ripple::uint256::size(), "The size of the key is expected to fit uint256 exactly"); + ASSERT( + key.size() == ripple::uint256::size(), + "The size of the key is expected to fit uint256 exactly" + ); - ripple::STLedgerEntry const sle = - ripple::STLedgerEntry(ripple::SerialIter{blob.data(), blob.size()}, ripple::uint256::fromVoid(key.data())); + ripple::STLedgerEntry const sle = ripple::STLedgerEntry( + ripple::SerialIter{blob.data(), blob.size()}, ripple::uint256::fromVoid(key.data()) + ); if (sle.getFieldU16(ripple::sfLedgerEntryType) != ripple::ltMPTOKEN) return {}; diff --git a/src/etl/Models.hpp b/src/etl/Models.hpp index d91448e0e..f46f143cf 100644 --- a/src/etl/Models.hpp +++ b/src/etl/Models.hpp @@ -43,8 +43,8 @@ namespace etl::model { /** * @brief A specification for the Registry. * - * This specification simply defines the transaction types that are to be filtered out from the incoming transactions by - * the Registry for its `onTransaction` and `onInitialTransaction` hooks. + * This specification simply defines the transaction types that are to be filtered out from the + * incoming transactions by the Registry for its `onTransaction` and `onInitialTransaction` hooks. * It's a compilation error to list the same transaction type more than once. */ template diff --git a/src/etl/MonitorInterface.hpp b/src/etl/MonitorInterface.hpp index 6a57c0579..2ad48d4f4 100644 --- a/src/etl/MonitorInterface.hpp +++ b/src/etl/MonitorInterface.hpp @@ -30,8 +30,8 @@ namespace etl { /** * @brief An interface for the monitor service - * An implementation of this service is responsible for periodically checking various datasources to detect newly - * ingested ledgers. + * An implementation of this service is responsible for periodically checking various datasources to + * detect newly ingested ledgers. */ class MonitorInterface { public: @@ -65,7 +65,8 @@ public: subscribeToNewSequence(NewSequenceSignalType::slot_type const& subscriber) = 0; /** - * @brief Allows clients to get notified when no database update is detected for a configured period. + * @brief Allows clients to get notified when no database update is detected for a configured + * period. * * @param subscriber The slot to connect * @return A connection object that automatically disconnects the subscription once destroyed diff --git a/src/etl/NFTHelpers.cpp b/src/etl/NFTHelpers.cpp index 0f36105d1..c604899f3 100644 --- a/src/etl/NFTHelpers.cpp +++ b/src/etl/NFTHelpers.cpp @@ -54,7 +54,9 @@ getNftokenModifyData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) auto const tokenID = sttx.getFieldH256(ripple::sfNFTokenID); // note: sfURI is optional, if it is absent, we will update the uri as empty string return { - {NFTTransactionsData(sttx.getFieldH256(ripple::sfNFTokenID), txMeta, sttx.getTransactionID())}, + {NFTTransactionsData( + sttx.getFieldH256(ripple::sfNFTokenID), txMeta, sttx.getTransactionID() + )}, NFTsData(tokenID, txMeta, sttx.getFieldVL(ripple::sfURI)) }; } @@ -83,8 +85,9 @@ getNFTokenMintData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) owner = ripple::AccountID::fromVoid(node.getFieldH256(ripple::sfLedgerIndex).data()); if (node.getFName() == ripple::sfCreatedNode) { - ripple::STArray const& toAddNFTs = - node.peekAtField(ripple::sfNewFields).downcast().getFieldArray(ripple::sfNFTokens); + ripple::STArray const& toAddNFTs = node.peekAtField(ripple::sfNewFields) + .downcast() + .getFieldArray(ripple::sfNFTokens); std::ranges::transform( toAddNFTs, @@ -117,8 +120,9 @@ getNFTokenMintData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) [](ripple::STObject const& nft) { return nft.getFieldH256(ripple::sfNFTokenID); } ); - ripple::STArray const& toAddFinalNFTs = - node.peekAtField(ripple::sfFinalFields).downcast().getFieldArray(ripple::sfNFTokens); + ripple::STArray const& toAddFinalNFTs = node.peekAtField(ripple::sfFinalFields) + .downcast() + .getFieldArray(ripple::sfNFTokens); std::ranges::transform( toAddFinalNFTs, @@ -134,7 +138,8 @@ getNFTokenMintData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) // Find the first NFT ID that doesn't match. We're looking for an // added NFT, so the one we want will be the mismatch in finalIDs. // NOLINTNEXTLINE(modernize-use-ranges) - auto const diff = std::mismatch(finalIDs.begin(), finalIDs.end(), prevIDs.begin(), prevIDs.end()); + auto const diff = + std::mismatch(finalIDs.begin(), finalIDs.end(), prevIDs.begin(), prevIDs.end()); // There should always be a difference so the returned finalIDs // iterator should never be end(). But better safe than sorry. @@ -154,7 +159,9 @@ std::pair, std::optional> getNFTokenBurnData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) { ripple::uint256 const tokenID = sttx.getFieldH256(ripple::sfNFTokenID); - std::vector const txs = {NFTTransactionsData(tokenID, txMeta, sttx.getTransactionID())}; + std::vector const txs = { + NFTTransactionsData(tokenID, txMeta, sttx.getTransactionID()) + }; // Determine who owned the token when it was burned by finding an // NFTokenPage that was deleted or modified that contains this @@ -180,22 +187,27 @@ getNFTokenBurnData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) if (previousFields.isFieldPresent(ripple::sfNFTokens)) prevNFTs = previousFields.getFieldArray(ripple::sfNFTokens); } else if (node.getFName() == ripple::sfDeletedNode) { - prevNFTs = - node.peekAtField(ripple::sfFinalFields).downcast().getFieldArray(ripple::sfNFTokens); + prevNFTs = node.peekAtField(ripple::sfFinalFields) + .downcast() + .getFieldArray(ripple::sfNFTokens); } if (!prevNFTs) continue; - auto const nft = - std::find_if(prevNFTs->begin(), prevNFTs->end(), [&tokenID](ripple::STObject const& candidate) { + auto const nft = std::find_if( + prevNFTs->begin(), prevNFTs->end(), [&tokenID](ripple::STObject const& candidate) { return candidate.getFieldH256(ripple::sfNFTokenID) == tokenID; - }); + } + ); if (nft != prevNFTs->end()) { return std::make_pair( txs, NFTsData( - tokenID, ripple::AccountID::fromVoid(node.getFieldH256(ripple::sfLedgerIndex).data()), txMeta, true + tokenID, + ripple::AccountID::fromVoid(node.getFieldH256(ripple::sfLedgerIndex).data()), + txMeta, + true ) ); } @@ -213,10 +225,14 @@ getNFTokenAcceptOfferData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx // more easily by just looking at the owner of the accepted NFTokenOffer // object. if (sttx.isFieldPresent(ripple::sfNFTokenBuyOffer)) { - auto const affectedBuyOffer = - std::find_if(txMeta.getNodes().begin(), txMeta.getNodes().end(), [&sttx](ripple::STObject const& node) { - return node.getFieldH256(ripple::sfLedgerIndex) == sttx.getFieldH256(ripple::sfNFTokenBuyOffer); - }); + auto const affectedBuyOffer = std::find_if( + txMeta.getNodes().begin(), + txMeta.getNodes().end(), + [&sttx](ripple::STObject const& node) { + return node.getFieldH256(ripple::sfLedgerIndex) == + sttx.getFieldH256(ripple::sfNFTokenBuyOffer); + } + ); if (affectedBuyOffer == txMeta.getNodes().end()) { std::stringstream msg; msg << " - unexpected NFTokenAcceptOffer data in tx " << sttx.getTransactionID(); @@ -231,15 +247,18 @@ getNFTokenAcceptOfferData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx .downcast() .getAccountID(ripple::sfOwner); return { - {NFTTransactionsData(tokenID, txMeta, sttx.getTransactionID())}, NFTsData(tokenID, owner, txMeta, false) + {NFTTransactionsData(tokenID, txMeta, sttx.getTransactionID())}, + NFTsData(tokenID, owner, txMeta, false) }; } // Otherwise we have to infer the new owner from the affected nodes. - auto const affectedSellOffer = - std::find_if(txMeta.getNodes().begin(), txMeta.getNodes().end(), [&sttx](ripple::STObject const& node) { - return node.getFieldH256(ripple::sfLedgerIndex) == sttx.getFieldH256(ripple::sfNFTokenSellOffer); - }); + auto const affectedSellOffer = std::find_if( + txMeta.getNodes().begin(), txMeta.getNodes().end(), [&sttx](ripple::STObject const& node) { + return node.getFieldH256(ripple::sfLedgerIndex) == + sttx.getFieldH256(ripple::sfNFTokenSellOffer); + } + ); if (affectedSellOffer == txMeta.getNodes().end()) { std::stringstream msg; msg << " - unexpected NFTokenAcceptOffer data in tx " << sttx.getTransactionID(); @@ -303,8 +322,9 @@ getNFTokenCancelOfferData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx if (node.getFieldU16(ripple::sfLedgerEntryType) != ripple::ltNFTOKEN_OFFER) continue; - ripple::uint256 const tokenID = - node.peekAtField(ripple::sfFinalFields).downcast().getFieldH256(ripple::sfNFTokenID); + ripple::uint256 const tokenID = node.peekAtField(ripple::sfFinalFields) + .downcast() + .getFieldH256(ripple::sfNFTokenID); txs.emplace_back(tokenID, txMeta, sttx.getTransactionID()); } @@ -312,9 +332,10 @@ getNFTokenCancelOfferData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx std::ranges::sort(txs, [](NFTTransactionsData const& a, NFTTransactionsData const& b) { return a.tokenID < b.tokenID; }); - auto [last, end] = std::ranges::unique(txs, [](NFTTransactionsData const& a, NFTTransactionsData const& b) { - return a.tokenID == b.tokenID; - }); + auto [last, end] = + std::ranges::unique(txs, [](NFTTransactionsData const& a, NFTTransactionsData const& b) { + return a.tokenID == b.tokenID; + }); txs.erase(last, end); return {txs, {}}; } @@ -324,7 +345,12 @@ getNFTokenCancelOfferData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx std::pair, std::optional> getNFTokenCreateOfferData(ripple::TxMeta const& txMeta, ripple::STTx const& sttx) { - return {{NFTTransactionsData(sttx.getFieldH256(ripple::sfNFTokenID), txMeta, sttx.getTransactionID())}, {}}; + return { + {NFTTransactionsData( + sttx.getFieldH256(ripple::sfNFTokenID), txMeta, sttx.getTransactionID() + )}, + {} + }; } std::pair, std::optional> @@ -361,10 +387,14 @@ std::vector getNFTDataFromObj(std::uint32_t const seq, std::string const& key, std::string const& blob) { // https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0020-non-fungible-tokens#tokenpage-id-format - ASSERT(key.size() == ripple::uint256::size(), "The size of the key (token) is expected to fit uint256 exactly"); + ASSERT( + key.size() == ripple::uint256::size(), + "The size of the key (token) is expected to fit uint256 exactly" + ); - auto const sle = - ripple::STLedgerEntry(ripple::SerialIter{blob.data(), blob.size()}, ripple::uint256::fromVoid(key.data())); + auto const sle = ripple::STLedgerEntry( + ripple::SerialIter{blob.data(), blob.size()}, ripple::uint256::fromVoid(key.data()) + ); if (sle.getFieldU16(ripple::sfLedgerEntryType) != ripple::ltNFTOKEN_PAGE) return {}; @@ -373,7 +403,9 @@ getNFTDataFromObj(std::uint32_t const seq, std::string const& key, std::string c std::vector nfts; for (ripple::STObject const& node : sle.getFieldArray(ripple::sfNFTokens)) - nfts.emplace_back(node.getFieldH256(ripple::sfNFTokenID), seq, owner, node.getFieldVL(ripple::sfURI)); + nfts.emplace_back( + node.getFieldH256(ripple::sfNFTokenID), seq, owner, node.getFieldVL(ripple::sfURI) + ); return nfts; } @@ -384,11 +416,13 @@ getUniqueNFTsDatas(std::vector const& nfts) std::vector results = nfts; std::ranges::sort(results, [](NFTsData const& a, NFTsData const& b) { - return a.tokenID == b.tokenID ? a.transactionIndex > b.transactionIndex : a.tokenID > b.tokenID; + return a.tokenID == b.tokenID ? a.transactionIndex > b.transactionIndex + : a.tokenID > b.tokenID; }); - auto const [last, end] = - std::ranges::unique(results, [](NFTsData const& a, NFTsData const& b) { return a.tokenID == b.tokenID; }); + auto const [last, end] = std::ranges::unique(results, [](NFTsData const& a, NFTsData const& b) { + return a.tokenID == b.tokenID; + }); results.erase(last, end); return results; } diff --git a/src/etl/NFTHelpers.hpp b/src/etl/NFTHelpers.hpp index ef8cdb74b..30c9b5726 100644 --- a/src/etl/NFTHelpers.hpp +++ b/src/etl/NFTHelpers.hpp @@ -115,7 +115,8 @@ std::vector getNFTDataFromObj(std::uint32_t seq, std::string const& key, std::string const& blob); /** - * @brief Get the unique NFTs data from a vector of NFTsData happening in the same ledger. For example, if a NFT has + * @brief Get the unique NFTs data from a vector of NFTsData happening in the same ledger. For + example, if a NFT has * both accept offer and burn happening in the same ledger,we only keep the final state of the NFT. * @param nfts The NFTs data to filter, happening in the same ledger diff --git a/src/etl/NetworkValidatedLedgers.cpp b/src/etl/NetworkValidatedLedgers.cpp index cd9fa93b8..04295866d 100644 --- a/src/etl/NetworkValidatedLedgers.cpp +++ b/src/etl/NetworkValidatedLedgers.cpp @@ -54,7 +54,10 @@ NetworkValidatedLedgers::getMostRecent() } bool -NetworkValidatedLedgers::waitUntilValidatedByNetwork(uint32_t sequence, std::optional maxWaitMs) +NetworkValidatedLedgers::waitUntilValidatedByNetwork( + uint32_t sequence, + std::optional maxWaitMs +) { std::unique_lock lck(mtx_); auto pred = [sequence, this]() -> bool { return (latest_ && sequence <= *latest_); }; diff --git a/src/etl/NetworkValidatedLedgers.hpp b/src/etl/NetworkValidatedLedgers.hpp index 28acc0abf..56ae963a7 100644 --- a/src/etl/NetworkValidatedLedgers.hpp +++ b/src/etl/NetworkValidatedLedgers.hpp @@ -34,12 +34,13 @@ namespace etl { /** - * @brief This datastructure is used to keep track of the sequence of the most recent ledger validated by the network. + * @brief This datastructure is used to keep track of the sequence of the most recent ledger + * validated by the network. * - * There are two methods that will wait until certain conditions are met. This datastructure is able to be "stopped". - * When the datastructure is stopped, any threads currently waiting are unblocked. - * Any later calls to methods of this datastructure will not wait. Once the datastructure is stopped, the datastructure - * remains stopped for the rest of its lifetime. + * There are two methods that will wait until certain conditions are met. This datastructure is able + * to be "stopped". When the datastructure is stopped, any threads currently waiting are unblocked. + * Any later calls to methods of this datastructure will not wait. Once the datastructure is + * stopped, the datastructure remains stopped for the rest of its lifetime. */ class NetworkValidatedLedgers : public NetworkValidatedLedgersInterface { std::optional latest_; // currently known latest sequence validated by network @@ -69,9 +70,11 @@ public: /** * @brief Get most recently validated sequence. * - * If no ledgers are known to have been validated, this function waits until the next ledger is validated + * If no ledgers are known to have been validated, this function waits until the next ledger is + * validated * - * @return Sequence of most recently validated ledger. empty optional if the datastructure has been stopped + * @return Sequence of most recently validated ledger. empty optional if the datastructure has + * been stopped */ std::optional getMostRecent() final; @@ -80,9 +83,10 @@ public: * @brief Waits for the sequence to be validated by the network. * * @param sequence The sequence to wait for - * @param maxWaitMs Maximum time to wait for the sequence to be validated. If empty, wait indefinitely - * @return true if sequence was validated, false otherwise a return value of false means the datastructure has been - * stopped + * @param maxWaitMs Maximum time to wait for the sequence to be validated. If empty, wait + * indefinitely + * @return true if sequence was validated, false otherwise a return value of false means the + * datastructure has been stopped */ bool waitUntilValidatedByNetwork(uint32_t sequence, std::optional maxWaitMs = {}) final; diff --git a/src/etl/NetworkValidatedLedgersInterface.hpp b/src/etl/NetworkValidatedLedgersInterface.hpp index 067407c8c..65ca866eb 100644 --- a/src/etl/NetworkValidatedLedgersInterface.hpp +++ b/src/etl/NetworkValidatedLedgersInterface.hpp @@ -49,9 +49,11 @@ public: /** * @brief Get most recently validated sequence. * - * If no ledgers are known to have been validated, this function waits until the next ledger is validated + * If no ledgers are known to have been validated, this function waits until the next ledger is + * validated * - * @return Sequence of most recently validated ledger. empty optional if the datastructure has been stopped + * @return Sequence of most recently validated ledger. empty optional if the datastructure has + * been stopped */ [[nodiscard]] virtual std::optional getMostRecent() = 0; @@ -60,9 +62,10 @@ public: * @brief Waits for the sequence to be validated by the network. * * @param sequence The sequence to wait for - * @param maxWaitMs Maximum time to wait for the sequence to be validated. If empty, wait indefinitely - * @return true if sequence was validated, false otherwise a return value of false means the datastructure has been - * stopped + * @param maxWaitMs Maximum time to wait for the sequence to be validated. If empty, wait + * indefinitely + * @return true if sequence was validated, false otherwise a return value of false means the + * datastructure has been stopped */ virtual bool waitUntilValidatedByNetwork(uint32_t sequence, std::optional maxWaitMs = {}) = 0; diff --git a/src/etl/RegistryInterface.hpp b/src/etl/RegistryInterface.hpp index 0b46e5857..cdd1113a1 100644 --- a/src/etl/RegistryInterface.hpp +++ b/src/etl/RegistryInterface.hpp @@ -46,13 +46,14 @@ namespace etl { * - void onInitialObjects(uint32_t, std::vector const&, std::string) * - void onInitialObject(uint32_t, etl::model::Object const&) * - * When the registry dispatches (initial)data or objects, each of the above hooks will be called in order on each - * registered extension. - * This means that the order of execution is from left to right (hooks) and top to bottom (registered extensions). + * When the registry dispatches (initial)data or objects, each of the above hooks will be called in + * order on each registered extension. This means that the order of execution is from left to right + * (hooks) and top to bottom (registered extensions). * - * If either `onTransaction` or `onInitialTransaction` are defined, the extension will have to additionally define a - * Specification. The specification lists transaction types to filter from the incoming data such that `onTransaction` - * and `onInitialTransaction` are only called for the transactions that are of interest for the given extension. + * If either `onTransaction` or `onInitialTransaction` are defined, the extension will have to + * additionally define a Specification. The specification lists transaction types to filter from the + * incoming data such that `onTransaction` and `onInitialTransaction` are only called for the + * transactions that are of interest for the given extension. * * The specification is setup like so: * @code{.cpp} @@ -82,7 +83,11 @@ struct RegistryInterface { * @param lastKey The predcessor of the first object in data if known; an empty string otherwise */ virtual void - dispatchInitialObjects(uint32_t seq, std::vector const& data, std::string lastKey) = 0; + dispatchInitialObjects( + uint32_t seq, + std::vector const& data, + std::string lastKey + ) = 0; /** * @brief Dispatch initial ledger data. diff --git a/src/etl/Source.cpp b/src/etl/Source.cpp index a9be91c80..04536ceb9 100644 --- a/src/etl/Source.cpp +++ b/src/etl/Source.cpp @@ -66,7 +66,12 @@ makeSource( ); return std::make_unique>( - ip, wsPort, grpcPort, std::move(grpcSource), std::move(subscriptionSource), std::move(forwardingSource) + ip, + wsPort, + grpcPort, + std::move(grpcSource), + std::move(subscriptionSource), + std::move(forwardingSource) ); } diff --git a/src/etl/Source.hpp b/src/etl/Source.hpp index 2b058648c..48cd2898e 100644 --- a/src/etl/Source.hpp +++ b/src/etl/Source.hpp @@ -112,11 +112,12 @@ public: /** * @brief Fetch data for a specific ledger. * - * This function will continuously try to fetch data for the specified ledger until the fetch succeeds, the ledger - * is found in the database, or the server is shutting down. + * This function will continuously try to fetch data for the specified ledger until the fetch + * succeeds, the ledger is found in the database, or the server is shutting down. * * @param sequence Sequence of the ledger to fetch - * @param getObjects Whether to get the account state diff between this ledger and the prior one; defaults to true + * @param getObjects Whether to get the account state diff between this ledger and the prior + * one; defaults to true * @param getObjectNeighbors Whether to request object neighbors; defaults to false * @return A std::pair of the response status and the response itself */ @@ -132,7 +133,11 @@ public: * @return A std::pair of the data and a bool indicating whether the download was successful */ virtual InitialLedgerLoadResult - loadInitialLedger(uint32_t sequence, std::uint32_t numMarkers, InitialLoadObserverInterface& loader) = 0; + loadInitialLedger( + uint32_t sequence, + std::uint32_t numMarkers, + InitialLoadObserverInterface& loader + ) = 0; /** * @brief Forward a request to rippled. @@ -175,8 +180,8 @@ using SourceFactory = std::function systemState_; /**< @brief Shared system state for ETL coordination */ + std::shared_ptr + systemState_; /**< @brief Shared system state for ETL coordination */ public: /** diff --git a/src/etl/impl/AmendmentBlockHandler.cpp b/src/etl/impl/AmendmentBlockHandler.cpp index b066ae11d..7291accd2 100644 --- a/src/etl/impl/AmendmentBlockHandler.cpp +++ b/src/etl/impl/AmendmentBlockHandler.cpp @@ -30,11 +30,15 @@ namespace etl::impl { -AmendmentBlockHandler::ActionType const AmendmentBlockHandler::kDEFAULT_AMENDMENT_BLOCK_ACTION = []() { - static util::Logger const log{"ETL"}; // NOLINT(readability-identifier-naming) - LOG(log.fatal()) << "Can't process new ledgers: The current ETL source is not compatible with the version of " - << "the libxrpl Clio is currently using. Please upgrade Clio to a newer version."; -}; +AmendmentBlockHandler::ActionType const AmendmentBlockHandler::kDEFAULT_AMENDMENT_BLOCK_ACTION = + []() { + static util::Logger const log{"ETL"}; // NOLINT(readability-identifier-naming) + LOG( + log.fatal() + ) << "Can't process new ledgers: The current ETL source is not compatible with the version " + "of " + << "the libxrpl Clio is currently using. Please upgrade Clio to a newer version."; + }; AmendmentBlockHandler::AmendmentBlockHandler( util::async::AnyExecutionContext ctx, diff --git a/src/etl/impl/AsyncGrpcCall.cpp b/src/etl/impl/AsyncGrpcCall.cpp index 7e34dd571..3e1416794 100644 --- a/src/etl/impl/AsyncGrpcCall.cpp +++ b/src/etl/impl/AsyncGrpcCall.cpp @@ -138,14 +138,17 @@ AsyncGrpcCall::process( if (not data.empty()) loader.onInitialLoadGotMoreObjects(request_.ledger().sequence(), data, predecessorKey_); - predecessorKey_ = lastKey_; // but for ongoing onInitialObjects calls we need to pass along the key we left - // off at so that we can link the two lists correctly + predecessorKey_ = lastKey_; // but for ongoing onInitialObjects calls we need to pass along the + // key we left off at so that we can link the two lists correctly return more ? CallStatus::More : CallStatus::Done; } void -AsyncGrpcCall::call(std::unique_ptr& stub, grpc::CompletionQueue& cq) +AsyncGrpcCall::call( + std::unique_ptr& stub, + grpc::CompletionQueue& cq +) { context_ = std::make_unique(); auto rpc = stub->PrepareAsyncGetLedgerData(context_.get(), request_, &cq); @@ -157,7 +160,8 @@ AsyncGrpcCall::call(std::unique_ptrmarker().empty() ? std::string{} : ripple::strHex(std::string{next_->marker().data()[0]}); + return next_->marker().empty() ? std::string{} + : ripple::strHex(std::string{next_->marker().data()[0]}); } // this is used to generate edgeKeys - keys that were the last one in the onInitialObjects list diff --git a/src/etl/impl/AsyncGrpcCall.hpp b/src/etl/impl/AsyncGrpcCall.hpp index 4d54fe3e6..7701cfff0 100644 --- a/src/etl/impl/AsyncGrpcCall.hpp +++ b/src/etl/impl/AsyncGrpcCall.hpp @@ -59,7 +59,11 @@ private: std::optional predecessorKey_; public: - AsyncGrpcCall(uint32_t seq, ripple::uint256 const& marker, std::optional const& nextMarker); + AsyncGrpcCall( + uint32_t seq, + ripple::uint256 const& marker, + std::optional const& nextMarker + ); static std::vector makeAsyncCalls(uint32_t const sequence, uint32_t const numMarkers); @@ -73,7 +77,10 @@ public: ); void - call(std::unique_ptr& stub, grpc::CompletionQueue& cq); + call( + std::unique_ptr& stub, + grpc::CompletionQueue& cq + ); std::string getMarkerPrefix(); diff --git a/src/etl/impl/CacheLoader.hpp b/src/etl/impl/CacheLoader.hpp index 6aab058a5..44b82431d 100644 --- a/src/etl/impl/CacheLoader.hpp +++ b/src/etl/impl/CacheLoader.hpp @@ -70,7 +70,11 @@ public: std::size_t const cachePageFetchSize, std::vector const& cursors ) - : ctx_{ctx}, backend_{backend}, cache_{std::ref(cache)}, queue_{cursors.size()}, remaining_{cursors.size()} + : ctx_{ctx} + , backend_{backend} + , cache_{std::ref(cache)} + , queue_{cursors.size()} + , remaining_{cursors.size()} { std::ranges::for_each(cursors, [this](auto const& cursor) { queue_.push(cursor); }); load(seq, numCacheMarkers, cachePageFetchSize); @@ -123,19 +127,25 @@ private: LOG(log_.debug()) << "Starting a cursor: " << ripple::strHex(start); while (not token.isStopRequested() and not cache_.get().isDisabled()) { - auto res = data::retryOnTimeout([this, seq, cachePageFetchSize, &start, token]() { - return backend_->fetchLedgerPage(start, seq, cachePageFetchSize, false, token); - }); + auto res = + data::retryOnTimeout([this, seq, cachePageFetchSize, &start, token]() { + return backend_->fetchLedgerPage( + start, seq, cachePageFetchSize, false, token + ); + }); cache_.get().update(res.objects, seq, true); if (not res.cursor or res.cursor > end) { if (--remaining_ <= 0) { auto endTime = std::chrono::steady_clock::now(); - auto duration = std::chrono::duration_cast(endTime - startTime_); + auto duration = std::chrono::duration_cast( + endTime - startTime_ + ); - LOG(log_.info()) << "Finished loading cache. Cache size = " << cache_.get().size() - << ". Took " << duration.count() << " seconds"; + LOG(log_.info()) + << "Finished loading cache. Cache size = " << cache_.get().size() + << ". Took " << duration.count() << " seconds"; cache_.get().setFull(); } else { diff --git a/src/etl/impl/CursorFromAccountProvider.hpp b/src/etl/impl/CursorFromAccountProvider.hpp index 0ae6d8a77..7dd3ae07a 100644 --- a/src/etl/impl/CursorFromAccountProvider.hpp +++ b/src/etl/impl/CursorFromAccountProvider.hpp @@ -41,7 +41,11 @@ class CursorFromAccountProvider : public BaseCursorProvider { size_t pageSize_; public: - CursorFromAccountProvider(std::shared_ptr const& backend, size_t numCursors, size_t pageSize) + CursorFromAccountProvider( + std::shared_ptr const& backend, + size_t numCursors, + size_t pageSize + ) : backend_{backend}, numCursors_{numCursors}, pageSize_{pageSize} { } diff --git a/src/etl/impl/CursorFromDiffProvider.hpp b/src/etl/impl/CursorFromDiffProvider.hpp index e5f091c13..45eeabed1 100644 --- a/src/etl/impl/CursorFromDiffProvider.hpp +++ b/src/etl/impl/CursorFromDiffProvider.hpp @@ -86,7 +86,10 @@ public: } std::vector cursors{data::kFIRST_KEY}; - rg::copy(liveCursors | vs::take(std::min(liveCursors.size(), numCursors_)), std::back_inserter(cursors)); + rg::copy( + liveCursors | vs::take(std::min(liveCursors.size(), numCursors_)), + std::back_inserter(cursors) + ); rg::sort(cursors); cursors.push_back(data::kLAST_KEY); diff --git a/src/etl/impl/CursorFromFixDiffNumProvider.hpp b/src/etl/impl/CursorFromFixDiffNumProvider.hpp index 5daac00b8..f31175600 100644 --- a/src/etl/impl/CursorFromFixDiffNumProvider.hpp +++ b/src/etl/impl/CursorFromFixDiffNumProvider.hpp @@ -58,7 +58,9 @@ public: auto diffs = std::vector{}; - auto const append = [](auto&& a, auto&& b) { a.insert(std::end(a), std::begin(b), std::end(b)); }; + auto const append = [](auto&& a, auto&& b) { + a.insert(std::end(a), std::begin(b), std::end(b)); + }; auto const fetchDiff = [this, seq](uint32_t offset) { return data::synchronousAndRetryOnTimeout([this, seq, offset](auto yield) { return backend_->fetchLedgerDiff(seq - offset, yield); diff --git a/src/etl/impl/Extraction.cpp b/src/etl/impl/Extraction.cpp index b048a4510..895e3d2ca 100644 --- a/src/etl/impl/Extraction.cpp +++ b/src/etl/impl/Extraction.cpp @@ -62,7 +62,11 @@ extractModType(PBModType type) case PBObjType::DELETED: return model::Object::ModType::Deleted; default: // some gRPC system values that we don't care about - ASSERT(false, "Tried to extract bogus mod type '{}'", PBObjType::ModificationType_Name(type)); + ASSERT( + false, + "Tried to extract bogus mod type '{}'", + PBObjType::ModificationType_Name(type) + ); } std::unreachable(); @@ -97,7 +101,10 @@ extractTxs(PBTxListType transactions, uint32_t seq) std::vector output; output.reserve(transactions.size()); - rg::move(transactions | vs::transform([seq](auto&& tx) { return extractTx(tx, seq); }), std::back_inserter(output)); + rg::move( + transactions | vs::transform([seq](auto&& tx) { return extractTx(tx, seq); }), + std::back_inserter(output) + ); return output; } @@ -134,7 +141,10 @@ extractObjs(PBObjListType objects) std::vector output; output.reserve(objects.size()); - rg::move(objects | vs::transform([](auto&& obj) { return extractObj(obj); }), std::back_inserter(output)); + rg::move( + objects | vs::transform([](auto&& obj) { return extractObj(obj); }), + std::back_inserter(output) + ); return output; } @@ -174,8 +184,9 @@ Extractor::unpack() auto header = ::util::deserializeHeader(ripple::makeSlice(data.ledger_header())); return std::make_optional({ - .transactions = - extractTxs(std::move(*data.mutable_transactions_list()->mutable_transactions()), header.seq), + .transactions = extractTxs( + std::move(*data.mutable_transactions_list()->mutable_transactions()), header.seq + ), .objects = extractObjs(std::move(*data.mutable_ledger_objects()->mutable_objects())), .successors = maybeExtractSuccessors(data), .edgeKeys = std::nullopt, @@ -197,7 +208,8 @@ Extractor::extractLedgerWithDiff(uint32_t seq) LOG(log_.debug()) << "Extracted and Transformed diff for " << seq << " in " << time << "ms"; - // can be nullopt. this means that either the server is stopping or another node took over ETL writing. + // can be nullopt. this means that either the server is stopping or another node took over ETL + // writing. return batch; } @@ -210,9 +222,11 @@ Extractor::extractLedgerOnly(uint32_t seq) return fetcher_->fetchData(seq).and_then(unpack()); }); - LOG(log_.debug()) << "Extracted and Transformed full ledger for " << seq << " in " << time << "ms"; + LOG(log_.debug()) << "Extracted and Transformed full ledger for " << seq << " in " << time + << "ms"; - // can be nullopt. this means that either the server is stopping or another node took over ETL writing. + // can be nullopt. this means that either the server is stopping or another node took over ETL + // writing. return batch; } diff --git a/src/etl/impl/ForwardingSource.cpp b/src/etl/impl/ForwardingSource.cpp index 65af8feb1..7bf72e1e7 100644 --- a/src/etl/impl/ForwardingSource.cpp +++ b/src/etl/impl/ForwardingSource.cpp @@ -52,7 +52,8 @@ ForwardingSource::ForwardingSource( { connectionBuilder_.setConnectionTimeout(connTimeout) .addHeader( - {boost::beast::http::field::user_agent, fmt::format("{} websocket-client-coro", BOOST_BEAST_VERSION_STRING)} + {boost::beast::http::field::user_agent, + fmt::format("{} websocket-client-coro", BOOST_BEAST_VERSION_STRING)} ); } @@ -103,7 +104,8 @@ ForwardingSource::forwardToRippled( if (not parsedResponse.is_object()) throw std::runtime_error("response is not an object"); } catch (std::exception const& e) { - LOG(log_.debug()) << "Error parsing response from rippled: " << e.what() << ". Response: " << *response; + LOG(log_.debug()) << "Error parsing response from rippled: " << e.what() + << ". Response: " << *response; return std::unexpected{rpc::ClioError::EtlInvalidResponse}; } diff --git a/src/etl/impl/GrpcSource.cpp b/src/etl/impl/GrpcSource.cpp index d257f82d8..5e5629294 100644 --- a/src/etl/impl/GrpcSource.cpp +++ b/src/etl/impl/GrpcSource.cpp @@ -65,7 +65,11 @@ resolve(std::string const& ip, std::string const& port) namespace etl::impl { -GrpcSource::GrpcSource(std::string const& ip, std::string const& grpcPort, std::chrono::system_clock::duration deadline) +GrpcSource::GrpcSource( + std::string const& ip, + std::string const& grpcPort, + std::chrono::system_clock::duration deadline +) : log_(fmt::format("ETL_Grpc[{}:{}]", ip, grpcPort)) , initialLoadShouldStop_(std::make_unique(false)) , deadline_{deadline} @@ -75,11 +79,16 @@ GrpcSource::GrpcSource(std::string const& ip, std::string const& grpcPort, std:: chArgs.SetMaxReceiveMessageSize(-1); chArgs.SetInt(GRPC_ARG_KEEPALIVE_TIME_MS, kKEEPALIVE_PING_INTERVAL_MS); chArgs.SetInt(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, kKEEPALIVE_TIMEOUT_MS); - chArgs.SetInt(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, static_cast(kKEEPALIVE_PERMIT_WITHOUT_CALLS)); + chArgs.SetInt( + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, + static_cast(kKEEPALIVE_PERMIT_WITHOUT_CALLS) + ); chArgs.SetInt(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, kMAX_PINGS_WITHOUT_DATA); stub_ = org::xrpl::rpc::v1::XRPLedgerAPIService::NewStub( - grpc::CreateCustomChannel(resolve(ip, grpcPort), grpc::InsecureChannelCredentials(), chArgs) + grpc::CreateCustomChannel( + resolve(ip, grpcPort), grpc::InsecureChannelCredentials(), chArgs + ) ); LOG(log_.debug()) << "Made stub for remote."; @@ -98,7 +107,9 @@ GrpcSource::fetchLedger(uint32_t sequence, bool getObjects, bool getObjectNeighb org::xrpl::rpc::v1::GetLedgerRequest request; grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + deadline_); // Prevent indefinite blocking + context.set_deadline( + std::chrono::system_clock::now() + deadline_ + ); // Prevent indefinite blocking request.mutable_ledger()->set_sequence(sequence); request.set_transactions(true); @@ -110,7 +121,8 @@ GrpcSource::fetchLedger(uint32_t sequence, bool getObjects, bool getObjectNeighb grpc::Status const status = stub_->GetLedger(&context, request, &response); if (status.ok() and not response.is_unlimited()) { - log_.warn() << "is_unlimited is false. Make sure secure_gateway is set correctly on the ETL source. Status = " + log_.warn() << "is_unlimited is false. Make sure secure_gateway is set correctly on the " + "ETL source. Status = " << status.error_message(); } diff --git a/src/etl/impl/GrpcSource.hpp b/src/etl/impl/GrpcSource.hpp index aa80b5eb5..0076c76f3 100644 --- a/src/etl/impl/GrpcSource.hpp +++ b/src/etl/impl/GrpcSource.hpp @@ -45,8 +45,9 @@ class GrpcSource { static constexpr auto kKEEPALIVE_PING_INTERVAL_MS = 10000; static constexpr auto kKEEPALIVE_TIMEOUT_MS = 5000; - static constexpr auto kKEEPALIVE_PERMIT_WITHOUT_CALLS = true; // Allow keepalive pings when no calls - static constexpr auto kMAX_PINGS_WITHOUT_DATA = 0; // No limit + static constexpr auto kKEEPALIVE_PERMIT_WITHOUT_CALLS = + true; // Allow keepalive pings when no calls + static constexpr auto kMAX_PINGS_WITHOUT_DATA = 0; // No limit static constexpr auto kDEADLINE = std::chrono::seconds(30); public: @@ -59,11 +60,12 @@ public: /** * @brief Fetch data for a specific ledger. * - * This function will continuously try to fetch data for the specified ledger until the fetch succeeds, the ledger - * is found in the database, or the server is shutting down. + * This function will continuously try to fetch data for the specified ledger until the fetch + * succeeds, the ledger is found in the database, or the server is shutting down. * * @param sequence Sequence of the ledger to fetch - * @param getObjects Whether to get the account state diff between this ledger and the prior one; defaults to true + * @param getObjects Whether to get the account state diff between this ledger and the prior + * one; defaults to true * @param getObjectNeighbors Whether to request object neighbors; defaults to false * @return A std::pair of the response status and the response itself */ @@ -79,7 +81,11 @@ public: * @return Downloaded data or an indication of error or cancellation */ InitialLedgerLoadResult - loadInitialLedger(uint32_t sequence, uint32_t numMarkers, InitialLoadObserverInterface& observer); + loadInitialLedger( + uint32_t sequence, + uint32_t numMarkers, + InitialLoadObserverInterface& observer + ); /** * @brief Stop any ongoing operations diff --git a/src/etl/impl/LedgerFetcher.hpp b/src/etl/impl/LedgerFetcher.hpp index b7865e3d8..aa67f9439 100644 --- a/src/etl/impl/LedgerFetcher.hpp +++ b/src/etl/impl/LedgerFetcher.hpp @@ -47,7 +47,10 @@ public: /** * @brief Create an instance of the fetcher */ - LedgerFetcher(std::shared_ptr backend, std::shared_ptr balancer) + LedgerFetcher( + std::shared_ptr backend, + std::shared_ptr balancer + ) : backend_(std::move(backend)), loadBalancer_(std::move(balancer)) { } @@ -55,11 +58,12 @@ public: /** * @brief Extract data for a particular ledger from an ETL source * - * This function continuously tries to extract the specified ledger (using all available ETL sources) until the - * extraction succeeds, or the server shuts down. + * This function continuously tries to extract the specified ledger (using all available ETL + * sources) until the extraction succeeds, or the server shuts down. * * @param sequence sequence of the ledger to extract - * @return Ledger header and transaction+metadata blobs; Empty optional if the server is shutting down + * @return Ledger header and transaction+metadata blobs; Empty optional if the server is + * shutting down */ [[nodiscard]] OptionalGetLedgerResponseType fetchData(uint32_t sequence) override @@ -75,11 +79,12 @@ public: /** * @brief Extract diff data for a particular ledger from an ETL source. * - * This function continuously tries to extract the specified ledger (using all available ETL sources) until the - * extraction succeeds, or the server shuts down. + * This function continuously tries to extract the specified ledger (using all available ETL + * sources) until the extraction succeeds, or the server shuts down. * * @param sequence sequence of the ledger to extract - * @return Ledger data diff between sequance and parent; Empty optional if the server is shutting down + * @return Ledger data diff between sequance and parent; Empty optional if the server is + * shutting down */ [[nodiscard]] OptionalGetLedgerResponseType fetchDataAndDiff(uint32_t sequence) override @@ -89,7 +94,8 @@ public: auto const isCacheFull = backend_->cache().isFull(); auto const isLedgerCached = backend_->cache().latestLedgerSequence() >= sequence; if (isLedgerCached) { - LOG(log_.info()) << sequence << " is already cached, the current latest seq in cache is " + LOG(log_.info()) << sequence + << " is already cached, the current latest seq in cache is " << backend_->cache().latestLedgerSequence() << " and the cache is " << (isCacheFull ? "full" : "not full"); } diff --git a/src/etl/impl/LedgerPublisher.hpp b/src/etl/impl/LedgerPublisher.hpp index 1db50299b..82cd7f353 100644 --- a/src/etl/impl/LedgerPublisher.hpp +++ b/src/etl/impl/LedgerPublisher.hpp @@ -64,13 +64,14 @@ namespace etl::impl { /** * @brief Publishes ledgers in a synchronized fashion. * - * If ETL is started far behind the network, ledgers will be written and published very rapidly. Monitoring processes - * will publish ledgers as they are written. However, to publish a ledger, the monitoring process needs to read all of - * the transactions for that ledger from the database. Reading the transactions from the database requires network - * calls, which can be slow. It is imperative however that the monitoring processes keep up with the writer, else the - * monitoring processes will not be able to detect if the writer failed. Therefore, publishing each ledger (which - * includes reading all of the transactions from the database) is done from the application wide asio io_service, and a - * strand is used to ensure ledgers are published in order. + * If ETL is started far behind the network, ledgers will be written and published very rapidly. + * Monitoring processes will publish ledgers as they are written. However, to publish a ledger, the + * monitoring process needs to read all of the transactions for that ledger from the database. + * Reading the transactions from the database requires network calls, which can be slow. It is + * imperative however that the monitoring processes keep up with the writer, else the monitoring + * processes will not be able to detect if the writer failed. Therefore, publishing each ledger + * (which includes reading all of the transactions from the database) is done from the application + * wide asio io_service, and a strand is used to ensure ledgers are published in order. */ class LedgerPublisher : public LedgerPublisherInterface { util::Logger log_{"ETL"}; @@ -85,11 +86,12 @@ class LedgerPublisher : public LedgerPublisherInterface { util::Mutex, std::shared_mutex> lastCloseTime_; - std::reference_wrapper lastPublishSeconds_ = PrometheusService::counterInt( - "etl_last_publish_seconds", - {}, - "Seconds since epoch of the last published ledger" - ); + std::reference_wrapper lastPublishSeconds_ = + PrometheusService::counterInt( + "etl_last_publish_seconds", + {}, + "Seconds since epoch of the last published ledger" + ); util::Mutex, std::shared_mutex> lastPublishedSequence_; @@ -111,8 +113,8 @@ public: } /** - * @brief Attempt to read the specified ledger from the database, and then publish that ledger to the ledgers - * stream. + * @brief Attempt to read the specified ledger from the database, and then publish that ledger + * to the ledgers stream. * * @param ledgerSequence the sequence of the ledger to publish * @param maxAttempts the number of times to attempt to read the ledger from the database @@ -133,11 +135,14 @@ public: if (!range || range->maxSequence < ledgerSequence) { ++numAttempts; - LOG(log_.debug()) << "Trying to publish. Could not find ledger with sequence = " << ledgerSequence; + LOG(log_.debug()) << "Trying to publish. Could not find ledger with sequence = " + << ledgerSequence; - // We try maxAttempts times to publish the ledger, waiting one second in between each attempt. + // We try maxAttempts times to publish the ledger, waiting one second in between + // each attempt. if (maxAttempts && numAttempts >= maxAttempts) { - LOG(log_.debug()) << "Failed to publish ledger after " << numAttempts << " attempts."; + LOG(log_.debug()) + << "Failed to publish ledger after " << numAttempts << " attempts."; return false; } std::this_thread::sleep_for(attemptsDelay); @@ -148,7 +153,11 @@ public: return backend_->fetchLedgerBySequence(ledgerSequence, yield); }); - ASSERT(lgr.has_value(), "Ledger must exist in database. Ledger sequence = {}", ledgerSequence); + ASSERT( + lgr.has_value(), + "Ledger must exist in database. Ledger sequence = {}", + ledgerSequence + ); publish(*lgr); return true; @@ -159,7 +168,8 @@ public: /** * @brief Publish the passed ledger asynchronously. * - * All ledgers are published thru publishStrand_ which ensures that all publishes are performed in a serial fashion. + * All ledgers are published thru publishStrand_ which ensures that all publishes are performed + * in a serial fashion. * * @param lgrInfo the ledger to publish */ @@ -172,12 +182,14 @@ public: setLastClose(lgrInfo.closeTime); auto age = lastCloseAgeSeconds(); - // if the ledger closed over MAX_LEDGER_AGE_SECONDS ago, assume we are still catching up and don't publish + // if the ledger closed over MAX_LEDGER_AGE_SECONDS ago, assume we are still catching up + // and don't publish static constexpr std::uint32_t kMAX_LEDGER_AGE_SECONDS = 600; if (age < kMAX_LEDGER_AGE_SECONDS) { - std::optional fees = data::synchronousAndRetryOnTimeout([&](auto yield) { - return backend_->fetchFees(lgrInfo.seq, yield); - }); + std::optional fees = + data::synchronousAndRetryOnTimeout([&](auto yield) { + return backend_->fetchFees(lgrInfo.seq, yield); + }); ASSERT(fees.has_value(), "Fees must exist for ledger {}", lgrInfo.seq); auto transactions = data::synchronousAndRetryOnTimeout([&](auto yield) { @@ -187,7 +199,8 @@ public: auto const ledgerRange = backend_->fetchLedgerRange(); ASSERT(ledgerRange.has_value(), "Ledger range must exist"); - auto const range = fmt::format("{}-{}", ledgerRange->minSequence, ledgerRange->maxSequence); + auto const range = + fmt::format("{}-{}", ledgerRange->minSequence, ledgerRange->maxSequence); subscriptions_->pubLedger(lgrInfo, *fees, range, transactions.size()); // order with transaction index @@ -222,7 +235,9 @@ public: std::uint32_t lastPublishAgeSeconds() const override { - return std::chrono::duration_cast(std::chrono::system_clock::now() - getLastPublish()) + return std::chrono::duration_cast( + std::chrono::system_clock::now() - getLastPublish() + ) .count(); } @@ -244,7 +259,9 @@ public: lastCloseAgeSeconds() const override { auto closeTime = lastCloseTime_.lock()->time_since_epoch().count(); - auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + auto now = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ) .count(); if (now < (kRIPPLE_EPOCH_START + closeTime)) return 0; @@ -252,8 +269,8 @@ public: } /** - * @brief Get the sequence of the last schueduled ledger to publish, Be aware that the ledger may not have been - * published to network + * @brief Get the sequence of the last schueduled ledger to publish, Be aware that the ledger + * may not have been published to network */ std::optional getLastPublishedSequence() const @@ -285,7 +302,8 @@ private: setLastPublishTime() { using namespace std::chrono; - auto const nowSeconds = duration_cast(system_clock::now().time_since_epoch()).count(); + auto const nowSeconds = + duration_cast(system_clock::now().time_since_epoch()).count(); lastPublishSeconds_.get().set(nowSeconds); } diff --git a/src/etl/impl/Loading.cpp b/src/etl/impl/Loading.cpp index 4b1e24458..1e642bc37 100644 --- a/src/etl/impl/Loading.cpp +++ b/src/etl/impl/Loading.cpp @@ -69,17 +69,20 @@ Loader::load(model::LedgerData const& data) // Only a writer should attempt to commit to DB // This is also where conflicts with other writer nodes will be detected if (state_->isWriting) { - auto [success, duration] = - ::util::timed([&]() { return backend_->finishWrites(data.seq); }); - LOG(log_.info()) << "Finished writes to DB for " << data.seq << ": " << (success ? "YES" : "NO") - << "; took " << duration << "ms"; + auto [success, duration] = ::util::timed([&]() { + return backend_->finishWrites(data.seq); + }); + LOG(log_.info()) << "Finished writes to DB for " << data.seq << ": " + << (success ? "YES" : "NO") << "; took " << duration << "ms"; if (not success) { // Write conflict detected - another node wrote to the database // This triggers the fallback mechanism and stops this node from writing state_->writeCommandSignal(SystemState::WriteCommand::StopWriting); state_->isWriterDecidingFallback = true; - LOG(log_.warn()) << "Another node wrote a ledger into the DB - we have a write conflict"; + LOG( + log_.warn() + ) << "Another node wrote a ledger into the DB - we have a write conflict"; return std::unexpected(LoaderError::WriteConflict); } } @@ -103,11 +106,14 @@ Loader::onInitialLoadGotMoreObjects( static auto kINITIAL_LOAD_START_TIME = std::chrono::steady_clock::now(); try { - LOG(log_.trace()) << "On initial load: got more objects for seq " << seq << ". size = " << data.size(); + LOG(log_.trace()) << "On initial load: got more objects for seq " << seq + << ". size = " << data.size(); registry_->dispatchInitialObjects( seq, data, - std::move(lastKey).value_or(std::string{}) // TODO: perhaps use optional all the way to extensions? + std::move(lastKey).value_or( + std::string{} + ) // TODO: perhaps use optional all the way to extensions? ); initialLoadWrittenObjects_ += data.size(); @@ -116,13 +122,15 @@ Loader::onInitialLoadGotMoreObjects( auto elapsedSinceStart = std::chrono::duration_cast( std::chrono::steady_clock::now() - kINITIAL_LOAD_START_TIME ); - auto elapsedSeconds = elapsedSinceStart.count() / static_cast(util::kMILLISECONDS_PER_SECOND); - auto objectsPerSecond = - elapsedSeconds > 0.0 ? static_cast(initialLoadWrittenObjects_) / elapsedSeconds : 0.0; + auto elapsedSeconds = + elapsedSinceStart.count() / static_cast(util::kMILLISECONDS_PER_SECOND); + auto objectsPerSecond = elapsedSeconds > 0.0 + ? static_cast(initialLoadWrittenObjects_) / elapsedSeconds + : 0.0; LOG(log_.info()) << "Wrote " << initialLoadWrittenObjects_ - << " initial ledger objects so far with average rate of " << objectsPerSecond - << " objects per second"; + << " initial ledger objects so far with average rate of " + << objectsPerSecond << " objects per second"; } } catch (std::runtime_error const& e) { @@ -142,8 +150,11 @@ Loader::loadInitialLedger(model::LedgerData const& data) LOG(log_.debug()) << "Deserialized ledger header. " << ::util::toString(data.header); - auto seconds = ::util::timed([this, &data]() { registry_->dispatchInitialData(data); }); - LOG(log_.info()) << "Dispatching initial data and submitting all writes took " << seconds << " seconds."; + auto seconds = ::util::timed([this, &data]() { + registry_->dispatchInitialData(data); + }); + LOG(log_.info()) << "Dispatching initial data and submitting all writes took " << seconds + << " seconds."; backend_->finishWrites(data.seq); LOG(log_.debug()) << "Loaded initial ledger"; diff --git a/src/etl/impl/Monitor.cpp b/src/etl/impl/Monitor.cpp index 1d73630f7..0f6d64d9c 100644 --- a/src/etl/impl/Monitor.cpp +++ b/src/etl/impl/Monitor.cpp @@ -77,7 +77,8 @@ void Monitor::notifyWriteConflict(uint32_t seq) { LOG(log_.warn()) << "Loader notified Monitor about write conflict at " << seq; - nextSequence_ = seq + 1; // we already loaded the cache for seq just before we detected conflict + nextSequence_ = + seq + 1; // we already loaded the cache for seq just before we detected conflict LOG(log_.warn()) << "Resume monitoring from " << nextSequence_; } @@ -87,13 +88,17 @@ Monitor::run(std::chrono::steady_clock::duration repeatInterval) ASSERT(not repeatedTask_.has_value(), "Monitor attempted to run more than once"); { auto lck = updateData_.lock(); - LOG(log_.debug()) << "Starting monitor with repeat interval: " - << std::chrono::duration_cast(repeatInterval).count() - << "s and dbStalledReportDelay: " - << std::chrono::duration_cast(lck->dbStalledReportDelay).count() << "s"; + LOG( + log_.debug() + ) << "Starting monitor with repeat interval: " + << std::chrono::duration_cast(repeatInterval).count() + << "s and dbStalledReportDelay: " + << std::chrono::duration_cast(lck->dbStalledReportDelay).count() + << "s"; } - repeatedTask_ = strand_.executeRepeatedly(repeatInterval, std::bind_front(&Monitor::doWork, this)); + repeatedTask_ = + strand_.executeRepeatedly(repeatInterval, std::bind_front(&Monitor::doWork, this)); subscription_ = validatedLedgers_->subscribe(std::bind_front(&Monitor::onNextSequence, this)); } @@ -143,23 +148,27 @@ Monitor::doWork() } while (lck->lastSeenMaxSeqInDb >= nextSequence_) { - LOG(log_.trace()) << "Publishing from Monitor::doWork. nextSequence_ = " << nextSequence_ + LOG(log_.trace()) << "Publishing from Monitor::doWork. nextSequence_ = " + << nextSequence_ << ", lastSeenMaxSeqInDb_ = " << lck->lastSeenMaxSeqInDb; notificationChannel_(nextSequence_++); dbProgressedThisCycle = true; } } else { - LOG(log_.trace()) << "DB range is not available or empty. lastSeenMaxSeqInDb_ = " << lck->lastSeenMaxSeqInDb - << ", nextSequence_ = " << nextSequence_; + LOG(log_.trace()) << "DB range is not available or empty. lastSeenMaxSeqInDb_ = " + << lck->lastSeenMaxSeqInDb << ", nextSequence_ = " << nextSequence_; } if (dbProgressedThisCycle) { lck->lastDbCheckTime = std::chrono::steady_clock::now(); - } else if (std::chrono::steady_clock::now() - lck->lastDbCheckTime > lck->dbStalledReportDelay) { - LOG(log_.info()) << "No DB update detected for " - << std::chrono::duration_cast(lck->dbStalledReportDelay).count() - << " seconds. Firing dbStalledChannel. Last seen max seq in DB: " << lck->lastSeenMaxSeqInDb - << ". Expecting next: " << nextSequence_; + } else if (std::chrono::steady_clock::now() - lck->lastDbCheckTime > + lck->dbStalledReportDelay) { + LOG( + log_.info() + ) << "No DB update detected for " + << std::chrono::duration_cast(lck->dbStalledReportDelay).count() + << " seconds. Firing dbStalledChannel. Last seen max seq in DB: " + << lck->lastSeenMaxSeqInDb << ". Expecting next: " << nextSequence_; dbStalledChannel_(); lck->lastDbCheckTime = std::chrono::steady_clock::now(); } diff --git a/src/etl/impl/Monitor.hpp b/src/etl/impl/Monitor.hpp index 1c4bffb14..f2fc0d061 100644 --- a/src/etl/impl/Monitor.hpp +++ b/src/etl/impl/Monitor.hpp @@ -47,7 +47,8 @@ class Monitor : public MonitorInterface { std::atomic_uint32_t nextSequence_; std::optional> repeatedTask_; - std::optional subscription_; // network validated ledgers subscription + std::optional + subscription_; // network validated ledgers subscription NewSequenceSignalType notificationChannel_; DbStalledSignalType dbStalledChannel_; diff --git a/src/etl/impl/MonitorProvider.hpp b/src/etl/impl/MonitorProvider.hpp index 0066eb21d..b04760523 100644 --- a/src/etl/impl/MonitorProvider.hpp +++ b/src/etl/impl/MonitorProvider.hpp @@ -45,7 +45,11 @@ public: ) override { return std::make_unique( - std::move(ctx), std::move(backend), std::move(validatedLedgers), startSequence, dbStalledReportDelay + std::move(ctx), + std::move(backend), + std::move(validatedLedgers), + startSequence, + dbStalledReportDelay ); } }; diff --git a/src/etl/impl/Registry.hpp b/src/etl/impl/Registry.hpp index 4e3b000eb..9d35c26bb 100644 --- a/src/etl/impl/Registry.hpp +++ b/src/etl/impl/Registry.hpp @@ -58,12 +58,16 @@ concept HasObjectHook = requires(T p) { template concept HasInitialTransactionHook = requires(T p) { - { p.onInitialTransaction(uint32_t{}, std::declval()) } -> std::same_as; + { + p.onInitialTransaction(uint32_t{}, std::declval()) + } -> std::same_as; }; template concept HasInitialObjectsHook = requires(T p) { - { p.onInitialObjects(uint32_t{}, std::declval>(), std::string{}) } -> std::same_as; + { + p.onInitialObjects(uint32_t{}, std::declval>(), std::string{}) + } -> std::same_as; }; template @@ -75,9 +79,10 @@ template concept ContainsSpec = std::decay_t::spec::kSPEC_TAG; template -concept ContainsValidHook = HasLedgerDataHook or HasInitialDataHook or - (HasTransactionHook and ContainsSpec) or (HasInitialTransactionHook and ContainsSpec) or - HasObjectHook or HasInitialObjectsHook or HasInitialObjectHook; +concept ContainsValidHook = + HasLedgerDataHook or HasInitialDataHook or (HasTransactionHook and ContainsSpec) or + (HasInitialTransactionHook and ContainsSpec) or HasObjectHook or + HasInitialObjectsHook or HasInitialObjectHook; template concept NoTwoOfKind = not(HasLedgerDataHook and HasTransactionHook) and @@ -98,7 +103,8 @@ class Registry : public RegistryInterface { ); static_assert( - (((not HasInitialTransactionHook>) or ContainsSpec>) and ...), + (((not HasInitialTransactionHook>) or ContainsSpec>) and + ...), "Spec must be specified when 'onInitialTransaction' function exists." ); @@ -158,13 +164,19 @@ public: } constexpr void - dispatchInitialObjects(uint32_t seq, std::vector const& data, std::string lastKey) override + dispatchInitialObjects( + uint32_t seq, + std::vector const& data, + std::string lastKey + ) override { // send entire vector path { auto const expand = [&](auto&& p) { if constexpr (requires { p.onInitialObjects(seq, data, lastKey); }) - executeIfAllowed(p, [seq, &data, &lastKey](auto& p) { p.onInitialObjects(seq, data, lastKey); }); + executeIfAllowed(p, [seq, &data, &lastKey](auto& p) { + p.onInitialObjects(seq, data, lastKey); + }); }; std::apply([&expand](auto&&... xs) { (expand(xs), ...); }, store_); @@ -201,7 +213,9 @@ public: auto const expand = [&](P&& p, model::Transaction const& tx) { if constexpr (requires { p.onInitialTransaction(data.seq, tx); }) { if (std::decay_t

::spec::wants(tx.type)) - executeIfAllowed(p, [&data, &tx](auto& p) { p.onInitialTransaction(data.seq, tx); }); + executeIfAllowed(p, [&data, &tx](auto& p) { + p.onInitialTransaction(data.seq, tx); + }); } }; @@ -228,7 +242,9 @@ private: static auto makeRegistry(SystemState const& state, auto&&... exts) { - return std::make_unique...>>(state, std::forward(exts)...); + return std::make_unique...>>( + state, std::forward(exts)... + ); } } // namespace etl::impl diff --git a/src/etl/impl/Scheduling.hpp b/src/etl/impl/Scheduling.hpp index e748ef4b9..ecdad72d7 100644 --- a/src/etl/impl/Scheduling.hpp +++ b/src/etl/impl/Scheduling.hpp @@ -49,7 +49,10 @@ class ForwardScheduler : public SchedulerInterface { public: ForwardScheduler(ForwardScheduler const& other) - : ledgers_(other.ledgers_), startSeq_(other.startSeq_), maxSeq_(other.maxSeq_), seq_(other.seq_.load()) + : ledgers_(other.ledgers_) + , startSeq_(other.startSeq_) + , maxSeq_(other.maxSeq_) + , seq_(other.seq_.load()) { } @@ -70,7 +73,9 @@ public: if (ledgers_.get().getMostRecent() >= currentSeq) { while (currentSeq < maxSeq_.value_or(kMAX)) { - if (seq_.compare_exchange_weak(currentSeq, currentSeq + 1u, std::memory_order_acq_rel)) { + if (seq_.compare_exchange_weak( + currentSeq, currentSeq + 1u, std::memory_order_acq_rel + )) { return {{.priority = model::Task::Priority::Higher, .seq = currentSeq}}; } } @@ -102,7 +107,9 @@ public: { uint32_t currentSeq = seq_; while (currentSeq > minSeq_) { - if (seq_.compare_exchange_weak(currentSeq, currentSeq - 1u, std::memory_order_acq_rel)) { + if (seq_.compare_exchange_weak( + currentSeq, currentSeq - 1u, std::memory_order_acq_rel + )) { return {{.priority = model::Task::Priority::Lower, .seq = currentSeq}}; } } diff --git a/src/etl/impl/SourceImpl.hpp b/src/etl/impl/SourceImpl.hpp index 2f0517a3a..76a67715d 100644 --- a/src/etl/impl/SourceImpl.hpp +++ b/src/etl/impl/SourceImpl.hpp @@ -152,7 +152,10 @@ public: auto last = subscriptionSource_->lastMessageTime(); if (last.time_since_epoch().count() != 0) { res["last_msg_age_seconds"] = std::to_string( - std::chrono::duration_cast(std::chrono::steady_clock::now() - last).count() + std::chrono::duration_cast( + std::chrono::steady_clock::now() - last + ) + .count() ); } @@ -182,11 +185,12 @@ public: /** * @brief Fetch data for a specific ledger. * - * This function will continuously try to fetch data for the specified ledger until the fetch succeeds, the ledger - * is found in the database, or the server is shutting down. + * This function will continuously try to fetch data for the specified ledger until the fetch + * succeeds, the ledger is found in the database, or the server is shutting down. * * @param sequence Sequence of the ledger to fetch - * @param getObjects Whether to get the account state diff between this ledger and the prior one; defaults to true + * @param getObjects Whether to get the account state diff between this ledger and the prior + * one; defaults to true * @param getObjectNeighbors Whether to request object neighbors; defaults to false * @return A std::pair of the response status and the response itself */ @@ -205,7 +209,11 @@ public: * @return A std::pair of the data and a bool indicating whether the download was successful */ InitialLedgerLoadResult - loadInitialLedger(uint32_t sequence, std::uint32_t numMarkers, InitialLoadObserverInterface& loader) final + loadInitialLedger( + uint32_t sequence, + std::uint32_t numMarkers, + InitialLoadObserverInterface& loader + ) final { return grpcSource_.loadInitialLedger(sequence, numMarkers, loader); } @@ -227,7 +235,9 @@ public: boost::asio::yield_context yield ) const final { - return forwardingSource_.forwardToRippled(request, forwardToRippledClientIp, xUserValue, yield); + return forwardingSource_.forwardToRippled( + request, forwardToRippledClientIp, xUserValue, yield + ); } }; diff --git a/src/etl/impl/SubscriptionSource.cpp b/src/etl/impl/SubscriptionSource.cpp index 278706406..d39108d07 100644 --- a/src/etl/impl/SubscriptionSource.cpp +++ b/src/etl/impl/SubscriptionSource.cpp @@ -159,44 +159,52 @@ SubscriptionSource::stop(boost::asio::yield_context yield) void SubscriptionSource::subscribe() { - util::spawn(strand_, [this, _ = boost::asio::make_work_guard(strand_)](boost::asio::yield_context yield) { - if (auto connection = wsConnectionBuilder_.connect(yield); connection) { - wsConnection_ = std::move(connection).value(); - } else { - handleError(connection.error(), yield); - return; - } - - auto const& subscribeCommand = getSubscribeCommandJson(); - - if (auto const writeErrorOpt = wsConnection_->write(subscribeCommand, yield, wsTimeout_); writeErrorOpt) { - handleError(writeErrorOpt.value(), yield); - return; - } - - isConnected_ = true; - LOG(log_.info()) << "Connected"; - onConnect_(); - - retry_.reset(); - - while (!stop_) { - auto const message = wsConnection_->read(yield, wsTimeout_); - if (not message) { - handleError(message.error(), yield); + util::spawn( + strand_, + [this, _ = boost::asio::make_work_guard(strand_)](boost::asio::yield_context yield) { + if (auto connection = wsConnectionBuilder_.connect(yield); connection) { + wsConnection_ = std::move(connection).value(); + } else { + handleError(connection.error(), yield); return; } - if (auto const handleErrorOpt = handleMessage(message.value()); handleErrorOpt) { - handleError(handleErrorOpt.value(), yield); + auto const& subscribeCommand = getSubscribeCommandJson(); + + if (auto const writeErrorOpt = + wsConnection_->write(subscribeCommand, yield, wsTimeout_); + writeErrorOpt) { + handleError(writeErrorOpt.value(), yield); return; } + + isConnected_ = true; + LOG(log_.info()) << "Connected"; + onConnect_(); + + retry_.reset(); + + while (!stop_) { + auto const message = wsConnection_->read(yield, wsTimeout_); + if (not message) { + handleError(message.error(), yield); + return; + } + + if (auto const handleErrorOpt = handleMessage(message.value()); handleErrorOpt) { + handleError(handleErrorOpt.value(), yield); + return; + } + } + // Close the connection + handleError( + util::requests::RequestError{ + "Subscription source stopped", boost::asio::error::operation_aborted + }, + yield + ); } - // Close the connection - handleError( - util::requests::RequestError{"Subscription source stopped", boost::asio::error::operation_aborted}, yield - ); - }); + ); } std::optional @@ -219,19 +227,23 @@ SubscriptionSource::handleMessage(std::string const& message) ledgerIndex = util::integralValueAs(result.at(JS(ledger_index))); if (result.contains(JS(validated_ledgers))) { - auto validatedLedgers = boost::json::value_to(result.at(JS(validated_ledgers))); + auto validatedLedgers = + boost::json::value_to(result.at(JS(validated_ledgers))); setValidatedRange(std::move(validatedLedgers)); } - LOG(log_.debug()) << "Received a message on ledger subscription stream. Message: " << object; + LOG(log_.debug()) << "Received a message on ledger subscription stream. Message: " + << object; } else if (object.contains(JS(type)) && object.at(JS(type)) == kJS_LEDGER_CLOSED) { - LOG(log_.debug()) << "Received a message of type 'ledgerClosed' on ledger subscription stream. Message: " + LOG(log_.debug()) << "Received a message of type 'ledgerClosed' on ledger subscription " + "stream. Message: " << object; if (object.contains(JS(ledger_index))) { ledgerIndex = util::integralValueAs(object.at(JS(ledger_index))); } if (object.contains(JS(validated_ledgers))) { - auto validatedLedgers = boost::json::value_to(object.at(JS(validated_ledgers))); + auto validatedLedgers = + boost::json::value_to(object.at(JS(validated_ledgers))); setValidatedRange(std::move(validatedLedgers)); } if (isForwarding_) @@ -239,17 +251,18 @@ SubscriptionSource::handleMessage(std::string const& message) } else { if (isForwarding_) { - // Clio as rippled's proposed_transactions subscriber, will receive two jsons for each transaction - // 1 - Proposed transaction - // 2 - Validated transaction - // Only forward proposed transaction, validated transactions are sent by Clio itself + // Clio as rippled's proposed_transactions subscriber, will receive two jsons for + // each transaction 1 - Proposed transaction 2 - Validated transaction Only forward + // proposed transaction, validated transactions are sent by Clio itself if (object.contains(JS(transaction)) and !object.contains(JS(meta))) { LOG(log_.debug()) << "Forwarding proposed transaction: " << object; subscriptions_->forwardProposedTransaction(object); - } else if (object.contains(JS(type)) && object.at(JS(type)) == kJS_VALIDATION_RECEIVED) { + } else if (object.contains(JS(type)) && + object.at(JS(type)) == kJS_VALIDATION_RECEIVED) { LOG(log_.debug()) << "Forwarding validation: " << object; subscriptions_->forwardValidation(object); - } else if (object.contains(JS(type)) && object.at(JS(type)) == kJS_MANIFEST_RECEIVED) { + } else if (object.contains(JS(type)) && + object.at(JS(type)) == kJS_MANIFEST_RECEIVED) { LOG(log_.debug()) << "Forwarding manifest: " << object; subscriptions_->forwardManifest(object); } @@ -269,7 +282,10 @@ SubscriptionSource::handleMessage(std::string const& message) } void -SubscriptionSource::handleError(util::requests::RequestError const& error, boost::asio::yield_context yield) +SubscriptionSource::handleError( + util::requests::RequestError const& error, + boost::asio::yield_context yield +) { isConnected_ = false; bool const wasForwarding = isForwarding_.exchange(false); @@ -309,7 +325,10 @@ void SubscriptionSource::setLastMessageTime() { lastMessageTimeSecondsSinceEpoch_.get().set( - std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count() + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ) + .count() ); auto lock = lastMessageTime_.lock(); lock.get() = std::chrono::steady_clock::now(); diff --git a/src/etl/impl/SubscriptionSource.hpp b/src/etl/impl/SubscriptionSource.hpp index 7701b4818..a33188987 100644 --- a/src/etl/impl/SubscriptionSource.hpp +++ b/src/etl/impl/SubscriptionSource.hpp @@ -49,7 +49,8 @@ namespace etl::impl { /** - * @brief This class is used to subscribe to a source of ledger data and forward it to the subscription manager. + * @brief This class is used to subscribe to a source of ledger data and forward it to the + * subscription manager. * @note This class is safe to delete only if io_context is stopped. */ class SubscriptionSource { @@ -108,7 +109,8 @@ public: * @param subscriptions The subscription manager object * @param onConnect The onConnect hook. Called when the connection is established * @param onDisconnect The onDisconnect hook. Called when the connection is lost - * @param onLedgerClosed The onLedgerClosed hook. Called when the ledger is closed if the source is forwarding + * @param onLedgerClosed The onLedgerClosed hook. Called when the ledger is closed if the source + * is forwarding * @param wsTimeout A timeout for websocket operations. Defaults to 30 seconds * @param retryDelay The retry delay. Defaults to 1 second */ @@ -159,8 +161,8 @@ public: /** * @brief Set source forwarding * - * @note If forwarding is true the source will forward messages to the subscription manager. Forwarding is being - * reset on disconnect. + * @note If forwarding is true the source will forward messages to the subscription manager. + * Forwarding is being reset on disconnect. * @param isForwarding The new forwarding state */ void @@ -183,7 +185,8 @@ public: validatedRange() const; /** - * @brief Stop the source. The source will complete already scheduled operations but will not schedule new ones + * @brief Stop the source. The source will complete already scheduled operations but will not + * schedule new ones */ void stop(boost::asio::yield_context yield); diff --git a/src/etl/impl/TaskManager.cpp b/src/etl/impl/TaskManager.cpp index 1bb8d31aa..f0305ec34 100644 --- a/src/etl/impl/TaskManager.cpp +++ b/src/etl/impl/TaskManager.cpp @@ -87,14 +87,16 @@ TaskManager::run(std::size_t numExtractors) util::async::AnyOperation TaskManager::spawnExtractor(TaskQueue& queue) { - // TODO https://github.com/XRPLF/clio/issues/2838: the approach should be changed to a reactive one instead + // TODO https://github.com/XRPLF/clio/issues/2838: the approach should be changed to a reactive + // one instead static constexpr auto kDELAY_BETWEEN_ATTEMPTS = std::chrono::milliseconds{10u}; static constexpr auto kDELAY_BETWEEN_ENQUEUE_ATTEMPTS = std::chrono::milliseconds{1u}; return ctx_.execute([this, &queue](auto stopRequested) { while (not stopRequested) { if (auto task = schedulers_->next(); task.has_value()) { - if (auto maybeBatch = extractor_.get().extractLedgerWithDiff(task->seq); maybeBatch.has_value()) { + if (auto maybeBatch = extractor_.get().extractLedgerWithDiff(task->seq); + maybeBatch.has_value()) { LOG(log_.debug()) << "Adding data after extracting diff"; while (not queue.enqueue(*maybeBatch)) { // TODO (https://github.com/XRPLF/clio/issues/1852) @@ -119,10 +121,12 @@ TaskManager::spawnLoader(TaskQueue& queue) { return ctx_.execute([this, &queue](auto stopRequested) { while (not stopRequested) { - // TODO (https://github.com/XRPLF/clio/issues/66): does not tell the loader whether it's out of order or not + // TODO (https://github.com/XRPLF/clio/issues/66): does not tell the loader whether it's + // out of order or not if (auto data = queue.dequeue(); data.has_value()) { - auto [expectedSuccess, nanos] = - util::timed([&] { return loader_.get().load(*data); }); + auto [expectedSuccess, nanos] = util::timed([&] { + return loader_.get().load(*data); + }); auto const shouldExitOnError = [&] { if (expectedSuccess.has_value()) @@ -149,16 +153,18 @@ TaskManager::spawnLoader(TaskQueue& queue) auto const txnCount = data->transactions.size(); auto const objCount = data->objects.size(); - LOG(log_.info()) << "Wrote ledger " << data->seq << " with header: " << util::toString(data->header) - << ". txns[" << txnCount << "]; objs[" << objCount << "]; in " << seconds + LOG(log_.info()) << "Wrote ledger " << data->seq + << " with header: " << util::toString(data->header) << ". txns[" + << txnCount << "]; objs[" << objCount << "]; in " << seconds << " seconds;" - << " tps[" << txnCount / seconds << "], ops[" << objCount / seconds << "]"; + << " tps[" << txnCount / seconds << "], ops[" << objCount / seconds + << "]"; monitor_.get().notifySequenceLoaded(data->seq); } else { - // TODO (https://github.com/XRPLF/clio/issues/1852) this is probably better done with a timeout (on - // coroutine) so that the thread itself is not blocked. for now this implies that the context - // (io_threads) needs at least 2 threads + // TODO (https://github.com/XRPLF/clio/issues/1852) this is probably better done + // with a timeout (on coroutine) so that the thread itself is not blocked. for now + // this implies that the context (io_threads) needs at least 2 threads queue.awaitTask(); } } diff --git a/src/etl/impl/TaskQueue.hpp b/src/etl/impl/TaskQueue.hpp index 66ab7cbea..1552b0aab 100644 --- a/src/etl/impl/TaskQueue.hpp +++ b/src/etl/impl/TaskQueue.hpp @@ -45,12 +45,17 @@ struct ReverseOrderComparator { /** * @brief A wrapper for std::priority_queue that serialises operations using a mutex - * @note This may be a candidate for future improvements if performance proves to be poor (e.g. use a lock free queue) + * @note This may be a candidate for future improvements if performance proves to be poor (e.g. use + * a lock free queue) */ class TaskQueue { struct Data { std::uint32_t expectedSequence; - std::priority_queue, ReverseOrderComparator> forwardLoadQueue; + std::priority_queue< + model::LedgerData, + std::vector, + ReverseOrderComparator> + forwardLoadQueue; Data(std::uint32_t seq) : expectedSequence(seq) { @@ -66,18 +71,22 @@ class TaskQueue { public: struct Settings { - std::uint32_t startSeq = 0u; // sequence to start from (for dequeue) - std::uint32_t increment = 1u; // increment sequence by this value once dequeue was successful + std::uint32_t startSeq = 0u; // sequence to start from (for dequeue) + std::uint32_t increment = + 1u; // increment sequence by this value once dequeue was successful std::optional limit = std::nullopt; }; /** * @brief Construct a new priority queue - * @param settings Settings for the queue, including starting sequence, increment value, and optional limit + * @param settings Settings for the queue, including starting sequence, increment value, and + * optional limit * @note If limit is not set, the queue will have no limit */ explicit TaskQueue(Settings settings) - : limit_(settings.limit.value_or(0uz)), increment_(settings.increment), data_(settings.startSeq) + : limit_(settings.limit.value_or(0uz)) + , increment_(settings.increment) + , data_(settings.startSeq) { } @@ -119,7 +128,8 @@ public: auto lock = data_.lock(); std::optional out; - if (not lock->forwardLoadQueue.empty() && lock->forwardLoadQueue.top().seq == lock->expectedSequence) { + if (not lock->forwardLoadQueue.empty() && + lock->forwardLoadQueue.top().seq == lock->expectedSequence) { out.emplace(lock->forwardLoadQueue.top()); lock->forwardLoadQueue.pop(); lock->expectedSequence += increment_; diff --git a/src/etl/impl/ext/Cache.cpp b/src/etl/impl/ext/Cache.cpp index 1845895d2..21bf41a33 100644 --- a/src/etl/impl/ext/Cache.cpp +++ b/src/etl/impl/ext/Cache.cpp @@ -31,7 +31,8 @@ namespace etl::impl { -CacheExt::CacheExt(std::shared_ptr cacheUpdater) : cacheUpdater_(std::move(cacheUpdater)) +CacheExt::CacheExt(std::shared_ptr cacheUpdater) + : cacheUpdater_(std::move(cacheUpdater)) { } @@ -51,7 +52,11 @@ CacheExt::onInitialData(model::LedgerData const& data) } void -CacheExt::onInitialObjects(uint32_t seq, std::vector const& objs, [[maybe_unused]] std::string lastKey) +CacheExt::onInitialObjects( + uint32_t seq, + std::vector const& objs, + [[maybe_unused]] std::string lastKey +) { LOG(log_.trace()) << "got initial objects cnt = " << objs.size(); cacheUpdater_->update(seq, objs); diff --git a/src/etl/impl/ext/Cache.hpp b/src/etl/impl/ext/Cache.hpp index 840148ed8..aa03fa3ef 100644 --- a/src/etl/impl/ext/Cache.hpp +++ b/src/etl/impl/ext/Cache.hpp @@ -46,9 +46,14 @@ public: onInitialData(model::LedgerData const& data); void - onInitialObjects(uint32_t seq, std::vector const& objs, [[maybe_unused]] std::string lastKey); + onInitialObjects( + uint32_t seq, + std::vector const& objs, + [[maybe_unused]] std::string lastKey + ); - // We want cache updates through ETL if we are a potential writer but currently are not writing to DB + // We want cache updates through ETL if we are a potential writer but currently are not writing + // to DB static bool allowInReadonly() { diff --git a/src/etl/impl/ext/Core.cpp b/src/etl/impl/ext/Core.cpp index a3f458c7a..f32155848 100644 --- a/src/etl/impl/ext/Core.cpp +++ b/src/etl/impl/ext/Core.cpp @@ -73,7 +73,8 @@ CoreExt::insertTransactions(model::LedgerData const& data) backend_->writeTransaction( auto{txn.key}, data.seq, - data.header.closeTime.time_since_epoch().count(), // This is why we can't use 'onTransaction' + data.header.closeTime.time_since_epoch() + .count(), // This is why we can't use 'onTransaction' auto{txn.raw}, auto{txn.metaRaw} ); diff --git a/src/etl/impl/ext/MPT.cpp b/src/etl/impl/ext/MPT.cpp index e88c01f1f..b66c31b93 100644 --- a/src/etl/impl/ext/MPT.cpp +++ b/src/etl/impl/ext/MPT.cpp @@ -42,7 +42,8 @@ MPTExt::MPTExt(std::shared_ptr backend) : backend_(std::move(b void MPTExt::onLedgerData(model::LedgerData const& data) { - LOG(log_.trace()) << "got TXS cnt = " << data.transactions.size() << "; OBJS size = " << data.objects.size(); + LOG(log_.trace()) << "got TXS cnt = " << data.transactions.size() + << "; OBJS size = " << data.objects.size(); writeMPTHoldersFromTransactions(data); } diff --git a/src/etl/impl/ext/NFT.cpp b/src/etl/impl/ext/NFT.cpp index ee177d7ce..8bd7385f0 100644 --- a/src/etl/impl/ext/NFT.cpp +++ b/src/etl/impl/ext/NFT.cpp @@ -39,7 +39,8 @@ NFTExt::NFTExt(std::shared_ptr backend) : backend_(std::move(b void NFTExt::onLedgerData(model::LedgerData const& data) { - LOG(log_.trace()) << "got TXS cnt = " << data.transactions.size() << "; OBJS size = " << data.objects.size(); + LOG(log_.trace()) << "got TXS cnt = " << data.transactions.size() + << "; OBJS size = " << data.objects.size(); writeNFTs(data); } diff --git a/src/etl/impl/ext/Successor.cpp b/src/etl/impl/ext/Successor.cpp index ff0092170..31b2b7c44 100644 --- a/src/etl/impl/ext/Successor.cpp +++ b/src/etl/impl/ext/Successor.cpp @@ -41,7 +41,10 @@ namespace etl::impl { -SuccessorExt::SuccessorExt(std::shared_ptr backend, data::LedgerCacheInterface& cache) +SuccessorExt::SuccessorExt( + std::shared_ptr backend, + data::LedgerCacheInterface& cache +) : backend_(std::move(backend)), cache_(cache) { } @@ -110,7 +113,10 @@ SuccessorExt::writeIncludedSuccessor(uint32_t seq, model::BookSuccessor const& s void SuccessorExt::writeIncludedSuccessor(uint32_t seq, model::Object const& obj) const { - ASSERT(obj.type != model::Object::ModType::Modified, "Attempt to write successor for a modified object"); + ASSERT( + obj.type != model::Object::ModType::Modified, + "Attempt to write successor for a modified object" + ); // TODO: perhaps make these optionals inside of obj and move value_or here auto pred = obj.predecessor; @@ -127,10 +133,12 @@ SuccessorExt::writeIncludedSuccessor(uint32_t seq, model::Object const& obj) con void SuccessorExt::updateSuccessorFromCache(uint32_t seq, model::Object const& obj) const { - auto const lb = - cache_.get().getPredecessor(obj.key, seq).value_or(data::LedgerObject{.key = data::kFIRST_KEY, .blob = {}}); - auto const ub = - cache_.get().getSuccessor(obj.key, seq).value_or(data::LedgerObject{.key = data::kLAST_KEY, .blob = {}}); + auto const lb = cache_.get() + .getPredecessor(obj.key, seq) + .value_or(data::LedgerObject{.key = data::kFIRST_KEY, .blob = {}}); + auto const ub = cache_.get() + .getSuccessor(obj.key, seq) + .value_or(data::LedgerObject{.key = data::kLAST_KEY, .blob = {}}); auto checkBookBase = false; auto const isDeleted = obj.data.empty(); @@ -176,7 +184,9 @@ SuccessorExt::updateBookSuccessor( ) const { if (maybeSuccessor.has_value()) { - backend_->writeSuccessor(uint256ToString(bookBase), seq, uint256ToString(maybeSuccessor->key)); + backend_->writeSuccessor( + uint256ToString(bookBase), seq, uint256ToString(maybeSuccessor->key) + ); } else { backend_->writeSuccessor(uint256ToString(bookBase), seq, uint256ToString(data::kLAST_KEY)); } @@ -196,7 +206,9 @@ SuccessorExt::writeSuccessors(uint32_t seq) const // make sure the base is not an actual object if (not cache_.get().get(base, seq)) { auto succ = cache_.get().getSuccessor(base, seq); - ASSERT(succ.has_value(), "Book base {} must have a successor", ripple::strHex(base)); + ASSERT( + succ.has_value(), "Book base {} must have a successor", ripple::strHex(base) + ); if (succ->key == cur->key) backend_->writeSuccessor(uint256ToString(base), seq, uint256ToString(cur->key)); diff --git a/src/etl/impl/ext/Successor.hpp b/src/etl/impl/ext/Successor.hpp index 7b86951de..d62ef3a16 100644 --- a/src/etl/impl/ext/Successor.hpp +++ b/src/etl/impl/ext/Successor.hpp @@ -50,7 +50,11 @@ public: onInitialData(model::LedgerData const& data) const; void - onInitialObjects(uint32_t seq, [[maybe_unused]] std::vector const& objs, std::string lastKey) const; + onInitialObjects( + uint32_t seq, + [[maybe_unused]] std::vector const& objs, + std::string lastKey + ) const; void onLedgerData(model::LedgerData const& data) const; diff --git a/src/feed/SubscriptionManager.cpp b/src/feed/SubscriptionManager.cpp index c8fc59caa..475cd7578 100644 --- a/src/feed/SubscriptionManager.cpp +++ b/src/feed/SubscriptionManager.cpp @@ -59,8 +59,9 @@ void SubscriptionManager::subProposedTransactions(SubscriberSharedPtr const& subscriber) { proposedTransactionFeed_.sub(subscriber); - // proposed_transactions subscribers not only receive the transaction json when it is proposed, but also the - // transaction json when it is validated. So the subscriber also subscribes to the transaction feed. + // proposed_transactions subscribers not only receive the transaction json when it is proposed, + // but also the transaction json when it is validated. So the subscriber also subscribes to the + // transaction feed. transactionFeed_.subProposed(subscriber); } @@ -72,16 +73,23 @@ SubscriptionManager::unsubProposedTransactions(SubscriberSharedPtr const& subscr } void -SubscriptionManager::subProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +SubscriptionManager::subProposedAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { proposedTransactionFeed_.sub(account, subscriber); - // Same as proposed_transactions subscribers, proposed_account subscribers also subscribe to the transaction feed to - // receive validated transaction feed. TransactionFeed class will filter out the sessions that have been sent to. + // Same as proposed_transactions subscribers, proposed_account subscribers also subscribe to the + // transaction feed to receive validated transaction feed. TransactionFeed class will filter out + // the sessions that have been sent to. transactionFeed_.subProposed(account, subscriber); } void -SubscriptionManager::unsubProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +SubscriptionManager::unsubProposedAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { proposedTransactionFeed_.unsub(account, subscriber); transactionFeed_.unsubProposed(account, subscriber); @@ -94,7 +102,10 @@ SubscriptionManager::forwardProposedTransaction(boost::json::object const& recei } boost::json::object -SubscriptionManager::subLedger(boost::asio::yield_context yield, SubscriberSharedPtr const& subscriber) +SubscriptionManager::subLedger( + boost::asio::yield_context yield, + SubscriberSharedPtr const& subscriber +) { return ledgerFeed_.sub(yield, backend_, subscriber, networkID_); } @@ -165,13 +176,19 @@ SubscriptionManager::unsubTransactions(SubscriberSharedPtr const& subscriber) } void -SubscriptionManager::subAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +SubscriptionManager::subAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { transactionFeed_.sub(account, subscriber); } void -SubscriptionManager::unsubAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +SubscriptionManager::unsubAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { transactionFeed_.unsub(account, subscriber); } @@ -189,7 +206,10 @@ SubscriptionManager::unsubBook(ripple::Book const& book, SubscriberSharedPtr con } void -SubscriptionManager::pubTransaction(data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo) +SubscriptionManager::pubTransaction( + data::TransactionAndMetadata const& txMeta, + ripple::LedgerHeader const& lgrInfo +) { transactionFeed_.pub(txMeta, lgrInfo, backend_, amendmentCenter_, networkID_); } diff --git a/src/feed/SubscriptionManager.hpp b/src/feed/SubscriptionManager.hpp index 26fa630e2..17845bf6c 100644 --- a/src/feed/SubscriptionManager.hpp +++ b/src/feed/SubscriptionManager.hpp @@ -57,7 +57,8 @@ namespace feed { /** - * @brief A subscription manager is responsible for managing the subscriptions and publishing the feeds + * @brief A subscription manager is responsible for managing the subscriptions and publishing the + * feeds */ class SubscriptionManager : public SubscriptionManagerInterface { std::shared_ptr backend_; @@ -122,7 +123,8 @@ public: } /** - * @brief Destructor of the SubscriptionManager object. It will block until all running jobs finished. + * @brief Destructor of the SubscriptionManager object. It will block until all running jobs + * finished. */ ~SubscriptionManager() override { @@ -179,12 +181,16 @@ public: unsubProposedTransactions(SubscriberSharedPtr const& subscriber) final; /** - * @brief Subscribe to the proposed transactions feed, only receive the feed when particular account is affected. + * @brief Subscribe to the proposed transactions feed, only receive the feed when particular + * account is affected. * @param account The account to watch. * @param subscriber */ void - subProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) final; + subProposedAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber + ) final; /** * @brief Unsubscribe to the proposed transactions feed for particular account. @@ -192,7 +198,10 @@ public: * @param subscriber */ void - unsubProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) final; + unsubProposedAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber + ) final; /** * @brief Forward the proposed transactions feed. @@ -289,7 +298,8 @@ public: unsubTransactions(SubscriberSharedPtr const& subscriber) final; /** - * @brief Subscribe to the transactions feed, only receive the feed when particular account is affected. + * @brief Subscribe to the transactions feed, only receive the feed when particular account is + * affected. * @param account The account to watch. * @param subscriber */ @@ -305,7 +315,8 @@ public: unsubAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) final; /** - * @brief Subscribe to the transactions feed, only receive feed when particular order book is affected. + * @brief Subscribe to the transactions feed, only receive feed when particular order book is + * affected. * @param book The book to watch. * @param subscriber */ @@ -326,7 +337,10 @@ public: * @param lgrInfo The ledger header. */ void - pubTransaction(data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo) final; + pubTransaction( + data::TransactionAndMetadata const& txMeta, + ripple::LedgerHeader const& lgrInfo + ) final; /** * @brief Get the number of subscribers. diff --git a/src/feed/SubscriptionManagerInterface.hpp b/src/feed/SubscriptionManagerInterface.hpp index 8303fb693..b6f483b79 100644 --- a/src/feed/SubscriptionManagerInterface.hpp +++ b/src/feed/SubscriptionManagerInterface.hpp @@ -91,7 +91,8 @@ public: unsubProposedTransactions(SubscriberSharedPtr const& subscriber) = 0; /** - * @brief Subscribe to the proposed transactions feed, only receive the feed when particular account is affected. + * @brief Subscribe to the proposed transactions feed, only receive the feed when particular + * account is affected. * @param account The account to watch. * @param subscriber */ @@ -104,7 +105,10 @@ public: * @param subscriber */ virtual void - unsubProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) = 0; + unsubProposedAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber + ) = 0; /** * @brief Forward the proposed transactions feed. @@ -202,7 +206,8 @@ public: unsubTransactions(SubscriberSharedPtr const& subscriber) = 0; /** - * @brief Subscribe to the transactions feed, only receive the feed when particular account is affected. + * @brief Subscribe to the transactions feed, only receive the feed when particular account is + * affected. * @param account The account to watch. * @param subscriber */ @@ -218,7 +223,8 @@ public: unsubAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) = 0; /** - * @brief Subscribe to the transactions feed, only receive feed when particular order book is affected. + * @brief Subscribe to the transactions feed, only receive feed when particular order book is + * affected. * @param book The book to watch. * @param subscriber */ @@ -239,7 +245,10 @@ public: * @param lgrInfo The ledger header. */ virtual void - pubTransaction(data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo) = 0; + pubTransaction( + data::TransactionAndMetadata const& txMeta, + ripple::LedgerHeader const& lgrInfo + ) = 0; /** * @brief Get the number of subscribers. diff --git a/src/feed/impl/BookChangesFeed.hpp b/src/feed/impl/BookChangesFeed.hpp index 4d2693959..43ae4d5a5 100644 --- a/src/feed/impl/BookChangesFeed.hpp +++ b/src/feed/impl/BookChangesFeed.hpp @@ -33,12 +33,14 @@ namespace feed::impl { /** - * @brief Feed that publishes book changes. This feed will be published every ledger, even if there are no changes. - * Example : {'type': 'bookChanges', 'ledger_index': 2647936, 'ledger_hash': - * '0A5010342D8AAFABDCA58A68F6F588E1C6E58C21B63ED6CA8DB2478F58F3ECD5', 'ledger_time': 756395682, 'changes': []} + * @brief Feed that publishes book changes. This feed will be published every ledger, even if there + * are no changes. Example : {'type': 'bookChanges', 'ledger_index': 2647936, 'ledger_hash': + * '0A5010342D8AAFABDCA58A68F6F588E1C6E58C21B63ED6CA8DB2478F58F3ECD5', 'ledger_time': 756395682, + * 'changes': []} */ struct BookChangesFeed : public SingleFeedBase { - BookChangesFeed(util::async::AnyExecutionContext& executionCtx) : SingleFeedBase(executionCtx, "book_changes") + BookChangesFeed(util::async::AnyExecutionContext& executionCtx) + : SingleFeedBase(executionCtx, "book_changes") { } @@ -48,7 +50,8 @@ struct BookChangesFeed : public SingleFeedBase { * @param transactions The transactions that were included in the ledger. */ void - pub(ripple::LedgerHeader const& lgrInfo, std::vector const& transactions) + pub(ripple::LedgerHeader const& lgrInfo, + std::vector const& transactions) { SingleFeedBase::pub(boost::json::serialize(rpc::computeBookChanges(lgrInfo, transactions))); } diff --git a/src/feed/impl/LedgerFeed.cpp b/src/feed/impl/LedgerFeed.cpp index a726c307a..00f76907f 100644 --- a/src/feed/impl/LedgerFeed.cpp +++ b/src/feed/impl/LedgerFeed.cpp @@ -82,7 +82,8 @@ LedgerFeed::sub( auto const fees = backend->fetchFees(lgrInfo->seq, yield); ASSERT(fees.has_value(), "Fees must be valid"); - auto const range = std::to_string(ledgerRange->minSequence) + "-" + std::to_string(ledgerRange->maxSequence); + auto const range = + std::to_string(ledgerRange->minSequence) + "-" + std::to_string(ledgerRange->maxSequence); auto pubMsg = makeLedgerPubMessage(*lgrInfo, *fees, range, 0, networkID); pubMsg.erase("txn_count"); @@ -100,6 +101,10 @@ LedgerFeed::pub( uint32_t const networkID ) { - SingleFeedBase::pub(boost::json::serialize(makeLedgerPubMessage(lgrInfo, fees, ledgerRange, txnCount, networkID))); + SingleFeedBase::pub( + boost::json::serialize( + makeLedgerPubMessage(lgrInfo, fees, ledgerRange, txnCount, networkID) + ) + ); } } // namespace feed::impl diff --git a/src/feed/impl/LedgerFeed.hpp b/src/feed/impl/LedgerFeed.hpp index f8e93cd02..8849c712d 100644 --- a/src/feed/impl/LedgerFeed.hpp +++ b/src/feed/impl/LedgerFeed.hpp @@ -40,9 +40,9 @@ namespace feed::impl { /** * @brief Feed that publishes the ledger info. * Example : {'type': 'ledgerClosed', 'ledger_index': 2647935, 'ledger_hash': - * '5D022718CD782A82EE10D2147FD90B5F42F26A7E937C870B4FE3CF1086C916AE', 'ledger_time': 756395681, 'fee_base': 10, - * 'reserve_base': 10000000, 'reserve_inc': 2000000, 'validated_ledgers': '2619127-2647935', 'txn_count': 0, - * 'network_id': 1} + * '5D022718CD782A82EE10D2147FD90B5F42F26A7E937C870B4FE3CF1086C916AE', 'ledger_time': 756395681, + * 'fee_base': 10, 'reserve_base': 10000000, 'reserve_inc': 2000000, 'validated_ledgers': + * '2619127-2647935', 'txn_count': 0, 'network_id': 1} */ class LedgerFeed : public SingleFeedBase { public: @@ -50,7 +50,8 @@ public: * @brief Construct a new Ledger Feed object * @param executionCtx The actual publish will be called in the strand of this. */ - LedgerFeed(util::async::AnyExecutionContext& executionCtx) : SingleFeedBase(executionCtx, "ledger") + LedgerFeed(util::async::AnyExecutionContext& executionCtx) + : SingleFeedBase(executionCtx, "ledger") { } diff --git a/src/feed/impl/ProposedTransactionFeed.cpp b/src/feed/impl/ProposedTransactionFeed.cpp index 6e305a8cb..e250d4c2f 100644 --- a/src/feed/impl/ProposedTransactionFeed.cpp +++ b/src/feed/impl/ProposedTransactionFeed.cpp @@ -39,11 +39,13 @@ void ProposedTransactionFeed::sub(SubscriberSharedPtr const& subscriber) { auto const weakPtr = std::weak_ptr(subscriber); - auto const added = signal_.connectTrackableSlot(subscriber, [weakPtr](std::shared_ptr const& msg) { - if (auto connectionPtr = weakPtr.lock()) { - connectionPtr->send(msg); + auto const added = signal_.connectTrackableSlot( + subscriber, [weakPtr](std::shared_ptr const& msg) { + if (auto connectionPtr = weakPtr.lock()) { + connectionPtr->send(msg); + } } - }); + ); if (added) { LOG(logger_.info()) << subscriber->tag() << "Subscribed tx_proposed"; @@ -53,7 +55,10 @@ ProposedTransactionFeed::sub(SubscriberSharedPtr const& subscriber) } void -ProposedTransactionFeed::sub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +ProposedTransactionFeed::sub( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { auto const weakPtr = std::weak_ptr(subscriber); auto const added = accountSignal_.connectTrackableSlot( @@ -71,7 +76,9 @@ ProposedTransactionFeed::sub(ripple::AccountID const& account, SubscriberSharedP if (added) { LOG(logger_.info()) << subscriber->tag() << "Subscribed accounts_proposed " << account; ++subAccountCount_.get(); - subscriber->onDisconnect([this, account](SubscriberPtr connection) { unsubInternal(account, connection); }); + subscriber->onDisconnect([this, account](SubscriberPtr connection) { + unsubInternal(account, connection); + }); } } @@ -82,7 +89,10 @@ ProposedTransactionFeed::unsub(SubscriberSharedPtr const& subscriber) } void -ProposedTransactionFeed::unsub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +ProposedTransactionFeed::unsub( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { unsubInternal(account, subscriber.get()); } @@ -94,20 +104,23 @@ ProposedTransactionFeed::pub(boost::json::object const& receivedTxJson) auto const transaction = receivedTxJson.at("transaction").as_object(); auto const accounts = rpc::getAccountsFromTransaction(transaction); - auto affectedAccounts = std::unordered_set(accounts.cbegin(), accounts.cend()); + auto affectedAccounts = + std::unordered_set(accounts.cbegin(), accounts.cend()); - [[maybe_unused]] auto task = - strand_.execute([this, pubMsg = std::move(pubMsg), affectedAccounts = std::move(affectedAccounts)]() { + [[maybe_unused]] auto task = strand_.execute( + [this, pubMsg = std::move(pubMsg), affectedAccounts = std::move(affectedAccounts)]() { notified_.clear(); signal_.emit(pubMsg); - // Prevent the same connection from receiving the same message twice if it is subscribed to multiple - // accounts However, if the same connection subscribe both stream and account, it will still receive the - // message twice. notified_ can be cleared before signal_ emit to improve this, but let's keep it as is for - // now, since rippled acts like this. + // Prevent the same connection from receiving the same message twice if it is subscribed + // to multiple accounts However, if the same connection subscribe both stream and + // account, it will still receive the message twice. notified_ can be cleared before + // signal_ emit to improve this, but let's keep it as is for now, since rippled acts + // like this. notified_.clear(); for (auto const& account : affectedAccounts) accountSignal_.emit(account, pubMsg); - }); + } + ); } std::uint64_t diff --git a/src/feed/impl/ProposedTransactionFeed.hpp b/src/feed/impl/ProposedTransactionFeed.hpp index 9d2a74367..cd599e0d6 100644 --- a/src/feed/impl/ProposedTransactionFeed.hpp +++ b/src/feed/impl/ProposedTransactionFeed.hpp @@ -51,8 +51,8 @@ namespace feed::impl { class ProposedTransactionFeed { util::Logger logger_{"Subscriptions"}; - std::unordered_set - notified_; // Used by slots to prevent double notifications if tx contains multiple subscribed accounts + std::unordered_set notified_; // Used by slots to prevent double notifications + // if tx contains multiple subscribed accounts util::async::AnyStrand strand_; std::reference_wrapper subAllCount_; std::reference_wrapper subAccountCount_; @@ -81,7 +81,8 @@ public: sub(SubscriberSharedPtr const& subscriber); /** - * @brief Subscribe to the proposed transaction feed, only receive the feed when particular account is affected. + * @brief Subscribe to the proposed transaction feed, only receive the feed when particular + * account is affected. * @param subscriber * @param account The account to watch. */ diff --git a/src/feed/impl/SingleFeedBase.cpp b/src/feed/impl/SingleFeedBase.cpp index 1a08609cf..58f80f950 100644 --- a/src/feed/impl/SingleFeedBase.cpp +++ b/src/feed/impl/SingleFeedBase.cpp @@ -32,7 +32,10 @@ namespace feed::impl { -SingleFeedBase::SingleFeedBase(util::async::AnyExecutionContext& executionCtx, std::string const& name) +SingleFeedBase::SingleFeedBase( + util::async::AnyExecutionContext& executionCtx, + std::string const& name +) : strand_(executionCtx.makeStrand()), subCount_(getSubscriptionsGaugeInt(name)), name_(name) { } @@ -41,10 +44,12 @@ void SingleFeedBase::sub(SubscriberSharedPtr const& subscriber) { auto const weakPtr = std::weak_ptr(subscriber); - auto const added = signal_.connectTrackableSlot(subscriber, [weakPtr](std::shared_ptr const& msg) { - if (auto connectionPtr = weakPtr.lock()) - connectionPtr->send(msg); - }); + auto const added = signal_.connectTrackableSlot( + subscriber, [weakPtr](std::shared_ptr const& msg) { + if (auto connectionPtr = weakPtr.lock()) + connectionPtr->send(msg); + } + ); if (added) { LOG(logger_.info()) << subscriber->tag() << "Subscribed " << name_; diff --git a/src/feed/impl/TrackableSignal.hpp b/src/feed/impl/TrackableSignal.hpp index 70407e1b9..e191f14f0 100644 --- a/src/feed/impl/TrackableSignal.hpp +++ b/src/feed/impl/TrackableSignal.hpp @@ -36,8 +36,9 @@ namespace feed::impl { /** * @brief A thread-safe class to manage a signal and its tracking connections. * - * @param Session The type of the object that will be tracked, when the object is destroyed, the connection will be - * removed lazily. The pointer of the session object will also be the key to disconnect. + * @param Session The type of the object that will be tracked, when the object is destroyed, the + * connection will be removed lazily. The pointer of the session object will also be the key to + * disconnect. * @param Args The types of the arguments that will be passed to the slot. */ template @@ -55,12 +56,13 @@ class TrackableSignal { public: /** - * @brief Connect a slot to the signal, the slot will be called when the signal is emitted and trackable is still - * alive. + * @brief Connect a slot to the signal, the slot will be called when the signal is emitted and + * trackable is still alive. * - * @param trackable Track this object's lifttime, if the object is destroyed, the connection will be removed lazily. - * When the slot is being called, the object is guaranteed to be alive. - * @param slot The slot connecting to the signal, the slot will be called when the signal is emitted. + * @param trackable Track this object's lifttime, if the object is destroyed, the connection + * will be removed lazily. When the slot is being called, the object is guaranteed to be alive. + * @param slot The slot connecting to the signal, the slot will be called when the signal is + * emitted. * @return true if the connection is successfully added, false if the connection already exists. */ bool @@ -71,14 +73,16 @@ public: return false; } - // This class can't hold the trackable's shared_ptr, because disconnect should be able to be called in the - // the trackable's destructor. However, the trackable can not be destroyed when the slot is being called - // either. `track_foreign` is racey when one shared_ptr is tracked by multiple signals. Therefore we are storing - // a weak_ptr of the trackable and using weak_ptr::lock() to atomically check existence and acquire a shared_ptr - // during slot invocation. This guarantees to keep the trackable alive for the duration of the slot call and - // avoids potential race conditions. + // This class can't hold the trackable's shared_ptr, because disconnect should be able to be + // called in the the trackable's destructor. However, the trackable can not be destroyed + // when the slot is being called either. `track_foreign` is racey when one shared_ptr is + // tracked by multiple signals. Therefore we are storing a weak_ptr of the trackable and + // using weak_ptr::lock() to atomically check existence and acquire a shared_ptr during slot + // invocation. This guarantees to keep the trackable alive for the duration of the slot call + // and avoids potential race conditions. connections->emplace( - trackable.get(), signal_.connect([slot, weakTrackable = std::weak_ptr(trackable)](Args&&... args) { + trackable.get(), + signal_.connect([slot, weakTrackable = std::weak_ptr(trackable)](Args&&... args) { if (auto lifeExtender = weakTrackable.lock(); lifeExtender) std::invoke(slot, std::forward(args)...); }) @@ -89,14 +93,17 @@ public: /** * @brief Disconnect a slot to the signal. * - * @param trackablePtr Disconnect the slot whose trackable is this pointer. Be aware that the pointer is a raw - * pointer, allowing disconnect to be called in the destructor of the trackable. - * @return true if the connection is successfully disconnected, false if the connection does not exist. + * @param trackablePtr Disconnect the slot whose trackable is this pointer. Be aware that the + * pointer is a raw pointer, allowing disconnect to be called in the destructor of the + * trackable. + * @return true if the connection is successfully disconnected, false if the connection does not + * exist. */ bool disconnect(ConnectionPtr trackablePtr) { - if (auto connections = connections_.template lock(); connections->contains(trackablePtr)) { + if (auto connections = connections_.template lock(); + connections->contains(trackablePtr)) { connections->operator[](trackablePtr).disconnect(); connections->erase(trackablePtr); return true; diff --git a/src/feed/impl/TrackableSignalMap.hpp b/src/feed/impl/TrackableSignalMap.hpp index f9e3a06d6..95e623c73 100644 --- a/src/feed/impl/TrackableSignalMap.hpp +++ b/src/feed/impl/TrackableSignalMap.hpp @@ -41,8 +41,8 @@ concept Hashable = requires(T a) { /** * @brief Class to manage a map of key and its associative signal. * @param Key The type of the key. - * @param Session The type of the object that will be tracked, when the object is destroyed, the connection will be - * removed lazily. + * @param Session The type of the object that will be tracked, when the object is destroyed, the + * connection will be removed lazily. * @param Args The types of the arguments that will be passed to the slot */ template @@ -55,17 +55,23 @@ class TrackableSignalMap { public: /** - * @brief Connect a slot to the signal, the slot will be called when the signal is emitted and trackable is still - * alive. + * @brief Connect a slot to the signal, the slot will be called when the signal is emitted and + * trackable is still alive. * - * @param trackable Track this object's lifttime, if the object is destroyed, the connection will be removed lazily. - * When the slot is being called, the object is guaranteed to be alive. + * @param trackable Track this object's lifttime, if the object is destroyed, the connection + * will be removed lazily. When the slot is being called, the object is guaranteed to be alive. * @param key The key to the signal. - * @param slot The slot connecting to the signal, the slot will be called when the assocaiative signal is emitted. - * @return true if the connection is successfully added, false if the connection already exists for the key. + * @param slot The slot connecting to the signal, the slot will be called when the assocaiative + * signal is emitted. + * @return true if the connection is successfully added, false if the connection already exists + * for the key. */ bool - connectTrackableSlot(ConnectionSharedPtr const& trackable, Key const& key, std::function slot) + connectTrackableSlot( + ConnectionSharedPtr const& trackable, + Key const& key, + std::function slot + ) { auto map = signalsMap_.template lock(); return map->operator[](key).connectTrackableSlot(trackable, slot); @@ -76,7 +82,8 @@ public: * * @param trackablePtr The pointer to the object that is being tracked. * @param key The key to the signal. - * @return true if the connection is successfully removed, false if the connection does not exist. + * @return true if the connection is successfully removed, false if the connection does not + * exist. */ bool disconnect(ConnectionPtr trackablePtr, Key const& key) diff --git a/src/feed/impl/TransactionFeed.cpp b/src/feed/impl/TransactionFeed.cpp index be79956b6..4458ef6ba 100644 --- a/src/feed/impl/TransactionFeed.cpp +++ b/src/feed/impl/TransactionFeed.cpp @@ -87,28 +87,39 @@ TransactionFeed::sub(SubscriberSharedPtr const& subscriber) void TransactionFeed::sub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) { - auto const added = accountSignal_.connectTrackableSlot(subscriber, account, TransactionSlot(*this, subscriber)); + auto const added = accountSignal_.connectTrackableSlot( + subscriber, account, TransactionSlot(*this, subscriber) + ); if (added) { LOG(logger_.info()) << subscriber->tag() << "Subscribed account " << account; ++subAccountCount_.get(); - subscriber->onDisconnect([this, account](SubscriberPtr connection) { unsubInternal(account, connection); }); + subscriber->onDisconnect([this, account](SubscriberPtr connection) { + unsubInternal(account, connection); + }); } } void TransactionFeed::subProposed(SubscriberSharedPtr const& subscriber) { - auto const added = txProposedSignal_.connectTrackableSlot(subscriber, TransactionSlot(*this, subscriber)); + auto const added = + txProposedSignal_.connectTrackableSlot(subscriber, TransactionSlot(*this, subscriber)); if (added) { - subscriber->onDisconnect([this](SubscriberPtr connection) { unsubProposedInternal(connection); }); + subscriber->onDisconnect([this](SubscriberPtr connection) { + unsubProposedInternal(connection); + }); } } void -TransactionFeed::subProposed(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +TransactionFeed::subProposed( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { - auto const added = - accountProposedSignal_.connectTrackableSlot(subscriber, account, TransactionSlot(*this, subscriber)); + auto const added = accountProposedSignal_.connectTrackableSlot( + subscriber, account, TransactionSlot(*this, subscriber) + ); if (added) { subscriber->onDisconnect([this, account](SubscriberPtr connection) { unsubProposedInternal(account, connection); @@ -119,11 +130,14 @@ TransactionFeed::subProposed(ripple::AccountID const& account, SubscriberSharedP void TransactionFeed::sub(ripple::Book const& book, SubscriberSharedPtr const& subscriber) { - auto const added = bookSignal_.connectTrackableSlot(subscriber, book, TransactionSlot(*this, subscriber)); + auto const added = + bookSignal_.connectTrackableSlot(subscriber, book, TransactionSlot(*this, subscriber)); if (added) { LOG(logger_.info()) << subscriber->tag() << "Subscribed book " << book; ++subBookCount_.get(); - subscriber->onDisconnect([this, book](SubscriberPtr connection) { unsubInternal(book, connection); }); + subscriber->onDisconnect([this, book](SubscriberPtr connection) { + unsubInternal(book, connection); + }); } } @@ -146,7 +160,10 @@ TransactionFeed::unsubProposed(SubscriberSharedPtr const& subscriber) } void -TransactionFeed::unsubProposed(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +TransactionFeed::unsubProposed( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber +) { unsubProposedInternal(account, subscriber.get()); } @@ -194,7 +211,9 @@ TransactionFeed::pub( if (account != amount.issue().account) { auto fetchFundsSynchronous = [&]() { data::synchronous([&](boost::asio::yield_context yield) { - ownerFunds = rpc::accountFunds(*backend, *amendmentCenter, lgrInfo.seq, amount, account, yield); + ownerFunds = rpc::accountFunds( + *backend, *amendmentCenter, lgrInfo.seq, amount, account, yield + ); }); }; data::retryOnTimeout(fetchFundsSynchronous); @@ -224,9 +243,12 @@ TransactionFeed::pub( auto const& metaObj = pubObj[JS(meta)]; ASSERT(metaObj.is_object(), "meta must be an obj in rippled and clio"); - if (metaObj.as_object().contains("TransactionIndex") && metaObj.as_object().at("TransactionIndex").is_int64()) { + if (metaObj.as_object().contains("TransactionIndex") && + metaObj.as_object().at("TransactionIndex").is_int64()) { if (auto const& ctid = rpc::encodeCTID( - lgrInfo.seq, util::integralValueAs(metaObj.as_object().at("TransactionIndex")), networkID + lgrInfo.seq, + util::integralValueAs(metaObj.as_object().at("TransactionIndex")), + networkID ); ctid) pubObj[JS(ctid)] = ctid.value(); @@ -266,8 +288,9 @@ TransactionFeed::pub( }; auto const affectedAccountsFlat = meta->getAffectedAccounts(); - auto affectedAccounts = - std::unordered_set(affectedAccountsFlat.cbegin(), affectedAccountsFlat.cend()); + auto affectedAccounts = std::unordered_set( + affectedAccountsFlat.cbegin(), affectedAccountsFlat.cend() + ); std::unordered_set affectedBooks; @@ -310,20 +333,20 @@ TransactionFeed::pub( affectedBooks = std::move(affectedBooks)]() { notified_.clear(); signal_.emit(allVersionsMsgs); - // clear the notified set. If the same connection subscribes both transactions + proposed_transactions, - // rippled SENDS the same message twice + // clear the notified set. If the same connection subscribes both transactions + + // proposed_transactions, rippled SENDS the same message twice notified_.clear(); txProposedSignal_.emit(allVersionsMsgs); notified_.clear(); - // check duplicate for account and proposed_account, this prevents sending the same message multiple times - // if it affects multiple accounts watched by the same connection + // check duplicate for account and proposed_account, this prevents sending the same message + // multiple times if it affects multiple accounts watched by the same connection for (auto const& account : affectedAccounts) { accountSignal_.emit(account, allVersionsMsgs); accountProposedSignal_.emit(account, allVersionsMsgs); } notified_.clear(); - // check duplicate for books, this prevents sending the same message multiple times if it affects multiple - // books watched by the same connection + // check duplicate for books, this prevents sending the same message multiple times if it + // affects multiple books watched by the same connection for (auto const& book : affectedBooks) { bookSignal_.emit(book, allVersionsMsgs); } diff --git a/src/feed/impl/TransactionFeed.hpp b/src/feed/impl/TransactionFeed.hpp index 8b2021298..44563de22 100644 --- a/src/feed/impl/TransactionFeed.hpp +++ b/src/feed/impl/TransactionFeed.hpp @@ -71,16 +71,18 @@ class TransactionFeed { std::reference_wrapper subAccountCount_; std::reference_wrapper subBookCount_; - TrackableSignalMap accountSignal_; + TrackableSignalMap + accountSignal_; TrackableSignalMap bookSignal_; TrackableSignal signal_; // Signals for proposed tx subscribers - TrackableSignalMap accountProposedSignal_; + TrackableSignalMap + accountProposedSignal_; TrackableSignal txProposedSignal_; - std::unordered_set - notified_; // Used by slots to prevent double notifications if tx contains multiple subscribed accounts + std::unordered_set notified_; // Used by slots to prevent double notifications + // if tx contains multiple subscribed accounts public: /** @@ -108,7 +110,8 @@ public: sub(SubscriberSharedPtr const& subscriber); /** - * @brief Subscribe to the transaction feed, only receive the feed when particular account is affected. + * @brief Subscribe to the transaction feed, only receive the feed when particular account is + * affected. * @param subscriber * @param account The account to watch. */ @@ -116,7 +119,8 @@ public: sub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber); /** - * @brief Subscribe to the transaction feed, only receive the feed when particular order book is affected. + * @brief Subscribe to the transaction feed, only receive the feed when particular order book is + * affected. * @param subscriber * @param book The order book to watch. */ @@ -131,8 +135,8 @@ public: subProposed(SubscriberSharedPtr const& subscriber); /** - * @brief Subscribe to the transaction feed for proposed account, only receive the feed when particular account is - * affected. + * @brief Subscribe to the transaction feed for proposed account, only receive the feed when + * particular account is affected. * @param subscriber * @param account The account to watch. */ diff --git a/src/migration/MigrationApplication.cpp b/src/migration/MigrationApplication.cpp index f0da3c286..de237ed73 100644 --- a/src/migration/MigrationApplication.cpp +++ b/src/migration/MigrationApplication.cpp @@ -36,7 +36,10 @@ namespace app { -MigratorApplication::MigratorApplication(util::config::ClioConfigDefinition const& config, MigrateSubCmd command) +MigratorApplication::MigratorApplication( + util::config::ClioConfigDefinition const& config, + MigrateSubCmd command +) : cmd_(std::move(command)) { PrometheusService::init(config); @@ -44,7 +47,9 @@ MigratorApplication::MigratorApplication(util::config::ClioConfigDefinition cons auto expectedMigrationManager = migration::impl::makeMigrationManager(config, cache_); if (not expectedMigrationManager) { - throw std::runtime_error("Failed to create migration manager: " + expectedMigrationManager.error()); + throw std::runtime_error( + "Failed to create migration manager: " + expectedMigrationManager.error() + ); } migrationManager_ = std::move(expectedMigrationManager.value()); @@ -56,7 +61,9 @@ MigratorApplication::run() return std::visit( util::OverloadSet{ [this](MigrateSubCmd::Status const&) { return printStatus(); }, - [this](MigrateSubCmd::Migration const& cmdBundle) { return migrate(cmdBundle.migratorName); } + [this](MigrateSubCmd::Migration const& cmdBundle) { + return migrate(cmdBundle.migratorName); + } }, cmd_.state ); @@ -73,8 +80,9 @@ MigratorApplication::printStatus() } for (auto const& [migrator, status] : allMigratorsStatusPairs) { - std::cout << "Migrator: " << migrator << " - " << migrationManager_->getMigratorDescriptionByName(migrator) - << " - " << status.toString() << std::endl; + std::cout << "Migrator: " << migrator << " - " + << migrationManager_->getMigratorDescriptionByName(migrator) << " - " + << status.toString() << std::endl; } return EXIT_SUCCESS; } diff --git a/src/migration/MigrationInspectorFactory.hpp b/src/migration/MigrationInspectorFactory.hpp index e42de7289..e2b09a12d 100644 --- a/src/migration/MigrationInspectorFactory.hpp +++ b/src/migration/MigrationInspectorFactory.hpp @@ -36,7 +36,8 @@ namespace migration { /** - * @brief A factory function that creates migration inspector instance and initializes the migration table if needed. + * @brief A factory function that creates migration inspector instance and initializes the migration + * table if needed. * * @param config The config. * @param backend The backend instance. It should be initialized before calling this function. diff --git a/src/migration/MigrationInspectorInterface.hpp b/src/migration/MigrationInspectorInterface.hpp index a3382bc0f..8dc852a55 100644 --- a/src/migration/MigrationInspectorInterface.hpp +++ b/src/migration/MigrationInspectorInterface.hpp @@ -28,15 +28,16 @@ namespace migration { /** - * @brief The interface for the migration inspector.The Clio server application will use this interface to inspect - * the migration status. + * @brief The interface for the migration inspector.The Clio server application will use this + * interface to inspect the migration status. */ struct MigrationInspectorInterface { virtual ~MigrationInspectorInterface() = default; /** * @brief Get the status of all the migrators - * @return A vector of tuple, the first element is the migrator's name, the second element is the status of the + * @return A vector of tuple, the first element is the migrator's name, the second element is + * the status of the */ virtual std::vector> allMigratorsStatusPairs() const = 0; diff --git a/src/migration/MigrationManagerInterface.hpp b/src/migration/MigrationManagerInterface.hpp index 3bc1644e9..b25a5ede6 100644 --- a/src/migration/MigrationManagerInterface.hpp +++ b/src/migration/MigrationManagerInterface.hpp @@ -26,9 +26,9 @@ namespace migration { /** - * @brief The interface for the migration manager. The migration application layer will use this interface to run the - * migrations. Unlike the MigrationInspectorInterface which only provides the status of migration, this interface - * contains the actual migration running method. + * @brief The interface for the migration manager. The migration application layer will use this + * interface to run the migrations. Unlike the MigrationInspectorInterface which only provides the + * status of migration, this interface contains the actual migration running method. */ struct MigrationManagerInterface : virtual public MigrationInspectorInterface { /** diff --git a/src/migration/MigratiorStatus.hpp b/src/migration/MigratiorStatus.hpp index 747f7f0a8..47a383ed3 100644 --- a/src/migration/MigratiorStatus.hpp +++ b/src/migration/MigratiorStatus.hpp @@ -26,7 +26,8 @@ namespace migration { /** - * @brief The status of a migrator, it provides the helper functions to convert the status to string and vice versa + * @brief The status of a migrator, it provides the helper functions to convert the status to string + * and vice versa */ class MigratorStatus { public: diff --git a/src/migration/cassandra/CassandraMigrationBackend.hpp b/src/migration/cassandra/CassandraMigrationBackend.hpp index b18bd0a29..6b6b69b92 100644 --- a/src/migration/cassandra/CassandraMigrationBackend.hpp +++ b/src/migration/cassandra/CassandraMigrationBackend.hpp @@ -35,8 +35,8 @@ namespace migration::cassandra { /** - * @brief The backend for the migration. It is a subclass of the CassandraBackend and provides the migration specific - * functionalities. + * @brief The backend for the migration. It is a subclass of the CassandraBackend and provides the + * migration specific functionalities. */ class CassandraMigrationBackend : public data::cassandra::CassandraBackend { util::Logger log_{"Migration"}; @@ -81,22 +81,23 @@ public: LOG(log_.debug()) << "Travsering token range: " << start << " - " << end << " ; table: " << TableDesc::kTABLE_NAME; // for each table we only have one prepared statement - static auto kSTATEMENT_PREPARED = - migrationSchema_.getPreparedFullScanStatement(handle_, TableDesc::kTABLE_NAME, TableDesc::kPARTITION_KEY); + static auto kSTATEMENT_PREPARED = migrationSchema_.getPreparedFullScanStatement( + handle_, TableDesc::kTABLE_NAME, TableDesc::kPARTITION_KEY + ); auto const statement = kSTATEMENT_PREPARED.bind(start, end); auto const res = this->executor_.read(yield, statement); if (not res) { - LOG(log_.error()) << "Could not fetch data from table: " << TableDesc::kTABLE_NAME << " range: " << start - << " - " << end << ";" << res.error(); + LOG(log_.error()) << "Could not fetch data from table: " << TableDesc::kTABLE_NAME + << " range: " << start << " - " << end << ";" << res.error(); return; } auto const& results = res.value(); if (not results.hasRows()) { - LOG(log_.debug()) << "No rows returned - table: " << TableDesc::kTABLE_NAME << " range: " << start << " - " - << end; + LOG(log_.debug()) << "No rows returned - table: " << TableDesc::kTABLE_NAME + << " range: " << start << " - " << end; return; } diff --git a/src/migration/cassandra/CassandraMigrationManager.hpp b/src/migration/cassandra/CassandraMigrationManager.hpp index 63a4c1d17..f84333e04 100644 --- a/src/migration/cassandra/CassandraMigrationManager.hpp +++ b/src/migration/cassandra/CassandraMigrationManager.hpp @@ -33,10 +33,11 @@ template using CassandraSupportedMigrators = migration::impl::MigratorsRegister; // Instantiates with the backend which supports actual migration running -using MigrationProcessor = CassandraSupportedMigrators; +using MigrationProcessor = + CassandraSupportedMigrators; -// Instantiates with backend interface, it doesn't support actual migration. But it can be used to inspect the migrators -// status +// Instantiates with backend interface, it doesn't support actual migration. But it can be used to +// inspect the migrators status using MigrationQuerier = CassandraSupportedMigrators; } // namespace diff --git a/src/migration/cassandra/impl/CassandraMigrationSchema.hpp b/src/migration/cassandra/impl/CassandraMigrationSchema.hpp index 154fdedac..e37f3c188 100644 --- a/src/migration/cassandra/impl/CassandraMigrationSchema.hpp +++ b/src/migration/cassandra/impl/CassandraMigrationSchema.hpp @@ -32,7 +32,8 @@ namespace migration::cassandra::impl { /** - * @brief The schema for the migration process. It contains the prepared statements only used for the migration process. + * @brief The schema for the migration process. It contains the prepared statements only used for + * the migration process. */ class CassandraMigrationSchema { using SettingsProviderType = data::cassandra::SettingsProvider; @@ -44,7 +45,8 @@ public: * * @param settings The settings provider of database */ - explicit CassandraMigrationSchema(SettingsProviderType const& settings) : settingsProvider_{settings} + explicit CassandraMigrationSchema(SettingsProviderType const& settings) + : settingsProvider_{settings} { } @@ -70,7 +72,9 @@ public: FROM {} WHERE TOKEN({}) >= ? AND TOKEN({}) <= ? )", - data::cassandra::qualifiedTableName(settingsProvider_.get(), tableName), + data::cassandra::qualifiedTableName( + settingsProvider_.get(), tableName + ), key, key ) @@ -93,7 +97,9 @@ public: (migrator_name, status) VALUES (?, ?) )", - data::cassandra::qualifiedTableName(settingsProvider_.get(), "migrator_status") + data::cassandra::qualifiedTableName( + settingsProvider_.get(), "migrator_status" + ) ) ); return kPREPARED; diff --git a/src/migration/cassandra/impl/FullTableScanner.hpp b/src/migration/cassandra/impl/FullTableScanner.hpp index 8407760c0..9af6adc72 100644 --- a/src/migration/cassandra/impl/FullTableScanner.hpp +++ b/src/migration/cassandra/impl/FullTableScanner.hpp @@ -58,13 +58,14 @@ struct TokenRange { * @brief The concept for an adapter. */ template -concept CanReadByTokenRange = requires(T obj, TokenRange const& range, boost::asio::yield_context yield) { - { obj.readByTokenRange(range, yield) } -> std::same_as; -}; +concept CanReadByTokenRange = + requires(T obj, TokenRange const& range, boost::asio::yield_context yield) { + { obj.readByTokenRange(range, yield) } -> std::same_as; + }; /** - * @brief The full table scanner. It will split the full table scan into multiple ranges and read the data in given - * executor. + * @brief The full table scanner. It will split the full table scan into multiple ranges and read + * the data in given executor. * * @tparam TableAdapter The table adapter type */ @@ -96,7 +97,8 @@ class FullTableScanner { for (std::int64_t i = 0; i < numRanges; ++i) { int64_t const start = minValue + (i * rangeSize); - int64_t const end = (i == numRanges - 1) ? maxValue : start + static_cast(rangeSize) - 1; + int64_t const end = + (i == numRanges - 1) ? maxValue : start + static_cast(rangeSize) - 1; ranges.emplace_back(start, end); } @@ -141,13 +143,14 @@ public: */ struct FullTableScannerSettings { std::uint32_t ctxThreadsNum; /**< number of threads used in the execution context */ - std::uint32_t jobsNum; /**< number of coroutines to run, it is the number of concurrent database reads */ + std::uint32_t jobsNum; /**< number of coroutines to run, it is the number of concurrent + database reads */ std::uint32_t cursorsPerJob; /**< number of cursors per coroutine */ }; /** - * @brief Construct a new Full Table Scanner object, it will run in a sync or async context according to the - * parameter. The scan process will immediately start. + * @brief Construct a new Full Table Scanner object, it will run in a sync or async context + * according to the parameter. The scan process will immediately start. * * @tparam ExecutionContextType The execution context type * @param settings The full table scanner settings @@ -161,7 +164,10 @@ public: , reader_{std::move(reader)} { ASSERT(settings.jobsNum > 0, "jobsNum for full table scanner must be greater than 0"); - ASSERT(settings.cursorsPerJob > 0, "cursorsPerJob for full table scanner must be greater than 0"); + ASSERT( + settings.cursorsPerJob > 0, + "cursorsPerJob for full table scanner must be greater than 0" + ); auto const cursors = TokenRangesProvider{cursorsNum_}.getRanges(); std::ranges::for_each(cursors, [this](auto const& cursor) { queue_.push(cursor); }); diff --git a/src/migration/cassandra/impl/FullTableScannerAdapterBase.hpp b/src/migration/cassandra/impl/FullTableScannerAdapterBase.hpp index 5373af47e..16fee120f 100644 --- a/src/migration/cassandra/impl/FullTableScannerAdapterBase.hpp +++ b/src/migration/cassandra/impl/FullTableScannerAdapterBase.hpp @@ -30,9 +30,9 @@ namespace migration::cassandra::impl { /** - * @brief The base class for the full table scanner adapter. It is responsible for reading the rows from the full table - * scanner and call the callback when a row is read. With this base class, each table adapter can focus on the actual - * row data converting. + * @brief The base class for the full table scanner adapter. It is responsible for reading the rows + * from the full table scanner and call the callback when a row is read. With this base class, each + * table adapter can focus on the actual row data converting. * * @tparam TableDesc The table description, it has to be a TableSpec. */ @@ -54,12 +54,14 @@ public: * * @param backend The backend */ - FullTableScannerAdapterBase(std::shared_ptr backend) : backend_(std::move(backend)) + FullTableScannerAdapterBase(std::shared_ptr backend) + : backend_(std::move(backend)) { } /** - * @brief Read the row in the given token range from database, this is the adapt function for the FullTableScanner. + * @brief Read the row in the given token range from database, this is the adapt function for + * the FullTableScanner. * * @param range The token range to read * @param yield The yield context @@ -73,8 +75,8 @@ public: } /** - * @brief Called when a row is read. The derived class should implement this function to convert the database blob - * to actual data type. + * @brief Called when a row is read. The derived class should implement this function to convert + * the database blob to actual data type. * * @param row The row read */ diff --git a/src/migration/cassandra/impl/ObjectsAdapter.hpp b/src/migration/cassandra/impl/ObjectsAdapter.hpp index 6d4362588..1e5963d3c 100644 --- a/src/migration/cassandra/impl/ObjectsAdapter.hpp +++ b/src/migration/cassandra/impl/ObjectsAdapter.hpp @@ -47,8 +47,8 @@ struct TableObjectsDesc { }; /** - * @brief The adapter for the objects table. This class is responsible for reading the objects from the - * FullTableScanner and converting the blobs to the STObject. + * @brief The adapter for the objects table. This class is responsible for reading the objects from + * the FullTableScanner and converting the blobs to the STObject. */ class ObjectsAdapter : public impl::FullTableScannerAdapterBase { public: @@ -60,8 +60,12 @@ public: * @param backend The backend to use * @param onStateRead The callback to call when a state is read */ - explicit ObjectsAdapter(std::shared_ptr backend, OnStateRead onStateRead) - : FullTableScannerAdapterBase(backend), onStateRead_{std::move(onStateRead)} + explicit ObjectsAdapter( + std::shared_ptr backend, + OnStateRead onStateRead + ) + : FullTableScannerAdapterBase(backend) + , onStateRead_{std::move(onStateRead)} { } diff --git a/src/migration/cassandra/impl/TransactionsAdapter.hpp b/src/migration/cassandra/impl/TransactionsAdapter.hpp index ed1b92b2d..28341da95 100644 --- a/src/migration/cassandra/impl/TransactionsAdapter.hpp +++ b/src/migration/cassandra/impl/TransactionsAdapter.hpp @@ -41,14 +41,15 @@ namespace migration::cassandra::impl { */ struct TableTransactionsDesc { // hash, date, ledger_seq, metadata, transaction - using Row = std::tuple; + using Row = + std::tuple; static constexpr char const* kPARTITION_KEY = "hash"; static constexpr char const* kTABLE_NAME = "transactions"; }; /** - * @brief The adapter for the transactions table. This class is responsible for reading the transactions from the - * FullTableScanner and converting the blobs to the STTx and TxMeta. + * @brief The adapter for the transactions table. This class is responsible for reading the + * transactions from the FullTableScanner and converting the blobs to the STTx and TxMeta. */ class TransactionsAdapter : public impl::FullTableScannerAdapterBase { public: @@ -60,8 +61,12 @@ public: * @param backend The backend * @param onTxRead The callback to call when a transaction is read */ - explicit TransactionsAdapter(std::shared_ptr backend, OnTransactionRead onTxRead) - : FullTableScannerAdapterBase(backend), onTransactionRead_{std::move(onTxRead)} + explicit TransactionsAdapter( + std::shared_ptr backend, + OnTransactionRead onTxRead + ) + : FullTableScannerAdapterBase(backend) + , onTransactionRead_{std::move(onTxRead)} { } diff --git a/src/migration/impl/MigrationInspectorBase.hpp b/src/migration/impl/MigrationInspectorBase.hpp index 106ba9556..2c496548e 100644 --- a/src/migration/impl/MigrationInspectorBase.hpp +++ b/src/migration/impl/MigrationInspectorBase.hpp @@ -31,8 +31,8 @@ namespace migration::impl { /** - * @brief The migration inspector implementation for Cassandra. It will report the migration status for Cassandra - * database. + * @brief The migration inspector implementation for Cassandra. It will report the migration status + * for Cassandra database. * * @tparam SupportedMigrators The migrators register that contains all the migrators */ @@ -47,7 +47,9 @@ public: * * @param backend The backend of the Cassandra database */ - explicit MigrationInspectorBase(std::shared_ptr backend) + explicit MigrationInspectorBase( + std::shared_ptr backend + ) : migrators_{std::move(backend)} { } @@ -55,8 +57,8 @@ public: /** * @brief Get the status of all the migrators * - * @return A vector of tuple, the first element is the migrator's name, the second element is the status of the - * migrator + * @return A vector of tuple, the first element is the migrator's name, the second element is + * the status of the migrator */ std::vector> allMigratorsStatusPairs() const override @@ -109,8 +111,10 @@ public: isBlockingClio() const override { return std::ranges::any_of(migrators_.getMigratorNames(), [&](auto const& migrator) { - if (auto canBlock = migrators_.canMigratorBlockClio(migrator); canBlock.has_value() and *canBlock and - migrators_.getMigratorStatus(std::string(migrator)) == MigratorStatus::Status::NotMigrated) { + if (auto canBlock = migrators_.canMigratorBlockClio(migrator); canBlock.has_value() and + *canBlock and + migrators_.getMigratorStatus(std::string(migrator)) == + MigratorStatus::Status::NotMigrated) { return true; } return false; diff --git a/src/migration/impl/MigrationManagerBase.hpp b/src/migration/impl/MigrationManagerBase.hpp index 775a3f90f..2edb9aff5 100644 --- a/src/migration/impl/MigrationManagerBase.hpp +++ b/src/migration/impl/MigrationManagerBase.hpp @@ -30,13 +30,14 @@ namespace migration::impl { /** - * @brief The migration manager implementation for Cassandra. It will run the migration for the Cassandra - * database. + * @brief The migration manager implementation for Cassandra. It will run the migration for the + * Cassandra database. * * @tparam SupportedMigrators The migrators register that contains all the migrators */ template -class MigrationManagerBase : public MigrationManagerInterface, public MigrationInspectorBase { +class MigrationManagerBase : public MigrationManagerInterface, + public MigrationInspectorBase { // contains only migration related settings util::config::ObjectView config_; diff --git a/src/migration/impl/MigrationManagerFactory.cpp b/src/migration/impl/MigrationManagerFactory.cpp index 216171f02..943fc7edd 100644 --- a/src/migration/impl/MigrationManagerFactory.cpp +++ b/src/migration/impl/MigrationManagerFactory.cpp @@ -36,7 +36,10 @@ namespace migration::impl { std::expected, std::string> -makeMigrationManager(util::config::ClioConfigDefinition const& config, data::LedgerCacheInterface& cache) +makeMigrationManager( + util::config::ClioConfigDefinition const& config, + data::LedgerCacheInterface& cache +) { static util::Logger const log{"Migration"}; // NOLINT(readability-identifier-naming) LOG(log.info()) << "Constructing MigrationManager"; @@ -52,7 +55,9 @@ makeMigrationManager(util::config::ClioConfigDefinition const& config, data::Led auto migrationCfg = config.getObject("migration"); return std::make_shared( - std::make_shared(data::cassandra::SettingsProvider{cfg}, cache), + std::make_shared( + data::cassandra::SettingsProvider{cfg}, cache + ), std::move(migrationCfg) ); } diff --git a/src/migration/impl/MigrationManagerFactory.hpp b/src/migration/impl/MigrationManagerFactory.hpp index 6de3dbe89..97d71cc95 100644 --- a/src/migration/impl/MigrationManagerFactory.hpp +++ b/src/migration/impl/MigrationManagerFactory.hpp @@ -32,12 +32,16 @@ namespace migration::impl { /** * @brief The factory to create a MigrationManagerInterface * - * @param config The configuration of the migration application, it contains the database connection configuration and - * other migration specific configurations + * @param config The configuration of the migration application, it contains the database connection + * configuration and other migration specific configurations * @param cache The ledger cache to use - * @return A shared pointer to the MigrationManagerInterface if the creation was successful, otherwise an error message + * @return A shared pointer to the MigrationManagerInterface if the creation was successful, + * otherwise an error message */ std::expected, std::string> -makeMigrationManager(util::config::ClioConfigDefinition const& config, data::LedgerCacheInterface& cache); +makeMigrationManager( + util::config::ClioConfigDefinition const& config, + data::LedgerCacheInterface& cache +); } // namespace migration::impl diff --git a/src/migration/impl/MigratorsRegister.hpp b/src/migration/impl/MigratorsRegister.hpp index ef571eb10..18ff4c22f 100644 --- a/src/migration/impl/MigratorsRegister.hpp +++ b/src/migration/impl/MigratorsRegister.hpp @@ -45,7 +45,8 @@ namespace migration::impl { * The concept to check if BackendType is the same as the migrator's required backend type */ template -concept MigrationBackend = requires { requires std::same_as; }; +concept MigrationBackend = + requires { requires std::same_as; }; template concept BackendMatchAllMigrators = (MigrationBackend && ...); @@ -56,11 +57,12 @@ concept HasCanBlockClio = requires(T t) { }; /** - *@brief The register of migrators. It will dispatch the migration to the corresponding migrator. It also - *hold the shared pointer of backend, which is used by the migrators. + *@brief The register of migrators. It will dispatch the migration to the corresponding migrator. It + * also hold the shared pointer of backend, which is used by the migrators. * *@tparam Backend The backend type - *@tparam MigratorType The migrator types. It should be a concept of MigratorSpec and not have duplicate names. + *@tparam MigratorType The migrator types. It should be a concept of MigratorSpec and not have + * duplicate names. */ template requires AllMigratorSpec @@ -77,7 +79,9 @@ class MigratorsRegister { if (name == Migrator::kNAME) { LOG(log_.info()) << "Running migration: " << name; Migrator::runMigration(backend_, config); - backend_->writeMigratorStatus(name, MigratorStatus(MigratorStatus::Migrated).toString()); + backend_->writeMigratorStatus( + name, MigratorStatus(MigratorStatus::Migrated).toString() + ); LOG(log_.info()) << "Finished migration: " << name; } } @@ -137,8 +141,8 @@ public: /** * @brief Get the status of all the migrators * - * @return A vector of tuple, the first element is the migrator's name, the second element is the status of the - * migrator + * @return A vector of tuple, the first element is the migrator's name, the second element is + * the status of the migrator */ std::vector> getMigratorsStatus() const @@ -167,10 +171,12 @@ public: if (std::ranges::find(fullList, name) == fullList.end()) { return MigratorStatus::NotKnown; } - auto const statusStringOpt = - data::synchronous([&](auto yield) { return backend_->fetchMigratorStatus(name, yield); }); + auto const statusStringOpt = data::synchronous([&](auto yield) { + return backend_->fetchMigratorStatus(name, yield); + }); - return statusStringOpt ? MigratorStatus::fromString(statusStringOpt.value()) : MigratorStatus::NotMigrated; + return statusStringOpt ? MigratorStatus::fromString(statusStringOpt.value()) + : MigratorStatus::NotMigrated; } /** @@ -209,8 +215,8 @@ public: * @brief Return if the given migrator can block Clio server * * @param name The migrator's name - * @return std::nullopt if the migrator name is not found, or a boolean value indicating whether the migrator is - * blocking Clio server. + * @return std::nullopt if the migrator name is not found, or a boolean value indicating whether + * the migrator is blocking Clio server. */ std::optional canMigratorBlockClio(std::string_view name) const diff --git a/src/migration/impl/Spec.hpp b/src/migration/impl/Spec.hpp index 59decd1fd..251c6d08f 100644 --- a/src/migration/impl/Spec.hpp +++ b/src/migration/impl/Spec.hpp @@ -33,19 +33,20 @@ namespace migration::impl { * @brief The migrator specification concept */ template -concept MigratorSpec = requires(std::shared_ptr const& backend, util::config::ObjectView const& cfg) { - // Check that 'kNAME' exists and is a string - { T::kNAME } -> std::convertible_to; +concept MigratorSpec = + requires(std::shared_ptr const& backend, util::config::ObjectView const& cfg) { + // Check that 'kNAME' exists and is a string + { T::kNAME } -> std::convertible_to; - // Check that 'kDESCRIPTION' exists and is a string - { T::kDESCRIPTION } -> std::convertible_to; + // Check that 'kDESCRIPTION' exists and is a string + { T::kDESCRIPTION } -> std::convertible_to; - // Check that the migrator specifies the backend type it supports - typename T::Backend; + // Check that the migrator specifies the backend type it supports + typename T::Backend; - // Check that 'runMigration' exists and is callable - { T::runMigration(backend, cfg) } -> std::same_as; -}; + // Check that 'runMigration' exists and is callable + { T::runMigration(backend, cfg) } -> std::same_as; + }; /** * @brief used by variadic template to check all migrators are MigratorSpec diff --git a/src/rpc/AMMHelpers.cpp b/src/rpc/AMMHelpers.cpp index 5cb5cf71e..c59c7f400 100644 --- a/src/rpc/AMMHelpers.cpp +++ b/src/rpc/AMMHelpers.cpp @@ -49,10 +49,24 @@ getAmmPoolHolds( ) { auto const assetInBalance = accountHolds( - backend, amendmentCenter, sequence, ammAccountID, issue1.currency, issue1.account, freezeHandling, yield + backend, + amendmentCenter, + sequence, + ammAccountID, + issue1.currency, + issue1.account, + freezeHandling, + yield ); auto const assetOutBalance = accountHolds( - backend, amendmentCenter, sequence, ammAccountID, issue2.currency, issue2.account, freezeHandling, yield + backend, + amendmentCenter, + sequence, + ammAccountID, + issue2.currency, + issue2.account, + freezeHandling, + yield ); return std::make_pair(assetInBalance, assetOutBalance); } @@ -70,7 +84,8 @@ getAmmLpHolds( { auto const lptCurrency = ammLPTCurrency(cur1, cur2); - // not using accountHolds because we don't need to check if the associated tokens of the LP are frozen + // not using accountHolds because we don't need to check if the associated tokens of the LP are + // frozen return ammAccountHolds(backend, sequence, lpAccount, lptCurrency, ammAccount, true, yield); } diff --git a/src/rpc/BookChangesHelper.hpp b/src/rpc/BookChangesHelper.hpp index ec4198567..54b5477f5 100644 --- a/src/rpc/BookChangesHelper.hpp +++ b/src/rpc/BookChangesHelper.hpp @@ -122,14 +122,18 @@ private: // if either FF or PF are missing we can't compute // but generally these are cancelled rather than crossed // so skipping them is consistent - if (!node.isFieldPresent(ripple::sfFinalFields) || !node.isFieldPresent(ripple::sfPreviousFields)) + if (!node.isFieldPresent(ripple::sfFinalFields) || + !node.isFieldPresent(ripple::sfPreviousFields)) return; - auto const& finalFields = node.peekAtField(ripple::sfFinalFields).downcast(); - auto const& previousFields = node.peekAtField(ripple::sfPreviousFields).downcast(); + auto const& finalFields = + node.peekAtField(ripple::sfFinalFields).downcast(); + auto const& previousFields = + node.peekAtField(ripple::sfPreviousFields).downcast(); // defensive case that should never be hit - if (!finalFields.isFieldPresent(ripple::sfTakerGets) || !finalFields.isFieldPresent(ripple::sfTakerPays) || + if (!finalFields.isFieldPresent(ripple::sfTakerGets) || + !finalFields.isFieldPresent(ripple::sfTakerPays) || !previousFields.isFieldPresent(ripple::sfTakerGets) || !previousFields.isFieldPresent(ripple::sfTakerPays)) return; @@ -141,10 +145,10 @@ private: // compute the difference in gets and pays actually // affected onto the offer - auto const deltaGets = - finalFields.getFieldAmount(ripple::sfTakerGets) - previousFields.getFieldAmount(ripple::sfTakerGets); - auto const deltaPays = - finalFields.getFieldAmount(ripple::sfTakerPays) - previousFields.getFieldAmount(ripple::sfTakerPays); + auto const deltaGets = finalFields.getFieldAmount(ripple::sfTakerGets) - + previousFields.getFieldAmount(ripple::sfTakerGets); + auto const deltaPays = finalFields.getFieldAmount(ripple::sfTakerPays) - + previousFields.getFieldAmount(ripple::sfTakerPays); transformAndStore(deltaGets, deltaPays, finalFields[~ripple::sfDomainID]); } @@ -278,6 +282,9 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, BookChange const * @return The book changes */ [[nodiscard]] boost::json::object -computeBookChanges(ripple::LedgerHeader const& lgrInfo, std::vector const& transactions); +computeBookChanges( + ripple::LedgerHeader const& lgrInfo, + std::vector const& transactions +); } // namespace rpc diff --git a/src/rpc/Counters.cpp b/src/rpc/Counters.cpp index a69e3cef7..b850a8333 100644 --- a/src/rpc/Counters.cpp +++ b/src/rpc/Counters.cpp @@ -220,7 +220,9 @@ Counters::onInternalError() std::chrono::seconds Counters::uptime() const { - return std::chrono::duration_cast(std::chrono::system_clock::now() - startupTime_); + return std::chrono::duration_cast( + std::chrono::system_clock::now() - startupTime_ + ); } boost::json::object diff --git a/src/rpc/CredentialHelpers.cpp b/src/rpc/CredentialHelpers.cpp index bbea85ca7..7dd755f46 100644 --- a/src/rpc/CredentialHelpers.cpp +++ b/src/rpc/CredentialHelpers.cpp @@ -82,20 +82,25 @@ parseAuthorizeCredentials(boost::json::array const& jv) jo.at(JS(issuer)).is_string(), "issuer must be string, should already be checked in AuthorizeCredentialValidator" ); - auto const issuer = - ripple::parseBase58(static_cast(jo.at(JS(issuer)).as_string())); + auto const issuer = ripple::parseBase58( + static_cast(jo.at(JS(issuer)).as_string()) + ); ASSERT( - issuer.has_value(), "issuer must be present, should already be checked in AuthorizeCredentialValidator." + issuer.has_value(), + "issuer must be present, should already be checked in AuthorizeCredentialValidator." ); ASSERT( jo.at(JS(credential_type)).is_string(), - "credential_type must be string, should already be checked in AuthorizeCredentialValidator" + "credential_type must be string, should already be checked in " + "AuthorizeCredentialValidator" ); - auto const credentialType = ripple::strUnHex(static_cast(jo.at(JS(credential_type)).as_string())); + auto const credentialType = + ripple::strUnHex(static_cast(jo.at(JS(credential_type)).as_string())); ASSERT( credentialType.has_value(), - "credential_type must be present, should already be checked in AuthorizeCredentialValidator." + "credential_type must be present, should already be checked in " + "AuthorizeCredentialValidator." ); auto credential = ripple::STObject::makeInnerObject(ripple::sfCredential); @@ -119,7 +124,9 @@ fetchCredentialArray( ripple::STArray authCreds; std::unordered_set elems; for (auto const& elem : credID.value()) { - ASSERT(elem.is_string(), "should already be checked in validators.hpp that elem is a string."); + ASSERT( + elem.is_string(), "should already be checked in validators.hpp that elem is a string." + ); if (elems.contains(elem.as_string())) return Error{Status{RippledError::rpcBAD_CREDENTIALS, "duplicates in credentials."}}; @@ -147,11 +154,15 @@ fetchCredentialArray( return Error{Status{RippledError::rpcBAD_CREDENTIALS, "credentials are expired"}}; if (sleCred.getAccountID(ripple::sfSubject) != srcAcc) - return Error{Status{RippledError::rpcBAD_CREDENTIALS, "credentials don't belong to the root account"}}; + return Error{Status{ + RippledError::rpcBAD_CREDENTIALS, "credentials don't belong to the root account" + }}; auto credential = ripple::STObject::makeInnerObject(ripple::sfCredential); credential.setAccountID(ripple::sfIssuer, sleCred.getAccountID(ripple::sfIssuer)); - credential.setFieldVL(ripple::sfCredentialType, sleCred.getFieldVL(ripple::sfCredentialType)); + credential.setFieldVL( + ripple::sfCredentialType, sleCred.getFieldVL(ripple::sfCredentialType) + ); authCreds.push_back(std::move(credential)); } diff --git a/src/rpc/CredentialHelpers.hpp b/src/rpc/CredentialHelpers.hpp index d4b84bb37..c0db97c7c 100644 --- a/src/rpc/CredentialHelpers.hpp +++ b/src/rpc/CredentialHelpers.hpp @@ -50,7 +50,8 @@ bool checkExpired(ripple::SLE const& sleCred, ripple::LedgerHeader const& ledger); /** - * @brief Creates authentication credential field (which is a set of pairs of AccountID and Credential ID) + * @brief Creates authentication credential field (which is a set of pairs of AccountID and + * Credential ID) * * @param in The array of Credential objects to check * @return Auth Credential array diff --git a/src/rpc/Errors.cpp b/src/rpc/Errors.cpp index e0aa79027..f508093f0 100644 --- a/src/rpc/Errors.cpp +++ b/src/rpc/Errors.cpp @@ -82,7 +82,8 @@ getWarningInfo(WarningCode code) static constexpr WarningInfo kINFOS[]{ {WarnUnknown, "Unknown warning"}, {WarnRpcClio, - "This is a clio server. clio only serves validated data. If you want to talk to rippled, include " + "This is a clio server. clio only serves validated data. If you want to talk to rippled, " + "include " "'ledger_index':'current' in your request"}, {WarnRpcOutdated, "This server may be out of date"}, {WarnRpcRateLimit, "You are about to be rate limited"}, @@ -112,11 +113,21 @@ ClioErrorInfo const& getErrorInfo(ClioError code) { static constexpr ClioErrorInfo kINFOS[]{ - {.code = ClioError::RpcMalformedCurrency, .error = "malformedCurrency", .message = "Malformed currency."}, - {.code = ClioError::RpcMalformedRequest, .error = "malformedRequest", .message = "Malformed request."}, - {.code = ClioError::RpcMalformedOwner, .error = "malformedOwner", .message = "Malformed owner."}, - {.code = ClioError::RpcMalformedAddress, .error = "malformedAddress", .message = "Malformed address."}, - {.code = ClioError::RpcUnknownOption, .error = "unknownOption", .message = "Unknown option."}, + {.code = ClioError::RpcMalformedCurrency, + .error = "malformedCurrency", + .message = "Malformed currency."}, + {.code = ClioError::RpcMalformedRequest, + .error = "malformedRequest", + .message = "Malformed request."}, + {.code = ClioError::RpcMalformedOwner, + .error = "malformedOwner", + .message = "Malformed owner."}, + {.code = ClioError::RpcMalformedAddress, + .error = "malformedAddress", + .message = "Malformed address."}, + {.code = ClioError::RpcUnknownOption, + .error = "unknownOption", + .message = "Unknown option."}, {.code = ClioError::RpcFieldNotFoundTransaction, .error = "fieldNotFoundTransaction", .message = "Missing field."}, @@ -127,19 +138,31 @@ getErrorInfo(ClioError code) .error = "malformedAuthorizedCredentials", .message = "Malformed authorized credentials."}, // special system errors - {.code = ClioError::RpcInvalidApiVersion, .error = JS(invalid_API_version), .message = "Invalid API version."}, + {.code = ClioError::RpcInvalidApiVersion, + .error = JS(invalid_API_version), + .message = "Invalid API version."}, {.code = ClioError::RpcCommandIsMissing, .error = JS(missingCommand), .message = "Method is not specified or is not a string."}, - {.code = ClioError::RpcCommandNotString, .error = "commandNotString", .message = "Method is not a string."}, - {.code = ClioError::RpcCommandIsEmpty, .error = "emptyCommand", .message = "Method is an empty string."}, + {.code = ClioError::RpcCommandNotString, + .error = "commandNotString", + .message = "Method is not a string."}, + {.code = ClioError::RpcCommandIsEmpty, + .error = "emptyCommand", + .message = "Method is an empty string."}, {.code = ClioError::RpcParamsUnparsable, .error = "paramsUnparsable", .message = "Params must be an array holding exactly one object."}, // etl related errors - {.code = ClioError::EtlConnectionError, .error = "connectionError", .message = "Couldn't connect to rippled."}, - {.code = ClioError::EtlRequestError, .error = "requestError", .message = "Error sending request to rippled."}, - {.code = ClioError::EtlRequestTimeout, .error = "timeout", .message = "Request to rippled timed out."}, + {.code = ClioError::EtlConnectionError, + .error = "connectionError", + .message = "Couldn't connect to rippled."}, + {.code = ClioError::EtlRequestError, + .error = "requestError", + .message = "Error sending request to rippled."}, + {.code = ClioError::EtlRequestTimeout, + .error = "timeout", + .message = "Request to rippled timed out."}, {.code = ClioError::EtlInvalidResponse, .error = "invalidResponse", .message = "Rippled returned an invalid response."} @@ -153,7 +176,11 @@ getErrorInfo(ClioError code) } boost::json::object -makeError(RippledError err, std::optional customError, std::optional customMessage) +makeError( + RippledError err, + std::optional customError, + std::optional customMessage +) { boost::json::object json; auto const& info = ripple::RPC::get_error_info(err); @@ -168,7 +195,11 @@ makeError(RippledError err, std::optional customError, std::op } boost::json::object -makeError(ClioError err, std::optional customError, std::optional customMessage) +makeError( + ClioError err, + std::optional customError, + std::optional customMessage +) { boost::json::object json; auto const& info = getErrorInfo(err); @@ -185,13 +216,17 @@ makeError(ClioError err, std::optional customError, std::optio boost::json::object makeError(Status const& status) { - auto wrapOptional = [](string_view const& str) { return str.empty() ? nullopt : make_optional(str); }; + auto wrapOptional = [](string_view const& str) { + return str.empty() ? nullopt : make_optional(str); + }; auto res = visit( util::OverloadSet{ [&status, &wrapOptional](RippledError err) { if (err == ripple::rpcUNKNOWN) - return boost::json::object{{"error", status.message}, {"type", "response"}, {"status", "error"}}; + return boost::json::object{ + {"error", status.message}, {"type", "response"}, {"status", "error"} + }; return makeError(err, wrapOptional(status.error), wrapOptional(status.message)); }, diff --git a/src/rpc/Errors.hpp b/src/rpc/Errors.hpp index 5dfa21ce2..cd244985d 100644 --- a/src/rpc/Errors.hpp +++ b/src/rpc/Errors.hpp @@ -102,13 +102,14 @@ struct Status { * @param code The error code * @param extraInfo The extra info */ - Status(CombinedError code, boost::json::object&& extraInfo) : code(code), extraInfo(std::move(extraInfo)) {}; + Status(CombinedError code, boost::json::object&& extraInfo) + : code(code), extraInfo(std::move(extraInfo)) {}; /** * @brief Construct a new Status object with a custom message * - * @note HACK. Some rippled handlers explicitly specify errors. This means that we have to be able to duplicate this - * functionality. + * @note HACK. Some rippled handlers explicitly specify errors. This means that we have to be + * able to duplicate this functionality. * * @param message The message */ diff --git a/src/rpc/Factories.cpp b/src/rpc/Factories.cpp index a4b2bf2cb..aa766b970 100644 --- a/src/rpc/Factories.cpp +++ b/src/rpc/Factories.cpp @@ -63,14 +63,18 @@ makeWsContext( } if (!commandValue.is_string()) - return Error{{ClioError::RpcCommandIsMissing, "Method/Command is not specified or is not a string."}}; + return Error{ + {ClioError::RpcCommandIsMissing, "Method/Command is not specified or is not a string."} + }; auto const apiVersion = apiVersionParser.get().parse(request); if (!apiVersion) return Error{{ClioError::RpcInvalidApiVersion, apiVersion.error()}}; auto const command = boost::json::value_to(commandValue); - return web::Context(yc, command, *apiVersion, request, std::move(session), tagFactory, range, clientIp, isAdmin); + return web::Context( + yc, command, *apiVersion, request, std::move(session), tagFactory, range, clientIp, isAdmin + ); } std::expected @@ -96,7 +100,10 @@ makeHttpContext( auto const command = boost::json::value_to(request.at("method")); if (command == "subscribe" || command == "unsubscribe") - return Error{{RippledError::rpcBAD_SYNTAX, "Subscribe and unsubscribe are only allowed for websocket."}}; + return Error{ + {RippledError::rpcBAD_SYNTAX, + "Subscribe and unsubscribe are only allowed for websocket."} + }; if (!request.at("params").is_array()) return Error{{ClioError::RpcParamsUnparsable, "Missing params array."}}; @@ -106,12 +113,21 @@ makeHttpContext( if (array.size() != 1 || !array.at(0).is_object()) return Error{{ClioError::RpcParamsUnparsable}}; - auto const apiVersion = apiVersionParser.get().parse(request.at("params").as_array().at(0).as_object()); + auto const apiVersion = + apiVersionParser.get().parse(request.at("params").as_array().at(0).as_object()); if (!apiVersion) return Error{{ClioError::RpcInvalidApiVersion, apiVersion.error()}}; return web::Context( - yc, command, *apiVersion, array.at(0).as_object(), nullptr, tagFactory, range, clientIp, isAdmin + yc, + command, + *apiVersion, + array.at(0).as_object(), + nullptr, + tagFactory, + range, + clientIp, + isAdmin ); } diff --git a/src/rpc/Factories.hpp b/src/rpc/Factories.hpp index 1569ba180..0930bbded 100644 --- a/src/rpc/Factories.hpp +++ b/src/rpc/Factories.hpp @@ -36,10 +36,11 @@ /* * This file contains various classes necessary for executing RPC handlers. - * Context gives the handlers access to various other parts of the application Status is used to report errors. - * And lastly, there are various functions for making Contexts, Statuses and serializing Status to JSON. - * This file is meant to contain any class or function that code outside of the rpc folder needs to use. - * For helper functions or classes used within the rpc folder, use RPCHelpers.h. + * Context gives the handlers access to various other parts of the application Status is used to + * report errors. And lastly, there are various functions for making Contexts, Statuses and + * serializing Status to JSON. This file is meant to contain any class or function that code outside + * of the rpc folder needs to use. For helper functions or classes used within the rpc folder, use + * RPCHelpers.h. */ namespace rpc { diff --git a/src/rpc/RPCEngine.hpp b/src/rpc/RPCEngine.hpp index 2af5d3e19..162b69485 100644 --- a/src/rpc/RPCEngine.hpp +++ b/src/rpc/RPCEngine.hpp @@ -137,7 +137,9 @@ public: std::shared_ptr const& handlerProvider ) { - return std::make_shared(config, backend, balancer, dosGuard, workQueue, counters, handlerProvider); + return std::make_shared( + config, backend, balancer, dosGuard, workQueue, counters, handlerProvider + ); } /** @@ -220,7 +222,9 @@ public: bool post(FnType&& func, std::string const& ip) { - return workQueue_.get().postCoro(std::forward(func), dosGuard_.get().isWhiteListed(ip)); + return workQueue_.get().postCoro( + std::forward(func), dosGuard_.get().isWhiteListed(ip) + ); } /** @@ -237,7 +241,8 @@ public: } /** - * @brief Notify the system that specified method failed to execute due to a recoverable user error. + * @brief Notify the system that specified method failed to execute due to a recoverable user + * error. * * Used for errors based on user input, not actual failures of the db or clio itself. * @@ -295,7 +300,8 @@ public: } /** - * @brief Notify the system that the incoming request specified an unknown/unsupported method/command. + * @brief Notify the system that the incoming request specified an unknown/unsupported + * method/command. */ void notifyUnknownCommand() diff --git a/src/rpc/RPCHelpers.cpp b/src/rpc/RPCHelpers.cpp index 72a6555ff..6448617d4 100644 --- a/src/rpc/RPCHelpers.cpp +++ b/src/rpc/RPCHelpers.cpp @@ -156,7 +156,8 @@ getDeliveredAmount( // 446000000 is in Feb 2014, well after DeliveredAmount went live static constexpr std::uint32_t kFIRST_LEDGER_WITH_DELIVERED_AMOUNT = 4594095; static constexpr std::uint32_t kDELIVERED_AMOUNT_LIVE_DATE = 446000000; - if (ledgerSequence >= kFIRST_LEDGER_WITH_DELIVERED_AMOUNT || date > kDELIVERED_AMOUNT_LIVE_DATE) { + if (ledgerSequence >= kFIRST_LEDGER_WITH_DELIVERED_AMOUNT || + date > kDELIVERED_AMOUNT_LIVE_DATE) { return txn->getFieldAmount(ripple::sfAmount); } } @@ -185,7 +186,8 @@ accountFromStringStrict(std::string const& account) if (blob && ripple::publicKeyType(ripple::makeSlice(*blob))) { publicKey = ripple::PublicKey(ripple::Slice{blob->data(), blob->size()}); } else { - publicKey = util::parseBase58Wrapper(ripple::TokenType::AccountPublic, account); + publicKey = + util::parseBase58Wrapper(ripple::TokenType::AccountPublic, account); } std::optional result; @@ -204,7 +206,8 @@ deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs) static util::Logger const log{"RPC"}; // NOLINT(readability-identifier-naming) try { - std::pair, std::shared_ptr> result; + std::pair, std::shared_ptr> + result; { ripple::SerialIter s{blobs.transaction.data(), blobs.transaction.size()}; result.first = std::make_shared(s); @@ -219,7 +222,8 @@ deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs) std::stringstream meta; std::ranges::copy(blobs.transaction, std::ostream_iterator(txn)); std::ranges::copy(blobs.metadata, std::ostream_iterator(meta)); - LOG(log.error()) << "Failed to deserialize transaction. txn = " << txn.str() << " - meta = " << meta.str() + LOG(log.error()) << "Failed to deserialize transaction. txn = " << txn.str() + << " - meta = " << meta.str() << " txn length = " << std::to_string(blobs.transaction.size()) << " meta length = " << std::to_string(blobs.metadata.size()); throw e; @@ -231,7 +235,8 @@ deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs, std::uint32_t s { auto [tx, meta] = deserializeTxPlusMeta(blobs); - std::shared_ptr const m = std::make_shared(tx->getTransactionID(), seq, *meta); + std::shared_ptr const m = + std::make_shared(tx->getTransactionID(), seq, *meta); return {tx, m}; } @@ -239,7 +244,8 @@ deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs, std::uint32_t s boost::json::object toJson(ripple::STBase const& obj) { - boost::json::value value = boost::json::parse(obj.getJson(ripple::JsonOptions::none).toStyledString()); + boost::json::value value = + boost::json::parse(obj.getJson(ripple::JsonOptions::none).toStyledString()); return value.as_object(); } @@ -291,8 +297,8 @@ encodeCTID(uint32_t ledgerSeq, uint16_t txnIndex, uint16_t networkId) noexcept return {}; static constexpr uint64_t kCTID_PREFIX = 0xC000'0000; - uint64_t const ctidValue = - ((kCTID_PREFIX + static_cast(ledgerSeq)) << 32) + (static_cast(txnIndex) << 16) + networkId; + uint64_t const ctidValue = ((kCTID_PREFIX + static_cast(ledgerSeq)) << 32) + + (static_cast(txnIndex) << 16) + networkId; return {fmt::format("{:016X}", ctidValue)}; } @@ -307,7 +313,8 @@ insertDeliveredAmount( { if (canHaveDeliveredAmount(txn, meta)) { if (auto amt = getDeliveredAmount(txn, meta, meta->getLgrSeq(), date)) { - metaJson["delivered_amount"] = toBoostJson(amt->getJson(ripple::JsonOptions::include_date)); + metaJson["delivered_amount"] = + toBoostJson(amt->getJson(ripple::JsonOptions::include_date)); } else { metaJson["delivered_amount"] = "unavailable"; } @@ -347,7 +354,10 @@ getMPTIssuanceID(std::shared_ptr const& meta) * @return true if the transaction can have a mpt_issuance_id */ static bool -canHaveMPTIssuanceID(std::shared_ptr const& txn, std::shared_ptr const& meta) +canHaveMPTIssuanceID( + std::shared_ptr const& txn, + std::shared_ptr const& meta +) { if (txn->getTxnType() != ripple::ttMPTOKEN_ISSUANCE_CREATE) return false; @@ -395,7 +405,8 @@ insertDeliverMaxAlias(boost::json::object& txJson, std::uint32_t const apiVersio boost::json::object toJson(ripple::TxMeta const& meta) { - boost::json::value value = boost::json::parse(meta.getJson(ripple::JsonOptions::none).toStyledString()); + boost::json::value value = + boost::json::parse(meta.getJson(ripple::JsonOptions::none).toStyledString()); return value.as_object(); } @@ -411,13 +422,15 @@ toBoostJson(Json::Value const& value) boost::json::object toJson(ripple::SLE const& sle) { - boost::json::value value = boost::json::parse(sle.getJson(ripple::JsonOptions::none).toStyledString()); + boost::json::value value = + boost::json::parse(sle.getJson(ripple::JsonOptions::none).toStyledString()); if (sle.getType() == ripple::ltACCOUNT_ROOT) { if (sle.isFieldPresent(ripple::sfEmailHash)) { auto const& hash = sle.getFieldH128(ripple::sfEmailHash); std::string md5 = strHex(hash); boost::algorithm::to_lower(md5); - value.as_object()["urlgravatar"] = str(boost::format("http://www.gravatar.com/avatar/%s") % md5); + value.as_object()["urlgravatar"] = + str(boost::format("http://www.gravatar.com/avatar/%s") % md5); } } return value.as_object(); @@ -466,7 +479,10 @@ parseStringAsUInt(std::string const& value) } std::expected -ledgerHeaderFromRequest(std::shared_ptr const& backend, web::Context const& ctx) +ledgerHeaderFromRequest( + std::shared_ptr const& backend, + web::Context const& ctx +) { auto hashValue = ctx.params.contains("ledger_hash") ? ctx.params.at("ledger_hash") : nullptr; @@ -659,14 +675,18 @@ traverseOwnedNodes( // the format is checked in RPC framework level auto [hexCursor, startHint] = *maybeCursor; - auto const isNftMarkerNonZero = startHint == std::numeric_limits::max() and hexCursor != beast::zero; - auto const isNftMarkerZero = startHint == std::numeric_limits::max() and hexCursor == beast::zero; + auto const isNftMarkerNonZero = + startHint == std::numeric_limits::max() and hexCursor != beast::zero; + auto const isNftMarkerZero = + startHint == std::numeric_limits::max() and hexCursor == beast::zero; // if we need to traverse nft objects and this is the first request -> traverse nft objects - // if we need to traverse nft objects and the marker is still in nft page -> traverse nft objects - // if we need to traverse nft objects and the marker is still in nft page but next page is zero -> owned nodes - // if we need to traverse nft objects and the marker is not in nft page -> traverse owned nodes + // if we need to traverse nft objects and the marker is still in nft page -> traverse nft + // objects if we need to traverse nft objects and the marker is still in nft page but next page + // is zero -> owned nodes if we need to traverse nft objects and the marker is not in nft page + // -> traverse owned nodes if (nftIncluded and (!jsonCursor or isNftMarkerNonZero)) { - auto const cursorMaybe = traverseNFTObjects(backend, sequence, accountID, hexCursor, limit, yield, atOwnedNode); + auto const cursorMaybe = + traverseNFTObjects(backend, sequence, accountID, hexCursor, limit, yield, atOwnedNode); if (!cursorMaybe.has_value()) return cursorMaybe; @@ -675,20 +695,30 @@ traverseOwnedNodes( // if limit reach , we return the next page and max as marker if (nftsCount >= limit) - return AccountCursor{.index = nextNFTPage, .hint = std::numeric_limits::max()}; + return AccountCursor{ + .index = nextNFTPage, .hint = std::numeric_limits::max() + }; // adjust limit ,continue traversing owned nodes limit -= nftsCount; hexCursor = beast::zero; startHint = 0; } else if (nftIncluded and isNftMarkerZero) { - // the last request happen to fetch all the nft, adjust marker to continue traversing owned nodes + // the last request happen to fetch all the nft, adjust marker to continue traversing owned + // nodes hexCursor = beast::zero; startHint = 0; } return traverseOwnedNodes( - backend, ripple::keylet::ownerDir(accountID), hexCursor, startHint, sequence, limit, yield, atOwnedNode + backend, + ripple::keylet::ownerDir(accountID), + hexCursor, + startHint, + sequence, + limit, + yield, + atOwnedNode ); } @@ -743,7 +773,9 @@ traverseOwnedNodes( auto const ownerDir = backend.fetchLedgerObject(currentIndex.key, sequence, yield); if (!ownerDir) - return std::unexpected{Status(ripple::rpcINVALID_PARAMS, "Owner directory not found.")}; + return std::unexpected{ + Status(ripple::rpcINVALID_PARAMS, "Owner directory not found.") + }; ripple::SerialIter ownedDirIt{ownerDir->data(), ownerDir->size()}; ripple::SLE const ownedDirSle{ownedDirIt, currentIndex.key}; @@ -813,7 +845,8 @@ traverseOwnedNodes( keys.size() ); - auto [objects, timeDiff] = util::timed([&]() { return backend.fetchLedgerObjects(keys, sequence, yield); }); + auto [objects, timeDiff] = + util::timed([&]() { return backend.fetchLedgerObjects(keys, sequence, yield); }); LOG(log.debug()) << "Time loading owned entries: " << timeDiff << " milliseconds"; @@ -836,8 +869,11 @@ read( web::Context const& context ) { - if (auto const blob = backend->fetchLedgerObject(keylet.key, lgrInfo.seq, context.yield); blob) { - return std::make_shared(ripple::SerialIter{blob->data(), blob->size()}, keylet.key); + if (auto const blob = backend->fetchLedgerObject(keylet.key, lgrInfo.seq, context.yield); + blob) { + return std::make_shared( + ripple::SerialIter{blob->data(), blob->size()}, keylet.key + ); } return nullptr; @@ -852,7 +888,9 @@ parseRippleLibSeed(boost::json::value const& value) if (!value.is_string()) return {}; - auto const result = ripple::decodeBase58Token(boost::json::value_to(value), ripple::TokenType::None); + auto const result = ripple::decodeBase58Token( + boost::json::value_to(value), ripple::TokenType::None + ); static constexpr std::size_t kSEED_SIZE = 18; static constexpr std::array kSEED_PREFIX = {0xE1, 0x4B}; @@ -872,7 +910,9 @@ getAccountsFromTransaction(boost::json::object const& transaction) auto inObject = getAccountsFromTransaction(value.as_object()); accounts.insert(accounts.end(), inObject.begin(), inObject.end()); } else if (value.is_string()) { - auto const account = util::parseBase58Wrapper(boost::json::value_to(value)); + auto const account = util::parseBase58Wrapper( + boost::json::value_to(value) + ); if (account) { accounts.push_back(*account); } @@ -973,7 +1013,11 @@ isDeepFrozen( auto const trustLineKeylet = ripple::keylet::line(account, issuer, currency); return fetchAndCheckAnyFlagsExists( - backend, sequence, trustLineKeylet, {ripple::lsfHighDeepFreeze, ripple::lsfLowDeepFreeze}, yield + backend, + sequence, + trustLineKeylet, + {ripple::lsfHighDeepFreeze, ripple::lsfLowDeepFreeze}, + yield ); } @@ -1040,7 +1084,16 @@ accountFunds( return amount; } - return accountHolds(backend, amendmentCenter, sequence, id, amount.getCurrency(), amount.getIssuer(), true, yield); + return accountHolds( + backend, + amendmentCenter, + sequence, + id, + amount.getCurrency(), + amount.getIssuer(), + true, + yield + ); } ripple::STAmount @@ -1120,18 +1173,22 @@ accountHolds( if (isFrozen(backend, sequence, account, currency, issuer, yield)) return false; - if (amendmentCenter.isEnabled(yield, data::Amendments::fixFrozenLPTokenTransfer, sequence)) { - auto const issuerBlob = backend.fetchLedgerObject(ripple::keylet::account(issuer).key, sequence, yield); + if (amendmentCenter.isEnabled( + yield, data::Amendments::fixFrozenLPTokenTransfer, sequence + )) { + auto const issuerBlob = + backend.fetchLedgerObject(ripple::keylet::account(issuer).key, sequence, yield); if (!issuerBlob) return false; ripple::SLE const issuerSle{ - ripple::SerialIter{issuerBlob->data(), issuerBlob->size()}, ripple::keylet::account(issuer).key + ripple::SerialIter{issuerBlob->data(), issuerBlob->size()}, + ripple::keylet::account(issuer).key }; - // if the issuer is an amm account, then currency is lptoken, so we will need to check if the - // assets in the pool are frozen as well + // if the issuer is an amm account, then currency is lptoken, so we will need to check + // if the assets in the pool are frozen as well if (issuerSle.isFieldPresent(ripple::sfAMMID)) { auto const ammKeylet = ripple::keylet::amm(issuerSle[ripple::sfAMMID]); auto const ammBlob = backend.fetchLedgerObject(ammKeylet.key, sequence, yield); @@ -1139,7 +1196,9 @@ accountHolds( if (!ammBlob) return false; - ripple::SLE const ammSle{ripple::SerialIter{ammBlob->data(), ammBlob->size()}, ammKeylet.key}; + ripple::SLE const ammSle{ + ripple::SerialIter{ammBlob->data(), ammBlob->size()}, ammKeylet.key + }; return !isLPTokenFrozen( backend, @@ -1283,9 +1342,13 @@ postProcessOrderBook( saTakerGetsFunded = saTakerGets; } else { saTakerGetsFunded = saOwnerFundsLimit; - offerJson["taker_gets_funded"] = toBoostJson(saTakerGetsFunded.getJson(ripple::JsonOptions::none)); + offerJson["taker_gets_funded"] = + toBoostJson(saTakerGetsFunded.getJson(ripple::JsonOptions::none)); offerJson["taker_pays_funded"] = toBoostJson( - std::min(saTakerPays, ripple::multiply(saTakerGetsFunded, dirRate, saTakerPays.issue())) + std::min( + saTakerPays, + ripple::multiply(saTakerGetsFunded, dirRate, saTakerPays.issue()) + ) .getJson(ripple::JsonOptions::none) ); } @@ -1322,26 +1385,30 @@ parseBook( { if (isXRP(pays) && !isXRP(payIssuer)) { return std::unexpected{Status{ - RippledError::rpcSRC_ISR_MALFORMED, "Unneeded field 'taker_pays.issuer' for XRP currency specification." + RippledError::rpcSRC_ISR_MALFORMED, + "Unneeded field 'taker_pays.issuer' for XRP currency specification." }}; } if (!isXRP(pays) && isXRP(payIssuer)) { - return std::unexpected{ - Status{RippledError::rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', expected non-XRP issuer."} - }; + return std::unexpected{Status{ + RippledError::rpcSRC_ISR_MALFORMED, + "Invalid field 'taker_pays.issuer', expected non-XRP issuer." + }}; } if (ripple::isXRP(gets) && !ripple::isXRP(getIssuer)) { return std::unexpected{Status{ - RippledError::rpcDST_ISR_MALFORMED, "Unneeded field 'taker_gets.issuer' for XRP currency specification." + RippledError::rpcDST_ISR_MALFORMED, + "Unneeded field 'taker_gets.issuer' for XRP currency specification." }}; } if (!ripple::isXRP(gets) && ripple::isXRP(getIssuer)) { - return std::unexpected{ - Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', expected non-XRP issuer."} - }; + return std::unexpected{Status{ + RippledError::rpcDST_ISR_MALFORMED, + "Invalid field 'taker_gets.issuer', expected non-XRP issuer." + }}; } if (pays == gets && payIssuer == getIssuer) @@ -1362,16 +1429,24 @@ std::expected parseBook(boost::json::object const& request) { if (!request.contains("taker_pays")) - return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_pays'"}}; + return std::unexpected{ + Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_pays'"} + }; if (!request.contains("taker_gets")) - return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_gets'"}}; + return std::unexpected{ + Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_gets'"} + }; if (!request.at("taker_pays").is_object()) - return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_pays' is not an object"}}; + return std::unexpected{ + Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_pays' is not an object"} + }; if (!request.at("taker_gets").is_object()) - return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_gets' is not an object"}}; + return std::unexpected{ + Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_gets' is not an object"} + }; auto takerPays = request.at("taker_pays").as_object(); if (!takerPays.contains("currency")) @@ -1394,19 +1469,27 @@ parseBook(boost::json::object const& request) return std::unexpected{Status{RippledError::rpcDOMAIN_MALFORMED}}; ripple::Currency payCurrency; - if (!ripple::to_currency(payCurrency, boost::json::value_to(takerPays.at("currency")))) + if (!ripple::to_currency( + payCurrency, boost::json::value_to(takerPays.at("currency")) + )) return std::unexpected{Status{RippledError::rpcSRC_CUR_MALFORMED}}; ripple::Currency getCurrency; - if (!ripple::to_currency(getCurrency, boost::json::value_to(takerGets["currency"]))) + if (!ripple::to_currency( + getCurrency, boost::json::value_to(takerGets["currency"]) + )) return std::unexpected{Status{RippledError::rpcDST_AMT_MALFORMED}}; ripple::AccountID payIssuer; if (takerPays.contains("issuer")) { if (!takerPays.at("issuer").is_string()) - return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "takerPaysIssuerNotString"}}; + return std::unexpected{ + Status{RippledError::rpcINVALID_PARAMS, "takerPaysIssuerNotString"} + }; - if (!ripple::to_issuer(payIssuer, boost::json::value_to(takerPays.at("issuer")))) + if (!ripple::to_issuer( + payIssuer, boost::json::value_to(takerPays.at("issuer")) + )) return std::unexpected{Status{RippledError::rpcSRC_ISR_MALFORMED}}; if (payIssuer == ripple::noAccount()) @@ -1417,35 +1500,44 @@ parseBook(boost::json::object const& request) if (isXRP(payCurrency) && !isXRP(payIssuer)) { return std::unexpected{Status{ - RippledError::rpcSRC_ISR_MALFORMED, "Unneeded field 'taker_pays.issuer' for XRP currency specification." + RippledError::rpcSRC_ISR_MALFORMED, + "Unneeded field 'taker_pays.issuer' for XRP currency specification." }}; } if (!isXRP(payCurrency) && isXRP(payIssuer)) { - return std::unexpected{ - Status{RippledError::rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', expected non-XRP issuer."} - }; + return std::unexpected{Status{ + RippledError::rpcSRC_ISR_MALFORMED, + "Invalid field 'taker_pays.issuer', expected non-XRP issuer." + }}; } if ((!isXRP(payCurrency)) && (!takerPays.contains("issuer"))) - return std::unexpected{Status{RippledError::rpcSRC_ISR_MALFORMED, "Missing non-XRP issuer."}}; + return std::unexpected{ + Status{RippledError::rpcSRC_ISR_MALFORMED, "Missing non-XRP issuer."} + }; ripple::AccountID getIssuer; if (takerGets.contains("issuer")) { if (!takerGets["issuer"].is_string()) - return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "taker_gets.issuer should be string"}}; - - if (!ripple::to_issuer(getIssuer, boost::json::value_to(takerGets.at("issuer")))) { return std::unexpected{ - Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer."} + Status{RippledError::rpcINVALID_PARAMS, "taker_gets.issuer should be string"} }; + + if (!ripple::to_issuer( + getIssuer, boost::json::value_to(takerGets.at("issuer")) + )) { + return std::unexpected{Status{ + RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer." + }}; } if (getIssuer == ripple::noAccount()) { - return std::unexpected{ - Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer account one."} - }; + return std::unexpected{Status{ + RippledError::rpcDST_ISR_MALFORMED, + "Invalid field 'taker_gets.issuer', bad issuer account one." + }}; } } else { getIssuer = ripple::xrpAccount(); @@ -1453,14 +1545,16 @@ parseBook(boost::json::object const& request) if (ripple::isXRP(getCurrency) && !ripple::isXRP(getIssuer)) { return std::unexpected{Status{ - RippledError::rpcDST_ISR_MALFORMED, "Unneeded field 'taker_gets.issuer' for XRP currency specification." + RippledError::rpcDST_ISR_MALFORMED, + "Unneeded field 'taker_gets.issuer' for XRP currency specification." }}; } if (!ripple::isXRP(getCurrency) && ripple::isXRP(getIssuer)) { - return std::unexpected{ - Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', expected non-XRP issuer."} - }; + return std::unexpected{Status{ + RippledError::rpcDST_ISR_MALFORMED, + "Invalid field 'taker_gets.issuer', expected non-XRP issuer." + }}; } if (payCurrency == getCurrency && payIssuer == getIssuer) @@ -1526,12 +1620,14 @@ isAdminCmd(std::string const& method, boost::json::object const& request) // rippled considers string/non-zero int/non-empty array/ non-empty json as true. // Use rippled's API asBool to get the same result. // https://github.com/XRPLF/rippled/issues/5119 - auto const isFieldSet = [&jv](auto const field) { return jv.isMember(field) and jv[field].asBool(); }; + auto const isFieldSet = [&jv](auto const field) { + return jv.isMember(field) and jv[field].asBool(); + }; // According to doc // https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/ledger-methods/ledger, - // full/accounts/type are admin only, but type only works when full/accounts are set, so we don't need to check - // type. + // full/accounts/type are admin only, but type only works when full/accounts are set, so we + // don't need to check type. if (isFieldSet(JS(full)) or isFieldSet(JS(accounts))) return true; } diff --git a/src/rpc/RPCHelpers.hpp b/src/rpc/RPCHelpers.hpp index 5d3f9bb99..852dd75da 100644 --- a/src/rpc/RPCHelpers.hpp +++ b/src/rpc/RPCHelpers.hpp @@ -164,8 +164,8 @@ toExpandedJson( ); /** - * @brief Convert a TransactionAndMetadata to JSON object containing tx and metadata data in hex format. According to - * the apiVersion, the key is "tx_blob" and "meta" or "meta_blob". + * @brief Convert a TransactionAndMetadata to JSON object containing tx and metadata data in hex + * format. According to the apiVersion, the key is "tx_blob" and "meta" or "meta_blob". * @param txnPlusMeta The TransactionAndMetadata to convert. * @param apiVersion The api version * @return The JSON object containing tx and metadata data in hex format. @@ -174,8 +174,8 @@ boost::json::object toJsonWithBinaryTx(data::TransactionAndMetadata const& txnPlusMeta, std::uint32_t apiVersion); /** - * @brief Add "DeliverMax" which is the alias of "Amount" for "Payment" transaction to transaction json. Remove the - * "Amount" field when version is greater than 1 + * @brief Add "DeliverMax" which is the alias of "Amount" for "Payment" transaction to transaction + * json. Remove the "Amount" field when version is greater than 1 * @param txJson The transaction json object * @param apiVersion The api version */ @@ -201,9 +201,9 @@ insertDeliveredAmount( /** * @brief Add "mpt_issuance_id" into various MPTToken transaction json. - * @note We add "mpt_issuance_id" into the meta part of MPTokenIssuanceCreate only. The reason is because the - * mpt_issuance_id is generated only after one submits MPTokenIssuanceCreate, so there’s no way to know what the id is. - * (rippled) + * @note We add "mpt_issuance_id" into the meta part of MPTokenIssuanceCreate only. The reason is + * because the mpt_issuance_id is generated only after one submits MPTokenIssuanceCreate, so there’s + * no way to know what the id is. (rippled) * * @param txnJson The transaction Json object * @param txn The txn object @@ -293,7 +293,10 @@ generatePubLedgerMessage( * @return The ledger info or an error status */ std::expected -ledgerHeaderFromRequest(std::shared_ptr const& backend, web::Context const& ctx); +ledgerHeaderFromRequest( + std::shared_ptr const& backend, + web::Context const& ctx +); /** * @brief Get ledger info from hash or sequence @@ -462,8 +465,8 @@ fetchAndCheckAnyFlagsExists( /** * @brief Whether the trustline is deep frozen. * - * For deep freeze, (unlike regular freeze) we do not care which account has the high/low deep freeze flag. - * We only care about if the trustline is deep frozen or not. + * For deep freeze, (unlike regular freeze) we do not care which account has the high/low deep + * freeze flag. We only care about if the trustline is deep frozen or not. * * @param backend The backend to use * @param sequence The sequence @@ -769,7 +772,11 @@ decodeCTID(T const ctid) noexcept */ template void -logDuration(boost::json::object const& request, util::BaseTagDecorator const& tag, DurationType const& dur) +logDuration( + boost::json::object const& request, + util::BaseTagDecorator const& tag, + DurationType const& dur +) { using boost::json::serialize; @@ -779,7 +786,9 @@ logDuration(boost::json::object const& request, util::BaseTagDecorator const& ta auto const millis = std::chrono::duration_cast(dur).count(); auto const seconds = std::chrono::duration_cast(dur).count(); auto const msg = fmt::format( - "Request processing duration = {} milliseconds. request = {}", millis, serialize(util::removeSecret(request)) + "Request processing duration = {} milliseconds. request = {}", + millis, + serialize(util::removeSecret(request)) ); if (seconds > kDURATION_ERROR_THRESHOLD_SECONDS) { diff --git a/src/rpc/WorkQueue.cpp b/src/rpc/WorkQueue.cpp index a0a968823..a4f6dab57 100644 --- a/src/rpc/WorkQueue.cpp +++ b/src/rpc/WorkQueue.cpp @@ -113,7 +113,8 @@ WorkQueue::postCoro(TaskType func, bool isWhiteListed, Priority priority) } if (size() >= maxSize_ && !isWhiteListed) { - LOG(log_.warn()) << "Queue is full. rejecting job. current size = " << size() << "; max size = " << maxSize_; + LOG(log_.warn()) << "Queue is full. rejecting job. current size = " << size() + << "; max size = " << maxSize_; return false; } @@ -151,7 +152,9 @@ WorkQueue::stop() { auto onTasksComplete = onQueueEmpty_.lock(); - ASSERT(onTasksComplete->operator bool(), "onTasksComplete must be set when stopping is true."); + ASSERT( + onTasksComplete->operator bool(), "onTasksComplete must be set when stopping is true." + ); onTasksComplete->operator()(); } } @@ -164,7 +167,8 @@ WorkQueue::makeWorkQueue(util::config::ClioConfigDefinition const& config) auto const numThreads = config.get("workers"); auto const maxQueueSize = serverConfig.get("max_queue_size"); - LOG(log.info()) << "Number of workers = " << numThreads << ". Max queue size = " << maxQueueSize; + LOG(log.info()) << "Number of workers = " << numThreads + << ". Max queue size = " << maxQueueSize; return WorkQueue{numThreads, maxQueueSize}; } @@ -202,7 +206,8 @@ WorkQueue::executeTask(boost::asio::yield_context yield) ); auto const takenAt = std::chrono::system_clock::now(); auto const waited = - std::chrono::duration_cast(takenAt - taskWithTimestamp->queuedAt).count(); + std::chrono::duration_cast(takenAt - taskWithTimestamp->queuedAt) + .count(); ++queued_.get(); durationUs_.get() += waited; diff --git a/src/rpc/WorkQueue.hpp b/src/rpc/WorkQueue.hpp index 30ea4d7b3..ff20c546f 100644 --- a/src/rpc/WorkQueue.hpp +++ b/src/rpc/WorkQueue.hpp @@ -93,7 +93,11 @@ private: return high; return normal; }(); - queue.push(TaskWithTimestamp{.task = std::move(task), .queuedAt = std::chrono::system_clock::now()}); + queue.push( + TaskWithTimestamp{ + .task = std::move(task), .queuedAt = std::chrono::system_clock::now() + } + ); } [[nodiscard]] bool @@ -189,7 +193,8 @@ public: startProcessing(); /** - * @brief Put the work queue into a stopping state. This will prevent new jobs from being queued. + * @brief Put the work queue into a stopping state. This will prevent new jobs from being + * queued. * * @param onQueueEmpty A callback to run when the last task in the queue is completed */ @@ -214,7 +219,8 @@ public: /** * @brief Submit a job to the work queue. * - * The job will be rejected if isWhiteListed is set to false and the current size of the queue reached capacity. + * The job will be rejected if isWhiteListed is set to false and the current size of the queue + * reached capacity. * * @param func The function object to queue as a job * @param isWhiteListed Whether the queue capacity applies to this job diff --git a/src/rpc/common/APIVersion.hpp b/src/rpc/common/APIVersion.hpp index d030e54f6..51c908469 100644 --- a/src/rpc/common/APIVersion.hpp +++ b/src/rpc/common/APIVersion.hpp @@ -55,7 +55,9 @@ public: * @param request A JSON object representing the request * @return The specified API version if contained in the JSON object; error string otherwise */ - std::expected virtual parse(boost::json::object const& request) const = 0; + std::expected virtual parse( + boost::json::object const& request + ) const = 0; }; } // namespace rpc diff --git a/src/rpc/common/AnyHandler.hpp b/src/rpc/common/AnyHandler.hpp index 879c47422..308c1a0b3 100644 --- a/src/rpc/common/AnyHandler.hpp +++ b/src/rpc/common/AnyHandler.hpp @@ -45,9 +45,13 @@ public: * @tparam ProcessingStrategy A strategy that implements how processing of JSON is to be done * @param handler The handler to wrap. Required to fulfil the @ref rpc::SomeHandler concept. */ - template > + template < + SomeHandler HandlerType, + typename ProcessingStrategy = impl::DefaultProcessor> /* implicit */ AnyHandler(HandlerType&& handler) - : pimpl_{std::make_unique>(std::forward(handler))} + : pimpl_{std::make_unique>( + std::forward(handler) + )} { } diff --git a/src/rpc/common/Checkers.hpp b/src/rpc/common/Checkers.hpp index 1af91b7ad..ef17e2b37 100644 --- a/src/rpc/common/Checkers.hpp +++ b/src/rpc/common/Checkers.hpp @@ -43,7 +43,8 @@ struct Warning { * @param code The warning code * @param message The warning message */ - Warning(WarningCode code, std::string message) : warningCode(code), extraMessage(std::move(message)) + Warning(WarningCode code, std::string message) + : warningCode(code), extraMessage(std::move(message)) { } @@ -78,7 +79,9 @@ public: check(boost::json::value const& value, std::string_view key) { if (value.is_object() and value.as_object().contains(key)) - return Warning{WarningCode::WarnRpcDeprecated, fmt::format("Field '{}' is deprecated.", key)}; + return Warning{ + WarningCode::WarnRpcDeprecated, fmt::format("Field '{}' is deprecated.", key) + }; return std::nullopt; } }; @@ -117,7 +120,8 @@ public: auto const res = value_to(value.as_object().at(key)); if (value_ == res) { return Warning{ - WarningCode::WarnRpcDeprecated, fmt::format("Value '{}' for field '{}' is deprecated", value_, key) + WarningCode::WarnRpcDeprecated, + fmt::format("Value '{}' for field '{}' is deprecated", value_, key) }; } } diff --git a/src/rpc/common/Concepts.hpp b/src/rpc/common/Concepts.hpp index aa4bbab45..08436b334 100644 --- a/src/rpc/common/Concepts.hpp +++ b/src/rpc/common/Concepts.hpp @@ -100,7 +100,7 @@ concept SomeHandlerWithoutInput = SomeContextProcessWithoutInput; * @brief Specifies what a Handler type must provide. */ template -concept SomeHandler = - (SomeHandlerWithInput or SomeHandlerWithoutInput) and boost::json::has_value_from::value; +concept SomeHandler = (SomeHandlerWithInput or SomeHandlerWithoutInput) and + boost::json::has_value_from::value; } // namespace rpc diff --git a/src/rpc/common/MetaProcessors.hpp b/src/rpc/common/MetaProcessors.hpp index 9264b5ea8..2fb6e4f6b 100644 --- a/src/rpc/common/MetaProcessors.hpp +++ b/src/rpc/common/MetaProcessors.hpp @@ -54,7 +54,8 @@ public: } /** - * @brief Verify that the JSON value representing the section is valid according to the given specs. + * @brief Verify that the JSON value representing the section is valid according to the given + * specs. * * @param value The JSON value representing the outer object * @param key The key used to retrieve the section from the outer object @@ -65,7 +66,8 @@ public: }; /** - * @brief A meta-processor that specifies a list of specs to run against the object at the given index in the array. + * @brief A meta-processor that specifies a list of specs to run against the object at the given + * index in the array. */ class ValidateArrayAt final { std::size_t idx_; @@ -78,7 +80,8 @@ public: * @param idx The index inside the array to validate * @param specs The specifications to validate against */ - ValidateArrayAt(std::size_t idx, std::initializer_list specs) : idx_{idx}, specs_{specs} + ValidateArrayAt(std::size_t idx, std::initializer_list specs) + : idx_{idx}, specs_{specs} { } @@ -94,8 +97,8 @@ public: }; /** - * @brief A meta-processor that specifies a list of requirements to run against when the type matches the template - * parameter. + * @brief A meta-processor that specifies a list of requirements to run against when the type + * matches the template parameter. */ template class IfType final { @@ -107,8 +110,9 @@ public: template explicit IfType(Requirements&&... requirements) : processor_( - [... r = std::forward(requirements)](boost::json::value& j, std::string_view key) - -> MaybeError { + [... r = std::forward( + requirements + )](boost::json::value& j, std::string_view key) -> MaybeError { std::optional firstFailure = std::nullopt; // the check logic is the same as fieldspec @@ -136,7 +140,8 @@ public: IfType(IfType&&) = default; /** - * @brief Verify that the element is valid according to the stored requirements when type matches. + * @brief Verify that the element is valid according to the stored requirements when type + * matches. * * @param value The JSON value representing the outer object * @param key The key used to retrieve the element from the outer object @@ -159,7 +164,8 @@ private: }; /** - * @brief A meta-processor that wraps a validator and produces a custom error in case the wrapped validator fails. + * @brief A meta-processor that wraps a validator and produces a custom error in case the wrapped + * validator fails. */ template requires SomeRequirement or SomeModifier @@ -169,8 +175,8 @@ class WithCustomError final { public: /** - * @brief Constructs a validator that calls the given validator `req` and returns a custom error `err` in case `req` - * fails. + * @brief Constructs a validator that calls the given validator `req` and returns a custom error + * `err` in case `req` fails. * * @param reqOrModifier The requirement to validate against * @param err The custom error to return in case `req` fails @@ -198,10 +204,11 @@ public: } /** - * @brief Runs the stored validator and produces a custom error if the wrapped validator fails. This is an overload - * for the requirement which can modify the value. Such as IfType. + * @brief Runs the stored validator and produces a custom error if the wrapped validator fails. + * This is an overload for the requirement which can modify the value. Such as IfType. * - * @param value The JSON value representing the outer object, this value can be modified by the requirement inside + * @param value The JSON value representing the outer object, this value can be modified by the + * requirement inside * @param key The key used to retrieve the element from the outer object * @return Possibly an error */ @@ -218,7 +225,8 @@ public: /** * @brief Runs the stored modifier and produces a custom error if the wrapped modifier fails. * - * @param value The JSON value representing the outer object. This value can be modified by the modifier. + * @param value The JSON value representing the outer object. This value can be modified by the + * modifier. * @param key The key used to retrieve the element from the outer object * @return Possibly an error */ diff --git a/src/rpc/common/Modifiers.hpp b/src/rpc/common/Modifiers.hpp index 35a6b0d3f..c279cc851 100644 --- a/src/rpc/common/Modifiers.hpp +++ b/src/rpc/common/Modifiers.hpp @@ -99,7 +99,8 @@ struct ToLower final { if (not value.as_object().at(key).is_string()) return {}; // ignore for non-string types - value.as_object()[key] = util::toLower(boost::json::value_to(value.as_object().at(key))); + value.as_object()[key] = + util::toLower(boost::json::value_to(value.as_object().at(key))); return {}; } }; @@ -163,7 +164,8 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return Any compatible user-provided error if modify/verify failed; otherwise no error is returned + * @return Any compatible user-provided error if modify/verify failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError modify(boost::json::value& value, std::string_view key) const diff --git a/src/rpc/common/Specs.hpp b/src/rpc/common/Specs.hpp index c5adca8a0..a001b6f51 100644 --- a/src/rpc/common/Specs.hpp +++ b/src/rpc/common/Specs.hpp @@ -43,11 +43,15 @@ struct FieldSpec final { * * @tparam Processors The types of processors * @param key The key in a JSON object that the field validates - * @param processors The processors, each of them have to fulfil the @ref rpc::SomeProcessor concept + * @param processors The processors, each of them have to fulfil the @ref rpc::SomeProcessor + * concept */ template FieldSpec(std::string const& key, Processors&&... processors) - : processor_{impl::makeFieldProcessor(key, std::forward(processors)...)} + : processor_{impl::makeFieldProcessor( + key, + std::forward(processors)... + )} , checker_{impl::kEMPTY_FIELD_CHECKER} { } @@ -111,7 +115,8 @@ struct RpcSpec final { * @param other The other spec to copy fields from * @param additionalFields The additional fields to add to the spec */ - RpcSpec(RpcSpec const& other, std::initializer_list additionalFields) : fields_{other.fields_} + RpcSpec(RpcSpec const& other, std::initializer_list additionalFields) + : fields_{other.fields_} { for (auto& f : additionalFields) fields_.push_back(f); diff --git a/src/rpc/common/ValidationHelpers.hpp b/src/rpc/common/ValidationHelpers.hpp index 9c84d3d57..26081c49c 100644 --- a/src/rpc/common/ValidationHelpers.hpp +++ b/src/rpc/common/ValidationHelpers.hpp @@ -94,7 +94,8 @@ checkType(boost::json::value const& value) } else if constexpr (std::is_same_v) { if (not value.is_object()) hasError = true; - } else if constexpr (std::is_convertible_v or std::is_convertible_v) { + } else if constexpr (std::is_convertible_v or + std::is_convertible_v) { if (not value.is_int64() && not value.is_uint64()) hasError = true; // if the type specified is unsigned, it should not be negative @@ -110,9 +111,9 @@ checkType(boost::json::value const& value) /** * @brief Check that the type is the same as what was expected optionally clamping it into range. * - * This is used to automatically clamp the value into the range available to the specified type. It is needed in - * order to avoid Min, Max and other validators throw "not exact" error from Boost.Json library if the value does not - * fit in the specified type. + * This is used to automatically clamp the value into the range available to the specified type. It + * is needed in order to avoid Min, Max and other validators throw "not exact" error from Boost.Json + * library if the value does not fit in the specified type. * * @tparam Expected The expected type that value should be convertible to * @param value The json value to check the type of diff --git a/src/rpc/common/Validators.cpp b/src/rpc/common/Validators.cpp index cb458252c..783e5ca17 100644 --- a/src/rpc/common/Validators.cpp +++ b/src/rpc/common/Validators.cpp @@ -52,7 +52,9 @@ namespace rpc::validation { Required::verify(boost::json::value const& value, std::string_view key) { if (not value.is_object() or not value.as_object().contains(key)) - return Error{Status{RippledError::rpcINVALID_PARAMS, "Required field '" + std::string{key} + "' missing"}}; + return Error{Status{ + RippledError::rpcINVALID_PARAMS, "Required field '" + std::string{key} + "' missing" + }}; return {}; } @@ -68,7 +70,8 @@ TimeFormatValidator::verify(boost::json::value const& value, std::string_view ke if (not value.as_object().at(key).is_string()) return Error{Status{RippledError::rpcINVALID_PARAMS}}; - auto const ret = util::systemTpFromUtcStr(value_to(value.as_object().at(key)), format_); + auto const ret = + util::systemTpFromUtcStr(value_to(value.as_object().at(key)), format_); if (!ret) return Error{Status{RippledError::rpcINVALID_PARAMS}}; @@ -125,11 +128,16 @@ CustomValidator CustomValidators::ledgerIndexValidator = CustomValidator CustomValidators::ledgerTypeValidator = CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError { if (!value.is_string()) - return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', not string.", key)}}; + return Error{Status{ + RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', not string.", key) + }}; - auto const type = util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to(value)); + auto const type = + util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to(value)); if (type == ripple::ltANY) - return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)} + }; return MaybeError{}; }}; @@ -152,7 +160,8 @@ CustomValidator CustomValidators::accountBase58Validator = if (!value.is_string()) return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}}; - auto const account = util::parseBase58Wrapper(boost::json::value_to(value)); + auto const account = + util::parseBase58Wrapper(boost::json::value_to(value)); if (!account || account->isZero()) return Error{Status{ClioError::RpcMalformedAddress}}; @@ -177,12 +186,17 @@ CustomValidator CustomValidators::accountMarkerValidator = CustomValidator CustomValidators::accountTypeValidator = CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError { if (!value.is_string()) - return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', not string.", key)}}; + return Error{Status{ + RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', not string.", key) + }}; - auto const type = - util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(boost::json::value_to(value)); + auto const type = util::LedgerTypes::getAccountOwnedLedgerTypeFromStr( + boost::json::value_to(value) + ); if (type == ripple::ltANY) - return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)} + }; return MaybeError{}; }}; @@ -212,12 +226,15 @@ CustomValidator CustomValidators::issuerValidator = // TODO: need to align with the error if (!ripple::to_issuer(issuer, boost::json::value_to(value))) - return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', bad issuer.", key)}}; + return Error{Status{ + RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', bad issuer.", key) + }}; if (issuer == ripple::noAccount()) { - return Error{ - Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}', bad issuer account one.", key)} - }; + return Error{Status{ + RippledError::rpcINVALID_PARAMS, + fmt::format("Invalid field '{}', bad issuer account one.", key) + }}; } return MaybeError{}; @@ -229,10 +246,17 @@ CustomValidator CustomValidators::subscribeStreamValidator = return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotArray"}}; static std::unordered_set const kVALID_STREAMS = { - "ledger", "transactions", "transactions_proposed", "book_changes", "manifests", "validations" + "ledger", + "transactions", + "transactions_proposed", + "book_changes", + "manifests", + "validations" }; - static std::unordered_set const kNOT_SUPPORT_STREAMS = {"peer_status", "consensus", "server"}; + static std::unordered_set const kNOT_SUPPORT_STREAMS = { + "peer_status", "consensus", "server" + }; for (auto const& v : value.as_array()) { if (!v.is_string()) return Error{Status{RippledError::rpcINVALID_PARAMS, "streamNotString"}}; @@ -285,19 +309,26 @@ CustomValidator CustomValidators::currencyIssueValidator = CustomValidator CustomValidators::credentialTypeValidator = CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError { if (not value.is_string()) - return Error{Status{ClioError::RpcMalformedAuthorizedCredentials, std::string(key) + " NotString"}}; + return Error{Status{ + ClioError::RpcMalformedAuthorizedCredentials, std::string(key) + " NotString" + }}; auto const& credTypeHex = ripple::strViewUnHex(value.as_string()); if (!credTypeHex.has_value()) - return Error{Status{ClioError::RpcMalformedAuthorizedCredentials, std::string(key) + " NotHexString"}}; + return Error{Status{ + ClioError::RpcMalformedAuthorizedCredentials, std::string(key) + " NotHexString" + }}; if (credTypeHex->empty()) - return Error{Status{ClioError::RpcMalformedAuthorizedCredentials, std::string(key) + " is empty"}}; + return Error{ + Status{ClioError::RpcMalformedAuthorizedCredentials, std::string(key) + " is empty"} + }; if (credTypeHex->size() > ripple::maxCredentialTypeLength) { - return Error{ - Status{ClioError::RpcMalformedAuthorizedCredentials, std::string(key) + " greater than max length"} - }; + return Error{Status{ + ClioError::RpcMalformedAuthorizedCredentials, + std::string(key) + " greater than max length" + }}; } return MaybeError{}; @@ -320,7 +351,8 @@ CustomValidator CustomValidators::authorizeCredentialValidator = return Error{Status{ ClioError::RpcMalformedAuthorizedCredentials, fmt::format( - "Max {} number of credentials in authorized_credentials array", ripple::maxCredentialsArraySize + "Max {} number of credentials in authorized_credentials array", + ripple::maxCredentialsArraySize ) }}; } @@ -335,18 +367,22 @@ CustomValidator CustomValidators::authorizeCredentialValidator = auto const& obj = credObj.as_object(); if (!obj.contains("issuer")) { - return Error{ - Status{ClioError::RpcMalformedAuthorizedCredentials, "Field 'Issuer' is required but missing."} - }; + return Error{Status{ + ClioError::RpcMalformedAuthorizedCredentials, + "Field 'Issuer' is required but missing." + }}; } // don't want to change issuer error message to be about credentials if (!issuerValidator.verify(credObj, "issuer")) - return Error{Status{ClioError::RpcMalformedAuthorizedCredentials, "issuer NotString"}}; + return Error{ + Status{ClioError::RpcMalformedAuthorizedCredentials, "issuer NotString"} + }; if (!obj.contains("credential_type")) { return Error{Status{ - ClioError::RpcMalformedAuthorizedCredentials, "Field 'CredentialType' is required but missing." + ClioError::RpcMalformedAuthorizedCredentials, + "Field 'CredentialType' is required but missing." }}; } diff --git a/src/rpc/common/Validators.hpp b/src/rpc/common/Validators.hpp index 633a6f6c9..d35c50f2a 100644 --- a/src/rpc/common/Validators.hpp +++ b/src/rpc/common/Validators.hpp @@ -66,7 +66,8 @@ template class NotSupported; /** - * @brief A specialized NotSupported validator that forbids a field to be present when the value equals the given value. + * @brief A specialized NotSupported validator that forbids a field to be present when the value + * equals the given value. */ template class NotSupported final { @@ -117,13 +118,16 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcNOT_SUPPORTED` if the field is found; otherwise no error is returned + * @return `RippledError::rpcNOT_SUPPORTED` if the field is found; otherwise no error is + * returned */ [[nodiscard]] static MaybeError verify(boost::json::value const& value, std::string_view key) { if (value.is_object() and value.as_object().contains(key)) - return Error{Status{RippledError::rpcNOT_SUPPORTED, "Not supported field '" + std::string{key} + '\''}}; + return Error{Status{ + RippledError::rpcNOT_SUPPORTED, "Not supported field '" + std::string{key} + '\'' + }}; return {}; } @@ -142,12 +146,13 @@ template struct Type final { /** * @brief Verify that the JSON value is (one) of specified type(s). - * @note The value itself can only change for integral types and only if the value is outside of the range of the - * expected integer type (see checkTypeAndClamp). + * @note The value itself can only change for integral types and only if the value is outside of + * the range of the expected integer type (see checkTypeAndClamp). * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value& value, std::string_view key) const @@ -189,7 +194,8 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value const& value, std::string_view key) const @@ -232,7 +238,8 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value const& value, std::string_view key) const @@ -273,7 +280,8 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value const& value, std::string_view key) const @@ -313,7 +321,8 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value const& value, std::string_view key) const; @@ -341,7 +350,8 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value const& value, std::string_view key) const @@ -360,7 +370,8 @@ public: }; /** - * @brief Deduction guide to help disambiguate what it means to EqualTo a "string" without specifying the type. + * @brief Deduction guide to help disambiguate what it means to EqualTo a "string" without + * specifying the type. */ EqualTo(char const*) -> EqualTo; @@ -396,7 +407,8 @@ public: * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value const& value, std::string_view key) const @@ -408,14 +420,17 @@ public: auto const res = value_to(value.as_object().at(key)); if (std::find(std::begin(options_), std::end(options_), res) == std::end(options_)) - return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)} + }; return {}; } }; /** - * @brief Deduction guide to help disambiguate what it means to OneOf a few "strings" without specifying the type. + * @brief Deduction guide to help disambiguate what it means to OneOf a few "strings" without + * specifying the type. */ OneOf(std::initializer_list) -> OneOf; @@ -439,11 +454,13 @@ public: } /** - * @brief Verify that the JSON value is valid according to the custom validation function stored. + * @brief Verify that the JSON value is valid according to the custom validation function + * stored. * * @param value The JSON value representing the outer object * @param key The key used to retrieve the tested value from the outer object - * @return Any compatible user-provided error if validation failed; otherwise no error is returned + * @return Any compatible user-provided error if validation failed; otherwise no error is + * returned */ [[nodiscard]] MaybeError verify(boost::json::value const& value, std::string_view key) const; @@ -483,8 +500,8 @@ struct CustomValidators final { /** * @brief Provides a commonly used validator for ledger index. * - * LedgerIndex must be a string or an int. If the specified LedgerIndex is a string, its value must be either - * "validated" or a valid integer value represented as a string. + * LedgerIndex must be a string or an int. If the specified LedgerIndex is a string, its value + * must be either "validated" or a valid integer value represented as a string. */ static CustomValidator ledgerIndexValidator; @@ -551,7 +568,8 @@ struct CustomValidators final { static CustomValidator uint256HexStringValidator; /** - * @brief Provides a commonly used validator for currency, including standard currency code and token code. + * @brief Provides a commonly used validator for currency, including standard currency code and + * token code. */ static CustomValidator currencyValidator; @@ -604,7 +622,8 @@ struct Hex256ItemType final { * * @param value the value to verify * @param key The key used to retrieve the tested value from the outer object - * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is returned + * @return `RippledError::rpcINVALID_PARAMS` if validation failed; otherwise no error is + * returned */ [[nodiscard]] static MaybeError verify(boost::json::value const& value, std::string_view key) @@ -618,7 +637,9 @@ struct Hex256ItemType final { for (auto const& elem : res.as_array()) { ripple::uint256 num; if (!elem.is_string() || !num.parseHex(elem.as_string())) { - return Error{Status{RippledError::rpcINVALID_PARAMS, "Item is not a valid uint256 type."}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, "Item is not a valid uint256 type."} + }; } } return {}; diff --git a/src/rpc/common/impl/APIVersionParser.cpp b/src/rpc/common/impl/APIVersionParser.cpp index 675b6156e..db5516d03 100644 --- a/src/rpc/common/impl/APIVersionParser.cpp +++ b/src/rpc/common/impl/APIVersionParser.cpp @@ -66,10 +66,14 @@ ProductionAPIVersionParser::parse(boost::json::object const& request) const auto const version = util::integralValueAs(request.at("api_version")); if (version > maxVersion_) - return Error{fmt::format("Requested API version is higher than maximum supported ({})", maxVersion_)}; + return Error{fmt::format( + "Requested API version is higher than maximum supported ({})", maxVersion_ + )}; if (version < minVersion_) - return Error{fmt::format("Requested API version is lower than minimum supported ({})", minVersion_)}; + return Error{fmt::format( + "Requested API version is lower than minimum supported ({})", minVersion_ + )}; return version; } diff --git a/src/rpc/common/impl/Factories.hpp b/src/rpc/common/impl/Factories.hpp index 16bd9d272..d52808c23 100644 --- a/src/rpc/common/impl/Factories.hpp +++ b/src/rpc/common/impl/Factories.hpp @@ -39,7 +39,9 @@ namespace rpc::impl { using FieldSpecProcessor = std::function; -static FieldSpecProcessor const kEMPTY_FIELD_PROCESSOR = [](boost::json::value&) -> MaybeError { return {}; }; +static FieldSpecProcessor const kEMPTY_FIELD_PROCESSOR = [](boost::json::value&) -> MaybeError { + return {}; +}; template [[nodiscard]] FieldSpecProcessor @@ -48,8 +50,9 @@ makeFieldProcessor(std::string const& key, Processors&&... procs) return [key, ... proc = std::forward(procs)](boost::json::value& j) -> MaybeError { std::optional firstFailure = std::nullopt; - // This expands in order of Requirements and stops evaluating after first failure which is stored in - // `firstFailure` and can be checked later on to see whether the verification failed as a whole or not. + // This expands in order of Requirements and stops evaluating after first failure which is + // stored in `firstFailure` and can be checked later on to see whether the verification + // failed as a whole or not. ( [&j, &key, &firstFailure, req = &proc]() { if (firstFailure) @@ -77,13 +80,17 @@ makeFieldProcessor(std::string const& key, Processors&&... procs) using FieldChecker = std::function; -static FieldChecker const kEMPTY_FIELD_CHECKER = [](boost::json::value const&) -> check::Warnings { return {}; }; +static FieldChecker const kEMPTY_FIELD_CHECKER = [](boost::json::value const&) -> check::Warnings { + return {}; +}; template [[nodiscard]] FieldChecker makeFieldChecker(std::string const& key, Checks&&... checks) { - return [key, ... checks = std::forward(checks)](boost::json::value const& j) -> check::Warnings { + return [key, + ... checks = + std::forward(checks)](boost::json::value const& j) -> check::Warnings { check::Warnings warnings; // This expands in order of Checks and collects all warnings into a WarningsCollection ( diff --git a/src/rpc/common/impl/ForwardingProxy.hpp b/src/rpc/common/impl/ForwardingProxy.hpp index 25a627673..46d6db239 100644 --- a/src/rpc/common/impl/ForwardingProxy.hpp +++ b/src/rpc/common/impl/ForwardingProxy.hpp @@ -76,13 +76,13 @@ public: return true; auto const checkAccountInfoForward = [&]() { - return ctx.method == "account_info" and request.contains("queue") and request.at("queue").is_bool() and - request.at("queue").as_bool(); + return ctx.method == "account_info" and request.contains("queue") and + request.at("queue").is_bool() and request.at("queue").as_bool(); }; auto const checkLedgerForward = [&]() { - return ctx.method == "ledger" and request.contains("queue") and request.at("queue").is_bool() and - request.at("queue").as_bool(); + return ctx.method == "ledger" and request.contains("queue") and + request.at("queue").is_bool() and request.at("queue").as_bool(); }; return static_cast(checkAccountInfoForward() or checkLedgerForward()); @@ -135,8 +135,8 @@ private: isForcedForward(web::Context const& ctx) const { static constexpr auto kFORCE_FORWARD = "force_forward"; - return ctx.isAdmin and ctx.params.contains(kFORCE_FORWARD) and ctx.params.at(kFORCE_FORWARD).is_bool() and - ctx.params.at(kFORCE_FORWARD).as_bool(); + return ctx.isAdmin and ctx.params.contains(kFORCE_FORWARD) and + ctx.params.at(kFORCE_FORWARD).is_bool() and ctx.params.at(kFORCE_FORWARD).as_bool(); } }; diff --git a/src/rpc/common/impl/HandlerProvider.cpp b/src/rpc/common/impl/HandlerProvider.cpp index 1a93392cf..a5767882d 100644 --- a/src/rpc/common/impl/HandlerProvider.cpp +++ b/src/rpc/common/impl/HandlerProvider.cpp @@ -88,8 +88,9 @@ ProductionHandlerProvider::ProductionHandlerProvider( {"account_info", {.handler = AccountInfoHandler{backend, amendmentCenter}}}, {"account_lines", {.handler = AccountLinesHandler{backend}}}, {"account_mptoken_issuances", - {.handler = AccountMPTokenIssuancesHandler{backend}, .isClioOnly = true}}, // clio only - {"account_mptokens", {.handler = AccountMPTokensHandler{backend}, .isClioOnly = true}}, // clio only + {.handler = AccountMPTokenIssuancesHandler{backend}, .isClioOnly = true}}, // clio only + {"account_mptokens", + {.handler = AccountMPTokensHandler{backend}, .isClioOnly = true}}, // clio only {"account_nfts", {.handler = AccountNFTsHandler{backend}}}, {"account_objects", {.handler = AccountObjectsHandler{backend}}}, {"account_offers", {.handler = AccountOffersHandler{backend}}}, @@ -104,21 +105,27 @@ ProductionHandlerProvider::ProductionHandlerProvider( {"ledger", {.handler = LedgerHandler{backend, amendmentCenter}}}, {"ledger_data", {.handler = LedgerDataHandler{backend}}}, {"ledger_entry", {.handler = LedgerEntryHandler{backend}}}, - {"ledger_index", {.handler = LedgerIndexHandler{backend}, .isClioOnly = true}}, // clio only + {"ledger_index", + {.handler = LedgerIndexHandler{backend}, .isClioOnly = true}}, // clio only {"ledger_range", {.handler = LedgerRangeHandler{backend}}}, - {"mpt_holders", {.handler = MPTHoldersHandler{backend}, .isClioOnly = true}}, // clio only - {"nfts_by_issuer", {.handler = NFTsByIssuerHandler{backend}, .isClioOnly = true}}, // clio only - {"nft_history", {.handler = NFTHistoryHandler{backend}, .isClioOnly = true}}, // clio only + {"mpt_holders", + {.handler = MPTHoldersHandler{backend}, .isClioOnly = true}}, // clio only + {"nfts_by_issuer", + {.handler = NFTsByIssuerHandler{backend}, .isClioOnly = true}}, // clio only + {"nft_history", + {.handler = NFTHistoryHandler{backend}, .isClioOnly = true}}, // clio only {"nft_buy_offers", {.handler = NFTBuyOffersHandler{backend}}}, {"nft_info", {.handler = NFTInfoHandler{backend}, .isClioOnly = true}}, // clio only {"nft_sell_offers", {.handler = NFTSellOffersHandler{backend}}}, {"noripple_check", {.handler = NoRippleCheckHandler{backend}}}, {"ping", {.handler = PingHandler{}}}, {"random", {.handler = RandomHandler{}}}, - {"server_info", {.handler = ServerInfoHandler{backend, subscriptionManager, balancer, etl, counters}}}, + {"server_info", + {.handler = ServerInfoHandler{backend, subscriptionManager, balancer, etl, counters}}}, {"transaction_entry", {.handler = TransactionEntryHandler{backend}}}, {"tx", {.handler = TxHandler{backend, etl}}}, - {"subscribe", {.handler = SubscribeHandler{backend, amendmentCenter, subscriptionManager}}}, + {"subscribe", + {.handler = SubscribeHandler{backend, amendmentCenter, subscriptionManager}}}, {"unsubscribe", {.handler = UnsubscribeHandler{subscriptionManager}}}, {"vault_info", {.handler = VaultInfoHandler{backend}}}, {"version", {.handler = VersionHandler{config}}}, diff --git a/src/rpc/common/impl/Processors.hpp b/src/rpc/common/impl/Processors.hpp index 0c5c16fc4..c720fe95f 100644 --- a/src/rpc/common/impl/Processors.hpp +++ b/src/rpc/common/impl/Processors.hpp @@ -30,7 +30,11 @@ namespace rpc::impl { template struct DefaultProcessor final { [[nodiscard]] ReturnType - operator()(HandlerType const& handler, boost::json::value const& value, Context const& ctx) const + operator()( + HandlerType const& handler, + boost::json::value const& value, + Context const& ctx + ) const { using boost::json::value_from; using boost::json::value_to; @@ -49,7 +53,9 @@ struct DefaultProcessor final { // real handler is given expected Input, not json if (!ret) { - return ReturnType{Error{std::move(ret).error()}, std::move(warnings)}; // forward Status + return ReturnType{ + Error{std::move(ret).error()}, std::move(warnings) + }; // forward Status } return ReturnType{value_from(std::move(ret).value()), std::move(warnings)}; } else if constexpr (SomeHandlerWithoutInput) { @@ -60,7 +66,8 @@ struct DefaultProcessor final { } return ReturnType{value_from(ret.value())}; } else { - // when concept SomeHandlerWithInput and SomeHandlerWithoutInput not cover all Handler case + // when concept SomeHandlerWithInput and SomeHandlerWithoutInput not cover all Handler + // case static_assert(util::Unsupported); } } diff --git a/src/rpc/handlers/AMMInfo.cpp b/src/rpc/handlers/AMMInfo.cpp index d2af7498d..88a29b28d 100644 --- a/src/rpc/handlers/AMMInfo.cpp +++ b/src/rpc/handlers/AMMInfo.cpp @@ -69,7 +69,9 @@ toIso8601(ripple::NetClock::time_point tp) return date::format( "%Y-%Om-%dT%H:%M:%OS%z", - date::sys_time(system_clock::time_point{tp.time_since_epoch() + kRIPPLE_EPOCH_OFFSET}) + date::sys_time( + system_clock::time_point{tp.time_since_epoch() + kRIPPLE_EPOCH_OFFSET} + ) ); }; @@ -120,7 +122,8 @@ AMMInfoHandler::process(AMMInfoHandler::Input const& input, Context const& ctx) if (not accountLedgerObject) return Error{Status{RippledError::rpcACT_MALFORMED}}; ripple::STLedgerEntry const sle{ - ripple::SerialIter{accountLedgerObject->data(), accountLedgerObject->size()}, accountKeylet.key + ripple::SerialIter{accountLedgerObject->data(), accountLedgerObject->size()}, + accountKeylet.key }; if (not sle.isFieldPresent(ripple::sfAMMID)) return Error{Status{RippledError::rpcACT_NOT_FOUND}}; @@ -130,27 +133,37 @@ AMMInfoHandler::process(AMMInfoHandler::Input const& input, Context const& ctx) auto issue1 = input.issue1; auto issue2 = input.issue2; auto ammKeylet = ammID != 0 ? keylet::amm(ammID) : keylet::amm(issue1, issue2); - auto const ammBlob = sharedPtrBackend_->fetchLedgerObject(ammKeylet.key, lgrInfo.seq, ctx.yield); + auto const ammBlob = + sharedPtrBackend_->fetchLedgerObject(ammKeylet.key, lgrInfo.seq, ctx.yield); if (not ammBlob) return Error{Status{RippledError::rpcACT_NOT_FOUND}}; auto const amm = SLE{SerialIter{ammBlob->data(), ammBlob->size()}, ammKeylet.key}; auto const ammAccountID = amm.getAccountID(sfAccount); - auto const accBlob = - sharedPtrBackend_->fetchLedgerObject(keylet::account(ammAccountID).key, lgrInfo.seq, ctx.yield); + auto const accBlob = sharedPtrBackend_->fetchLedgerObject( + keylet::account(ammAccountID).key, lgrInfo.seq, ctx.yield + ); if (not accBlob) return Error{Status{RippledError::rpcACT_NOT_FOUND}}; // If the issue1 and issue2 are not specified, we need to get them from the AMM. - // Otherwise we preserve the mapping of asset1 -> issue1 and asset2 -> issue2 as requested by the user. + // Otherwise we preserve the mapping of asset1 -> issue1 and asset2 -> issue2 as requested by + // the user. if (issue1 == ripple::noIssue() and issue2 == ripple::noIssue()) { issue1 = amm[sfAsset].get(); issue2 = amm[sfAsset2].get(); } auto const [asset1Balance, asset2Balance] = getAmmPoolHolds( - *sharedPtrBackend_, *amendmentCenter_, lgrInfo.seq, ammAccountID, issue1, issue2, false, ctx.yield + *sharedPtrBackend_, + *amendmentCenter_, + lgrInfo.seq, + ammAccountID, + issue1, + issue2, + false, + ctx.yield ); auto const lptAMMBalance = input.accountID ? getAmmLpHolds(*sharedPtrBackend_, lgrInfo.seq, amm, *input.accountID, ctx.yield) @@ -180,13 +193,15 @@ AMMInfoHandler::process(AMMInfoHandler::Input const& input, Context const& ctx) auto const& auctionSlot = amm.peekAtField(sfAuctionSlot).downcast(); if (auctionSlot.isFieldPresent(sfAccount)) { boost::json::object auction; - auto const timeSlot = ammAuctionTimeSlot(lgrInfo.parentCloseTime.time_since_epoch().count(), auctionSlot); + auto const timeSlot = + ammAuctionTimeSlot(lgrInfo.parentCloseTime.time_since_epoch().count(), auctionSlot); auction[JS(time_interval)] = timeSlot ? *timeSlot : AUCTION_SLOT_TIME_INTERVALS; auction[JS(price)] = toBoostJson(auctionSlot[sfPrice].getJson(JsonOptions::none)); auction[JS(discounted_fee)] = auctionSlot[sfDiscountedFee]; auction[JS(account)] = to_string(auctionSlot.getAccountID(sfAccount)); - auction[JS(expiration)] = toIso8601(NetClock::time_point{NetClock::duration{auctionSlot[sfExpiration]}}); + auction[JS(expiration)] = + toIso8601(NetClock::time_point{NetClock::duration{auctionSlot[sfExpiration]}}); if (auctionSlot.isFieldPresent(sfAuthAccounts)) { boost::json::array auth; @@ -230,10 +245,12 @@ AMMInfoHandler::process(AMMInfoHandler::Input const& input, Context const& ctx) RpcSpecConstRef AMMInfoHandler::spec([[maybe_unused]] uint32_t apiVersion) { - static auto const kSTRING_ISSUE_VALIDATOR = - validation::CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError { + static auto const kSTRING_ISSUE_VALIDATOR = validation::CustomValidator{ + [](boost::json::value const& value, std::string_view key) -> MaybeError { if (not value.is_string()) - return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"} + }; try { ripple::issueFromJson(boost::json::value_to(value)); @@ -242,42 +259,55 @@ AMMInfoHandler::spec([[maybe_unused]] uint32_t apiVersion) } return MaybeError{}; - }}; + } + }; static auto const kRPC_SPEC = RpcSpec{ {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, {JS(asset), meta::WithCustomError{ - validation::Type{}, Status(RippledError::rpcISSUE_MALFORMED) + validation::Type{}, + Status(RippledError::rpcISSUE_MALFORMED) }, meta::IfType{kSTRING_ISSUE_VALIDATOR}, meta::IfType{ meta::WithCustomError{ - validation::CustomValidators::currencyIssueValidator, Status(RippledError::rpcISSUE_MALFORMED) + validation::CustomValidators::currencyIssueValidator, + Status(RippledError::rpcISSUE_MALFORMED) }, }}, {JS(asset2), meta::WithCustomError{ - validation::Type{}, Status(RippledError::rpcISSUE_MALFORMED) + validation::Type{}, + Status(RippledError::rpcISSUE_MALFORMED) }, meta::IfType{kSTRING_ISSUE_VALIDATOR}, meta::IfType{ meta::WithCustomError{ - validation::CustomValidators::currencyIssueValidator, Status(RippledError::rpcISSUE_MALFORMED) + validation::CustomValidators::currencyIssueValidator, + Status(RippledError::rpcISSUE_MALFORMED) }, }}, {JS(amm_account), - meta::WithCustomError{validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED)}}, + meta::WithCustomError{ + validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED) + }}, {JS(account), - meta::WithCustomError{validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED)}}, + meta::WithCustomError{ + validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED) + }}, }; return kRPC_SPEC; } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AMMInfoHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AMMInfoHandler::Output const& output +) { boost::json::object amm = { {JS(lp_token), output.lpToken}, @@ -329,10 +359,13 @@ tag_invoke(boost::json::value_to_tag, boost::json::value input.issue2 = parseIssue(jsonObject.at(JS(asset2)).as_object()); if (jsonObject.contains(JS(account))) - input.accountID = accountFromStringStrict(boost::json::value_to(jsonObject.at(JS(account)))); + input.accountID = + accountFromStringStrict(boost::json::value_to(jsonObject.at(JS(account)))); if (jsonObject.contains(JS(amm_account))) - input.ammAccount = accountFromStringStrict(boost::json::value_to(jsonObject.at(JS(amm_account)))); + input.ammAccount = accountFromStringStrict( + boost::json::value_to(jsonObject.at(JS(amm_account))) + ); return input; } diff --git a/src/rpc/handlers/AccountChannels.cpp b/src/rpc/handlers/AccountChannels.cpp index 1fb38b4b0..9b7e89fbf 100644 --- a/src/rpc/handlers/AccountChannels.cpp +++ b/src/rpc/handlers/AccountChannels.cpp @@ -51,7 +51,10 @@ namespace rpc { void -AccountChannelsHandler::addChannel(std::vector& jsonChannels, ripple::SLE const& channelSle) +AccountChannelsHandler::addChannel( + std::vector& jsonChannels, + ripple::SLE const& channelSle +) { ChannelResponse channel; channel.channelID = ripple::to_string(channelSle.key()); @@ -83,7 +86,10 @@ AccountChannelsHandler::addChannel(std::vector& jsonChannels, r } AccountChannelsHandler::Result -AccountChannelsHandler::process(AccountChannelsHandler::Input const& input, Context const& ctx) const +AccountChannelsHandler::process( + AccountChannelsHandler::Input const& input, + Context const& ctx +) const { auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "AccountChannel's ledger range must be available"); @@ -96,18 +102,21 @@ AccountChannelsHandler::process(AccountChannelsHandler::Input const& input, Cont auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; - auto const destAccountID = input.destinationAccount ? accountFromStringStrict(input.destinationAccount.value()) - : std::optional{}; + auto const destAccountID = input.destinationAccount + ? accountFromStringStrict(input.destinationAccount.value()) + : std::optional{}; Output response; auto const addToResponse = [&](ripple::SLE const sle) { - if (sle.getType() == ripple::ltPAYCHAN && sle.getAccountID(ripple::sfAccount) == accountID && + if (sle.getType() == ripple::ltPAYCHAN && + sle.getAccountID(ripple::sfAccount) == accountID && (!destAccountID || *destAccountID == sle.getAccountID(ripple::sfDestination))) { addChannel(response.channels, sle); } @@ -116,7 +125,13 @@ AccountChannelsHandler::process(AccountChannelsHandler::Input const& input, Cont }; auto const expectedNext = traverseOwnedNodes( - *sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse + *sharedPtrBackend_, + *accountID, + lgrInfo.seq, + input.limit, + input.marker, + ctx.yield, + addToResponse ); if (!expectedNext.has_value()) @@ -152,7 +167,8 @@ tag_invoke(boost::json::value_to_tag, boost::json input.ledgerHash = boost::json::value_to(jv.at(JS(ledger_hash))); if (jsonObject.contains(JS(destination_account))) - input.destinationAccount = boost::json::value_to(jv.at(JS(destination_account))); + input.destinationAccount = + boost::json::value_to(jv.at(JS(destination_account))); if (jsonObject.contains(JS(ledger_index))) { auto const expectedLedgerIndex = util::getLedgerIndex(jv.at(JS(ledger_index))); @@ -164,7 +180,11 @@ tag_invoke(boost::json::value_to_tag, boost::json } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountChannelsHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountChannelsHandler::Output const& output +) { using boost::json::value_from; @@ -184,7 +204,11 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountChannelsH } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountChannelsHandler::ChannelResponse const& channel) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountChannelsHandler::ChannelResponse const& channel +) { auto obj = boost::json::object{ {JS(channel_id), channel.channelID}, diff --git a/src/rpc/handlers/AccountChannels.hpp b/src/rpc/handlers/AccountChannels.hpp index 2168882a6..ff79db721 100644 --- a/src/rpc/handlers/AccountChannels.hpp +++ b/src/rpc/handlers/AccountChannels.hpp @@ -40,8 +40,8 @@ namespace rpc { /** - * @brief The account_channels method returns information about an account's Payment Channels. This includes only - * channels where the specified account is the channel's source, not the destination. + * @brief The account_channels method returns information about an account's Payment Channels. This + * includes only channels where the specified account is the channel's source, not the destination. * All information retrieved is relative to a particular version of the ledger. * * For more details see: https://xrpl.org/account_channels.html @@ -124,7 +124,9 @@ public: { static auto const kRPC_SPEC = RpcSpec{ {JS(account), validation::Required{}, validation::CustomValidators::accountValidator}, - {JS(destination_account), validation::Type{}, validation::CustomValidators::accountValidator}, + {JS(destination_account), + validation::Type{}, + validation::CustomValidators::accountValidator}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(limit), validation::Type{}, diff --git a/src/rpc/handlers/AccountCurrencies.cpp b/src/rpc/handlers/AccountCurrencies.cpp index d23fbe688..2e7980f7c 100644 --- a/src/rpc/handlers/AccountCurrencies.cpp +++ b/src/rpc/handlers/AccountCurrencies.cpp @@ -44,7 +44,10 @@ namespace rpc { AccountCurrenciesHandler::Result -AccountCurrenciesHandler::process(AccountCurrenciesHandler::Input const& input, Context const& ctx) const +AccountCurrenciesHandler::process( + AccountCurrenciesHandler::Input const& input, + Context const& ctx +) const { auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "AccountCurrencies' ledger range must be available"); @@ -58,8 +61,9 @@ AccountCurrenciesHandler::process(AccountCurrenciesHandler::Input const& input, auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; @@ -104,7 +108,11 @@ AccountCurrenciesHandler::process(AccountCurrenciesHandler::Input const& input, } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountCurrenciesHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountCurrenciesHandler::Output const& output +) { using boost::json::value_from; diff --git a/src/rpc/handlers/AccountCurrencies.hpp b/src/rpc/handlers/AccountCurrencies.hpp index c79e8b1cf..521422603 100644 --- a/src/rpc/handlers/AccountCurrencies.hpp +++ b/src/rpc/handlers/AccountCurrencies.hpp @@ -39,8 +39,8 @@ namespace rpc { /** - * @brief The account_currencies command retrieves a list of currencies that an account can send or receive, - * based on its trust lines. + * @brief The account_currencies command retrieves a list of currencies that an account can send or + * receive, based on its trust lines. * * For more details see: https://xrpl.org/account_currencies.html */ diff --git a/src/rpc/handlers/AccountInfo.cpp b/src/rpc/handlers/AccountInfo.cpp index b272ec3e6..9ec8dee01 100644 --- a/src/rpc/handlers/AccountInfo.cpp +++ b/src/rpc/handlers/AccountInfo.cpp @@ -58,7 +58,9 @@ AccountInfoHandler::process(AccountInfoHandler::Input const& input, Context cons using namespace data; if (!input.account && !input.ident) - return Error{Status{RippledError::rpcINVALID_PARAMS, ripple::RPC::missing_field_message(JS(account))}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, ripple::RPC::missing_field_message(JS(account))} + }; auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "AccountInfo's ledger range must be available"); @@ -73,13 +75,15 @@ AccountInfoHandler::process(AccountInfoHandler::Input const& input, Context cons auto const accountStr = input.account.value_or(input.ident.value_or("")); auto const accountID = accountFromStringStrict(accountStr); auto const accountKeylet = ripple::keylet::account(*accountID); - auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject(accountKeylet.key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = + sharedPtrBackend_->fetchLedgerObject(accountKeylet.key, lgrInfo.seq, ctx.yield); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND}}; ripple::STLedgerEntry const sle{ - ripple::SerialIter{accountLedgerObject->data(), accountLedgerObject->size()}, accountKeylet.key + ripple::SerialIter{accountLedgerObject->data(), accountLedgerObject->size()}, + accountKeylet.key }; if (!accountKeylet.check(sle)) @@ -112,7 +116,8 @@ AccountInfoHandler::process(AccountInfoHandler::Input const& input, Context cons // This code will need to be revisited if in the future we // support multiple SignerLists on one account. - auto const signers = sharedPtrBackend_->fetchLedgerObject(signersKey.key, lgrInfo.seq, ctx.yield); + auto const signers = + sharedPtrBackend_->fetchLedgerObject(signersKey.key, lgrInfo.seq, ctx.yield); out.signerLists = std::vector(); if (signers) { @@ -131,7 +136,11 @@ AccountInfoHandler::process(AccountInfoHandler::Input const& input, Context cons } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountInfoHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountInfoHandler::Output const& output +) { jv = boost::json::object{ {JS(account_data), toJson(output.accountData)}, @@ -153,12 +162,13 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountInfoHandl }}; if (output.isDisallowIncomingEnabled) { - std::vector> const disallowIncomingFlags = { - {"disallowIncomingNFTokenOffer", ripple::lsfDisallowIncomingNFTokenOffer}, - {"disallowIncomingCheck", ripple::lsfDisallowIncomingCheck}, - {"disallowIncomingPayChan", ripple::lsfDisallowIncomingPayChan}, - {"disallowIncomingTrustline", ripple::lsfDisallowIncomingTrustline}, - }; + std::vector> const + disallowIncomingFlags = { + {"disallowIncomingNFTokenOffer", ripple::lsfDisallowIncomingNFTokenOffer}, + {"disallowIncomingCheck", ripple::lsfDisallowIncomingCheck}, + {"disallowIncomingPayChan", ripple::lsfDisallowIncomingPayChan}, + {"disallowIncomingTrustline", ripple::lsfDisallowIncomingTrustline}, + }; lsFlags.insert(lsFlags.end(), disallowIncomingFlags.begin(), disallowIncomingFlags.end()); } diff --git a/src/rpc/handlers/AccountInfo.hpp b/src/rpc/handlers/AccountInfo.hpp index 1b3897372..d0105dea1 100644 --- a/src/rpc/handlers/AccountInfo.hpp +++ b/src/rpc/handlers/AccountInfo.hpp @@ -42,7 +42,8 @@ namespace rpc { /** - * @brief The account_info command retrieves information about an account, its activity, and its XRP balance. + * @brief The account_info command retrieves information about an account, its activity, and its XRP + * balance. * * For more details see: https://xrpl.org/account_info.html */ @@ -116,7 +117,8 @@ public: {JS(strict), check::Deprecated{}} }; - static auto const kRPC_SPEC = RpcSpec{kRPC_SPEC_V1, {{JS(signer_lists), validation::Type{}}}}; + static auto const kRPC_SPEC = + RpcSpec{kRPC_SPEC_V1, {{JS(signer_lists), validation::Type{}}}}; return apiVersion == 1 ? kRPC_SPEC_V1 : kRPC_SPEC; } diff --git a/src/rpc/handlers/AccountLines.cpp b/src/rpc/handlers/AccountLines.cpp index 159089b9f..d93c9cca2 100644 --- a/src/rpc/handlers/AccountLines.cpp +++ b/src/rpc/handlers/AccountLines.cpp @@ -82,12 +82,18 @@ AccountLinesHandler::addLine( balance.negate(); bool const lineAuth = (flags & (viewLowest ? ripple::lsfLowAuth : ripple::lsfHighAuth)) != 0u; - bool const lineAuthPeer = (flags & (not viewLowest ? ripple::lsfLowAuth : ripple::lsfHighAuth)) != 0u; - bool const lineNoRipple = (flags & (viewLowest ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u; - bool const lineNoRipplePeer = (flags & (not viewLowest ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u; - bool const lineFreeze = (flags & (viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u; - bool const lineFreezePeer = (flags & (not viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u; - bool const lineDeepFreeze = (flags & (viewLowest ? ripple::lsfLowDeepFreeze : ripple::lsfHighDeepFreeze)) != 0u; + bool const lineAuthPeer = + (flags & (not viewLowest ? ripple::lsfLowAuth : ripple::lsfHighAuth)) != 0u; + bool const lineNoRipple = + (flags & (viewLowest ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u; + bool const lineNoRipplePeer = + (flags & (not viewLowest ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u; + bool const lineFreeze = + (flags & (viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u; + bool const lineFreezePeer = + (flags & (not viewLowest ? ripple::lsfLowFreeze : ripple::lsfHighFreeze)) != 0u; + bool const lineDeepFreeze = + (flags & (viewLowest ? ripple::lsfLowDeepFreeze : ripple::lsfHighDeepFreeze)) != 0u; bool const lineDeepFreezePeer = (flags & (not viewLowest ? ripple::lsfLowDeepFreeze : ripple::lsfHighDeepFreeze)) != 0u; @@ -145,13 +151,15 @@ AccountLinesHandler::process(AccountLinesHandler::Input const& input, Context co auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (not accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; - auto const peerAccountID = input.peer ? accountFromStringStrict(*(input.peer)) : std::optional{}; + auto const peerAccountID = + input.peer ? accountFromStringStrict(*(input.peer)) : std::optional{}; Output response; response.lines.reserve(input.limit); @@ -173,7 +181,13 @@ AccountLinesHandler::process(AccountLinesHandler::Input const& input, Context co }; auto const expectedNext = traverseOwnedNodes( - *sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse + *sharedPtrBackend_, + *accountID, + lgrInfo.seq, + input.limit, + input.marker, + ctx.yield, + addToResponse ); if (!expectedNext.has_value()) @@ -225,7 +239,11 @@ tag_invoke(boost::json::value_to_tag, boost::json::v } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountLinesHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountLinesHandler::Output const& output +) { using boost::json::value_from; diff --git a/src/rpc/handlers/AccountLines.hpp b/src/rpc/handlers/AccountLines.hpp index 1df1cf161..0c5d846da 100644 --- a/src/rpc/handlers/AccountLines.hpp +++ b/src/rpc/handlers/AccountLines.hpp @@ -45,8 +45,8 @@ namespace rpc { /** - * @brief The account_lines method returns information about an account's trust lines, which contain balances in all - * non-XRP currencies and assets. + * @brief The account_lines method returns information about an account's trust lines, which contain + * balances in all non-XRP currencies and assets. * * For more details see: https://xrpl.org/account_lines.html */ @@ -114,7 +114,8 @@ public: * * @param sharedPtrBackend The backend to use */ - AccountLinesHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + AccountLinesHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } @@ -131,11 +132,13 @@ public: {JS(account), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED) + validation::CustomValidators::accountValidator, + Status(RippledError::rpcACT_MALFORMED) }}, {JS(peer), meta::WithCustomError{ - validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED) + validation::CustomValidators::accountValidator, + Status(RippledError::rpcACT_MALFORMED) }}, {JS(ignore_default), validation::Type{}}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, diff --git a/src/rpc/handlers/AccountMPTokenIssuances.cpp b/src/rpc/handlers/AccountMPTokenIssuances.cpp index 942431738..1f5840c28 100644 --- a/src/rpc/handlers/AccountMPTokenIssuances.cpp +++ b/src/rpc/handlers/AccountMPTokenIssuances.cpp @@ -117,7 +117,10 @@ AccountMPTokenIssuancesHandler::addMPTokenIssuance( } AccountMPTokenIssuancesHandler::Result -AccountMPTokenIssuancesHandler::process(AccountMPTokenIssuancesHandler::Input const& input, Context const& ctx) const +AccountMPTokenIssuancesHandler::process( + AccountMPTokenIssuancesHandler::Input const& input, + Context const& ctx +) const { auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "AccountMPTokenIssuances' ledger range must be available"); @@ -130,8 +133,9 @@ AccountMPTokenIssuancesHandler::process(AccountMPTokenIssuancesHandler::Input co auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (not accountLedgerObject.has_value()) return Error{Status{RippledError::rpcACT_NOT_FOUND}}; @@ -146,7 +150,13 @@ AccountMPTokenIssuancesHandler::process(AccountMPTokenIssuancesHandler::Input co }; auto const expectedNext = traverseOwnedNodes( - *sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse + *sharedPtrBackend_, + *accountID, + lgrInfo.seq, + input.limit, + input.marker, + ctx.yield, + addToResponse ); if (!expectedNext.has_value()) @@ -167,7 +177,10 @@ AccountMPTokenIssuancesHandler::process(AccountMPTokenIssuancesHandler::Input co } AccountMPTokenIssuancesHandler::Input -tag_invoke(boost::json::value_to_tag, boost::json::value const& jv) +tag_invoke( + boost::json::value_to_tag, + boost::json::value const& jv +) { auto input = AccountMPTokenIssuancesHandler::Input{}; auto const& jsonObject = jv.as_object(); @@ -193,7 +206,11 @@ tag_invoke(boost::json::value_to_tag, boo } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountMPTokenIssuancesHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountMPTokenIssuancesHandler::Output const& output +) { using boost::json::value_from; diff --git a/src/rpc/handlers/AccountMPTokenIssuances.hpp b/src/rpc/handlers/AccountMPTokenIssuances.hpp index eafe228d1..4b49bc52e 100644 --- a/src/rpc/handlers/AccountMPTokenIssuances.hpp +++ b/src/rpc/handlers/AccountMPTokenIssuances.hpp @@ -45,8 +45,8 @@ namespace rpc { /** - * @brief The account_mptoken_issuances method returns information about all MPTokenIssuance objects the account has - * created. + * @brief The account_mptoken_issuances method returns information about all MPTokenIssuance objects + * the account has created. */ class AccountMPTokenIssuancesHandler { // dependencies @@ -141,7 +141,8 @@ public: {JS(account), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED) + validation::CustomValidators::accountValidator, + Status(RippledError::rpcACT_MALFORMED) }}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(limit), @@ -200,7 +201,11 @@ private: * @param issuance The MPTokenIssuance response to convert */ friend void - tag_invoke(boost::json::value_from_tag, boost::json::value& jv, MPTokenIssuanceResponse const& issuance); + tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + MPTokenIssuanceResponse const& issuance + ); }; } // namespace rpc diff --git a/src/rpc/handlers/AccountMPTokens.cpp b/src/rpc/handlers/AccountMPTokens.cpp index 085841d0b..580e52b7b 100644 --- a/src/rpc/handlers/AccountMPTokens.cpp +++ b/src/rpc/handlers/AccountMPTokens.cpp @@ -74,7 +74,10 @@ AccountMPTokensHandler::addMPToken(std::vector& mpts, ripple::S } AccountMPTokensHandler::Result -AccountMPTokensHandler::process(AccountMPTokensHandler::Input const& input, Context const& ctx) const +AccountMPTokensHandler::process( + AccountMPTokensHandler::Input const& input, + Context const& ctx +) const { auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "AccountMPTokens' ledger range must be available"); @@ -87,8 +90,9 @@ AccountMPTokensHandler::process(AccountMPTokensHandler::Input const& input, Cont auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (not accountLedgerObject.has_value()) return Error{Status{RippledError::rpcACT_NOT_FOUND}}; @@ -103,7 +107,13 @@ AccountMPTokensHandler::process(AccountMPTokensHandler::Input const& input, Cont }; auto const expectedNext = traverseOwnedNodes( - *sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse + *sharedPtrBackend_, + *accountID, + lgrInfo.seq, + input.limit, + input.marker, + ctx.yield, + addToResponse ); if (!expectedNext.has_value()) @@ -150,7 +160,11 @@ tag_invoke(boost::json::value_to_tag, boost::json } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountMPTokensHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountMPTokensHandler::Output const& output +) { auto obj = boost::json::object{ {JS(account), output.account}, @@ -168,7 +182,11 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountMPTokensH } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountMPTokensHandler::MPTokenResponse const& mptoken) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountMPTokensHandler::MPTokenResponse const& mptoken +) { auto obj = boost::json::object{ {"mpt_id", mptoken.MPTokenID}, diff --git a/src/rpc/handlers/AccountMPTokens.hpp b/src/rpc/handlers/AccountMPTokens.hpp index 67bdccfc0..2536bf5ad 100644 --- a/src/rpc/handlers/AccountMPTokens.hpp +++ b/src/rpc/handlers/AccountMPTokens.hpp @@ -44,7 +44,8 @@ namespace rpc { /** - * @brief The account_mptokens method returns information about the MPTokens the account currently holds. + * @brief The account_mptokens method returns information about the MPTokens the account currently + * holds. */ class AccountMPTokensHandler { // dependencies @@ -118,7 +119,8 @@ public: {JS(account), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::accountValidator, Status(RippledError::rpcACT_MALFORMED) + validation::CustomValidators::accountValidator, + Status(RippledError::rpcACT_MALFORMED) }}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(limit), diff --git a/src/rpc/handlers/AccountNFTs.cpp b/src/rpc/handlers/AccountNFTs.cpp index d16ccebe6..b689ccbde 100644 --- a/src/rpc/handlers/AccountNFTs.cpp +++ b/src/rpc/handlers/AccountNFTs.cpp @@ -63,8 +63,9 @@ AccountNFTsHandler::process(AccountNFTsHandler::Input const& input, Context cons auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; @@ -76,20 +77,26 @@ AccountNFTsHandler::process(AccountNFTsHandler::Input const& input, Context cons response.ledgerIndex = lgrInfo.seq; // if a marker was passed, start at the page specified in marker. Else, start at the max page - auto const pageKey = - input.marker ? ripple::uint256{input.marker->c_str()} : ripple::keylet::nftpage_max(*accountID).key; + auto const pageKey = input.marker ? ripple::uint256{input.marker->c_str()} + : ripple::keylet::nftpage_max(*accountID).key; auto const blob = sharedPtrBackend_->fetchLedgerObject(pageKey, lgrInfo.seq, ctx.yield); if (!blob) { if (input.marker.has_value()) - return Error{Status{RippledError::rpcINVALID_PARAMS, "Marker field does not match any valid Page ID"}}; + return Error{Status{ + RippledError::rpcINVALID_PARAMS, "Marker field does not match any valid Page ID" + }}; return response; } - std::optional page{ripple::SLE{ripple::SerialIter{blob->data(), blob->size()}, pageKey}}; + std::optional page{ + ripple::SLE{ripple::SerialIter{blob->data(), blob->size()}, pageKey} + }; if (page->getType() != ripple::ltNFTOKEN_PAGE) - return Error{Status{RippledError::rpcINVALID_PARAMS, "Marker matches Page ID from another Account"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, "Marker matches Page ID from another Account"} + }; auto numPages = 0u; @@ -120,8 +127,11 @@ AccountNFTsHandler::process(AccountNFTsHandler::Input const& input, Context cons return response; } - auto const nextBlob = sharedPtrBackend_->fetchLedgerObject(nextKey.key, lgrInfo.seq, ctx.yield); - page.emplace(ripple::SLE{ripple::SerialIter{nextBlob->data(), nextBlob->size()}, nextKey.key}); + auto const nextBlob = + sharedPtrBackend_->fetchLedgerObject(nextKey.key, lgrInfo.seq, ctx.yield); + page.emplace( + ripple::SLE{ripple::SerialIter{nextBlob->data(), nextBlob->size()}, nextKey.key} + ); } else { page.reset(); } @@ -131,7 +141,11 @@ AccountNFTsHandler::process(AccountNFTsHandler::Input const& input, Context cons } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountNFTsHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountNFTsHandler::Output const& output +) { jv = { {JS(ledger_hash), output.ledgerHash}, diff --git a/src/rpc/handlers/AccountNFTs.hpp b/src/rpc/handlers/AccountNFTs.hpp index f6f670bf7..edea3f0d3 100644 --- a/src/rpc/handlers/AccountNFTs.hpp +++ b/src/rpc/handlers/AccountNFTs.hpp @@ -83,7 +83,8 @@ public: * * @param sharedPtrBackend The backend to use */ - AccountNFTsHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + AccountNFTsHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } diff --git a/src/rpc/handlers/AccountObjects.cpp b/src/rpc/handlers/AccountObjects.cpp index 323b3e3cb..c3de2ca4e 100644 --- a/src/rpc/handlers/AccountObjects.cpp +++ b/src/rpc/handlers/AccountObjects.cpp @@ -64,8 +64,9 @@ AccountObjectsHandler::process(AccountObjectsHandler::Input const& input, Contex auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; @@ -91,15 +92,23 @@ AccountObjectsHandler::process(AccountObjectsHandler::Input const& input, Contex Output response; auto const addToResponse = [&](ripple::SLE&& sle) { if (not typeFilter or - std::find(std::begin(typeFilter.value()), std::end(typeFilter.value()), sle.getType()) != - std::end(typeFilter.value())) { + std::find( + std::begin(typeFilter.value()), std::end(typeFilter.value()), sle.getType() + ) != std::end(typeFilter.value())) { response.accountObjects.push_back(std::move(sle)); } return true; }; auto const expectedNext = traverseOwnedNodes( - *sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse, true + *sharedPtrBackend_, + *accountID, + lgrInfo.seq, + input.limit, + input.marker, + ctx.yield, + addToResponse, + true ); if (!expectedNext.has_value()) @@ -119,7 +128,11 @@ AccountObjectsHandler::process(AccountObjectsHandler::Input const& input, Contex } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountObjectsHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountObjectsHandler::Output const& output +) { auto objects = boost::json::array{}; std::ranges::transform( @@ -160,8 +173,9 @@ tag_invoke(boost::json::value_to_tag, boost::json: } if (jsonObject.contains(JS(type))) { - input.type = - util::LedgerTypes::getAccountOwnedLedgerTypeFromStr(boost::json::value_to(jv.at(JS(type)))); + input.type = util::LedgerTypes::getAccountOwnedLedgerTypeFromStr( + boost::json::value_to(jv.at(JS(type))) + ); } if (jsonObject.contains(JS(limit))) diff --git a/src/rpc/handlers/AccountObjects.hpp b/src/rpc/handlers/AccountObjects.hpp index f795518b2..19885221d 100644 --- a/src/rpc/handlers/AccountObjects.hpp +++ b/src/rpc/handlers/AccountObjects.hpp @@ -42,10 +42,9 @@ namespace rpc { /** - * @brief The account_objects command returns the raw ledger format for all objects owned by an account. - * The results can be filtered by the type. - * The valid types are: check, deposit_preauth, escrow, nft_offer, offer, payment_channel, signer_list, state (trust - * line), did and ticket. + * @brief The account_objects command returns the raw ledger format for all objects owned by an + * account. The results can be filtered by the type. The valid types are: check, deposit_preauth, + * escrow, nft_offer, offer, payment_channel, signer_list, state (trust line), did and ticket. * * For more details see: https://xrpl.org/account_objects.html */ diff --git a/src/rpc/handlers/AccountOffers.cpp b/src/rpc/handlers/AccountOffers.cpp index 2d987678f..656d44f50 100644 --- a/src/rpc/handlers/AccountOffers.cpp +++ b/src/rpc/handlers/AccountOffers.cpp @@ -80,8 +80,9 @@ AccountOffersHandler::process(AccountOffersHandler::Input const& input, Context auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; @@ -99,7 +100,13 @@ AccountOffersHandler::process(AccountOffersHandler::Input const& input, Context }; auto const expectedNext = traverseOwnedNodes( - *sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse + *sharedPtrBackend_, + *accountID, + lgrInfo.seq, + input.limit, + input.marker, + ctx.yield, + addToResponse ); if (!expectedNext.has_value()) @@ -114,7 +121,11 @@ AccountOffersHandler::process(AccountOffersHandler::Input const& input, Context } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountOffersHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountOffersHandler::Output const& output +) { jv = { {JS(ledger_hash), output.ledgerHash}, @@ -129,7 +140,11 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountOffersHan } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountOffersHandler::Offer const& offer) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountOffersHandler::Offer const& offer +) { jv = { {JS(seq), offer.seq}, diff --git a/src/rpc/handlers/AccountTx.cpp b/src/rpc/handlers/AccountTx.cpp index ad82919e6..1b7a58daa 100644 --- a/src/rpc/handlers/AccountTx.cpp +++ b/src/rpc/handlers/AccountTx.cpp @@ -61,7 +61,8 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c if (input.ledgerIndexMin) { if (ctx.apiVersion > 1u && - (input.ledgerIndexMin > range->maxSequence || input.ledgerIndexMin < range->minSequence)) { + (input.ledgerIndexMin > range->maxSequence || + input.ledgerIndexMin < range->minSequence)) { return Error{Status{RippledError::rpcLGR_IDX_MALFORMED, "ledgerSeqMinOutOfRange"}}; } @@ -71,7 +72,8 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c if (input.ledgerIndexMax) { if (ctx.apiVersion > 1u && - (input.ledgerIndexMax > range->maxSequence || input.ledgerIndexMax < range->minSequence)) { + (input.ledgerIndexMax > range->maxSequence || + input.ledgerIndexMax < range->minSequence)) { return Error{Status{RippledError::rpcLGR_IDX_MALFORMED, "ledgerSeqMaxOutOfRange"}}; } @@ -88,13 +90,19 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c if (input.ledgerHash || input.ledgerIndex || input.usingValidatedLedger) { if (ctx.apiVersion > 1u && (input.ledgerIndexMax || input.ledgerIndexMin)) - return Error{Status{RippledError::rpcINVALID_PARAMS, "containsLedgerSpecifierAndRange"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, "containsLedgerSpecifierAndRange"} + }; if (!input.ledgerIndexMax && !input.ledgerIndexMin) { // mimic rippled, when both range and index specified, respect the range. // take ledger from ledgerHash or ledgerIndex only when range is not specified auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq( - *sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence + *sharedPtrBackend_, + ctx.yield, + input.ledgerHash, + input.ledgerIndex, + range->maxSequence ); if (!expectedLgrInfo.has_value()) @@ -110,8 +118,8 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c if (input.marker) { cursor = {input.marker->ledger, input.marker->seq}; } else { - // if forward, start at minIndex - 1, because the SQL query is exclusive, we need to include the 0 - // transaction index of minIndex + // if forward, start at minIndex - 1, because the SQL query is exclusive, we need to include + // the 0 transaction index of minIndex if (input.forward) { cursor = {minIndex - 1, std::numeric_limits::max()}; } else { @@ -122,10 +130,13 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c auto const limit = input.limit.value_or(kLIMIT_DEFAULT); auto const accountID = accountFromStringStrict(input.account); auto const [txnsAndCursor, timeDiff] = util::timed([&]() { - return sharedPtrBackend_->fetchAccountTransactions(*accountID, limit, input.forward, cursor, ctx.yield); + return sharedPtrBackend_->fetchAccountTransactions( + *accountID, limit, input.forward, cursor, ctx.yield + ); }); - LOG(log_.info()) << "db fetch took " << timeDiff << " milliseconds - num blobs = " << txnsAndCursor.txns.size(); + LOG(log_.info()) << "db fetch took " << timeDiff + << " milliseconds - num blobs = " << txnsAndCursor.txns.size(); auto const [blobs, retCursor] = txnsAndCursor; Output response; @@ -167,9 +178,12 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c if (auto const& etlState = etl_->getETLState(); etlState.has_value()) networkID = etlState->networkID; - auto const txnIdx = - util::integralValueAs(obj[JS(meta)].as_object().at("TransactionIndex")); - if (auto const& ctid = rpc::encodeCTID(txnPlusMeta.ledgerSequence, txnIdx, networkID); ctid) + auto const txnIdx = util::integralValueAs( + obj[JS(meta)].as_object().at("TransactionIndex") + ); + if (auto const& ctid = + rpc::encodeCTID(txnPlusMeta.ledgerSequence, txnIdx, networkID); + ctid) obj[txKey].as_object()[JS(ctid)] = ctid.value(); } @@ -184,8 +198,9 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c obj[JS(hash)] = obj[txKey].as_object()[JS(hash)]; obj[txKey].as_object().erase(JS(hash)); } - if (auto const ledgerHeader = - sharedPtrBackend_->fetchLedgerBySequence(txnPlusMeta.ledgerSequence, ctx.yield); + if (auto const ledgerHeader = sharedPtrBackend_->fetchLedgerBySequence( + txnPlusMeta.ledgerSequence, ctx.yield + ); ledgerHeader) { obj[JS(ledger_hash)] = ripple::strHex(ledgerHeader->hash); obj[JS(close_time_iso)] = ripple::to_string_iso(ledgerHeader->closeTime); @@ -212,7 +227,11 @@ AccountTxHandler::process(AccountTxHandler::Input const& input, Context const& c } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountTxHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountTxHandler::Output const& output +) { jv = { {JS(account), output.account}, @@ -230,7 +249,11 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountTxHandler } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountTxHandler::Marker const& marker) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + AccountTxHandler::Marker const& marker +) { jv = { {JS(ledger), marker.ledger}, @@ -278,13 +301,17 @@ tag_invoke(boost::json::value_to_tag, boost::json::valu if (jsonObject.contains(JS(marker))) { input.marker = AccountTxHandler::Marker{ - .ledger = util::integralValueAs(jsonObject.at(JS(marker)).as_object().at(JS(ledger))), - .seq = util::integralValueAs(jsonObject.at(JS(marker)).as_object().at(JS(seq))) + .ledger = util::integralValueAs( + jsonObject.at(JS(marker)).as_object().at(JS(ledger)) + ), + .seq = + util::integralValueAs(jsonObject.at(JS(marker)).as_object().at(JS(seq))) }; } if (jsonObject.contains("tx_type")) - input.transactionTypeInLowercase = boost::json::value_to(jsonObject.at("tx_type")); + input.transactionTypeInLowercase = + boost::json::value_to(jsonObject.at("tx_type")); return input; } diff --git a/src/rpc/handlers/AccountTx.hpp b/src/rpc/handlers/AccountTx.hpp index e29bb4355..534135b76 100644 --- a/src/rpc/handlers/AccountTx.hpp +++ b/src/rpc/handlers/AccountTx.hpp @@ -49,7 +49,8 @@ namespace rpc { /** - * @brief The account_tx method retrieves a list of transactions that involved the specified account. + * @brief The account_tx method retrieves a list of transactions that involved the specified + * account. * * For more details see: https://xrpl.org/account_tx.html */ @@ -155,7 +156,9 @@ public: "tx_type", validation::Type{}, modifiers::ToLower{}, - validation::OneOf(typesKeysInLowercase.cbegin(), typesKeysInLowercase.cend()), + validation::OneOf( + typesKeysInLowercase.cbegin(), typesKeysInLowercase.cend() + ), }, }; diff --git a/src/rpc/handlers/BookChanges.cpp b/src/rpc/handlers/BookChanges.cpp index 003ce4ef8..a9d1d97fd 100644 --- a/src/rpc/handlers/BookChanges.cpp +++ b/src/rpc/handlers/BookChanges.cpp @@ -55,7 +55,8 @@ BookChangesHandler::process(BookChangesHandler::Input const& input, Context cons return Error{expectedLgrInfo.error()}; auto const& lgrInfo = expectedLgrInfo.value(); - auto const transactions = sharedPtrBackend_->fetchAllTransactionsInLedger(lgrInfo.seq, ctx.yield); + auto const transactions = + sharedPtrBackend_->fetchAllTransactionsInLedger(lgrInfo.seq, ctx.yield); Output response; response.bookChanges = BookChanges::compute(transactions); @@ -67,7 +68,11 @@ BookChangesHandler::process(BookChangesHandler::Input const& input, Context cons } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, BookChangesHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + BookChangesHandler::Output const& output +) { using boost::json::value_from; @@ -100,7 +105,10 @@ tag_invoke(boost::json::value_to_tag, boost::json::va } [[nodiscard]] boost::json::object -computeBookChanges(ripple::LedgerHeader const& lgrInfo, std::vector const& transactions) +computeBookChanges( + ripple::LedgerHeader const& lgrInfo, + std::vector const& transactions +) { using boost::json::value_from; diff --git a/src/rpc/handlers/BookChanges.hpp b/src/rpc/handlers/BookChanges.hpp index 972f5dbd1..8125fc4ac 100644 --- a/src/rpc/handlers/BookChanges.hpp +++ b/src/rpc/handlers/BookChanges.hpp @@ -75,7 +75,8 @@ public: * * @param sharedPtrBackend The backend to use */ - BookChangesHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + BookChangesHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } diff --git a/src/rpc/handlers/BookOffers.cpp b/src/rpc/handlers/BookOffers.cpp index 1383c68fd..bddbdec4e 100644 --- a/src/rpc/handlers/BookOffers.cpp +++ b/src/rpc/handlers/BookOffers.cpp @@ -46,7 +46,8 @@ namespace rpc { BookOffersHandler::Result BookOffersHandler::process(Input const& input, Context const& ctx) const { - auto bookMaybe = parseBook(input.paysCurrency, input.paysID, input.getsCurrency, input.getsID, input.domain); + auto bookMaybe = + parseBook(input.paysCurrency, input.paysID, input.getsCurrency, input.getsID, input.domain); if (!bookMaybe.has_value()) return Error{bookMaybe.error()}; @@ -66,7 +67,8 @@ BookOffersHandler::process(Input const& input, Context const& ctx) const auto const bookKey = getBookBase(book); // TODO: Add performance metrics if needed in future - auto [offers, _] = sharedPtrBackend_->fetchBookOffers(bookKey, lgrInfo.seq, input.limit, ctx.yield); + auto [offers, _] = + sharedPtrBackend_->fetchBookOffers(bookKey, lgrInfo.seq, input.limit, ctx.yield); auto output = BookOffersHandler::Output{}; output.ledgerHash = ripple::strHex(lgrInfo.hash); @@ -85,7 +87,11 @@ BookOffersHandler::process(Input const& input, Context const& ctx) const } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, BookOffersHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + BookOffersHandler::Output const& output +) { jv = boost::json::object{ {JS(ledger_hash), output.ledgerHash}, @@ -101,21 +107,25 @@ tag_invoke(boost::json::value_to_tag, boost::json::val auto const& jsonObject = jv.as_object(); ripple::to_currency( - input.getsCurrency, boost::json::value_to(jv.at(JS(taker_gets)).as_object().at(JS(currency))) + input.getsCurrency, + boost::json::value_to(jv.at(JS(taker_gets)).as_object().at(JS(currency))) ); ripple::to_currency( - input.paysCurrency, boost::json::value_to(jv.at(JS(taker_pays)).as_object().at(JS(currency))) + input.paysCurrency, + boost::json::value_to(jv.at(JS(taker_pays)).as_object().at(JS(currency))) ); if (jv.at(JS(taker_gets)).as_object().contains(JS(issuer))) { ripple::to_issuer( - input.getsID, boost::json::value_to(jv.at(JS(taker_gets)).as_object().at(JS(issuer))) + input.getsID, + boost::json::value_to(jv.at(JS(taker_gets)).as_object().at(JS(issuer))) ); } if (jv.at(JS(taker_pays)).as_object().contains(JS(issuer))) { ripple::to_issuer( - input.paysID, boost::json::value_to(jv.at(JS(taker_pays)).as_object().at(JS(issuer))) + input.paysID, + boost::json::value_to(jv.at(JS(taker_pays)).as_object().at(JS(issuer))) ); } diff --git a/src/rpc/handlers/BookOffers.hpp b/src/rpc/handlers/BookOffers.hpp index be85dfedc..6a79cd848 100644 --- a/src/rpc/handlers/BookOffers.hpp +++ b/src/rpc/handlers/BookOffers.hpp @@ -46,7 +46,8 @@ namespace rpc { /** - * @brief The book_offers method retrieves a list of Offers between two currencies, also known as an order book. + * @brief The book_offers method retrieves a list of Offers between two currencies, also known as an + * order book. * * For more details see: https://xrpl.org/book_offers.html */ @@ -72,8 +73,8 @@ public: /** * @brief A struct to hold the input data for the command * - * @note The taker is not really used in both Clio and `rippled`, both of them return all the offers regardless of - * the funding status + * @note The taker is not really used in both Clio and `rippled`, both of them return all the + * offers regardless of the funding status */ struct Input { std::optional ledgerHash; @@ -121,11 +122,13 @@ public: {JS(currency), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::currencyValidator, Status(RippledError::rpcDST_AMT_MALFORMED) + validation::CustomValidators::currencyValidator, + Status(RippledError::rpcDST_AMT_MALFORMED) }}, {JS(issuer), meta::WithCustomError{ - validation::CustomValidators::issuerValidator, Status(RippledError::rpcDST_ISR_MALFORMED) + validation::CustomValidators::issuerValidator, + Status(RippledError::rpcDST_ISR_MALFORMED) }} }}, {JS(taker_pays), @@ -135,11 +138,13 @@ public: {JS(currency), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::currencyValidator, Status(RippledError::rpcSRC_CUR_MALFORMED) + validation::CustomValidators::currencyValidator, + Status(RippledError::rpcSRC_CUR_MALFORMED) }}, {JS(issuer), meta::WithCustomError{ - validation::CustomValidators::issuerValidator, Status(RippledError::rpcSRC_ISR_MALFORMED) + validation::CustomValidators::issuerValidator, + Status(RippledError::rpcSRC_ISR_MALFORMED) }} }}, // return INVALID_PARAMS if account format is wrong for "taker" @@ -150,7 +155,8 @@ public: }}, {JS(domain), meta::WithCustomError{ - validation::Type{}, Status(RippledError::rpcDOMAIN_MALFORMED, "Unable to parse domain.") + validation::Type{}, + Status(RippledError::rpcDOMAIN_MALFORMED, "Unable to parse domain.") }, meta::WithCustomError{ validation::CustomValidators::uint256HexStringValidator, diff --git a/src/rpc/handlers/DepositAuthorized.cpp b/src/rpc/handlers/DepositAuthorized.cpp index 364760f5d..65e24eb42 100644 --- a/src/rpc/handlers/DepositAuthorized.cpp +++ b/src/rpc/handlers/DepositAuthorized.cpp @@ -50,7 +50,10 @@ namespace rpc { DepositAuthorizedHandler::Result -DepositAuthorizedHandler::process(DepositAuthorizedHandler::Input const& input, Context const& ctx) const +DepositAuthorizedHandler::process( + DepositAuthorizedHandler::Input const& input, + Context const& ctx +) const { auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "DepositAuthorized ledger range must be available"); @@ -66,14 +69,16 @@ DepositAuthorizedHandler::process(DepositAuthorizedHandler::Input const& input, auto const sourceAccountID = accountFromStringStrict(input.sourceAccount); auto const destinationAccountID = accountFromStringStrict(input.destinationAccount); - auto const srcAccountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*sourceAccountID).key, lgrInfo.seq, ctx.yield); + auto const srcAccountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*sourceAccountID).key, lgrInfo.seq, ctx.yield + ); if (!srcAccountLedgerObject) return Error{Status{RippledError::rpcSRC_ACT_NOT_FOUND, "source_accountNotFound"}}; auto const dstKeylet = ripple::keylet::account(*destinationAccountID).key; - auto const dstAccountLedgerObject = sharedPtrBackend_->fetchLedgerObject(dstKeylet, lgrInfo.seq, ctx.yield); + auto const dstAccountLedgerObject = + sharedPtrBackend_->fetchLedgerObject(dstKeylet, lgrInfo.seq, ctx.yield); if (!dstAccountLedgerObject) return Error{Status{RippledError::rpcDST_ACT_NOT_FOUND, "destination_accountNotFound"}}; @@ -82,14 +87,17 @@ DepositAuthorizedHandler::process(DepositAuthorizedHandler::Input const& input, auto it = ripple::SerialIter{dstAccountLedgerObject->data(), dstAccountLedgerObject->size()}; auto const sleDest = ripple::SLE{it, dstKeylet}; - bool const reqAuth = sleDest.isFlag(ripple::lsfDepositAuth) && (sourceAccountID != destinationAccountID); + bool const reqAuth = + sleDest.isFlag(ripple::lsfDepositAuth) && (sourceAccountID != destinationAccountID); auto const& creds = input.credentials; bool const credentialsPresent = creds.has_value(); ripple::STArray authCreds; if (credentialsPresent) { if (creds.value().empty()) { - return Error{Status{RippledError::rpcINVALID_PARAMS, "credential array has no elements."}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, "credential array has no elements."} + }; } if (creds.value().size() > ripple::maxCredentialsArraySize) { return Error{Status{RippledError::rpcINVALID_PARAMS, "credential array too long."}}; @@ -111,7 +119,8 @@ DepositAuthorizedHandler::process(DepositAuthorizedHandler::Input const& input, if (credentialsPresent) { auto const sortedAuthCreds = credentials::createAuthCredentials(authCreds); ASSERT( - sortedAuthCreds.size() == authCreds.size(), "should already be checked above that there is no duplicate" + sortedAuthCreds.size() == authCreds.size(), + "should already be checked above that there is no duplicate" ); hashKey = ripple::keylet::depositPreauth(*destinationAccountID, sortedAuthCreds).key; @@ -119,7 +128,8 @@ DepositAuthorizedHandler::process(DepositAuthorizedHandler::Input const& input, hashKey = ripple::keylet::depositPreauth(*destinationAccountID, *sourceAccountID).key; } - depositAuthorized = sharedPtrBackend_->fetchLedgerObject(hashKey, lgrInfo.seq, ctx.yield).has_value(); + depositAuthorized = + sharedPtrBackend_->fetchLedgerObject(hashKey, lgrInfo.seq, ctx.yield).has_value(); } response.sourceAccount = input.sourceAccount; @@ -158,7 +168,11 @@ tag_invoke(boost::json::value_to_tag, boost::js } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, DepositAuthorizedHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + DepositAuthorizedHandler::Output const& output +) { jv = boost::json::object{ {JS(deposit_authorized), output.depositAuthorized}, diff --git a/src/rpc/handlers/DepositAuthorized.hpp b/src/rpc/handlers/DepositAuthorized.hpp index 758e42a60..8c0a740e1 100644 --- a/src/rpc/handlers/DepositAuthorized.hpp +++ b/src/rpc/handlers/DepositAuthorized.hpp @@ -41,8 +41,9 @@ namespace rpc { /** * @brief Handles the `deposit_authorized` command * - * The deposit_authorized command indicates whether one account is authorized to send payments directly to - * another. See Deposit Authorization for information on how to require authorization to deliver money to your account. + * The deposit_authorized command indicates whether one account is authorized to send payments + * directly to another. See Deposit Authorization for information on how to require authorization to + * deliver money to your account. * * For more details see: https://xrpl.org/deposit_authorized.html */ @@ -100,8 +101,12 @@ public: spec([[maybe_unused]] uint32_t apiVersion) { static auto const kRPC_SPEC = RpcSpec{ - {JS(source_account), validation::Required{}, validation::CustomValidators::accountValidator}, - {JS(destination_account), validation::Required{}, validation::CustomValidators::accountValidator}, + {JS(source_account), + validation::Required{}, + validation::CustomValidators::accountValidator}, + {JS(destination_account), + validation::Required{}, + validation::CustomValidators::accountValidator}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, {JS(credentials), validation::Type{}, validation::Hex256ItemType()} diff --git a/src/rpc/handlers/Feature.cpp b/src/rpc/handlers/Feature.cpp index 1a8422739..83589b39b 100644 --- a/src/rpc/handlers/Feature.cpp +++ b/src/rpc/handlers/Feature.cpp @@ -71,24 +71,29 @@ FeatureHandler::process(FeatureHandler::Input const& input, Context const& ctx) auto searchPredicate = [search = input.feature](auto const& feature) { if (search) - return ripple::to_string(feature.feature) == search.value() or feature.name == search.value(); + return ripple::to_string(feature.feature) == search.value() or + feature.name == search.value(); return true; }; std::vector filtered; - rg::transform(all | vs::filter(searchPredicate), std::back_inserter(filtered), [&](auto const& feature) { - return Output::Feature{ - .name = feature.name, - .key = ripple::to_string(feature.feature), - .supported = feature.isSupportedByClio, - }; - }); + rg::transform( + all | vs::filter(searchPredicate), std::back_inserter(filtered), [&](auto const& feature) { + return Output::Feature{ + .name = feature.name, + .key = ripple::to_string(feature.feature), + .supported = feature.isSupportedByClio, + }; + } + ); if (filtered.empty()) return Error{Status{RippledError::rpcBAD_FEATURE}}; std::vector names; - rg::transform(filtered, std::back_inserter(names), [](auto const& feature) { return feature.name; }); + rg::transform(filtered, std::back_inserter(names), [](auto const& feature) { + return feature.name; + }); std::map features; rg::transform( @@ -117,7 +122,10 @@ FeatureHandler::spec([[maybe_unused]] uint32_t apiVersion) {JS(vetoed), meta::WithCustomError{ validation::NotSupported{}, - Status(RippledError::rpcNO_PERMISSION, "The admin portion of feature API is not available through Clio.") + Status( + RippledError::rpcNO_PERMISSION, + "The admin portion of feature API is not available through Clio." + ) }}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, @@ -126,7 +134,11 @@ FeatureHandler::spec([[maybe_unused]] uint32_t apiVersion) } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, FeatureHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + FeatureHandler::Output const& output +) { using boost::json::value_from; @@ -145,7 +157,11 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, FeatureHandler:: } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, FeatureHandler::Output::Feature const& feature) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + FeatureHandler::Output::Feature const& feature +) { using boost::json::value_from; diff --git a/src/rpc/handlers/Feature.hpp b/src/rpc/handlers/Feature.hpp index 0217ac2ba..34f1bf685 100644 --- a/src/rpc/handlers/Feature.hpp +++ b/src/rpc/handlers/Feature.hpp @@ -71,7 +71,8 @@ public: std::string ledgerHash; uint32_t ledgerIndex{}; - // when set to true, output will be inlined in `result` instead of wrapping as `features` inside of `result`. + // when set to true, output will be inlined in `result` instead of wrapping as `features` + // inside of `result`. bool inlineResult = false; // validated should be sent via framework @@ -111,7 +112,10 @@ public: * @return The result of the operation */ Result - process(Input const& input, Context const& ctx) const; // NOLINT(readability-convert-member-functions-to-static) + process( + Input const& input, + Context const& ctx + ) const; // NOLINT(readability-convert-member-functions-to-static) private: /** diff --git a/src/rpc/handlers/GatewayBalances.cpp b/src/rpc/handlers/GatewayBalances.cpp index ca95142fc..5567b489a 100644 --- a/src/rpc/handlers/GatewayBalances.cpp +++ b/src/rpc/handlers/GatewayBalances.cpp @@ -56,7 +56,10 @@ namespace rpc { GatewayBalancesHandler::Result -GatewayBalancesHandler::process(GatewayBalancesHandler::Input const& input, Context const& ctx) const +GatewayBalancesHandler::process( + GatewayBalancesHandler::Input const& input, + Context const& ctx +) const { // check ledger auto const range = sharedPtrBackend_->fetchLedgerRange(); @@ -72,8 +75,9 @@ GatewayBalancesHandler::process(GatewayBalancesHandler::Input const& input, Cont // check account auto const& lgrInfo = expectedLgrInfo.value(); auto const accountID = accountFromStringStrict(input.account); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield + ); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; @@ -96,7 +100,9 @@ GatewayBalancesHandler::process(GatewayBalancesHandler::Input const& input, Cont // Very large sums of STAmount are approximations // anyway. lockedBalance = ripple::STAmount( - lockedBalance.issue(), ripple::STAmount::cMaxValue, ripple::STAmount::cMaxOffset + lockedBalance.issue(), + ripple::STAmount::cMaxValue, + ripple::STAmount::cMaxOffset ); } } @@ -147,7 +153,9 @@ GatewayBalancesHandler::process(GatewayBalancesHandler::Input const& input, Cont try { bal -= balance; } catch (std::runtime_error const& e) { - bal = ripple::STAmount(bal.issue(), ripple::STAmount::cMaxValue, ripple::STAmount::cMaxOffset); + bal = ripple::STAmount( + bal.issue(), ripple::STAmount::cMaxValue, ripple::STAmount::cMaxOffset + ); } } } @@ -178,7 +186,11 @@ GatewayBalancesHandler::process(GatewayBalancesHandler::Input const& input, Cont } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, GatewayBalancesHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + GatewayBalancesHandler::Output const& output +) { boost::json::object obj; if (!output.sums.empty()) { @@ -189,25 +201,26 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, GatewayBalancesH obj[JS(obligations)] = std::move(obligations); } - auto const toJson = [](std::map> const& balances) { - boost::json::object balancesObj; + auto const toJson = + [](std::map> const& balances) { + boost::json::object balancesObj; - if (not balances.empty()) { - for (auto const& [accId, accBalances] : balances) { - boost::json::array arr; - for (auto const& balance : accBalances) { - boost::json::object entry; - entry[JS(currency)] = ripple::to_string(balance.issue().currency); - entry[JS(value)] = balance.getText(); - arr.push_back(std::move(entry)); + if (not balances.empty()) { + for (auto const& [accId, accBalances] : balances) { + boost::json::array arr; + for (auto const& balance : accBalances) { + boost::json::object entry; + entry[JS(currency)] = ripple::to_string(balance.issue().currency); + entry[JS(value)] = balance.getText(); + arr.push_back(std::move(entry)); + } + + balancesObj[ripple::to_string(accId)] = std::move(arr); } - - balancesObj[ripple::to_string(accId)] = std::move(arr); } - } - return balancesObj; - }; + return balancesObj; + }; if (auto balances = toJson(output.hotBalances); !balances.empty()) obj[JS(balances)] = balances; @@ -257,7 +270,9 @@ tag_invoke(boost::json::value_to_tag, boost::json if (jsonObject.contains(JS(hotwallet))) { if (jsonObject.at(JS(hotwallet)).is_string()) { - input.hotWallets.insert(*accountFromStringStrict(boost::json::value_to(jv.at(JS(hotwallet))))); + input.hotWallets.insert( + *accountFromStringStrict(boost::json::value_to(jv.at(JS(hotwallet)))) + ); } else { auto const& hotWallets = jv.at(JS(hotwallet)).as_array(); std::ranges::transform( diff --git a/src/rpc/handlers/GatewayBalances.hpp b/src/rpc/handlers/GatewayBalances.hpp index d354c6325..89d4e6f06 100644 --- a/src/rpc/handlers/GatewayBalances.hpp +++ b/src/rpc/handlers/GatewayBalances.hpp @@ -52,8 +52,8 @@ namespace rpc { /** * @brief Handles the `gateway_balances` command * - * The gateway_balances command calculates the total balances issued by a given account, optionally excluding amounts - * held by operational addresses. + * The gateway_balances command calculates the total balances issued by a given account, optionally + * excluding amounts held by operational addresses. * * For more details see: https://xrpl.org/gateway_balances.html#gateway_balances */ @@ -116,17 +116,22 @@ public: return Error{Status{errCode, std::string(key) + "NotStringOrArray"}}; // wallet needs to be an valid accountID or public key - auto const wallets = value.is_array() ? value.as_array() : boost::json::array{value}; - auto const getAccountID = [](auto const& j) -> std::optional { + auto const wallets = + value.is_array() ? value.as_array() : boost::json::array{value}; + auto const getAccountID = + [](auto const& j) -> std::optional { if (j.is_string()) { auto const pk = util::parseBase58Wrapper( - ripple::TokenType::AccountPublic, boost::json::value_to(j) + ripple::TokenType::AccountPublic, + boost::json::value_to(j) ); if (pk) return ripple::calcAccountID(*pk); - return util::parseBase58Wrapper(boost::json::value_to(j)); + return util::parseBase58Wrapper( + boost::json::value_to(j) + ); } return {}; @@ -148,10 +153,12 @@ public: {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator} }; - static auto const kSPEC_V1 = - RpcSpec{kSPEC_COMMON, {{JS(hotwallet), getHotWalletValidator(ripple::rpcINVALID_HOTWALLET)}}}; - static auto const kSPEC_V2 = - RpcSpec{kSPEC_COMMON, {{JS(hotwallet), getHotWalletValidator(ripple::rpcINVALID_PARAMS)}}}; + static auto const kSPEC_V1 = RpcSpec{ + kSPEC_COMMON, {{JS(hotwallet), getHotWalletValidator(ripple::rpcINVALID_HOTWALLET)}} + }; + static auto const kSPEC_V2 = RpcSpec{ + kSPEC_COMMON, {{JS(hotwallet), getHotWalletValidator(ripple::rpcINVALID_PARAMS)}} + }; return apiVersion == 1 ? kSPEC_V1 : kSPEC_V2; } diff --git a/src/rpc/handlers/GetAggregatePrice.cpp b/src/rpc/handlers/GetAggregatePrice.cpp index f09e2f7c2..3f4023b4e 100644 --- a/src/rpc/handlers/GetAggregatePrice.cpp +++ b/src/rpc/handlers/GetAggregatePrice.cpp @@ -59,7 +59,10 @@ namespace rpc { GetAggregatePriceHandler::Result -GetAggregatePriceHandler::process(GetAggregatePriceHandler::Input const& input, Context const& ctx) const +GetAggregatePriceHandler::process( + GetAggregatePriceHandler::Input const& input, + Context const& ctx +) const { auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "GetAggregatePrice's ledger range must be available"); @@ -83,7 +86,8 @@ GetAggregatePriceHandler::process(GetAggregatePriceHandler::Input const& input, for (auto const& oracle : input.oracles) { auto const oracleIndex = ripple::keylet::oracle(oracle.account, oracle.documentId).key; - auto const oracleObject = sharedPtrBackend_->fetchLedgerObject(oracleIndex, lgrInfo.seq, ctx.yield); + auto const oracleObject = + sharedPtrBackend_->fetchLedgerObject(oracleIndex, lgrInfo.seq, ctx.yield); if (not oracleObject) continue; @@ -98,20 +102,24 @@ GetAggregatePriceHandler::process(GetAggregatePriceHandler::Input const& input, series.begin(), series.end(), [&](ripple::STObject const& o) -> bool { - return o.getFieldCurrency(ripple::sfBaseAsset).getText() == input.baseAsset and - o.getFieldCurrency(ripple::sfQuoteAsset).getText() == input.quoteAsset and + return o.getFieldCurrency(ripple::sfBaseAsset).getText() == + input.baseAsset and + o.getFieldCurrency(ripple::sfQuoteAsset).getText() == + input.quoteAsset and o.isFieldPresent(ripple::sfAssetPrice); } ); iter != series.end()) { auto const price = iter->getFieldU64(ripple::sfAssetPrice); // Asset price is after scale, so we need to get the negative of the scale - auto const scale = - iter->isFieldPresent(ripple::sfScale) ? -static_cast(iter->getFieldU8(ripple::sfScale)) : 0; + auto const scale = iter->isFieldPresent(ripple::sfScale) + ? -static_cast(iter->getFieldU8(ripple::sfScale)) + : 0; timestampPricesBiMap.insert( TimestampPricesBiMap::value_type( - node.getFieldU32(ripple::sfLastUpdateTime), ripple::STAmount{ripple::noIssue(), price, scale} + node.getFieldU32(ripple::sfLastUpdateTime), + ripple::STAmount{ripple::noIssue(), price, scale} ) ); return true; @@ -135,9 +143,11 @@ GetAggregatePriceHandler::process(GetAggregatePriceHandler::Input const& input, if (input.timeThreshold) { auto const oldestTime = timestampPricesBiMap.left.rbegin()->first; - auto const upperBound = latestTime > *input.timeThreshold ? (latestTime - *input.timeThreshold) : oldestTime; + auto const upperBound = + latestTime > *input.timeThreshold ? (latestTime - *input.timeThreshold) : oldestTime; if (upperBound > oldestTime) { - // Note : upperBound must not be greater than the latestTime, so timestampPricesBiMap can not be empty + // Note : upperBound must not be greater than the latestTime, so timestampPricesBiMap + // can not be empty timestampPricesBiMap.left.erase( timestampPricesBiMap.left.upper_bound(upperBound), timestampPricesBiMap.left.end() ); @@ -162,7 +172,8 @@ GetAggregatePriceHandler::process(GetAggregatePriceHandler::Input const& input, return {.avg = avg, .sd = sd, .size = size}; }; - out.extireStats = getStats(timestampPricesBiMap.right.begin(), timestampPricesBiMap.right.end()); + out.extireStats = + getStats(timestampPricesBiMap.right.begin(), timestampPricesBiMap.right.end()); auto const itAdvance = [&](auto it, int distance) { std::advance(it, distance); @@ -246,8 +257,9 @@ GetAggregatePriceHandler::tracebackOracleObject( if (isNew and history == 1) return; - optOracleObject = isNew ? dynamic_cast(node.peekAtField(ripple::sfNewFields)) - : dynamic_cast(node.peekAtField(ripple::sfFinalFields)); + optOracleObject = isNew + ? dynamic_cast(node.peekAtField(ripple::sfNewFields)) + : dynamic_cast(node.peekAtField(ripple::sfFinalFields)); break; } @@ -272,7 +284,9 @@ tag_invoke(boost::json::value_to_tag, boost::js for (auto const& oracle : jsonObject.at(JS(oracles)).as_array()) { input.oracles.push_back( GetAggregatePriceHandler::Oracle{ - .documentId = boost::json::value_to(oracle.as_object().at(JS(oracle_document_id))), + .documentId = boost::json::value_to( + oracle.as_object().at(JS(oracle_document_id)) + ), .account = *util::parseBase58Wrapper( boost::json::value_to(oracle.as_object().at(JS(account))) ) @@ -292,7 +306,11 @@ tag_invoke(boost::json::value_to_tag, boost::js } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, GetAggregatePriceHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + GetAggregatePriceHandler::Output const& output +) { jv = boost::json::object{ {JS(ledger_hash), output.ledgerHash}, diff --git a/src/rpc/handlers/GetAggregatePrice.hpp b/src/rpc/handlers/GetAggregatePrice.hpp index 9d2953493..32b729ac0 100644 --- a/src/rpc/handlers/GetAggregatePrice.hpp +++ b/src/rpc/handlers/GetAggregatePrice.hpp @@ -121,18 +121,21 @@ public: { static constexpr auto kORACLES_MAX = 200; - static auto const kORACLES_VALIDATOR = - modifiers::CustomModifier{[](boost::json::value& value, std::string_view) -> MaybeError { - if (!value.is_array() or value.as_array().empty() or value.as_array().size() > kORACLES_MAX) + static auto const kORACLES_VALIDATOR = modifiers::CustomModifier{ + [](boost::json::value& value, std::string_view) -> MaybeError { + if (!value.is_array() or value.as_array().empty() or + value.as_array().size() > kORACLES_MAX) return Error{Status{RippledError::rpcORACLE_MALFORMED}}; for (auto& oracle : value.as_array()) { - if (!oracle.is_object() or !oracle.as_object().contains(JS(oracle_document_id)) or + if (!oracle.is_object() or + !oracle.as_object().contains(JS(oracle_document_id)) or !oracle.as_object().contains(JS(account))) return Error{Status{RippledError::rpcORACLE_MALFORMED}}; - auto maybeError = - validation::Type{}.verify(oracle, JS(oracle_document_id)); + auto maybeError = validation::Type{}.verify( + oracle, JS(oracle_document_id) + ); if (!maybeError) return maybeError; @@ -140,30 +143,36 @@ public: if (!maybeError) return maybeError; - maybeError = - validation::CustomValidators::accountBase58Validator.verify(oracle.as_object(), JS(account)); + maybeError = validation::CustomValidators::accountBase58Validator.verify( + oracle.as_object(), JS(account) + ); if (!maybeError) return Error{Status{RippledError::rpcINVALID_PARAMS}}; }; return MaybeError{}; - }}; + } + }; static auto const kRPC_SPEC = RpcSpec{ {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, - // validate quoteAsset and base_asset in accordance to the currency code found in XRPL doc: + // validate quoteAsset and base_asset in accordance to the currency code found in XRPL + // doc: // https://xrpl.org/docs/references/protocol/data-types/currency-formats#currency-codes - // usually Clio returns rpcMALFORMED_CURRENCY , return InvalidParam here just to mimic rippled + // usually Clio returns rpcMALFORMED_CURRENCY , return InvalidParam here just to mimic + // rippled {JS(base_asset), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::currencyValidator, Status(RippledError::rpcINVALID_PARAMS) + validation::CustomValidators::currencyValidator, + Status(RippledError::rpcINVALID_PARAMS) }}, {JS(quote_asset), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::currencyValidator, Status(RippledError::rpcINVALID_PARAMS) + validation::CustomValidators::currencyValidator, + Status(RippledError::rpcINVALID_PARAMS) }}, {JS(oracles), validation::Required{}, kORACLES_VALIDATOR}, // note: Unlike `rippled`, Clio only supports UInt as input, no string, no `null`, etc. @@ -191,8 +200,8 @@ public: private: /** * @brief Calls callback on the oracle ledger entry - If the oracle entry does not contains the price pair, search up to three previous metadata objects. Stops early if - the callback returns true. + If the oracle entry does not contains the price pair, search up to three previous metadata + objects. Stops early if the callback returns true. */ void tracebackOracleObject( diff --git a/src/rpc/handlers/Ledger.cpp b/src/rpc/handlers/Ledger.cpp index 69923636c..13609577c 100644 --- a/src/rpc/handlers/Ledger.cpp +++ b/src/rpc/handlers/Ledger.cpp @@ -118,7 +118,8 @@ LedgerHandler::process(LedgerHandler::Input const& input, Context const& ctx) co std::move_iterator(txns.end()), std::back_inserter(jsonTxs), [&](auto obj) { - boost::json::object entry = ctx.apiVersion < 2u ? expandTxJsonV1(obj) : expandTxJsonV2(obj); + boost::json::object entry = + ctx.apiVersion < 2u ? expandTxJsonV1(obj) : expandTxJsonV2(obj); if (input.ownerFunds) { // check the type of tx @@ -149,7 +150,8 @@ LedgerHandler::process(LedgerHandler::Input const& input, Context const& ctx) co } ); } else { - auto hashes = sharedPtrBackend_->fetchAllTransactionHashesInLedger(lgrInfo.seq, ctx.yield); + auto hashes = + sharedPtrBackend_->fetchAllTransactionHashesInLedger(lgrInfo.seq, ctx.yield); std::transform( std::move_iterator(hashes.begin()), std::move_iterator(hashes.end()), @@ -172,7 +174,9 @@ LedgerHandler::process(LedgerHandler::Input const& input, Context const& ctx) co if (input.binary) { entry["object"] = ripple::strHex(obj.blob); } else if (!obj.blob.empty()) { - ripple::STLedgerEntry const sle{ripple::SerialIter{obj.blob.data(), obj.blob.size()}, obj.key}; + ripple::STLedgerEntry const sle{ + ripple::SerialIter{obj.blob.data(), obj.blob.size()}, obj.key + }; entry["object"] = toJson(sle); } else { entry["object"] = ""; diff --git a/src/rpc/handlers/LedgerData.cpp b/src/rpc/handlers/LedgerData.cpp index 9b35eed9b..f0c352372 100644 --- a/src/rpc/handlers/LedgerData.cpp +++ b/src/rpc/handlers/LedgerData.cpp @@ -80,7 +80,8 @@ LedgerDataHandler::process(Input const& input, Context const& ctx) const if ((!input.marker) && (!input.diffMarker)) { output.header = toJson(lgrInfo, input.binary, ctx.apiVersion); } else { - if (input.marker && !sharedPtrBackend_->fetchLedgerObject(*(input.marker), lgrInfo.seq, ctx.yield)) + if (input.marker && + !sharedPtrBackend_->fetchLedgerObject(*(input.marker), lgrInfo.seq, ctx.yield)) return Error{Status{RippledError::rpcINVALID_PARAMS, "markerDoesNotExist"}}; } @@ -113,9 +114,13 @@ LedgerDataHandler::process(Input const& input, Context const& ctx) const } else { // limit's limitation is different based on binary or json // framework can not handler the check right now, adjust the value here - auto const limit = - std::min(input.limit, input.binary ? LedgerDataHandler::kLIMIT_BINARY : LedgerDataHandler::kLIMIT_JSON); - auto page = sharedPtrBackend_->fetchLedgerPage(input.marker, lgrInfo.seq, limit, input.outOfOrder, ctx.yield); + auto const limit = std::min( + input.limit, + input.binary ? LedgerDataHandler::kLIMIT_BINARY : LedgerDataHandler::kLIMIT_JSON + ); + auto page = sharedPtrBackend_->fetchLedgerPage( + input.marker, lgrInfo.seq, limit, input.outOfOrder, ctx.yield + ); results = std::move(page.objects); if (page.cursor) { @@ -127,7 +132,8 @@ LedgerDataHandler::process(Input const& input, Context const& ctx) const auto const end = std::chrono::system_clock::now(); LOG(log_.debug()) << "Number of results = " << results.size() << " fetched in " - << std::chrono::duration_cast(end - start).count() << " microseconds"; + << std::chrono::duration_cast(end - start).count() + << " microseconds"; output.states.reserve(results.size()); @@ -152,13 +158,18 @@ LedgerDataHandler::process(Input const& input, Context const& ctx) const auto const end2 = std::chrono::system_clock::now(); LOG(log_.debug()) << "Number of results = " << results.size() << " serialized in " - << std::chrono::duration_cast(end2 - end).count() << " microseconds"; + << std::chrono::duration_cast(end2 - end).count() + << " microseconds"; return output; } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, LedgerDataHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + LedgerDataHandler::Output const& output +) { auto obj = boost::json::object{ {JS(ledger_hash), output.ledgerHash}, @@ -190,7 +201,8 @@ tag_invoke(boost::json::value_to_tag, boost::json::val if (jsonObject.contains(JS(binary))) { input.binary = jsonObject.at(JS(binary)).as_bool(); - input.limit = input.binary ? LedgerDataHandler::kLIMIT_BINARY : LedgerDataHandler::kLIMIT_JSON; + input.limit = + input.binary ? LedgerDataHandler::kLIMIT_BINARY : LedgerDataHandler::kLIMIT_JSON; } if (jsonObject.contains(JS(limit))) @@ -201,7 +213,9 @@ tag_invoke(boost::json::value_to_tag, boost::json::val if (jsonObject.contains(JS(marker))) { if (jsonObject.at(JS(marker)).is_string()) { - input.marker = ripple::uint256{boost::json::value_to(jsonObject.at(JS(marker))).data()}; + input.marker = ripple::uint256{ + boost::json::value_to(jsonObject.at(JS(marker))).data() + }; } else { input.diffMarker = util::integralValueAs(jsonObject.at(JS(marker))); } @@ -217,7 +231,9 @@ tag_invoke(boost::json::value_to_tag, boost::json::val } if (jsonObject.contains(JS(type))) - input.type = util::LedgerTypes::getLedgerEntryTypeFromStr(boost::json::value_to(jv.at(JS(type)))); + input.type = util::LedgerTypes::getLedgerEntryTypeFromStr( + boost::json::value_to(jv.at(JS(type))) + ); return input; } diff --git a/src/rpc/handlers/LedgerData.hpp b/src/rpc/handlers/LedgerData.hpp index 5fbc8ba6b..88f389648 100644 --- a/src/rpc/handlers/LedgerData.hpp +++ b/src/rpc/handlers/LedgerData.hpp @@ -44,8 +44,8 @@ namespace rpc { /** - * @brief The ledger_data method retrieves contents of the specified ledger. You can iterate through several calls to - * retrieve the entire contents of a single ledger version. + * @brief The ledger_data method retrieves contents of the specified ledger. You can iterate through + * several calls to retrieve the entire contents of a single ledger version. * * For more details see: https://xrpl.org/ledger_data.html */ @@ -76,8 +76,8 @@ public: /** * @brief A struct to hold the input data for the command * - * @note `outOfOrder` is only for Clio, there is no document, traverse via seq diff (outOfOrder implementation is - * copied from old rpc handler) + * @note `outOfOrder` is only for Clio, there is no document, traverse via seq diff (outOfOrder + * implementation is copied from old rpc handler) */ struct Input { std::optional ledgerHash; @@ -97,7 +97,8 @@ public: * * @param sharedPtrBackend The backend to use */ - LedgerDataHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + LedgerDataHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } diff --git a/src/rpc/handlers/LedgerEntry.cpp b/src/rpc/handlers/LedgerEntry.cpp index 41c912fb2..030875691 100644 --- a/src/rpc/handlers/LedgerEntry.cpp +++ b/src/rpc/handlers/LedgerEntry.cpp @@ -68,7 +68,10 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons if (key.isZero()) return Error{Status{RippledError::rpcENTRY_NOT_FOUND}}; } else if (input.accountRoot) { - key = ripple::keylet::account(*util::parseBase58Wrapper(*(input.accountRoot))).key; + key = ripple::keylet::account( + *util::parseBase58Wrapper(*(input.accountRoot)) + ) + .key; } else if (input.did) { key = ripple::keylet::did(*util::parseBase58Wrapper(*(input.did))).key; } else if (input.directory) { @@ -81,23 +84,31 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons auto const id = util::parseBase58Wrapper( boost::json::value_to(input.offer->at(JS(account))) ); - key = ripple::keylet::offer(*id, boost::json::value_to(input.offer->at(JS(seq)))).key; + key = ripple::keylet::offer( + *id, boost::json::value_to(input.offer->at(JS(seq))) + ) + .key; } else if (input.rippleStateAccount) { - auto const id1 = util::parseBase58Wrapper( - boost::json::value_to(input.rippleStateAccount->at(JS(accounts)).as_array().at(0)) + auto const id1 = + util::parseBase58Wrapper(boost::json::value_to( + input.rippleStateAccount->at(JS(accounts)).as_array().at(0) + )); + auto const id2 = + util::parseBase58Wrapper(boost::json::value_to( + input.rippleStateAccount->at(JS(accounts)).as_array().at(1) + )); + auto const currency = ripple::to_currency( + boost::json::value_to(input.rippleStateAccount->at(JS(currency))) ); - auto const id2 = util::parseBase58Wrapper( - boost::json::value_to(input.rippleStateAccount->at(JS(accounts)).as_array().at(1)) - ); - auto const currency = - ripple::to_currency(boost::json::value_to(input.rippleStateAccount->at(JS(currency)))); key = ripple::keylet::line(*id1, *id2, currency).key; } else if (input.escrow) { auto const id = util::parseBase58Wrapper( boost::json::value_to(input.escrow->at(JS(owner))) ); - key = ripple::keylet::escrow(*id, util::integralValueAs(input.escrow->at(JS(seq)))).key; + key = + ripple::keylet::escrow(*id, util::integralValueAs(input.escrow->at(JS(seq)))) + .key; } else if (input.depositPreauth) { auto const owner = util::parseBase58Wrapper( boost::json::value_to(input.depositPreauth->at(JS(owner))) @@ -105,9 +116,10 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons // Only one of authorize or authorized_credentials MUST exist; if (input.depositPreauth->contains(JS(authorized)) == input.depositPreauth->contains(JS(authorized_credentials))) { - return Error{ - Status{ClioError::RpcMalformedRequest, "Must have one of authorized or authorized_credentials."} - }; + return Error{Status{ + ClioError::RpcMalformedRequest, + "Must have one of authorized or authorized_credentials." + }}; } if (input.depositPreauth->contains(JS(authorized))) { @@ -122,7 +134,9 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons auto const authCreds = credentials::createAuthCredentials(authorizedCredentials); if (authCreds.size() != authorizedCredentials.size()) - return Error{Status{ClioError::RpcMalformedAuthorizedCredentials, "duplicates in credentials."}}; + return Error{Status{ + ClioError::RpcMalformedAuthorizedCredentials, "duplicates in credentials." + }}; key = ripple::keylet::depositPreauth(owner.value(), authCreds).key; } @@ -131,11 +145,14 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons boost::json::value_to(input.ticket->at(JS(account))) ); - key = ripple::getTicketIndex(*id, util::integralValueAs(input.ticket->at(JS(ticket_seq)))); + key = ripple::getTicketIndex( + *id, util::integralValueAs(input.ticket->at(JS(ticket_seq))) + ); } else if (input.amm) { auto const getIssuerFromJson = [](auto const& assetJson) { // the field check has been done in validator - auto const currency = ripple::to_currency(boost::json::value_to(assetJson.at(JS(currency)))); + auto const currency = + ripple::to_currency(boost::json::value_to(assetJson.at(JS(currency)))); if (ripple::isXRP(currency)) { return ripple::xrpIssue(); } @@ -146,7 +163,8 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons }; key = ripple::keylet::amm( - getIssuerFromJson(input.amm->at(JS(asset))), getIssuerFromJson(input.amm->at(JS(asset2))) + getIssuerFromJson(input.amm->at(JS(asset))), + getIssuerFromJson(input.amm->at(JS(asset2))) ) .key; } else if (input.bridge) { @@ -154,17 +172,22 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons return Error{Status{ClioError::RpcMalformedRequest}}; if (input.bridgeAccount) { - auto const bridgeAccount = util::parseBase58Wrapper(*(input.bridgeAccount)); - auto const chainType = ripple::STXChainBridge::srcChain(bridgeAccount == input.bridge->lockingChainDoor()); + auto const bridgeAccount = + util::parseBase58Wrapper(*(input.bridgeAccount)); + auto const chainType = + ripple::STXChainBridge::srcChain(bridgeAccount == input.bridge->lockingChainDoor()); if (bridgeAccount != input.bridge->door(chainType)) return Error{Status{ClioError::RpcMalformedRequest}}; key = ripple::keylet::bridge(input.bridge->value(), chainType).key; } else if (input.chainClaimId) { - key = ripple::keylet::xChainClaimID(input.bridge->value(), input.chainClaimId.value()).key; + key = ripple::keylet::xChainClaimID(input.bridge->value(), input.chainClaimId.value()) + .key; } else { - key = ripple::keylet::xChainCreateAccountClaimID(input.bridge->value(), input.createAccountClaimId.value()) + key = ripple::keylet::xChainCreateAccountClaimID( + input.bridge->value(), input.createAccountClaimId.value() + ) .key; } } else if (input.oracleNode) { @@ -175,11 +198,12 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons auto const mptIssuanceID = ripple::uint192{std::string_view(*(input.mptIssuance))}; key = ripple::keylet::mptIssuance(mptIssuanceID).key; } else if (input.mptoken) { - auto const holder = - ripple::parseBase58(boost::json::value_to(input.mptoken->at(JS(account)))); - auto const mptIssuanceID = ripple::uint192{ - std::string_view(boost::json::value_to(input.mptoken->at(JS(mpt_issuance_id)))) - }; + auto const holder = ripple::parseBase58( + boost::json::value_to(input.mptoken->at(JS(account))) + ); + auto const mptIssuanceID = ripple::uint192{std::string_view( + boost::json::value_to(input.mptoken->at(JS(mpt_issuance_id))) + )}; key = ripple::keylet::mptoken(mptIssuanceID, *holder).key; } else if (input.permissionedDomain) { auto const account = ripple::parseBase58( @@ -188,22 +212,27 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons auto const seq = util::integralValueAs(input.permissionedDomain->at(JS(seq))); key = ripple::keylet::permissionedDomain(*account, seq).key; } else if (input.vault) { - auto const account = - ripple::parseBase58(boost::json::value_to(input.vault->at(JS(owner)))); + auto const account = ripple::parseBase58( + boost::json::value_to(input.vault->at(JS(owner))) + ); auto const seq = util::integralValueAs(input.vault->at(JS(seq))); key = ripple::keylet::vault(*account, seq).key; } else if (input.loanBroker) { - auto const account = - ripple::parseBase58(boost::json::value_to(input.loanBroker->at(JS(owner)))); + auto const account = ripple::parseBase58( + boost::json::value_to(input.loanBroker->at(JS(owner))) + ); auto const seq = util::integralValueAs(input.loanBroker->at(JS(seq))); key = ripple::keylet::loanbroker(*account, seq).key; } else if (input.loan) { - auto const id = ripple::uint256{boost::json::value_to(input.loan->at(JS(loan_broker_id))).data()}; + auto const id = ripple::uint256{ + boost::json::value_to(input.loan->at(JS(loan_broker_id))).data() + }; auto const seq = util::integralValueAs(input.loan->at(JS(loan_seq))); key = ripple::keylet::loan(id, seq).key; } else if (input.delegate) { - auto const account = - ripple::parseBase58(boost::json::value_to(input.delegate->at(JS(account)))); + auto const account = ripple::parseBase58( + boost::json::value_to(input.delegate->at(JS(account))) + ); auto const authorize = ripple::parseBase58( boost::json::value_to(input.delegate->at(JS(authorize))) ); @@ -232,7 +261,8 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons if (!ledgerObject || ledgerObject->empty()) { if (not input.includeDeleted) return Error{Status{RippledError::rpcENTRY_NOT_FOUND}}; - auto const deletedSeq = sharedPtrBackend_->fetchLedgerObjectSeq(key, lgrInfo.seq, ctx.yield); + auto const deletedSeq = + sharedPtrBackend_->fetchLedgerObjectSeq(key, lgrInfo.seq, ctx.yield); if (!deletedSeq) return Error{Status{RippledError::rpcENTRY_NOT_FOUND}}; ledgerObject = sharedPtrBackend_->fetchLedgerObject(key, deletedSeq.value() - 1, ctx.yield); @@ -241,7 +271,9 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input const& input, Context cons output.deletedLedgerIndex = deletedSeq; } - ripple::STLedgerEntry const sle{ripple::SerialIter{ledgerObject->data(), ledgerObject->size()}, key}; + ripple::STLedgerEntry const sle{ + ripple::SerialIter{ledgerObject->data(), ledgerObject->size()}, key + }; if (input.expectedType != ripple::ltANY && sle.getType() != input.expectedType) return Error{Status{RippledError::rpcUNEXPECTED_LEDGER_TYPE}}; @@ -264,27 +296,37 @@ LedgerEntryHandler::composeKeyFromDirectory(boost::json::object const& directory { // can not specify both dir_root and owner. if (directory.contains(JS(dir_root)) && directory.contains(JS(owner))) - return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "mayNotSpecifyBothDirRootAndOwner"}}; + return std::unexpected{ + Status{RippledError::rpcINVALID_PARAMS, "mayNotSpecifyBothDirRootAndOwner"} + }; // at least one should available if (!(directory.contains(JS(dir_root)) || directory.contains(JS(owner)))) return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "missingOwnerOrDirRoot"}}; - uint64_t const subIndex = - directory.contains(JS(sub_index)) ? boost::json::value_to(directory.at(JS(sub_index))) : 0; + uint64_t const subIndex = directory.contains(JS(sub_index)) + ? boost::json::value_to(directory.at(JS(sub_index))) + : 0; if (directory.contains(JS(dir_root))) { - ripple::uint256 const uDirRoot{boost::json::value_to(directory.at(JS(dir_root))).data()}; + ripple::uint256 const uDirRoot{ + boost::json::value_to(directory.at(JS(dir_root))).data() + }; return ripple::keylet::page(uDirRoot, subIndex).key; } - auto const ownerID = - util::parseBase58Wrapper(boost::json::value_to(directory.at(JS(owner)))); + auto const ownerID = util::parseBase58Wrapper( + boost::json::value_to(directory.at(JS(owner))) + ); return ripple::keylet::page(ripple::keylet::ownerDir(*ownerID), subIndex).key; } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, LedgerEntryHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + LedgerEntryHandler::Output const& output +) { auto object = boost::json::object{ {JS(ledger_hash), output.ledgerHash}, @@ -324,72 +366,86 @@ tag_invoke(boost::json::value_to_tag, boost::json::va input.binary = jv.at(JS(binary)).as_bool(); // check all the potential index - static auto const kINDEX_FIELD_TYPE_MAP = std::unordered_map{ - {JS(index), ripple::ltANY}, - {JS(directory), ripple::ltDIR_NODE}, - {JS(offer), ripple::ltOFFER}, - {JS(check), ripple::ltCHECK}, - {JS(escrow), ripple::ltESCROW}, - {JS(payment_channel), ripple::ltPAYCHAN}, - {JS(deposit_preauth), ripple::ltDEPOSIT_PREAUTH}, - {JS(ticket), ripple::ltTICKET}, - {JS(nft_page), ripple::ltNFTOKEN_PAGE}, - {JS(amm), ripple::ltAMM}, - {JS(xchain_owned_create_account_claim_id), ripple::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, - {JS(xchain_owned_claim_id), ripple::ltXCHAIN_OWNED_CLAIM_ID}, - {JS(oracle), ripple::ltORACLE}, - {JS(credential), ripple::ltCREDENTIAL}, - {JS(mptoken), ripple::ltMPTOKEN}, - {JS(permissioned_domain), ripple::ltPERMISSIONED_DOMAIN}, - {JS(vault), ripple::ltVAULT}, - {JS(loan_broker), ripple::ltLOAN_BROKER}, - {JS(loan), ripple::ltLOAN}, - {JS(delegate), ripple::ltDELEGATE}, - {JS(amendments), ripple::ltAMENDMENTS}, - {JS(fee), ripple::ltFEE_SETTINGS}, - {JS(hashes), ripple::ltLEDGER_HASHES}, - {JS(nft_offer), ripple::ltNFTOKEN_OFFER}, - {JS(nunl), ripple::ltNEGATIVE_UNL}, - {JS(signer_list), ripple::ltSIGNER_LIST}, - }; + static auto const kINDEX_FIELD_TYPE_MAP = + std::unordered_map{ + {JS(index), ripple::ltANY}, + {JS(directory), ripple::ltDIR_NODE}, + {JS(offer), ripple::ltOFFER}, + {JS(check), ripple::ltCHECK}, + {JS(escrow), ripple::ltESCROW}, + {JS(payment_channel), ripple::ltPAYCHAN}, + {JS(deposit_preauth), ripple::ltDEPOSIT_PREAUTH}, + {JS(ticket), ripple::ltTICKET}, + {JS(nft_page), ripple::ltNFTOKEN_PAGE}, + {JS(amm), ripple::ltAMM}, + {JS(xchain_owned_create_account_claim_id), + ripple::ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, + {JS(xchain_owned_claim_id), ripple::ltXCHAIN_OWNED_CLAIM_ID}, + {JS(oracle), ripple::ltORACLE}, + {JS(credential), ripple::ltCREDENTIAL}, + {JS(mptoken), ripple::ltMPTOKEN}, + {JS(permissioned_domain), ripple::ltPERMISSIONED_DOMAIN}, + {JS(vault), ripple::ltVAULT}, + {JS(loan_broker), ripple::ltLOAN_BROKER}, + {JS(loan), ripple::ltLOAN}, + {JS(delegate), ripple::ltDELEGATE}, + {JS(amendments), ripple::ltAMENDMENTS}, + {JS(fee), ripple::ltFEE_SETTINGS}, + {JS(hashes), ripple::ltLEDGER_HASHES}, + {JS(nft_offer), ripple::ltNFTOKEN_OFFER}, + {JS(nunl), ripple::ltNEGATIVE_UNL}, + {JS(signer_list), ripple::ltSIGNER_LIST}, + }; auto const parseBridgeFromJson = [](boost::json::value const& bridgeJson) { - auto const lockingDoor = *util::parseBase58Wrapper( - boost::json::value_to(bridgeJson.at(ripple::sfLockingChainDoor.getJsonName().c_str())) + auto const lockingDoor = + *util::parseBase58Wrapper(boost::json::value_to( + bridgeJson.at(ripple::sfLockingChainDoor.getJsonName().c_str()) + )); + auto const issuingDoor = + *util::parseBase58Wrapper(boost::json::value_to( + bridgeJson.at(ripple::sfIssuingChainDoor.getJsonName().c_str()) + )); + auto const lockingIssue = parseIssue( + bridgeJson.at(ripple::sfLockingChainIssue.getJsonName().c_str()).as_object() ); - auto const issuingDoor = *util::parseBase58Wrapper( - boost::json::value_to(bridgeJson.at(ripple::sfIssuingChainDoor.getJsonName().c_str())) + auto const issuingIssue = parseIssue( + bridgeJson.at(ripple::sfIssuingChainIssue.getJsonName().c_str()).as_object() ); - auto const lockingIssue = - parseIssue(bridgeJson.at(ripple::sfLockingChainIssue.getJsonName().c_str()).as_object()); - auto const issuingIssue = - parseIssue(bridgeJson.at(ripple::sfIssuingChainIssue.getJsonName().c_str()).as_object()); return ripple::STXChainBridge{lockingDoor, lockingIssue, issuingDoor, issuingIssue}; }; auto const parseOracleFromJson = [](boost::json::value const& json) { - auto const account = - util::parseBase58Wrapper(boost::json::value_to(json.at(JS(account)))); + auto const account = util::parseBase58Wrapper( + boost::json::value_to(json.at(JS(account))) + ); auto const documentId = boost::json::value_to(json.at(JS(oracle_document_id))); return ripple::keylet::oracle(*account, documentId).key; }; auto const parseCredentialFromJson = [](boost::json::value const& json) { - auto const subject = - util::parseBase58Wrapper(boost::json::value_to(json.at(JS(subject)))); - auto const issuer = - util::parseBase58Wrapper(boost::json::value_to(json.at(JS(issuer)))); - auto const credType = ripple::strUnHex(boost::json::value_to(json.at(JS(credential_type)))); + auto const subject = util::parseBase58Wrapper( + boost::json::value_to(json.at(JS(subject))) + ); + auto const issuer = util::parseBase58Wrapper( + boost::json::value_to(json.at(JS(issuer))) + ); + auto const credType = + ripple::strUnHex(boost::json::value_to(json.at(JS(credential_type)))); - return ripple::keylet::credential(*subject, *issuer, ripple::Slice(credType->data(), credType->size())).key; + return ripple::keylet::credential( + *subject, *issuer, ripple::Slice(credType->data(), credType->size()) + ) + .key; }; - auto const indexFieldType = std::ranges::find_if(kINDEX_FIELD_TYPE_MAP, [&jsonObject](auto const& pair) { - auto const& [field, _] = pair; - return jsonObject.contains(field) && jsonObject.at(field).is_string(); - }); + auto const indexFieldType = + std::ranges::find_if(kINDEX_FIELD_TYPE_MAP, [&jsonObject](auto const& pair) { + auto const& [field, _] = pair; + return jsonObject.contains(field) && jsonObject.at(field).is_string(); + }); if (indexFieldType != kINDEX_FIELD_TYPE_MAP.end()) { input.index = boost::json::value_to(jv.at(indexFieldType->first)); @@ -424,13 +480,14 @@ tag_invoke(boost::json::value_to_tag, boost::json::va input.bridgeAccount = boost::json::value_to(jv.at(JS(bridge_account))); } else if (jsonObject.contains(JS(xchain_owned_claim_id))) { input.bridge.emplace(parseBridgeFromJson(jv.at(JS(xchain_owned_claim_id)))); - input.chainClaimId = - boost::json::value_to(jv.at(JS(xchain_owned_claim_id)).at(JS(xchain_owned_claim_id))); + input.chainClaimId = boost::json::value_to( + jv.at(JS(xchain_owned_claim_id)).at(JS(xchain_owned_claim_id)) + ); } else if (jsonObject.contains(JS(xchain_owned_create_account_claim_id))) { input.bridge.emplace(parseBridgeFromJson(jv.at(JS(xchain_owned_create_account_claim_id)))); - input.createAccountClaimId = boost::json::value_to( - jv.at(JS(xchain_owned_create_account_claim_id)).at(JS(xchain_owned_create_account_claim_id)) - ); + input.createAccountClaimId = + boost::json::value_to(jv.at(JS(xchain_owned_create_account_claim_id)) + .at(JS(xchain_owned_create_account_claim_id))); } else if (jsonObject.contains(JS(oracle))) { input.oracleNode = parseOracleFromJson(jv.at(JS(oracle))); } else if (jsonObject.contains(JS(credential))) { diff --git a/src/rpc/handlers/LedgerEntry.hpp b/src/rpc/handlers/LedgerEntry.hpp index 97070bf07..33d70a98c 100644 --- a/src/rpc/handlers/LedgerEntry.hpp +++ b/src/rpc/handlers/LedgerEntry.hpp @@ -55,7 +55,8 @@ namespace rpc { /** - * @brief The ledger_entry method returns a single ledger object from the XRP Ledger in its raw format. + * @brief The ledger_entry method returns a single ledger object from the XRP Ledger in its raw + * format. * * For more details see: https://xrpl.org/ledger_entry.html */ @@ -124,7 +125,8 @@ public: * * @param sharedPtrBackend The backend to use */ - LedgerEntryHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + LedgerEntryHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } @@ -140,10 +142,10 @@ public: // Validator only works in this handler // The accounts array must have two different elements // Each element must be a valid address - static auto const kRIPPLE_STATE_ACCOUNTS_CHECK = - validation::CustomValidator{[](boost::json::value const& value, std::string_view /* key */) -> MaybeError { - if (!value.is_array() || value.as_array().size() != 2 || !value.as_array()[0].is_string() || - !value.as_array()[1].is_string() || + static auto const kRIPPLE_STATE_ACCOUNTS_CHECK = validation::CustomValidator{ + [](boost::json::value const& value, std::string_view /* key */) -> MaybeError { + if (!value.is_array() || value.as_array().size() != 2 || + !value.as_array()[0].is_string() || !value.as_array()[1].is_string() || value.as_array()[0].as_string() == value.as_array()[1].as_string()) { return Error{Status{RippledError::rpcINVALID_PARAMS, "malformedAccounts"}}; } @@ -159,14 +161,17 @@ public: return Error{Status{ClioError::RpcMalformedAddress, "malformedAddresses"}}; return MaybeError{}; - }}; - - static auto const kMALFORMED_REQUEST_HEX_STRING_VALIDATOR = meta::WithCustomError{ - validation::CustomValidators::uint256HexStringValidator, Status(ClioError::RpcMalformedRequest) + } }; - static auto const kMALFORMED_REQUEST_INT_VALIDATOR = - meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}; + static auto const kMALFORMED_REQUEST_HEX_STRING_VALIDATOR = meta::WithCustomError{ + validation::CustomValidators::uint256HexStringValidator, + Status(ClioError::RpcMalformedRequest) + }; + + static auto const kMALFORMED_REQUEST_INT_VALIDATOR = meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }; static auto const kBRIDGE_JSON_VALIDATOR = meta::WithCustomError{ meta::IfType{meta::Section{ @@ -202,10 +207,12 @@ public: {JS(owner), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedOwner) + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedOwner) }}, {JS(authorized), validation::CustomValidators::accountBase58Validator}, - {JS(authorized_credentials), validation::CustomValidators::authorizeCredentialValidator} + {JS(authorized_credentials), + validation::CustomValidators::authorizeCredentialValidator} }, }}, {JS(directory), @@ -224,7 +231,8 @@ public: {JS(owner), validation::Required{}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedOwner) + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedOwner) }}, {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR}, }, @@ -234,7 +242,9 @@ public: meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{ meta::Section{ - {JS(account), validation::Required{}, validation::CustomValidators::accountBase58Validator}, + {JS(account), + validation::Required{}, + validation::CustomValidators::accountBase58Validator}, {JS(seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR}, }, }}, @@ -243,14 +253,18 @@ public: validation::Type{}, meta::Section{ {JS(accounts), validation::Required{}, kRIPPLE_STATE_ACCOUNTS_CHECK}, - {JS(currency), validation::Required{}, validation::CustomValidators::currencyValidator}, + {JS(currency), + validation::Required{}, + validation::CustomValidators::currencyValidator}, }}, {JS(ticket), validation::Type{}, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{ meta::Section{ - {JS(account), validation::Required{}, validation::CustomValidators::accountBase58Validator}, + {JS(account), + validation::Required{}, + validation::CustomValidators::accountBase58Validator}, {JS(ticket_seq), validation::Required{}, kMALFORMED_REQUEST_INT_VALIDATOR}, }, }}, @@ -261,109 +275,149 @@ public: meta::IfType{ meta::Section{ {JS(asset), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, validation::CustomValidators::currencyIssueValidator}, {JS(asset2), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, validation::CustomValidators::currencyIssueValidator}, }, }}, {JS(bridge), - meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}, + meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }, kBRIDGE_JSON_VALIDATOR}, {JS(bridge_account), meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedRequest) + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedRequest) }}, {JS(xchain_owned_claim_id), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) - }, - meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, - kBRIDGE_JSON_VALIDATOR, - meta::WithCustomError{ - meta::IfType{ - meta::Section{{JS(xchain_owned_claim_id), validation::Required{}, validation::Type{}}} - }, + validation::Type{}, Status(ClioError::RpcMalformedRequest) - }}, - {JS(xchain_owned_create_account_claim_id), - meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) }, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, kBRIDGE_JSON_VALIDATOR, meta::WithCustomError{ meta::IfType{meta::Section{ - {JS(xchain_owned_create_account_claim_id), validation::Required{}, validation::Type{}} + {JS(xchain_owned_claim_id), + validation::Required{}, + validation::Type{}} + }}, + Status(ClioError::RpcMalformedRequest) + }}, + {JS(xchain_owned_create_account_claim_id), + meta::WithCustomError{ + validation::Type{}, + Status(ClioError::RpcMalformedRequest) + }, + meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, + kBRIDGE_JSON_VALIDATOR, + meta::WithCustomError{ + meta::IfType{meta::Section{ + {JS(xchain_owned_create_account_claim_id), + validation::Required{}, + validation::Type{}} }}, Status(ClioError::RpcMalformedRequest) }}, {JS(oracle), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) - }, - meta::IfType{ - meta::WithCustomError{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)} + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, + meta::IfType{meta::WithCustomError{ + kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress) + }}, meta::IfType{meta::Section{ {JS(account), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress) - }}, - // note: Unlike `rippled`, Clio only supports UInt as input, no string, no `null`, etc.: - {JS(oracle_document_id), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, - meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedOracleDocumentId) + validation::Required{}, Status(ClioError::RpcMalformedRequest) }, - meta::WithCustomError{modifiers::ToNumber{}, Status(ClioError::RpcMalformedOracleDocumentId)}}, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedAddress) + }}, + // note: Unlike `rippled`, Clio only supports UInt as input, no string, no `null`, + // etc.: + {JS(oracle_document_id), + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, + Status(ClioError::RpcMalformedOracleDocumentId) + }, + meta::WithCustomError{ + modifiers::ToNumber{}, Status(ClioError::RpcMalformedOracleDocumentId) + }}, }}}, {JS(credential), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) - }, - meta::IfType{ - meta::WithCustomError{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress)} + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, + meta::IfType{meta::WithCustomError{ + kMALFORMED_REQUEST_HEX_STRING_VALIDATOR, Status(ClioError::RpcMalformedAddress) + }}, meta::IfType{meta::Section{ {JS(subject), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedAddress) }}, {JS(issuer), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedAddress) }}, { JS(credential_type), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, - meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }, }, }}}, {JS(mpt_issuance), meta::WithCustomError{ - validation::CustomValidators::uint192HexStringValidator, Status(ClioError::RpcMalformedRequest) + validation::CustomValidators::uint192HexStringValidator, + Status(ClioError::RpcMalformedRequest) }}, {JS(mptoken), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{ meta::Section{ { JS(account), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, meta::WithCustomError{ validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress) @@ -371,7 +425,9 @@ public: }, { JS(mpt_issuance_id), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, meta::WithCustomError{ validation::CustomValidators::uint192HexStringValidator, Status(ClioError::RpcMalformedRequest) @@ -381,87 +437,126 @@ public: }}, {JS(permissioned_domain), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{meta::Section{ {JS(seq), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, - meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }}, { JS(account), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedAddress) }, }, }}}, {JS(vault), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{meta::Section{ {JS(seq), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, - meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }}, { JS(owner), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedOwner) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedOwner) }, }, }}}, {JS(loan_broker), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{meta::Section{ {JS(seq), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, - meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }}, { JS(owner), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedOwner) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedOwner) }, }, }}}, {JS(loan), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{meta::Section{ {JS(loan_seq), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, - meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }}, { JS(loan_broker_id), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::uint256HexStringValidator, Status(ClioError::RpcMalformedRequest) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::uint256HexStringValidator, + Status(ClioError::RpcMalformedRequest) }, }, }}}, {JS(delegate), meta::WithCustomError{ - validation::Type{}, Status(ClioError::RpcMalformedRequest) + validation::Type{}, + Status(ClioError::RpcMalformedRequest) }, meta::IfType{kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, meta::IfType{meta::Section{ {JS(account), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedAddress) }}, {JS(authorize), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcMalformedRequest)}, meta::WithCustomError{ - validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedAddress) + validation::Required{}, Status(ClioError::RpcMalformedRequest) + }, + meta::WithCustomError{ + validation::CustomValidators::accountBase58Validator, + Status(ClioError::RpcMalformedAddress) }} }}}, {JS(amendments), kMALFORMED_REQUEST_HEX_STRING_VALIDATOR}, diff --git a/src/rpc/handlers/LedgerIndex.cpp b/src/rpc/handlers/LedgerIndex.cpp index 297d4f047..ab01a1010 100644 --- a/src/rpc/handlers/LedgerIndex.cpp +++ b/src/rpc/handlers/LedgerIndex.cpp @@ -80,12 +80,15 @@ LedgerIndexHandler::process(LedgerIndexHandler::Input const& input, Context cons auto const view = std::ranges::iota_view{minIndex, maxIndex + 1}; - auto const greaterEqLedgerIter = std::ranges::lower_bound( - view, ticks, [&](std::uint32_t ledgerIndex, std::int64_t) { return not earlierThan(ledgerIndex); } - ); + auto const greaterEqLedgerIter = + std::ranges::lower_bound(view, ticks, [&](std::uint32_t ledgerIndex, std::int64_t) { + return not earlierThan(ledgerIndex); + }); if (greaterEqLedgerIter != view.end()) - return fillOutputByIndex(std::max(static_cast(*greaterEqLedgerIter) - 1, minIndex)); + return fillOutputByIndex( + std::max(static_cast(*greaterEqLedgerIter) - 1, minIndex) + ); return fillOutputByIndex(maxIndex); } @@ -102,7 +105,11 @@ tag_invoke(boost::json::value_to_tag, boost::json::va } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, LedgerIndexHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + LedgerIndexHandler::Output const& output +) { jv = boost::json::object{ {JS(ledger_index), output.ledgerIndex}, diff --git a/src/rpc/handlers/LedgerIndex.hpp b/src/rpc/handlers/LedgerIndex.hpp index c22e17b98..803aba2df 100644 --- a/src/rpc/handlers/LedgerIndex.hpp +++ b/src/rpc/handlers/LedgerIndex.hpp @@ -67,7 +67,8 @@ public: * * @param sharedPtrBackend The backend to use */ - LedgerIndexHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + LedgerIndexHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } @@ -81,7 +82,9 @@ public: spec([[maybe_unused]] uint32_t apiVersion) { static auto const kRPC_SPEC = RpcSpec{ - {JS(date), validation::Type{}, validation::TimeFormatValidator{kDATE_FORMAT}}, + {JS(date), + validation::Type{}, + validation::TimeFormatValidator{kDATE_FORMAT}}, }; return kRPC_SPEC; } diff --git a/src/rpc/handlers/LedgerRange.cpp b/src/rpc/handlers/LedgerRange.cpp index cd9e41318..86e1d19e4 100644 --- a/src/rpc/handlers/LedgerRange.cpp +++ b/src/rpc/handlers/LedgerRange.cpp @@ -39,7 +39,11 @@ LedgerRangeHandler::process([[maybe_unused]] Context const& ctx) const } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, LedgerRangeHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + LedgerRangeHandler::Output const& output +) { jv = boost::json::object{ {JS(ledger_index_min), output.range.minSequence}, diff --git a/src/rpc/handlers/LedgerRange.hpp b/src/rpc/handlers/LedgerRange.hpp index 8ac695119..074b6aa91 100644 --- a/src/rpc/handlers/LedgerRange.hpp +++ b/src/rpc/handlers/LedgerRange.hpp @@ -32,7 +32,8 @@ namespace rpc { /** - * @brief The ledger_range command returns the index number of the earliest and latest ledgers that the server has. + * @brief The ledger_range command returns the index number of the earliest and latest ledgers that + * the server has. * * Not documented in the official rippled API docs. */ @@ -54,7 +55,8 @@ public: * * @param sharedPtrBackend The backend to use */ - LedgerRangeHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + LedgerRangeHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } diff --git a/src/rpc/handlers/MPTHolders.cpp b/src/rpc/handlers/MPTHolders.cpp index 86aa3a99a..bec6fa63e 100644 --- a/src/rpc/handlers/MPTHolders.cpp +++ b/src/rpc/handlers/MPTHolders.cpp @@ -63,8 +63,9 @@ MPTHoldersHandler::process(MPTHoldersHandler::Input const& input, Context const& auto const limit = input.limit.value_or(MPTHoldersHandler::kLIMIT_DEFAULT); auto const mptID = ripple::uint192{input.mptID.c_str()}; - auto const issuanceLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::mptIssuance(mptID).key, lgrInfo.seq, ctx.yield); + auto const issuanceLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::mptIssuance(mptID).key, lgrInfo.seq, ctx.yield + ); if (!issuanceLedgerObject) return Error{Status{RippledError::rpcOBJECT_NOT_FOUND, "objectNotFound"}}; @@ -72,7 +73,8 @@ MPTHoldersHandler::process(MPTHoldersHandler::Input const& input, Context const& if (input.marker) cursor = ripple::AccountID{input.marker->c_str()}; - auto const dbResponse = sharedPtrBackend_->fetchMPTHolders(mptID, limit, cursor, lgrInfo.seq, ctx.yield); + auto const dbResponse = + sharedPtrBackend_->fetchMPTHolders(mptID, limit, cursor, lgrInfo.seq, ctx.yield); auto output = MPTHoldersHandler::Output{}; output.mptID = to_string(mptID); output.limit = limit; @@ -80,14 +82,20 @@ MPTHoldersHandler::process(MPTHoldersHandler::Input const& input, Context const& boost::json::array const mpts; for (auto const& mpt : dbResponse.mptokens) { - ripple::STLedgerEntry const sle{ripple::SerialIter{mpt.data(), mpt.size()}, keylet::mptIssuance(mptID).key}; + ripple::STLedgerEntry const sle{ + ripple::SerialIter{mpt.data(), mpt.size()}, keylet::mptIssuance(mptID).key + }; boost::json::object mptJson; mptJson[JS(account)] = toBase58(sle[ripple::sfAccount]); mptJson[JS(flags)] = sle.getFlags(); - mptJson["mpt_amount"] = - toBoostJson(ripple::STUInt64{ripple::sfMPTAmount, sle[ripple::sfMPTAmount]}.getJson(JsonOptions::none)); - mptJson["mptoken_index"] = ripple::to_string(ripple::keylet::mptoken(mptID, sle[ripple::sfAccount]).key); + mptJson["mpt_amount"] = toBoostJson( + ripple::STUInt64{ripple::sfMPTAmount, sle[ripple::sfMPTAmount]}.getJson( + JsonOptions::none + ) + ); + mptJson["mptoken_index"] = + ripple::to_string(ripple::keylet::mptoken(mptID, sle[ripple::sfAccount]).key); output.mpts.push_back(mptJson); } @@ -99,7 +107,11 @@ MPTHoldersHandler::process(MPTHoldersHandler::Input const& input, Context const& } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, MPTHoldersHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + MPTHoldersHandler::Output const& output +) { jv = { {JS(mpt_issuance_id), output.mptID}, diff --git a/src/rpc/handlers/MPTHolders.hpp b/src/rpc/handlers/MPTHolders.hpp index c5b3992ee..d82ac319d 100644 --- a/src/rpc/handlers/MPTHolders.hpp +++ b/src/rpc/handlers/MPTHolders.hpp @@ -39,7 +39,8 @@ namespace rpc { /** - * @brief The mpt_holders command asks the Clio server for all holders of a particular MPTokenIssuance. + * @brief The mpt_holders command asks the Clio server for all holders of a particular + * MPTokenIssuance. */ class MPTHoldersHandler { std::shared_ptr sharedPtrBackend_; @@ -79,7 +80,8 @@ public: * * @param sharedPtrBackend The backend to use */ - MPTHoldersHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + MPTHoldersHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } @@ -93,7 +95,9 @@ public: spec([[maybe_unused]] uint32_t apiVersion) { static auto const kRPC_SPEC = RpcSpec{ - {JS(mpt_issuance_id), validation::Required{}, validation::CustomValidators::uint192HexStringValidator}, + {JS(mpt_issuance_id), + validation::Required{}, + validation::CustomValidators::uint192HexStringValidator}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, {JS(limit), diff --git a/src/rpc/handlers/NFTHistory.cpp b/src/rpc/handlers/NFTHistory.cpp index 9d3dc17ac..27a6a5197 100644 --- a/src/rpc/handlers/NFTHistory.cpp +++ b/src/rpc/handlers/NFTHistory.cpp @@ -78,7 +78,9 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input const& input, Context const& if (input.ledgerHash || input.ledgerIndex) { // rippled does not have this check if (input.ledgerIndexMax || input.ledgerIndexMin) - return Error{Status{RippledError::rpcINVALID_PARAMS, "containsLedgerSpecifierAndRange"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, "containsLedgerSpecifierAndRange"} + }; auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq( *sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence @@ -107,9 +109,12 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input const& input, Context const& auto const tokenID = ripple::uint256{input.nftID.c_str()}; auto const [txnsAndCursor, timeDiff] = util::timed([&]() { - return sharedPtrBackend_->fetchNFTTransactions(tokenID, limit, input.forward, cursor, ctx.yield); + return sharedPtrBackend_->fetchNFTTransactions( + tokenID, limit, input.forward, cursor, ctx.yield + ); }); - LOG(log_.info()) << "db fetch took " << timeDiff << " milliseconds - num blobs = " << txnsAndCursor.txns.size(); + LOG(log_.info()) << "db fetch took " << timeDiff + << " milliseconds - num blobs = " << txnsAndCursor.txns.size(); Output response; auto const [blobs, retCursor] = txnsAndCursor; @@ -144,8 +149,9 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input const& input, Context const& obj[JS(hash)] = obj[txKey].at(JS(hash)); obj[txKey].as_object().erase(JS(hash)); } - if (auto const lgrInfo = - sharedPtrBackend_->fetchLedgerBySequence(txnPlusMeta.ledgerSequence, ctx.yield); + if (auto const lgrInfo = sharedPtrBackend_->fetchLedgerBySequence( + txnPlusMeta.ledgerSequence, ctx.yield + ); lgrInfo) { obj[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo->closeTime); obj[JS(ledger_hash)] = ripple::strHex(lgrInfo->hash); @@ -170,7 +176,11 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input const& input, Context const& } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, NFTHistoryHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + NFTHistoryHandler::Output const& output +) { jv = { {JS(nft_id), output.nftID}, @@ -188,7 +198,11 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, NFTHistoryHandle } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, NFTHistoryHandler::Marker const& marker) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + NFTHistoryHandler::Marker const& marker +) { jv = { {JS(ledger), marker.ledger}, @@ -232,8 +246,11 @@ tag_invoke(boost::json::value_to_tag, boost::json::val if (jsonObject.contains(JS(marker))) { input.marker = NFTHistoryHandler::Marker{ - .ledger = util::integralValueAs(jsonObject.at(JS(marker)).as_object().at(JS(ledger))), - .seq = util::integralValueAs(jsonObject.at(JS(marker)).as_object().at(JS(seq))) + .ledger = util::integralValueAs( + jsonObject.at(JS(marker)).as_object().at(JS(ledger)) + ), + .seq = + util::integralValueAs(jsonObject.at(JS(marker)).as_object().at(JS(seq))) }; } diff --git a/src/rpc/handlers/NFTHistory.hpp b/src/rpc/handlers/NFTHistory.hpp index 58425c1d7..4d91d8d70 100644 --- a/src/rpc/handlers/NFTHistory.hpp +++ b/src/rpc/handlers/NFTHistory.hpp @@ -44,7 +44,8 @@ namespace rpc { /** - * @brief The nft_history command asks the Clio server for past transaction metadata for the NFT being queried. + * @brief The nft_history command asks the Clio server for past transaction metadata for the NFT + * being queried. * * For more details see: https://xrpl.org/nft_history.html#nft_history */ @@ -105,7 +106,8 @@ public: * * @param sharedPtrBackend The backend to use */ - NFTHistoryHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + NFTHistoryHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } @@ -119,7 +121,9 @@ public: spec([[maybe_unused]] uint32_t apiVersion) { static auto const kRPC_SPEC = RpcSpec{ - {JS(nft_id), validation::Required{}, validation::CustomValidators::uint256HexStringValidator}, + {JS(nft_id), + validation::Required{}, + validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, {JS(ledger_index_min), validation::Type{}}, @@ -132,7 +136,8 @@ public: modifiers::Clamp{kLIMIT_MIN, kLIMIT_MAX}}, {JS(marker), meta::WithCustomError{ - validation::Type{}, Status{RippledError::rpcINVALID_PARAMS, "invalidMarker"} + validation::Type{}, + Status{RippledError::rpcINVALID_PARAMS, "invalidMarker"} }, meta::Section{ {JS(ledger), validation::Required{}, validation::Type{}}, diff --git a/src/rpc/handlers/NFTInfo.cpp b/src/rpc/handlers/NFTInfo.cpp index 32d6e4578..636a7ba36 100644 --- a/src/rpc/handlers/NFTInfo.cpp +++ b/src/rpc/handlers/NFTInfo.cpp @@ -86,7 +86,11 @@ NFTInfoHandler::process(NFTInfoHandler::Input const& input, Context const& ctx) } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, NFTInfoHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + NFTInfoHandler::Output const& output +) { // TODO: use JStrings when they become available jv = boost::json::object{ diff --git a/src/rpc/handlers/NFTInfo.hpp b/src/rpc/handlers/NFTInfo.hpp index 670c220eb..3e5e1a7fe 100644 --- a/src/rpc/handlers/NFTInfo.hpp +++ b/src/rpc/handlers/NFTInfo.hpp @@ -81,7 +81,8 @@ public: * * @param sharedPtrBackend The backend to use */ - NFTInfoHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + NFTInfoHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } @@ -95,7 +96,9 @@ public: spec([[maybe_unused]] uint32_t apiVersion) { static auto const kRPC_SPEC = RpcSpec{ - {JS(nft_id), validation::Required{}, validation::CustomValidators::uint256HexStringValidator}, + {JS(nft_id), + validation::Required{}, + validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, }; diff --git a/src/rpc/handlers/NFTOffersCommon.cpp b/src/rpc/handlers/NFTOffersCommon.cpp index 3e33578ae..6be78ee2d 100644 --- a/src/rpc/handlers/NFTOffersCommon.cpp +++ b/src/rpc/handlers/NFTOffersCommon.cpp @@ -115,11 +115,13 @@ NFTOffersHandlerBase::iterateOfferDirectory( if (input.marker) { cursor = uint256(input.marker->c_str()); - // We have a start point. Use limit - 1 from the result and use the very last one for the resume. + // We have a start point. Use limit - 1 from the result and use the very last one for the + // resume. auto const sle = [this, &cursor, &lgrInfo, yield]() -> std::shared_ptr { auto const key = keylet::nftoffer(cursor).key; - if (auto const blob = sharedPtrBackend_->fetchLedgerObject(key, lgrInfo.seq, yield); blob) + if (auto const blob = sharedPtrBackend_->fetchLedgerObject(key, lgrInfo.seq, yield); + blob) return std::make_shared(SerialIter{blob->data(), blob->size()}, key); return nullptr; @@ -139,7 +141,14 @@ NFTOffersHandlerBase::iterateOfferDirectory( } auto result = traverseOwnedNodes( - *sharedPtrBackend_, directory, cursor, startHint, lgrInfo.seq, reserve, yield, [&offers](ripple::SLE&& offer) { + *sharedPtrBackend_, + directory, + cursor, + startHint, + lgrInfo.seq, + reserve, + yield, + [&offers](ripple::SLE&& offer) { if (offer.getType() == ripple::ltNFTOKEN_OFFER) { offers.push_back(std::move(offer)); return true; @@ -164,7 +173,11 @@ NFTOffersHandlerBase::iterateOfferDirectory( } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, NFTOffersHandlerBase::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + NFTOffersHandlerBase::Output const& output +) { using boost::json::value_from; diff --git a/src/rpc/handlers/NFTOffersCommon.hpp b/src/rpc/handlers/NFTOffersCommon.hpp index 21eb23bd3..9f3bce68e 100644 --- a/src/rpc/handlers/NFTOffersCommon.hpp +++ b/src/rpc/handlers/NFTOffersCommon.hpp @@ -99,7 +99,9 @@ public: spec([[maybe_unused]] uint32_t apiVersion) { static auto const kRPC_SPEC = RpcSpec{ - {JS(nft_id), validation::Required{}, validation::CustomValidators::uint256HexStringValidator}, + {JS(nft_id), + validation::Required{}, + validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, {JS(limit), diff --git a/src/rpc/handlers/NFTsByIssuer.cpp b/src/rpc/handlers/NFTsByIssuer.cpp index c5f3f9c75..fc0b03435 100644 --- a/src/rpc/handlers/NFTsByIssuer.cpp +++ b/src/rpc/handlers/NFTsByIssuer.cpp @@ -63,8 +63,9 @@ NFTsByIssuerHandler::process(NFTsByIssuerHandler::Input const& input, Context co auto const limit = input.limit.value_or(NFTsByIssuerHandler::kLIMIT_DEFAULT); auto const issuer = accountFromStringStrict(input.issuer); - auto const accountLedgerObject = - sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*issuer).key, lgrInfo.seq, ctx.yield); + auto const accountLedgerObject = sharedPtrBackend_->fetchLedgerObject( + ripple::keylet::account(*issuer).key, lgrInfo.seq, ctx.yield + ); if (!accountLedgerObject) return Error{Status{RippledError::rpcACT_NOT_FOUND, "accountNotFound"}}; @@ -73,8 +74,9 @@ NFTsByIssuerHandler::process(NFTsByIssuerHandler::Input const& input, Context co if (input.marker) cursor = uint256{input.marker->c_str()}; - auto const dbResponse = - sharedPtrBackend_->fetchNFTsByIssuer(*issuer, input.nftTaxon, lgrInfo.seq, limit, cursor, ctx.yield); + auto const dbResponse = sharedPtrBackend_->fetchNFTsByIssuer( + *issuer, input.nftTaxon, lgrInfo.seq, limit, cursor, ctx.yield + ); auto output = NFTsByIssuerHandler::Output{}; @@ -108,7 +110,11 @@ NFTsByIssuerHandler::process(NFTsByIssuerHandler::Input const& input, Context co } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, NFTsByIssuerHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + NFTsByIssuerHandler::Output const& output +) { jv = { {JS(issuer), output.issuer}, diff --git a/src/rpc/handlers/NFTsByIssuer.hpp b/src/rpc/handlers/NFTsByIssuer.hpp index dbb1d89fd..053c3850a 100644 --- a/src/rpc/handlers/NFTsByIssuer.hpp +++ b/src/rpc/handlers/NFTsByIssuer.hpp @@ -81,7 +81,8 @@ public: * * @param sharedPtrBackend The backend to use */ - NFTsByIssuerHandler(std::shared_ptr const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend) + NFTsByIssuerHandler(std::shared_ptr const& sharedPtrBackend) + : sharedPtrBackend_(sharedPtrBackend) { } diff --git a/src/rpc/handlers/NoRippleCheck.cpp b/src/rpc/handlers/NoRippleCheck.cpp index 4fe0cb046..4a1a20c3a 100644 --- a/src/rpc/handlers/NoRippleCheck.cpp +++ b/src/rpc/handlers/NoRippleCheck.cpp @@ -80,7 +80,8 @@ NoRippleCheckHandler::process(NoRippleCheckHandler::Input const& input, Context auto sle = ripple::SLE{it, keylet}; auto accountSeq = sle.getFieldU32(ripple::sfSequence); bool const bDefaultRipple = (sle.getFieldU32(ripple::sfFlags) & ripple::lsfDefaultRipple) != 0u; - auto const fees = input.transactions ? sharedPtrBackend_->fetchFees(lgrInfo.seq, ctx.yield) : std::nullopt; + auto const fees = + input.transactions ? sharedPtrBackend_->fetchFees(lgrInfo.seq, ctx.yield) : std::nullopt; auto output = NoRippleCheckHandler::Output(); @@ -98,7 +99,8 @@ NoRippleCheckHandler::process(NoRippleCheckHandler::Input const& input, Context if (bDefaultRipple && !input.roleGateway) { output.problems.emplace_back( - "You appear to have set your default ripple flag even though you are not a gateway. This is not " + "You appear to have set your default ripple flag even though you are not a gateway. " + "This is not " "recommended unless you are experimenting" ); } else if (input.roleGateway && !bDefaultRipple) { @@ -124,10 +126,12 @@ NoRippleCheckHandler::process(NoRippleCheckHandler::Input const& input, Context [&](ripple::SLE const ownedItem) { // don't push to result if limit is reached if (limit != 0 && ownedItem.getType() == ripple::ltRIPPLE_STATE) { - bool const bLow = accountID == ownedItem.getFieldAmount(ripple::sfLowLimit).getIssuer(); + bool const bLow = + accountID == ownedItem.getFieldAmount(ripple::sfLowLimit).getIssuer(); - bool const bNoRipple = (ownedItem.getFieldU32(ripple::sfFlags) & - (bLow ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u; + bool const bNoRipple = + (ownedItem.getFieldU32(ripple::sfFlags) & + (bLow ? ripple::lsfLowNoRipple : ripple::lsfHighNoRipple)) != 0u; std::string problem; bool needFix = false; @@ -142,25 +146,29 @@ NoRippleCheckHandler::process(NoRippleCheckHandler::Input const& input, Context --limit; ripple::AccountID const peer = - ownedItem.getFieldAmount(bLow ? ripple::sfHighLimit : ripple::sfLowLimit).getIssuer(); + ownedItem.getFieldAmount(bLow ? ripple::sfHighLimit : ripple::sfLowLimit) + .getIssuer(); ripple::STAmount const peerLimit = ownedItem.getFieldAmount(bLow ? ripple::sfHighLimit : ripple::sfLowLimit); problem += fmt::format( - "{} line to {}", to_string(peerLimit.getCurrency()), to_string(peerLimit.getIssuer()) + "{} line to {}", + to_string(peerLimit.getCurrency()), + to_string(peerLimit.getIssuer()) ); output.problems.emplace_back(problem); if (input.transactions) { - ripple::STAmount limitAmount( - ownedItem.getFieldAmount(bLow ? ripple::sfLowLimit : ripple::sfHighLimit) - ); + ripple::STAmount limitAmount(ownedItem.getFieldAmount( + bLow ? ripple::sfLowLimit : ripple::sfHighLimit + )); limitAmount.setIssuer(peer); auto tx = getBaseTx(*accountID, accountSeq++); tx[JS(TransactionType)] = "TrustSet"; - tx[JS(LimitAmount)] = toBoostJson(limitAmount.getJson(ripple::JsonOptions::none)); + tx[JS(LimitAmount)] = + toBoostJson(limitAmount.getJson(ripple::JsonOptions::none)); tx[JS(Flags)] = bNoRipple ? ripple::tfClearNoRipple : ripple::tfSetNoRipple; output.transactions->push_back(tx); @@ -206,7 +214,11 @@ tag_invoke(boost::json::value_to_tag, boost::json:: } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, NoRippleCheckHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + NoRippleCheckHandler::Output const& output +) { using boost::json::value_from; diff --git a/src/rpc/handlers/NoRippleCheck.hpp b/src/rpc/handlers/NoRippleCheck.hpp index c7da7ae62..1030a0263 100644 --- a/src/rpc/handlers/NoRippleCheck.hpp +++ b/src/rpc/handlers/NoRippleCheck.hpp @@ -46,8 +46,8 @@ namespace rpc { /** * @brief Handles the `noripple_check` command * - * The noripple_check command provides a quick way to check the status of the Default Ripple field for an account - * and the No Ripple flag of its trust lines, compared with the recommended settings. + * The noripple_check command provides a quick way to check the status of the Default Ripple field + * for an account and the No Ripple flag of its trust lines, compared with the recommended settings. * * For more details see: https://xrpl.org/noripple_check.html */ @@ -109,7 +109,8 @@ public: {JS(role), validation::Required{}, meta::WithCustomError{ - validation::OneOf{"gateway", "user"}, Status{RippledError::rpcINVALID_PARAMS, "role field is invalid"} + validation::OneOf{"gateway", "user"}, + Status{RippledError::rpcINVALID_PARAMS, "role field is invalid"} }}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, diff --git a/src/rpc/handlers/Ping.hpp b/src/rpc/handlers/Ping.hpp index e86164654..23266bf4e 100644 --- a/src/rpc/handlers/Ping.hpp +++ b/src/rpc/handlers/Ping.hpp @@ -24,7 +24,8 @@ namespace rpc { /** - * @brief The ping command returns an acknowledgement, so that clients can test the connection status and latency. + * @brief The ping command returns an acknowledgement, so that clients can test the connection + * status and latency. * * For more details see https://xrpl.org/ping.html */ diff --git a/src/rpc/handlers/Random.hpp b/src/rpc/handlers/Random.hpp index c73f115c5..9f49a9461 100644 --- a/src/rpc/handlers/Random.hpp +++ b/src/rpc/handlers/Random.hpp @@ -29,8 +29,8 @@ namespace rpc { /** - * @brief The random command provides a random number to be used as a source of entropy for random number generation by - * clients. + * @brief The random command provides a random number to be used as a source of entropy for random + * number generation by clients. * * For more details see: https://xrpl.org/random.html */ diff --git a/src/rpc/handlers/ServerInfo.hpp b/src/rpc/handlers/ServerInfo.hpp index b54e83f71..39dace5f0 100644 --- a/src/rpc/handlers/ServerInfo.hpp +++ b/src/rpc/handlers/ServerInfo.hpp @@ -204,7 +204,8 @@ public: return Error{Status{RippledError::rpcINTERNAL}}; auto output = Output{}; - auto const sinceEpoch = duration_cast(system_clock::now().time_since_epoch()).count(); + auto const sinceEpoch = + duration_cast(system_clock::now().time_since_epoch()).count(); auto const age = static_cast(sinceEpoch) - static_cast(lgrInfo->closeTime.time_since_epoch().count()) - static_cast(kRIPPLE_EPOCH_START); @@ -214,19 +215,22 @@ public: if (ctx.isAdmin) { output.info.adminSection = { .counters = counters_.get().report(), - .backendCounters = input.backendCounters ? std::make_optional(backend_->stats()) : std::nullopt, + .backendCounters = + input.backendCounters ? std::make_optional(backend_->stats()) : std::nullopt, .subscriptions = subscriptions_->report(), .etl = etl_->getInfo() }; } - auto const serverInfoRippled = - balancer_->forwardToRippled({{"command", "server_info"}}, ctx.clientIp, ctx.isAdmin, ctx.yield); + auto const serverInfoRippled = balancer_->forwardToRippled( + {{"command", "server_info"}}, ctx.clientIp, ctx.isAdmin, ctx.yield + ); if (serverInfoRippled && !serverInfoRippled->contains(JS(error))) { if (serverInfoRippled->contains(JS(result)) && serverInfoRippled->at(JS(result)).as_object().contains(JS(info))) { - output.info.rippledInfo = serverInfoRippled->at(JS(result)).as_object().at(JS(info)).as_object(); + output.info.rippledInfo = + serverInfoRippled->at(JS(result)).as_object().at(JS(info)).as_object(); } } @@ -298,7 +302,8 @@ private: if (info.adminSection) { jv.as_object()["etl"] = info.adminSection->etl; jv.as_object()[JS(counters)] = info.adminSection->counters; - jv.as_object()[JS(counters)].as_object()["subscriptions"] = info.adminSection->subscriptions; + jv.as_object()[JS(counters)].as_object()["subscriptions"] = + info.adminSection->subscriptions; if (info.adminSection->backendCounters.has_value()) { jv.as_object()[kBACKEND_COUNTERS_KEY] = *info.adminSection->backendCounters; } @@ -306,7 +311,11 @@ private: } friend void - tag_invoke(boost::json::value_from_tag, boost::json::value& jv, ValidatedLedgerSection const& validated) + tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + ValidatedLedgerSection const& validated + ) { jv = { {JS(age), validated.age}, @@ -336,15 +345,16 @@ private: { auto input = BaseServerInfoHandler::Input{}; auto const jsonObject = jv.as_object(); - if (jsonObject.contains(kBACKEND_COUNTERS_KEY) && jsonObject.at(kBACKEND_COUNTERS_KEY).is_bool()) + if (jsonObject.contains(kBACKEND_COUNTERS_KEY) && + jsonObject.at(kBACKEND_COUNTERS_KEY).is_bool()) input.backendCounters = jv.at(kBACKEND_COUNTERS_KEY).as_bool(); return input; } }; /** - * @brief The server_info command asks the Clio server for a human-readable version of various information about the - * Clio server being queried. + * @brief The server_info command asks the Clio server for a human-readable version of various + * information about the Clio server being queried. * * For more details see: https://xrpl.org/server_info-clio.html */ diff --git a/src/rpc/handlers/Subscribe.cpp b/src/rpc/handlers/Subscribe.cpp index 6e2f75dc0..245bf7cc6 100644 --- a/src/rpc/handlers/Subscribe.cpp +++ b/src/rpc/handlers/Subscribe.cpp @@ -58,34 +58,42 @@ SubscribeHandler::SubscribeHandler( std::shared_ptr const& amendmentCenter, std::shared_ptr const& subscriptions ) - : sharedPtrBackend_(sharedPtrBackend), amendmentCenter_(amendmentCenter), subscriptions_(subscriptions) + : sharedPtrBackend_(sharedPtrBackend) + , amendmentCenter_(amendmentCenter) + , subscriptions_(subscriptions) { } RpcSpecConstRef SubscribeHandler::spec([[maybe_unused]] uint32_t apiVersion) { - static auto const kBOOKS_VALIDATOR = - validation::CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError { + static auto const kBOOKS_VALIDATOR = validation::CustomValidator{ + [](boost::json::value const& value, std::string_view key) -> MaybeError { if (!value.is_array()) - return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotArray"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotArray"} + }; for (auto const& book : value.as_array()) { if (!book.is_object()) - return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "ItemNotObject"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "ItemNotObject"} + }; if (book.as_object().contains("both") && !book.as_object().at("both").is_bool()) return Error{Status{RippledError::rpcINVALID_PARAMS, "bothNotBool"}}; - if (book.as_object().contains("snapshot") && !book.as_object().at("snapshot").is_bool()) + if (book.as_object().contains("snapshot") && + !book.as_object().at("snapshot").is_bool()) return Error{Status{RippledError::rpcINVALID_PARAMS, "snapshotNotBool"}}; if (book.as_object().contains("taker")) { - if (auto err = meta::WithCustomError( - validation::CustomValidators::accountValidator, - Status{RippledError::rpcBAD_ISSUER, "Issuer account malformed."} - ) - .verify(book.as_object(), "taker"); + if (auto err = + meta::WithCustomError( + validation::CustomValidators::accountValidator, + Status{RippledError::rpcBAD_ISSUER, "Issuer account malformed."} + ) + .verify(book.as_object(), "taker"); !err) return err; } @@ -96,7 +104,8 @@ SubscribeHandler::spec([[maybe_unused]] uint32_t apiVersion) } return MaybeError{}; - }}; + } + }; static auto const kRPC_SPEC = RpcSpec{ {JS(streams), validation::CustomValidators::subscribeStreamValidator}, @@ -210,15 +219,24 @@ SubscribeHandler::subscribeToBooks( auto const getOrderBook = [&](auto const& book, auto& snapshots) { auto const bookBase = getBookBase(book); - auto const [offers, _] = - sharedPtrBackend_->fetchBookOffers(bookBase, rng->maxSequence, kFETCH_LIMIT, yield); + auto const [offers, _] = sharedPtrBackend_->fetchBookOffers( + bookBase, rng->maxSequence, kFETCH_LIMIT, yield + ); // the taker is not really used, same issue with // https://github.com/XRPLF/xrpl-dev-portal/issues/1818 - auto const takerID = internalBook.taker ? accountFromStringStrict(*(internalBook.taker)) : beast::zero; + auto const takerID = internalBook.taker + ? accountFromStringStrict(*(internalBook.taker)) + : beast::zero; auto const orderBook = postProcessOrderBook( - offers, book, *takerID, *sharedPtrBackend_, *amendmentCenter_, rng->maxSequence, yield + offers, + book, + *takerID, + *sharedPtrBackend_, + *amendmentCenter_, + rng->maxSequence, + yield ); std::copy(orderBook.begin(), orderBook.end(), std::back_inserter(snapshots)); }; @@ -245,7 +263,11 @@ SubscribeHandler::subscribeToBooks( } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, SubscribeHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + SubscribeHandler::Output const& output +) { jv = output.ledger ? *(output.ledger) : boost::json::object(); @@ -275,7 +297,8 @@ tag_invoke(boost::json::value_to_tag, boost::json::valu input.accounts->push_back(boost::json::value_to(account)); } - if (auto const& accountsProposed = jsonObject.find(JS(accounts_proposed)); accountsProposed != jsonObject.end()) { + if (auto const& accountsProposed = jsonObject.find(JS(accounts_proposed)); + accountsProposed != jsonObject.end()) { input.accountsProposed = std::vector(); for (auto const& account : accountsProposed->value().as_array()) input.accountsProposed->push_back(boost::json::value_to(account)); diff --git a/src/rpc/handlers/Subscribe.hpp b/src/rpc/handlers/Subscribe.hpp index 0d7c6816d..c2aeaad69 100644 --- a/src/rpc/handlers/Subscribe.hpp +++ b/src/rpc/handlers/Subscribe.hpp @@ -65,7 +65,8 @@ public: // response of stream "ledger" // TODO: use better type than json, this type will be used in the stream as well std::optional ledger; - // books returns nothing by default, if snapshot is true and both is false, offers go to offers list + // books returns nothing by default, if snapshot is true and both is false, offers go to + // offers list // TODO: use better type than json std::optional offers; // if snapshot is true and both is true, reversed book' offers go to asks list @@ -137,7 +138,10 @@ private: ) const; void - subscribeToAccounts(std::vector const& accounts, feed::SubscriberSharedPtr const& session) const; + subscribeToAccounts( + std::vector const& accounts, + feed::SubscriberSharedPtr const& session + ) const; void subscribeToAccountsProposed( diff --git a/src/rpc/handlers/TransactionEntry.cpp b/src/rpc/handlers/TransactionEntry.cpp index 19d7df8ad..acc4447d1 100644 --- a/src/rpc/handlers/TransactionEntry.cpp +++ b/src/rpc/handlers/TransactionEntry.cpp @@ -40,7 +40,10 @@ namespace rpc { TransactionEntryHandler::Result -TransactionEntryHandler::process(TransactionEntryHandler::Input const& input, Context const& ctx) const +TransactionEntryHandler::process( + TransactionEntryHandler::Input const& input, + Context const& ctx +) const { auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "TransactionEntry's ledger range must be available"); @@ -56,7 +59,8 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input const& input, Co output.apiVersion = ctx.apiVersion; output.ledgerHeader = expectedLgrInfo.value(); - auto const dbRet = sharedPtrBackend_->fetchTransaction(ripple::uint256{input.txHash.c_str()}, ctx.yield); + auto const dbRet = + sharedPtrBackend_->fetchTransaction(ripple::uint256{input.txHash.c_str()}, ctx.yield); // Note: transaction_entry is meant to only search a specified ledger for // the specified transaction. tx searches the entire range of history. For // rippled, having two separate commands made sense, as tx would use SQLite @@ -67,7 +71,9 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input const& input, Co // ledger; we simulate that here by returning not found if the transaction // is in a different ledger than the one specified. if (!dbRet || dbRet->ledgerSequence != output.ledgerHeader->seq) - return Error{Status{RippledError::rpcTXN_NOT_FOUND, "transactionNotFound", "Transaction not found."}}; + return Error{ + Status{RippledError::rpcTXN_NOT_FOUND, "transactionNotFound", "Transaction not found."} + }; auto [txn, meta] = toExpandedJson(*dbRet, ctx.apiVersion); @@ -78,7 +84,11 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input const& input, Co } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, TransactionEntryHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + TransactionEntryHandler::Output const& output +) { auto const metaKey = output.apiVersion > 1u ? JS(meta) : JS(metadata); jv = { diff --git a/src/rpc/handlers/TransactionEntry.hpp b/src/rpc/handlers/TransactionEntry.hpp index fb2fb82c3..cf6e812cc 100644 --- a/src/rpc/handlers/TransactionEntry.hpp +++ b/src/rpc/handlers/TransactionEntry.hpp @@ -41,7 +41,8 @@ namespace rpc { /** - * @brief The transaction_entry method retrieves information on a single transaction from a specific ledger version. + * @brief The transaction_entry method retrieves information on a single transaction from a specific + * ledger version. * * For more details see: https://xrpl.org/transaction_entry.html */ @@ -94,7 +95,9 @@ public: { static auto const kRPC_SPEC = RpcSpec{ {JS(tx_hash), - meta::WithCustomError{validation::Required{}, Status(ClioError::RpcFieldNotFoundTransaction)}, + meta::WithCustomError{ + validation::Required{}, Status(ClioError::RpcFieldNotFoundTransaction) + }, validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_hash), validation::CustomValidators::uint256HexStringValidator}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, diff --git a/src/rpc/handlers/Tx.hpp b/src/rpc/handlers/Tx.hpp index df681deb2..f3ecaff14 100644 --- a/src/rpc/handlers/Tx.hpp +++ b/src/rpc/handlers/Tx.hpp @@ -70,14 +70,19 @@ public: uint32_t date = 0u; std::string hash = {}; // NOLINT(readability-redundant-member-init) uint32_t ledgerIndex = 0u; - std::optional meta = std::nullopt; // NOLINT(readability-redundant-member-init) - std::optional tx = std::nullopt; // NOLINT(readability-redundant-member-init) - std::optional metaStr = std::nullopt; // NOLINT(readability-redundant-member-init) - std::optional txStr = std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional meta = + std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional tx = + std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional metaStr = + std::nullopt; // NOLINT(readability-redundant-member-init) + std::optional txStr = + std::nullopt; // NOLINT(readability-redundant-member-init) std::optional ctid = std::nullopt; // NOLINT(readability-redundant-member-init) ctid when binary=true std::optional ledgerHeader = - std::nullopt; // NOLINT(readability-redundant-member-init) ledger hash when apiVersion >= 2 + std::nullopt; // NOLINT(readability-redundant-member-init) ledger hash when apiVersion + // >= 2 uint32_t apiVersion = 0u; bool validated = true; }; @@ -125,7 +130,8 @@ public: {JS(ctid), validation::Type{}}, }; - static auto const kRPC_SPEC = RpcSpec{kRPC_SPEC_FOR_V1, {{JS(binary), validation::Type{}}}}; + static auto const kRPC_SPEC = + RpcSpec{kRPC_SPEC_FOR_V1, {{JS(binary), validation::Type{}}}}; return apiVersion == 1 ? kRPC_SPEC_FOR_V1 : kRPC_SPEC; } @@ -174,14 +180,18 @@ public: return Error{Status{ RippledError::rpcWRONG_NETWORK, fmt::format( - "Wrong network. You should submit this request to a node running on NetworkID: {}", netId + "Wrong network. You should submit this request to a node running on " + "NetworkID: {}", + netId ) }}; } dbResponse = fetchTxViaCtid(lgrSeq, txnIdx, ctx.yield); } else { - dbResponse = sharedPtrBackend_->fetchTransaction(ripple::uint256{input.transaction->c_str()}, ctx.yield); + dbResponse = sharedPtrBackend_->fetchTransaction( + ripple::uint256{input.transaction->c_str()}, ctx.yield + ); } auto output = TxHandler::Output{.apiVersion = ctx.apiVersion}; @@ -192,8 +202,8 @@ public: auto const range = sharedPtrBackend_->fetchLedgerRange(); ASSERT(range.has_value(), "Tx's ledger range must be available"); - auto const searchedAll = - range->maxSequence >= *input.maxLedger && range->minSequence <= *input.minLedger; + auto const searchedAll = range->maxSequence >= *input.maxLedger && + range->minSequence <= *input.minLedger; boost::json::object extra; extra["searched_all"] = searchedAll; @@ -203,7 +213,8 @@ public: return Error{Status{RippledError::rpcTXN_NOT_FOUND}}; } - auto const [txn, meta] = toExpandedJson(*dbResponse, ctx.apiVersion, NFTokenjson::ENABLE, currentNetId); + auto const [txn, meta] = + toExpandedJson(*dbResponse, ctx.apiVersion, NFTokenjson::ENABLE, currentNetId); if (!input.binary) { output.tx = txn; @@ -222,7 +233,9 @@ public: if (txnIdx <= 0xFFFFU && dbResponse->ledgerSequence < 0x0FFF'FFFFUL && currentNetId && *currentNetId <= 0xFFFFU) { output.ctid = rpc::encodeCTID( - dbResponse->ledgerSequence, static_cast(txnIdx), static_cast(*currentNetId) + dbResponse->ledgerSequence, + static_cast(txnIdx), + static_cast(*currentNetId) ); } @@ -231,7 +244,8 @@ public: // fetch ledger hash if (ctx.apiVersion > 1u) - output.ledgerHeader = sharedPtrBackend_->fetchLedgerBySequence(dbResponse->ledgerSequence, ctx.yield); + output.ledgerHeader = + sharedPtrBackend_->fetchLedgerBySequence(dbResponse->ledgerSequence, ctx.yield); return output; } diff --git a/src/rpc/handlers/Unsubscribe.cpp b/src/rpc/handlers/Unsubscribe.cpp index c47f9d052..978331c8e 100644 --- a/src/rpc/handlers/Unsubscribe.cpp +++ b/src/rpc/handlers/Unsubscribe.cpp @@ -44,7 +44,9 @@ namespace rpc { -UnsubscribeHandler::UnsubscribeHandler(std::shared_ptr const& subscriptions) +UnsubscribeHandler::UnsubscribeHandler( + std::shared_ptr const& subscriptions +) : subscriptions_(subscriptions) { } @@ -52,14 +54,18 @@ UnsubscribeHandler::UnsubscribeHandler(std::shared_ptr MaybeError { + static auto const kBOOKS_VALIDATOR = validation::CustomValidator{ + [](boost::json::value const& value, std::string_view key) -> MaybeError { if (!value.is_array()) - return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotArray"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotArray"} + }; for (auto const& book : value.as_array()) { if (!book.is_object()) - return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "ItemNotObject"}}; + return Error{ + Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "ItemNotObject"} + }; if (book.as_object().contains("both") && !book.as_object().at("both").is_bool()) return Error{Status{RippledError::rpcINVALID_PARAMS, "bothNotBool"}}; @@ -70,7 +76,8 @@ UnsubscribeHandler::spec([[maybe_unused]] uint32_t apiVersion) } return MaybeError{}; - }}; + } + }; static auto const kRPC_SPEC = RpcSpec{ {JS(streams), validation::CustomValidators::subscribeStreamValidator}, @@ -181,7 +188,8 @@ tag_invoke(boost::json::value_to_tag, boost::json::va for (auto const& account : accounts->value().as_array()) input.accounts->push_back(boost::json::value_to(account)); } - if (auto const& accountsProposed = jsonObject.find(JS(accounts_proposed)); accountsProposed != jsonObject.end()) { + if (auto const& accountsProposed = jsonObject.find(JS(accounts_proposed)); + accountsProposed != jsonObject.end()) { input.accountsProposed = std::vector(); for (auto const& account : accountsProposed->value().as_array()) input.accountsProposed->push_back(boost::json::value_to(account)); diff --git a/src/rpc/handlers/Unsubscribe.hpp b/src/rpc/handlers/Unsubscribe.hpp index 64a251657..0f40881d1 100644 --- a/src/rpc/handlers/Unsubscribe.hpp +++ b/src/rpc/handlers/Unsubscribe.hpp @@ -41,8 +41,8 @@ namespace rpc { /** * @brief Handles the `unsubscribe` command which is used to disconnect a subscriber from a feed. - * The unsubscribe command tells the server to stop sending messages for a particular subscription or set of - * subscriptions. + * The unsubscribe command tells the server to stop sending messages for a particular subscription + * or set of subscriptions. * * For more details see: https://xrpl.org/unsubscribe.html */ @@ -100,10 +100,16 @@ public: private: void - unsubscribeFromStreams(std::vector const& streams, feed::SubscriberSharedPtr const& session) const; + unsubscribeFromStreams( + std::vector const& streams, + feed::SubscriberSharedPtr const& session + ) const; void - unsubscribeFromAccounts(std::vector accounts, feed::SubscriberSharedPtr const& session) const; + unsubscribeFromAccounts( + std::vector accounts, + feed::SubscriberSharedPtr const& session + ) const; void unsubscribeFromProposedAccounts( @@ -112,7 +118,10 @@ private: ) const; void - unsubscribeFromBooks(std::vector const& books, feed::SubscriberSharedPtr const& session) const; + unsubscribeFromBooks( + std::vector const& books, + feed::SubscriberSharedPtr const& session + ) const; /** * @brief Convert a JSON object to an Input diff --git a/src/rpc/handlers/VaultInfo.cpp b/src/rpc/handlers/VaultInfo.cpp index 64e9a2d72..74a2d15d3 100644 --- a/src/rpc/handlers/VaultInfo.cpp +++ b/src/rpc/handlers/VaultInfo.cpp @@ -50,8 +50,8 @@ namespace rpc { namespace { /** - * @brief Ensures that the input contains either a `vaultID` alone, or both `owner` and `tnxSequence`. - * Any other combination is considered malformed. + * @brief Ensures that the input contains either a `vaultID` alone, or both `owner` and + * `tnxSequence`. Any other combination is considered malformed. * * @param input The input object containing optional fields for the vault request. * @return Returns true if the input is valid, false otherwise. @@ -130,11 +130,13 @@ VaultInfoHandler::process(VaultInfoHandler::Input const& input, Context const& c return Error{Status{RippledError::rpcENTRY_NOT_FOUND, "vault object not found."}}; ripple::STLedgerEntry const vaultSle{ - ripple::SerialIter{vaultLedgerObject->data(), vaultLedgerObject->size()}, vaultKeylet.value().key + ripple::SerialIter{vaultLedgerObject->data(), vaultLedgerObject->size()}, + vaultKeylet.value().key }; auto const issuanceKeylet = ripple::keylet::mptIssuance(vaultSle[ripple::sfShareMPTID]).key; - auto const issuanceObject = sharedPtrBackend_->fetchLedgerObject(issuanceKeylet, lgrInfo.seq, ctx.yield); + auto const issuanceObject = + sharedPtrBackend_->fetchLedgerObject(issuanceKeylet, lgrInfo.seq, ctx.yield); if (not issuanceObject) return Error{Status{RippledError::rpcENTRY_NOT_FOUND, "issuance object not found."}}; @@ -148,17 +150,24 @@ VaultInfoHandler::process(VaultInfoHandler::Input const& input, Context const& c // https://github.com/XRPLF/rippled/pull/5224/files#diff-6cb544622c7942261f097d628f61f1c1fcf34a1bcfd954aedbada4238fc28f69R107 Output response; response.vault = toBoostJson(vaultSle.getJson(ripple::JsonOptions::none)); - response.vault.as_object()[JS(shares)] = toBoostJson(issuanceSle.getJson(ripple::JsonOptions::none)); + response.vault.as_object()[JS(shares)] = + toBoostJson(issuanceSle.getJson(ripple::JsonOptions::none)); response.ledgerIndex = lgrInfo.seq; return response; } void -tag_invoke(boost::json::value_from_tag, boost::json::value& jv, VaultInfoHandler::Output const& output) +tag_invoke( + boost::json::value_from_tag, + boost::json::value& jv, + VaultInfoHandler::Output const& output +) { jv = boost::json::object{ - {JS(ledger_index), output.ledgerIndex}, {JS(validated), output.validated}, {JS(vault), output.vault} + {JS(ledger_index), output.ledgerIndex}, + {JS(validated), output.validated}, + {JS(vault), output.vault} }; } diff --git a/src/rpc/handlers/VaultInfo.hpp b/src/rpc/handlers/VaultInfo.hpp index fe0ab10dc..2af07dbcf 100644 --- a/src/rpc/handlers/VaultInfo.hpp +++ b/src/rpc/handlers/VaultInfo.hpp @@ -87,14 +87,18 @@ public: static auto const kRPC_SPEC = RpcSpec{ {JS(vault_id), meta::WithCustomError{ - validation::CustomValidators::uint256HexStringValidator, Status(ClioError::RpcMalformedRequest) + validation::CustomValidators::uint256HexStringValidator, + Status(ClioError::RpcMalformedRequest) }}, {JS(owner), meta::WithCustomError{ validation::CustomValidators::accountBase58Validator, Status(ClioError::RpcMalformedRequest, "OwnerNotHexString") }}, - {JS(seq), meta::WithCustomError{validation::Type{}, Status(ClioError::RpcMalformedRequest)}}, + {JS(seq), + meta::WithCustomError{ + validation::Type{}, Status(ClioError::RpcMalformedRequest) + }}, {JS(ledger_index), validation::CustomValidators::ledgerIndexValidator}, }; diff --git a/src/util/AccountUtils.hpp b/src/util/AccountUtils.hpp index ce4ea9f98..923946bb6 100644 --- a/src/util/AccountUtils.hpp +++ b/src/util/AccountUtils.hpp @@ -30,8 +30,9 @@ namespace util { /** - * @brief A wrapper of parseBase58 function. It adds the check if all characters in the input string are alphanumeric. - * If not, it returns an empty optional, instead of calling the parseBase58 function. + * @brief A wrapper of parseBase58 function. It adds the check if all characters in the input string + * are alphanumeric. If not, it returns an empty optional, instead of calling the parseBase58 + * function. * * @tparam T The type of the value to parse to. * @param str The string to parse. @@ -41,15 +42,18 @@ template [[nodiscard]] std::optional parseBase58Wrapper(std::string const& str) { - if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { return std::isalnum(c); })) + if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { + return std::isalnum(c); + })) return std::nullopt; return ripple::parseBase58(str); } /** - * @brief A wrapper of parseBase58 function. It add the check if all characters in the input string are alphanumeric. If - * not, it returns an empty optional, instead of calling the parseBase58 function. + * @brief A wrapper of parseBase58 function. It add the check if all characters in the input string + * are alphanumeric. If not, it returns an empty optional, instead of calling the parseBase58 + * function. * * @tparam T The type of the value to parse to. * @param type The type of the token to parse. @@ -60,7 +64,9 @@ template [[nodiscard]] std::optional parseBase58Wrapper(ripple::TokenType type, std::string const& str) { - if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { return std::isalnum(c); })) + if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { + return std::isalnum(c); + })) return std::nullopt; return ripple::parseBase58(type, str); diff --git a/src/util/Assert.hpp b/src/util/Assert.hpp index 70782b20c..a2b2907fc 100644 --- a/src/util/Assert.hpp +++ b/src/util/Assert.hpp @@ -105,5 +105,7 @@ assertImpl( } // namespace util::impl -#define ASSERT(condition, ...) \ - util::impl::assertImpl(CURRENT_SRC_LOCATION, #condition, static_cast(condition), __VA_ARGS__) +#define ASSERT(condition, ...) \ + util::impl::assertImpl( \ + CURRENT_SRC_LOCATION, #condition, static_cast(condition), __VA_ARGS__ \ + ) diff --git a/src/util/Atomic.hpp b/src/util/Atomic.hpp index 5b83cf3a8..6ab85cc28 100644 --- a/src/util/Atomic.hpp +++ b/src/util/Atomic.hpp @@ -70,7 +70,8 @@ public: value_.fetch_add(value); #else // Workaround for atomic float not being supported by the standard library - // compare_exchange_weak returns false if the value is not exchanged and updates the current value + // compare_exchange_weak returns false if the value is not exchanged and updates the + // current value auto current = value_.load(); while (!value_.compare_exchange_weak(current, current + value)) { } diff --git a/src/util/BlockingCache.hpp b/src/util/BlockingCache.hpp index 6fd031aed..330c14fcf 100644 --- a/src/util/BlockingCache.hpp +++ b/src/util/BlockingCache.hpp @@ -70,7 +70,8 @@ public: * @brief Construct a cache with an initial value * @param initialValue The value to initialize the cache with */ - explicit BlockingCache(ValueType initialValue) : state_{State::HasValue}, value_(std::move(initialValue)) + explicit BlockingCache(ValueType initialValue) + : state_{State::HasValue}, value_(std::move(initialValue)) { } @@ -212,11 +213,15 @@ private: boost::system::error_code errorCode; boost::signals2::scoped_connection const slot = - updateFinished_.connect([yield, sharedContext](std::expected value) { - util::spawn(yield, [sharedContext = std::move(sharedContext), value = std::move(value)](auto&&) { - sharedContext->result = std::move(value); - sharedContext->timer.cancel(); - }); + updateFinished_.connect([yield, + sharedContext](std::expected value) { + util::spawn( + yield, + [sharedContext = std::move(sharedContext), value = std::move(value)](auto&&) { + sharedContext->result = std::move(value); + sharedContext->timer.cancel(); + } + ); }); if (state_ == State::Updating) { diff --git a/src/util/Channel.hpp b/src/util/Channel.hpp index af4fbbeed..05845061a 100644 --- a/src/util/Channel.hpp +++ b/src/util/Channel.hpp @@ -48,26 +48,33 @@ struct ChannelInstantiated; * @brief Specifies the producer concurrency model for a Channel. */ enum class ProducerType { - Single, /**< Only one Sender can exist (non-copyable). Uses direct Guard ownership for zero overhead. */ - Multi /**< Multiple Senders can exist (copyable). Uses shared_ptr for shared ownership. */ + Single, /**< Only one Sender can exist (non-copyable). Uses direct Guard ownership for zero + overhead. */ + Multi /**< Multiple Senders can exist (copyable). Uses shared_ptr for shared ownership. + */ }; /** * @brief Specifies the consumer concurrency model for a Channel. */ enum class ConsumerType { - Single, /**< Only one Receiver can exist (non-copyable). Uses direct Guard ownership for zero overhead. */ - Multi /**< Multiple Receivers can exist (copyable). Uses shared_ptr for shared ownership. */ + Single, /**< Only one Receiver can exist (non-copyable). Uses direct Guard ownership for zero + overhead. */ + Multi /**< Multiple Receivers can exist (copyable). Uses shared_ptr for shared ownership. + */ }; /** - * @brief Represents a go-like channel, a multi-producer (Sender) multi-consumer (Receiver) thread-safe data pipe. - * @note Use INSTANTIATE_CHANNEL_FOR_CLANG macro when using this class. See docs at the bottom of the file for more - * details. + * @brief Represents a go-like channel, a multi-producer (Sender) multi-consumer (Receiver) + * thread-safe data pipe. + * @note Use INSTANTIATE_CHANNEL_FOR_CLANG macro when using this class. See docs at the bottom of + * the file for more details. * * @tparam T The type of data the channel transfers - * @tparam P ProducerType::Multi (default) for multi-producer or ProducerType::Single for single-producer - * @tparam C ConsumerType::Multi (default) for multi-consumer or ConsumerType::Single for single-consumer + * @tparam P ProducerType::Multi (default) for multi-producer or ProducerType::Single for + * single-producer + * @tparam C ConsumerType::Multi (default) for multi-consumer or ConsumerType::Single for + * single-consumer */ template class Channel { @@ -76,7 +83,8 @@ class Channel { private: class ControlBlock { - using InternalChannelType = boost::asio::experimental::concurrent_channel; + using InternalChannelType = + boost::asio::experimental::concurrent_channel; boost::asio::any_io_executor executor_; InternalChannelType ch_; @@ -122,7 +130,8 @@ private: }; /** - * @brief This is used to close the channel once either all Senders or all Receivers are destroyed + * @brief This is used to close the channel once either all Senders or all Receivers are + * destroyed */ struct Guard { std::shared_ptr shared; @@ -139,7 +148,8 @@ public: * * Sender is movable. For multi-producer channels, Sender is also copyable. * The channel remains open as long as at least one Sender exists. - * When all Sender instances are destroyed, the channel is closed and receivers will receive std::nullopt. + * When all Sender instances are destroyed, the channel is closed and receivers will receive + * std::nullopt. */ class Sender { std::shared_ptr shared_; @@ -215,7 +225,8 @@ public: * * @tparam D The type of data to send (must be convertible to T) * @param data The data to send - * @param fn Callback function invoked with true if successful, false if the channel is closed + * @param fn Callback function invoked with true if successful, false if the channel is + * closed */ template void @@ -226,8 +237,10 @@ public: shared_->channel().async_send( ecIn, std::forward(data), - [fn = std::forward(fn), shared = shared_](boost::system::error_code ec) mutable { - // Workaround: asio channels bug returns ec=0 on cancel, check isClosed() instead + [fn = std::forward(fn), + shared = shared_](boost::system::error_code ec) mutable { + // Workaround: asio channels bug returns ec=0 on cancel, check isClosed() + // instead if (not ec and shared->isClosed()) { fn(false); return; @@ -260,7 +273,8 @@ public: * * Receiver is movable. For multi-consumer channels, Receiver is also copyable. * Multiple receivers can consume from the same multi-consumer channel concurrently. - * When all Receiver instances are destroyed, the channel is closed and senders will fail to send. + * When all Receiver instances are destroyed, the channel is closed and senders will fail to + * send. */ class Receiver { std::shared_ptr shared_; @@ -306,7 +320,8 @@ public: /** * @brief Attempts to receive data from the channel without blocking. * - * @return std::optional containing the received value, or std::nullopt if the channel is empty or closed + * @return std::optional containing the received value, or std::nullopt if the channel is + * empty or closed */ std::optional tryReceive() @@ -326,7 +341,8 @@ public: * Blocks the coroutine until data is available or the channel is closed. * * @param yield The Boost.Asio yield context for coroutine suspension - * @return std::optional containing the received value, or std::nullopt if the channel is closed + * @return std::optional containing the received value, or std::nullopt if the channel is + * closed */ [[nodiscard]] std::optional asyncReceive(boost::asio::yield_context yield) @@ -345,21 +361,22 @@ public: * * The callback is invoked when data is available or the channel is closed. * - * @param fn Callback function invoked with std::optional containing the value, or std::nullopt if closed + * @param fn Callback function invoked with std::optional containing the value, or + * std::nullopt if closed */ void asyncReceive(std::invocable>> auto&& fn) { - shared_->channel().async_receive( - [fn = std::forward(fn)](boost::system::error_code ec, T&& value) mutable { - if (ec) { - fn(std::optional(std::nullopt)); - return; - } - - fn(std::make_optional(std::move(value))); + shared_->channel().async_receive([fn = std::forward(fn)]( + boost::system::error_code ec, T&& value + ) mutable { + if (ec) { + fn(std::optional(std::nullopt)); + return; } - ); + + fn(std::make_optional(std::move(value))); + }); } /** @@ -392,7 +409,8 @@ public: "to one .cpp file. See documentation at the bottom of Channel.hpp for details." ); #endif - auto shared = std::make_shared(std::forward(context), capacity); + auto shared = + std::make_shared(std::forward(context), capacity); auto sender = Sender{shared}; auto receiver = Receiver{std::move(shared)}; @@ -442,14 +460,16 @@ template struct ChannelInstantiated : std::false_type {}; } // namespace util::detail -#define INSTANTIATE_CHANNEL_FOR_CLANG(T) \ - /* NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor) */ \ - template class boost::asio::detail::cancellation_handler< \ - boost::asio::experimental::detail::channel_service:: \ - op_cancellation, void(boost::system::error_code, T)>>; \ - namespace util::detail { \ - template <> \ - struct ChannelInstantiated : std::true_type {}; \ +#define INSTANTIATE_CHANNEL_FOR_CLANG(T) \ + /* NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor) */ \ + template class boost::asio::detail::cancellation_handler< \ + boost::asio::experimental::detail::channel_service:: \ + op_cancellation< \ + boost::asio::experimental::channel_traits<>, \ + void(boost::system::error_code, T)>>; \ + namespace util::detail { \ + template <> \ + struct ChannelInstantiated : std::true_type {}; \ } #else diff --git a/src/util/Coroutine.cpp b/src/util/Coroutine.cpp index 9ab6bdb14..8f249f366 100644 --- a/src/util/Coroutine.cpp +++ b/src/util/Coroutine.cpp @@ -32,7 +32,10 @@ namespace util { -Coroutine::Coroutine(boost::asio::yield_context&& yield, std::shared_ptr signal) +Coroutine::Coroutine( + boost::asio::yield_context&& yield, + std::shared_ptr signal +) : yield_(std::move(yield)) , cyield_(boost::asio::bind_cancellation_slot(cancellationSignal_.slot(), yield_[error_])) , familySignal_{std::move(signal)} diff --git a/src/util/Coroutine.hpp b/src/util/Coroutine.hpp index 5f21f163e..0d1af4dea 100644 --- a/src/util/Coroutine.hpp +++ b/src/util/Coroutine.hpp @@ -65,8 +65,8 @@ public: * @brief Type alias for a yield_context that is bound to a cancellation slot. * This allows asynchronous operations initiated with this context to be cancelled. */ - using cancellable_yield_context_type = - boost::asio::cancellation_slot_binder; + using cancellable_yield_context_type = boost::asio:: + cancellation_slot_binder; private: boost::asio::yield_context yield_; @@ -75,18 +75,21 @@ private: cancellable_yield_context_type cyield_; std::atomic_bool isCancelled_{false}; - using FamilyCancellationSignal = boost::signals2::signal; + using FamilyCancellationSignal = + boost::signals2::signal; std::shared_ptr familySignal_; boost::signals2::connection connection_; /** * @brief Private constructor to create a Coroutine instance. * @param yield The Boost.Asio yield_context for this coroutine. - * @param signal A shared signal used for propagating cancellation requests among related coroutines. + * @param signal A shared signal used for propagating cancellation requests among related + * coroutines. */ explicit Coroutine( boost::asio::yield_context&& yield, - std::shared_ptr signal = std::make_shared() + std::shared_ptr signal = + std::make_shared() ); public: @@ -107,10 +110,12 @@ public: /** * @brief Spawns a new top-level coroutine. - * @tparam ExecutionContext The type of the I/O execution context (e.g., boost::asio::io_context). + * @tparam ExecutionContext The type of the I/O execution context (e.g., + * boost::asio::io_context). * @tparam Fn The type of the invocable function that represents the coroutine body. * @param ioContext The I/O execution context on which to spawn the coroutine. - * @param fn The function to be executed as the coroutine. It will receive a Coroutine& argument. + * @param fn The function to be executed as the coroutine. It will receive a Coroutine& + * argument. */ template static void @@ -126,7 +131,8 @@ public: * @brief Spawns a child coroutine from this coroutine. * The child coroutine shares the same cancellation signal. * @tparam Fn The type of the invocable function that represents the child coroutine body. - * @param fn The function to be executed as the child coroutine. It will receive a Coroutine& argument. + * @param fn The function to be executed as the child coroutine. It will receive a Coroutine& + * argument. */ template void @@ -135,10 +141,13 @@ public: if (isCancelled_) return; - util::spawn(yield_, [signal = familySignal_, fn = std::move(fn)](boost::asio::yield_context yield) mutable { - Coroutine coroutine(std::move(yield), std::move(signal)); - fn(coroutine); - }); + util::spawn( + yield_, + [signal = familySignal_, fn = std::move(fn)](boost::asio::yield_context yield) mutable { + Coroutine coroutine(std::move(yield), std::move(signal)); + fn(coroutine); + } + ); } /** @@ -154,7 +163,9 @@ public: * Defaults to boost::asio::cancellation_type::terminal. */ void - cancelAll(boost::asio::cancellation_type_t cancellationType = boost::asio::cancellation_type::terminal); + cancelAll( + boost::asio::cancellation_type_t cancellationType = boost::asio::cancellation_type::terminal + ); /** * @brief Checks if this coroutine has been cancelled. diff --git a/src/util/CoroutineGroup.cpp b/src/util/CoroutineGroup.cpp index 11f0229db..9fc1432f6 100644 --- a/src/util/CoroutineGroup.cpp +++ b/src/util/CoroutineGroup.cpp @@ -33,17 +33,24 @@ namespace util { CoroutineGroup::CoroutineGroup(boost::asio::yield_context yield, std::optional maxChildren) - : timer_{yield.get_executor(), boost::asio::steady_timer::duration::max()}, maxChildren_{maxChildren} + : timer_{yield.get_executor(), boost::asio::steady_timer::duration::max()} + , maxChildren_{maxChildren} { } CoroutineGroup::~CoroutineGroup() { - ASSERT(childrenCounter_ == 0, "CoroutineGroup is destroyed without waiting for child coroutines to finish"); + ASSERT( + childrenCounter_ == 0, + "CoroutineGroup is destroyed without waiting for child coroutines to finish" + ); } bool -CoroutineGroup::spawn(boost::asio::yield_context yield, std::function fn) +CoroutineGroup::spawn( + boost::asio::yield_context yield, + std::function fn +) { if (isFull()) return false; @@ -63,8 +70,8 @@ CoroutineGroup::registerForeign(boost::asio::yield_context yield) return std::nullopt; ++childrenCounter_; - // It is important to spawn onCoroutineCompleted() to the same coroutine as will be calling asyncWait(). - // timer_ here is not thread safe, so without spawn there could be a data race. + // It is important to spawn onCoroutineCompleted() to the same coroutine as will be calling + // asyncWait(). timer_ here is not thread safe, so without spawn there could be a data race. return [this, yield]() { util::spawn(yield, [this](auto&&) { onCoroutineCompleted(); }); }; } @@ -93,7 +100,10 @@ CoroutineGroup::isFull() const void CoroutineGroup::onCoroutineCompleted() { - ASSERT(childrenCounter_ != 0, "onCoroutineCompleted() called more times than the number of child coroutines"); + ASSERT( + childrenCounter_ != 0, + "onCoroutineCompleted() called more times than the number of child coroutines" + ); --childrenCounter_; if (childrenCounter_ == 0) diff --git a/src/util/CoroutineGroup.hpp b/src/util/CoroutineGroup.hpp index b14c3b0ff..01dd8c4f1 100644 --- a/src/util/CoroutineGroup.hpp +++ b/src/util/CoroutineGroup.hpp @@ -30,8 +30,8 @@ namespace util { /** - * @brief CoroutineGroup is a helper class to manage a group of coroutines. It allows to spawn multiple coroutines and - * wait for all of them to finish. + * @brief CoroutineGroup is a helper class to manage a group of coroutines. It allows to spawn + * multiple coroutines and wait for all of them to finish. * @note This class is safe to use from multiple threads. */ class CoroutineGroup { @@ -44,10 +44,13 @@ public: * @brief Construct a new Coroutine Group object * * @param yield The yield context to use for the internal timer - * @param maxChildren The maximum number of coroutines that can be spawned at the same time. If not provided, there - * is no limit + * @param maxChildren The maximum number of coroutines that can be spawned at the same time. If + * not provided, there is no limit */ - CoroutineGroup(boost::asio::yield_context yield, std::optional maxChildren = std::nullopt); + CoroutineGroup( + boost::asio::yield_context yield, + std::optional maxChildren = std::nullopt + ); /** * @brief Destroy the Coroutine Group object @@ -59,22 +62,23 @@ public: /** * @brief Spawn a new coroutine in the group * - * @param yield The yield context to use for the coroutine (it should be the same as the one used in the - * constructor) + * @param yield The yield context to use for the coroutine (it should be the same as the one + * used in the constructor) * @param fn The function to execute - * @return true If the coroutine was spawned successfully. false if the maximum number of coroutines has been - * reached + * @return true If the coroutine was spawned successfully. false if the maximum number of + * coroutines has been reached */ bool spawn(boost::asio::yield_context yield, std::function fn); /** * @brief Register a foreign coroutine this group should wait for. - * @note A foreign coroutine is still counted as a child one, i.e. calling this method increases the size of the - * group. + * @note A foreign coroutine is still counted as a child one, i.e. calling this method increases + * the size of the group. * * @param yield The yield context owning the coroutine group. - * @return A callback to call on foreign coroutine completes or std::nullopt if the group is already full. + * @return A callback to call on foreign coroutine completes or std::nullopt if the group is + * already full. */ std::optional> registerForeign(boost::asio::yield_context yield); diff --git a/src/util/JsonUtils.hpp b/src/util/JsonUtils.hpp index 40800e4de..413f22814 100644 --- a/src/util/JsonUtils.hpp +++ b/src/util/JsonUtils.hpp @@ -77,7 +77,8 @@ removeSecret(boost::json::object const& object) auto const secretFields = {"secret", "seed", "seed_hex", "passphrase"}; if (newObject.contains("params") and newObject.at("params").is_array() and - not newObject.at("params").as_array().empty() and newObject.at("params").as_array()[0].is_object()) { + not newObject.at("params").as_array().empty() and + newObject.at("params").as_array()[0].is_object()) { for (auto const& secretField : secretFields) { if (newObject.at("params").as_array()[0].as_object().contains(secretField)) newObject.at("params").as_array()[0].as_object()[secretField] = "*"; diff --git a/src/util/LedgerUtils.cpp b/src/util/LedgerUtils.cpp index ca7cfb515..7d142c82e 100644 --- a/src/util/LedgerUtils.cpp +++ b/src/util/LedgerUtils.cpp @@ -43,8 +43,8 @@ LedgerTypes::getLedgerEntryTypeFromStr(std::string const& entryName) ripple::LedgerEntryType LedgerTypes::getAccountOwnedLedgerTypeFromStr(std::string const& entryName) { - if (auto const result = getLedgerTypeAttributeFromStr(entryName); - result.has_value() && result->get().category_ != LedgerTypeAttribute::LedgerCategory::Chain) { + if (auto const result = getLedgerTypeAttributeFromStr(entryName); result.has_value() && + result->get().category_ != LedgerTypeAttribute::LedgerCategory::Chain) { return result->get().type_; } @@ -54,21 +54,27 @@ LedgerTypes::getAccountOwnedLedgerTypeFromStr(std::string const& entryName) std::optional> LedgerTypes::getLedgerTypeAttributeFromStr(std::string const& entryName) { - static std::unordered_map> const kNAME_MAP = - []() { - std::unordered_map> map; - std::ranges::for_each(kLEDGER_TYPES, [&map](auto const& item) { - map.insert({util::toLower(item.name_), item}); - }); - return map; - }(); + static std::unordered_map< + std::string, + std::reference_wrapper> const kNAME_MAP = []() { + std::unordered_map> + map; + std::ranges::for_each(kLEDGER_TYPES, [&map](auto const& item) { + map.insert({util::toLower(item.name_), item}); + }); + return map; + }(); - static std::unordered_map> const - kRPC_NAME_MAP = []() { - std::unordered_map> map; - std::ranges::for_each(kLEDGER_TYPES, [&map](auto const& item) { map.insert({item.rpcName_, item}); }); - return map; - }(); + static std::unordered_map< + std::string, + std::reference_wrapper> const kRPC_NAME_MAP = []() { + std::unordered_map> + map; + std::ranges::for_each(kLEDGER_TYPES, [&map](auto const& item) { + map.insert({item.rpcName_, item}); + }); + return map; + }(); if (auto const it = kRPC_NAME_MAP.find(entryName); it != kRPC_NAME_MAP.end()) { return it->second; diff --git a/src/util/LedgerUtils.hpp b/src/util/LedgerUtils.hpp index cbf81fc33..2f463eb9f 100644 --- a/src/util/LedgerUtils.hpp +++ b/src/util/LedgerUtils.hpp @@ -98,22 +98,50 @@ class LedgerTypes { using LedgerTypeAttributeList = LedgerTypeAttribute[]; static constexpr LedgerTypeAttributeList const kLEDGER_TYPES{ - LedgerTypeAttribute::accountOwnedLedgerType(JS(AccountRoot), JS(account), ripple::ltACCOUNT_ROOT), + LedgerTypeAttribute::accountOwnedLedgerType( + JS(AccountRoot), + JS(account), + ripple::ltACCOUNT_ROOT + ), LedgerTypeAttribute::chainLedgerType(JS(Amendments), JS(amendments), ripple::ltAMENDMENTS), LedgerTypeAttribute::deletionBlockerLedgerType(JS(Check), JS(check), ripple::ltCHECK), - LedgerTypeAttribute::accountOwnedLedgerType(JS(DepositPreauth), JS(deposit_preauth), ripple::ltDEPOSIT_PREAUTH), + LedgerTypeAttribute::accountOwnedLedgerType( + JS(DepositPreauth), + JS(deposit_preauth), + ripple::ltDEPOSIT_PREAUTH + ), // dir node belongs to account, but can not be filtered from account_objects LedgerTypeAttribute::chainLedgerType(JS(DirectoryNode), JS(directory), ripple::ltDIR_NODE), LedgerTypeAttribute::deletionBlockerLedgerType(JS(Escrow), JS(escrow), ripple::ltESCROW), LedgerTypeAttribute::chainLedgerType(JS(FeeSettings), JS(fee), ripple::ltFEE_SETTINGS), LedgerTypeAttribute::chainLedgerType(JS(LedgerHashes), JS(hashes), ripple::ltLEDGER_HASHES), LedgerTypeAttribute::accountOwnedLedgerType(JS(Offer), JS(offer), ripple::ltOFFER), - LedgerTypeAttribute::deletionBlockerLedgerType(JS(PayChannel), JS(payment_channel), ripple::ltPAYCHAN), - LedgerTypeAttribute::accountOwnedLedgerType(JS(SignerList), JS(signer_list), ripple::ltSIGNER_LIST), - LedgerTypeAttribute::deletionBlockerLedgerType(JS(RippleState), JS(state), ripple::ltRIPPLE_STATE), + LedgerTypeAttribute::deletionBlockerLedgerType( + JS(PayChannel), + JS(payment_channel), + ripple::ltPAYCHAN + ), + LedgerTypeAttribute::accountOwnedLedgerType( + JS(SignerList), + JS(signer_list), + ripple::ltSIGNER_LIST + ), + LedgerTypeAttribute::deletionBlockerLedgerType( + JS(RippleState), + JS(state), + ripple::ltRIPPLE_STATE + ), LedgerTypeAttribute::accountOwnedLedgerType(JS(Ticket), JS(ticket), ripple::ltTICKET), - LedgerTypeAttribute::accountOwnedLedgerType(JS(NFTokenOffer), JS(nft_offer), ripple::ltNFTOKEN_OFFER), - LedgerTypeAttribute::deletionBlockerLedgerType(JS(NFTokenPage), JS(nft_page), ripple::ltNFTOKEN_PAGE), + LedgerTypeAttribute::accountOwnedLedgerType( + JS(NFTokenOffer), + JS(nft_offer), + ripple::ltNFTOKEN_OFFER + ), + LedgerTypeAttribute::deletionBlockerLedgerType( + JS(NFTokenPage), + JS(nft_page), + ripple::ltNFTOKEN_PAGE + ), LedgerTypeAttribute::accountOwnedLedgerType(JS(AMM), JS(amm), ripple::ltAMM), LedgerTypeAttribute::deletionBlockerLedgerType(JS(Bridge), JS(bridge), ripple::ltBRIDGE), LedgerTypeAttribute::deletionBlockerLedgerType( @@ -128,7 +156,11 @@ class LedgerTypes { ), LedgerTypeAttribute::accountOwnedLedgerType(JS(DID), JS(did), ripple::ltDID), LedgerTypeAttribute::accountOwnedLedgerType(JS(Oracle), JS(oracle), ripple::ltORACLE), - LedgerTypeAttribute::accountOwnedLedgerType(JS(Credential), JS(credential), ripple::ltCREDENTIAL), + LedgerTypeAttribute::accountOwnedLedgerType( + JS(Credential), + JS(credential), + ripple::ltCREDENTIAL + ), LedgerTypeAttribute::accountOwnedLedgerType(JS(Vault), JS(vault), ripple::ltVAULT), LedgerTypeAttribute::chainLedgerType(JS(NegativeUNL), JS(nunl), ripple::ltNEGATIVE_UNL), LedgerTypeAttribute::deletionBlockerLedgerType( @@ -154,7 +186,9 @@ public: getLedgerEntryTypeStrList() { std::array res{}; - std::ranges::transform(kLEDGER_TYPES, std::begin(res), [](auto const& item) { return item.rpcName_; }); + std::ranges::transform(kLEDGER_TYPES, std::begin(res), [](auto const& item) { + return item.rpcName_; + }); return res; } @@ -186,7 +220,8 @@ public: /** * @brief Returns the ripple::LedgerEntryType from the given string. * - * @param entryName The name or canonical name (case-insensitive) of the ledger entry type for all categories + * @param entryName The name or canonical name (case-insensitive) of the ledger entry type for + * all categories * @return The ripple::LedgerEntryType of the given string, returns ltANY if not found. */ static ripple::LedgerEntryType @@ -195,8 +230,8 @@ public: /** * @brief Returns the ripple::LedgerEntryType from the given string. * - * @param entryName The name or canonical name (case-insensitive) of the ledger entry type for account owned - * category + * @param entryName The name or canonical name (case-insensitive) of the ledger entry type for + * account owned category * @return The ripple::LedgerEntryType of the given string, returns ltANY if not found. */ static ripple::LedgerEntryType diff --git a/src/util/MoveTracker.hpp b/src/util/MoveTracker.hpp index 22d0bd8ae..33f527af8 100644 --- a/src/util/MoveTracker.hpp +++ b/src/util/MoveTracker.hpp @@ -31,7 +31,8 @@ class MoveTracker { protected: /** - * @brief The function to be used by clients in order to check whether the instance was moved from + * @brief The function to be used by clients in order to check whether the instance was moved + * from * @return true if moved from; false otherwise */ [[nodiscard]] bool diff --git a/src/util/ObservableValue.hpp b/src/util/ObservableValue.hpp index c44d2b768..f735a00eb 100644 --- a/src/util/ObservableValue.hpp +++ b/src/util/ObservableValue.hpp @@ -30,7 +30,8 @@ namespace util { template -concept SomeAtomic = std::same_as, std::atomic>>; +concept SomeAtomic = + std::same_as, std::atomic>>; /** * @brief Concept defining types that can be observed for changes. @@ -46,7 +47,8 @@ concept SomeAtomic = std::same_as, std::atomic -concept Observable = std::equality_comparable && std::copy_constructible && std::move_constructible; +concept Observable = + std::equality_comparable && std::copy_constructible && std::move_constructible; namespace impl { @@ -56,7 +58,8 @@ namespace impl { * This class contains all the observer management and notification logic * that is shared between regular and atomic ObservableValue specializations. * - * @tparam T The value type (for atomic specializations, this is the underlying type, not std::atomic) + * @tparam T The value type (for atomic specializations, this is the underlying type, not + * std::atomic) */ template class ObservableValueBase { @@ -117,14 +120,15 @@ class ObservableValue; /** * @brief An observable value container that notifies observers when the value changes. * - * ObservableValue wraps a value of type T and provides a mechanism to observe changes to that value. - * When the value is modified (and actually changes), all registered observers are notified. + * ObservableValue wraps a value of type T and provides a mechanism to observe changes to that + * value. When the value is modified (and actually changes), all registered observers are notified. * * @tparam T The type of value to observe. Must satisfy the Observable concept. * * @par Thread Safety * - Observer subscription/unsubscription (observe() and connection.disconnect()) are thread-safe - * - Value modification operations (set(), operator=) are NOT thread-safe and require external synchronization + * - Value modification operations (set(), operator=) are NOT thread-safe and require external + * synchronization * - Observer callbacks are invoked synchronously on the same thread that triggered the value change * - If observers need to perform work on different threads, they must handle dispatch themselves * (e.g., using an async execution context or message queue) @@ -190,7 +194,8 @@ public: * @brief Constructs ObservableValue with initial value. * @param value Initial value (must be convertible to T) */ - ObservableValue(std::convertible_to auto&& value) : value_{std::forward(value)} + ObservableValue(std::convertible_to auto&& value) + : value_{std::forward(value)} { } @@ -327,7 +332,8 @@ public: * @brief Constructs ObservableValue with initial atomic value. * @param value Initial value (will be stored in the atomic) */ - ObservableValue(std::convertible_to auto&& value) : value_{std::forward(value)} + ObservableValue(std::convertible_to auto&& value) + : value_{std::forward(value)} { } diff --git a/src/util/Profiler.hpp b/src/util/Profiler.hpp index 39b4b0605..7f6b4e79a 100644 --- a/src/util/Profiler.hpp +++ b/src/util/Profiler.hpp @@ -31,8 +31,8 @@ namespace util { * @tparam U The duration measurement to use; defaults to milliseconds * @tparam FnType The type of the function object * @param func Any function object - * @return If the function object has a return value, the result of the function call and the elapsed time(ms) is - * returned as a pair + * @return If the function object has a return value, the result of the function call and the + * elapsed time(ms) is returned as a pair * @return Only return the elapsed time if passed function object does not have a return value */ template @@ -46,7 +46,8 @@ timed(FnType&& func) return std::chrono::duration_cast(std::chrono::system_clock::now() - start).count(); } else { auto ret = func(); - auto elapsed = std::chrono::duration_cast(std::chrono::system_clock::now() - start).count(); + auto elapsed = + std::chrono::duration_cast(std::chrono::system_clock::now() - start).count(); return std::make_pair(std::move(ret), std::move(elapsed)); } } diff --git a/src/util/Random.cpp b/src/util/Random.cpp index 3c0e5ad26..929aba229 100644 --- a/src/util/Random.cpp +++ b/src/util/Random.cpp @@ -25,7 +25,8 @@ namespace util { -MTRandomGenerator::MTRandomGenerator() : generator_{std::chrono::system_clock::now().time_since_epoch().count()} +MTRandomGenerator::MTRandomGenerator() + : generator_{std::chrono::system_clock::now().time_since_epoch().count()} { } diff --git a/src/util/Repeat.hpp b/src/util/Repeat.hpp index de21e02c4..abd5080a8 100644 --- a/src/util/Repeat.hpp +++ b/src/util/Repeat.hpp @@ -38,7 +38,8 @@ namespace util { /** * @brief A class to repeat some action at a regular interval - * @note io_context must be stopped before the Repeat object is destroyed. Otherwise it is undefined behavior + * @note io_context must be stopped before the Repeat object is destroyed. Otherwise it is undefined + * behavior */ class Repeat { struct Control { @@ -57,7 +58,8 @@ class Repeat { public: /** * @brief Construct a new Repeat object - * @note The `ctx` parameter is `auto` so that this util supports `strand` and `thread_pool` as well as `io_context` + * @note The `ctx` parameter is `auto` so that this util supports `strand` and `thread_pool` as + * well as `io_context` * * @param ctx The io_context-like object to use */ @@ -74,7 +76,8 @@ public: /** * @brief Stop repeating - * @note This method will block to ensure the repeating is actually stopped. But blocking time should be very short. + * @note This method will block to ensure the repeating is actually stopped. But blocking time + * should be very short. */ void stop(); @@ -99,27 +102,35 @@ public: private: template static void - startImpl(std::shared_ptr control, std::chrono::steady_clock::duration interval, Action&& action) + startImpl( + std::shared_ptr control, + std::chrono::steady_clock::duration interval, + Action&& action + ) { - boost::asio::post(control->strand, [control, interval, action = std::forward(action)]() mutable { - if (control->stopping) { - control->semaphore.release(); - return; - } - - control->timer.expires_after(interval); - control->timer.async_wait( - [control, interval, action = std::forward(action)](auto const& ec) mutable { - if (ec or control->stopping) { - control->semaphore.release(); - return; - } - action(); - - startImpl(std::move(control), interval, std::forward(action)); + boost::asio::post( + control->strand, [control, interval, action = std::forward(action)]() mutable { + if (control->stopping) { + control->semaphore.release(); + return; } - ); - }); + + control->timer.expires_after(interval); + control->timer.async_wait( + [control, + interval, + action = std::forward(action)](auto const& ec) mutable { + if (ec or control->stopping) { + control->semaphore.release(); + return; + } + action(); + + startImpl(std::move(control), interval, std::forward(action)); + } + ); + } + ); } }; diff --git a/src/util/Retry.cpp b/src/util/Retry.cpp index ec52034a9..388293f4f 100644 --- a/src/util/Retry.cpp +++ b/src/util/Retry.cpp @@ -30,7 +30,8 @@ namespace util { -RetryStrategy::RetryStrategy(std::chrono::steady_clock::duration delay) : initialDelay_(delay), delay_(delay) +RetryStrategy::RetryStrategy(std::chrono::steady_clock::duration delay) + : initialDelay_(delay), delay_(delay) { } @@ -52,7 +53,10 @@ RetryStrategy::reset() delay_ = initialDelay_; } -Retry::Retry(RetryStrategyPtr strategy, boost::asio::strand strand) +Retry::Retry( + RetryStrategyPtr strategy, + boost::asio::strand strand +) : strategy_(std::move(strategy)), timer_(strand.get_inner_executor()) { } diff --git a/src/util/Retry.hpp b/src/util/Retry.hpp index a6af95bcd..4406e2256 100644 --- a/src/util/Retry.hpp +++ b/src/util/Retry.hpp @@ -90,7 +90,10 @@ public: * @param strategy The retry strategy to use * @param strand The strand to use for async operations */ - Retry(RetryStrategyPtr strategy, boost::asio::strand strand); + Retry( + RetryStrategyPtr strategy, + boost::asio::strand strand + ); /** * @brief Destroy the Retry object @@ -110,15 +113,15 @@ public: *canceled_ = false; timer_.expires_after(strategy_->getDelay()); strategy_->increaseDelay(); - timer_.async_wait( - [this, canceled = canceled_, func = std::forward(func)](boost::system::error_code const& ec) { - if (ec == boost::asio::error::operation_aborted or *canceled) { - return; - } - ++attemptNumber_; - func(); + timer_.async_wait([this, + canceled = canceled_, + func = std::forward(func)](boost::system::error_code const& ec) { + if (ec == boost::asio::error::operation_aborted or *canceled) { + return; } - ); + ++attemptNumber_; + func(); + }); } /** @@ -159,7 +162,10 @@ public: * @param delay The initial delay value * @param maxDelay The maximum delay value */ - ExponentialBackoffStrategy(std::chrono::steady_clock::duration delay, std::chrono::steady_clock::duration maxDelay); + ExponentialBackoffStrategy( + std::chrono::steady_clock::duration delay, + std::chrono::steady_clock::duration maxDelay + ); private: std::chrono::steady_clock::duration diff --git a/src/util/SignalsHandler.cpp b/src/util/SignalsHandler.cpp index 1e1507d91..838ce149e 100644 --- a/src/util/SignalsHandler.cpp +++ b/src/util/SignalsHandler.cpp @@ -65,8 +65,13 @@ SignalsHandler* SignalsHandlerStatic::installedHandler = nullptr; } // namespace impl -SignalsHandler::SignalsHandler(config::ClioConfigDefinition const& config, std::function forceExitHandler) - : gracefulPeriod_(util::config::ClioConfigDefinition::toMilliseconds(config.get("graceful_period"))) +SignalsHandler::SignalsHandler( + config::ClioConfigDefinition const& config, + std::function forceExitHandler +) + : gracefulPeriod_( + util::config::ClioConfigDefinition::toMilliseconds(config.get("graceful_period")) + ) , forceExitHandler_(std::move(forceExitHandler)) { impl::SignalsHandlerStatic::registerHandler(*this); @@ -84,7 +89,8 @@ SignalsHandler::~SignalsHandler() if (workerThread_.joinable()) workerThread_.join(); - impl::SignalsHandlerStatic::resetHandler(); // This is needed mostly for tests to reset static state + impl::SignalsHandlerStatic::resetHandler(); // This is needed mostly for tests to reset static + // state } void @@ -114,7 +120,9 @@ SignalsHandler::runStateMachine() case State::WaitingForSignal: { { std::unique_lock lock(mutex_); - cv_.wait(lock, [this]() { return signalReceived_ or state_ == State::NormalExit; }); + cv_.wait(lock, [this]() { + return signalReceived_ or state_ == State::NormalExit; + }); } if (state_ == State::NormalExit) @@ -123,7 +131,8 @@ SignalsHandler::runStateMachine() LOG( LogService::info() ) << "Got stop signal. Stopping Clio. Graceful period is " - << std::chrono::duration_cast(gracefulPeriod_).count() << " milliseconds."; + << std::chrono::duration_cast(gracefulPeriod_).count() + << " milliseconds."; state_ = State::GracefulShutdown; signalReceived_ = false; diff --git a/src/util/Spawn.hpp b/src/util/Spawn.hpp index 79229cf9e..65f58a9d4 100644 --- a/src/util/Spawn.hpp +++ b/src/util/Spawn.hpp @@ -30,13 +30,14 @@ namespace util { namespace impl { template -concept IsStrand = std::same_as, boost::asio::strand::inner_executor_type>>; +concept IsStrand = std:: + same_as, boost::asio::strand::inner_executor_type>>; /** * @brief A completion handler that restores `boost::asio::spawn`'s behaviour from Boost 1.83 * - * This is intended to be passed as the third argument to `boost::asio::spawn` so that exceptions are not ignored but - * propagated to `io_context.run()` call site. + * This is intended to be passed as the third argument to `boost::asio::spawn` so that exceptions + * are not ignored but propagated to `io_context.run()` call site. */ inline constexpr struct PropagatingCompletionHandler { /** @@ -57,7 +58,8 @@ inline constexpr struct PropagatingCompletionHandler { * @brief Spawns a coroutine using `boost::asio::spawn` * * @note This uses kPROPAGATE_EXCEPTIONS to force asio to propagate exceptions through `io_context` - * @note Since implicit strand was removed from boost::asio::spawn this helper function adds the strand back + * @note Since implicit strand was removed from boost::asio::spawn this helper function adds the + * strand back * * @tparam Ctx The type of the context/strand * @tparam F The type of the function to execute @@ -70,7 +72,9 @@ void spawn(Ctx&& ctx, F&& func) { if constexpr (impl::IsStrand) { - boost::asio::spawn(std::forward(ctx), std::forward(func), impl::kPROPAGATE_EXCEPTIONS); + boost::asio::spawn( + std::forward(ctx), std::forward(func), impl::kPROPAGATE_EXCEPTIONS + ); } else { boost::asio::spawn( boost::asio::make_strand(std::forward(ctx).get_executor()), diff --git a/src/util/StopHelper.cpp b/src/util/StopHelper.cpp index 733e3585c..e5f488dae 100644 --- a/src/util/StopHelper.cpp +++ b/src/util/StopHelper.cpp @@ -38,7 +38,9 @@ StopHelper::readyToStop() void StopHelper::asyncWaitForStop(boost::asio::yield_context yield) { - boost::asio::steady_timer timer{yield.get_executor(), std::chrono::steady_clock::duration::max()}; + boost::asio::steady_timer timer{ + yield.get_executor(), std::chrono::steady_clock::duration::max() + }; onStopReady_.connect([&]() { util::spawn(yield, [&timer](auto&&) { timer.cancel(); }); }); boost::system::error_code error; if (!*stopped_) diff --git a/src/util/Taggable.hpp b/src/util/Taggable.hpp index e694b6112..52a054c88 100644 --- a/src/util/Taggable.hpp +++ b/src/util/Taggable.hpp @@ -128,10 +128,11 @@ public: /** * @brief Create a new tag decorator with an optional parent. * - * If the `parent` is specified it will be streamed out as a chain when this decorator will decorate an ostream. + * If the `parent` is specified it will be streamed out as a chain when this decorator will + * decorate an ostream. * - * Note that if `parent` is specified it is your responsibility that the decorator referred to by `parent` outlives - * this decorator. + * Note that if `parent` is specified it is your responsibility that the decorator referred to + * by `parent` outlives this decorator. * * @param parent An optional parent tag decorator */ @@ -159,7 +160,8 @@ public: /** * @brief Specialization for a nop/null decorator. * - * This generates a pass-through decorate member function which can be optimized away by the compiler. + * This generates a pass-through decorate member function which can be optimized away by the + * compiler. */ template <> class TagDecorator final : public BaseTagDecorator { @@ -260,7 +262,8 @@ protected: * * @param tagFactory The factory to use */ - explicit Taggable(util::TagDecoratorFactory const& tagFactory) : tagDecorator_{tagFactory.make()} + explicit Taggable(util::TagDecoratorFactory const& tagFactory) + : tagDecorator_{tagFactory.make()} { } diff --git a/src/util/TerminationHandler.cpp b/src/util/TerminationHandler.cpp index 8a924834a..4310eb668 100644 --- a/src/util/TerminationHandler.cpp +++ b/src/util/TerminationHandler.cpp @@ -37,7 +37,8 @@ terminationHandler() { #ifndef CLIO_WITHOUT_STACKTRACE try { - LOG(LogService::fatal()) << "Exit on terminate. Backtrace:\n" << boost::stacktrace::stacktrace(); + LOG(LogService::fatal()) << "Exit on terminate. Backtrace:\n" + << boost::stacktrace::stacktrace(); } catch (...) { LOG(LogService::fatal()) << "Exit on terminate. Can't get backtrace."; } diff --git a/src/util/TimeUtils.cpp b/src/util/TimeUtils.cpp index 557b9c2eb..be991ced8 100644 --- a/src/util/TimeUtils.cpp +++ b/src/util/TimeUtils.cpp @@ -51,7 +51,9 @@ systemTpToUtcStr(std::chrono::system_clock::time_point const& tp, std::string co [[nodiscard]] std::chrono::system_clock::time_point systemTpFromLedgerCloseTime(ripple::NetClock::time_point closeTime) { - return std::chrono::system_clock::time_point{closeTime.time_since_epoch() + ripple::epoch_offset}; + return std::chrono::system_clock::time_point{ + closeTime.time_since_epoch() + ripple::epoch_offset + }; } } // namespace util diff --git a/src/util/WithTimeout.hpp b/src/util/WithTimeout.hpp index 0a1b5b864..dfea3e2ef 100644 --- a/src/util/WithTimeout.hpp +++ b/src/util/WithTimeout.hpp @@ -37,8 +37,8 @@ namespace util { /** * @brief Perform a coroutine operation with a timeout. * - * @tparam Operation The operation type to perform. Must be a callable accepting yield context with bound cancellation - * token. + * @tparam Operation The operation type to perform. Must be a callable accepting yield context with + * bound cancellation token. * @param operation The operation to perform. * @param yield The yield context. * @param timeout The timeout duration. @@ -46,7 +46,11 @@ namespace util { */ template boost::system::error_code -withTimeout(Operation&& operation, boost::asio::yield_context yield, std::chrono::steady_clock::duration timeout) +withTimeout( + Operation&& operation, + boost::asio::yield_context yield, + std::chrono::steady_clock::duration timeout +) { boost::system::error_code error; auto operationCompleted = std::make_shared(false); @@ -54,7 +58,8 @@ withTimeout(Operation&& operation, boost::asio::yield_context yield, std::chrono auto cyield = boost::asio::bind_cancellation_slot(cancellationSignal.slot(), yield[error]); boost::asio::steady_timer timer{boost::asio::get_associated_executor(cyield), timeout}; - timer.async_wait([&cancellationSignal, operationCompleted](boost::system::error_code errorCode) { + timer.async_wait([&cancellationSignal, + operationCompleted](boost::system::error_code errorCode) { if (!errorCode and !*operationCompleted) cancellationSignal.emit(boost::asio::cancellation_type::terminal); }); diff --git a/src/util/async/AnyExecutionContext.hpp b/src/util/async/AnyExecutionContext.hpp index f98e66236..e5870eb7b 100644 --- a/src/util/async/AnyExecutionContext.hpp +++ b/src/util/async/AnyExecutionContext.hpp @@ -64,7 +64,8 @@ public: */ template CtxType> /* implicit */ - AnyExecutionContext(CtxType&& ctx) : pimpl_{std::make_shared>(std::forward(ctx))} + AnyExecutionContext(CtxType&& ctx) + : pimpl_{std::make_shared>(std::forward(ctx))} { } @@ -88,14 +89,16 @@ public: using RetType = std::decay_t>; static_assert(not std::is_same_v); - return AnyOperation(pimpl_->execute([fn = std::forward(fn)] mutable -> std::any { - if constexpr (std::is_void_v) { - std::invoke(std::forward(fn)); - return {}; - } else { - return std::make_any(std::invoke(std::forward(fn))); - } - })); + return AnyOperation( + pimpl_->execute([fn = std::forward(fn)] mutable -> std::any { + if constexpr (std::is_void_v) { + std::invoke(std::forward(fn)); + return {}; + } else { + return std::make_any(std::invoke(std::forward(fn))); + } + }) + ); } /** @@ -112,16 +115,18 @@ public: using RetType = std::decay_t>; static_assert(not std::is_same_v); - return AnyOperation( - pimpl_->execute([fn = std::forward(fn)](auto stopToken) mutable -> std::any { + return AnyOperation(pimpl_->execute( + [fn = std::forward(fn)](auto stopToken) mutable -> std::any { if constexpr (std::is_void_v) { std::invoke(std::forward(fn), std::move(stopToken)); return {}; } else { - return std::make_any(std::invoke(std::forward(fn), std::move(stopToken))); + return std::make_any( + std::invoke(std::forward(fn), std::move(stopToken)) + ); } - }) - ); + } + )); } /** @@ -145,7 +150,9 @@ public: std::invoke(std::forward(fn), std::move(stopToken)); return {}; } else { - return std::make_any(std::invoke(std::forward(fn), std::move(stopToken))); + return std::make_any( + std::invoke(std::forward(fn), std::move(stopToken)) + ); } }, std::chrono::duration_cast(timeout) @@ -168,16 +175,18 @@ public: static_assert(not std::is_same_v); auto const millis = std::chrono::duration_cast(delay); - return AnyOperation( - pimpl_->scheduleAfter(millis, [fn = std::forward(fn)](auto stopToken) mutable -> std::any { + return AnyOperation(pimpl_->scheduleAfter( + millis, [fn = std::forward(fn)](auto stopToken) mutable -> std::any { if constexpr (std::is_void_v) { std::invoke(std::forward(fn), std::move(stopToken)); return {}; } else { - return std::make_any(std::invoke(std::forward(fn), std::move(stopToken))); + return std::make_any( + std::invoke(std::forward(fn), std::move(stopToken)) + ); } - }) - ); + } + )); } /** @@ -187,8 +196,8 @@ public: * @param fn The function to execute * @returns A stoppable operation that can be used to wait for the result * - * @note The function is expected to take a stop token and a boolean representing whether the scheduled operation - * got cancelled + * @note The function is expected to take a stop token and a boolean representing whether the + * scheduled operation got cancelled */ [[nodiscard]] auto scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith auto&& fn) @@ -198,7 +207,9 @@ public: auto const millis = std::chrono::duration_cast(delay); return AnyOperation(pimpl_->scheduleAfter( - millis, [fn = std::forward(fn)](auto stopToken, auto cancelled) mutable -> std::any { + millis, + [fn = std::forward(fn)](auto stopToken, auto cancelled) mutable + -> std::any { if constexpr (std::is_void_v) { std::invoke(std::forward(fn), std::move(stopToken), cancelled); return {}; @@ -226,10 +237,12 @@ public: auto const millis = std::chrono::duration_cast(interval); return AnyOperation( // - pimpl_->executeRepeatedly(millis, [fn = std::forward(fn)] mutable -> std::any { - std::invoke(std::forward(fn)); - return {}; - }) + pimpl_->executeRepeatedly( + millis, [fn = std::forward(fn)] mutable -> std::any { + std::invoke(std::forward(fn)); + return {}; + } + ) ); } @@ -250,8 +263,8 @@ public: * * @return A strand for this execution context * - * @note The strand can be used similarly to the execution context and guarantees serial execution of all submitted - * operations + * @note The strand can be used similarly to the execution context and guarantees serial + * execution of all submitted operations */ [[nodiscard]] auto makeStrand() @@ -289,9 +302,12 @@ private: virtual impl::ErasedOperation execute(std::function) = 0; virtual impl::ErasedOperation scheduleAfter(std::chrono::milliseconds, std::function) = 0; + virtual impl::ErasedOperation scheduleAfter( + std::chrono::milliseconds, + std::function + ) = 0; virtual impl::ErasedOperation - scheduleAfter(std::chrono::milliseconds, std::function) = 0; - virtual impl::ErasedOperation executeRepeatedly(std::chrono::milliseconds, std::function) = 0; + executeRepeatedly(std::chrono::milliseconds, std::function) = 0; virtual void submit(std::function) = 0; virtual AnyStrand makeStrand() = 0; @@ -311,7 +327,10 @@ private: } impl::ErasedOperation - execute(std::function fn, std::optional timeout) override + execute( + std::function fn, + std::optional timeout + ) override { return ctx.execute(std::move(fn), timeout); } @@ -323,13 +342,19 @@ private: } impl::ErasedOperation - scheduleAfter(std::chrono::milliseconds delay, std::function fn) override + scheduleAfter( + std::chrono::milliseconds delay, + std::function fn + ) override { return ctx.scheduleAfter(delay, std::move(fn)); } impl::ErasedOperation - scheduleAfter(std::chrono::milliseconds delay, std::function fn) override + scheduleAfter( + std::chrono::milliseconds delay, + std::function fn + ) override { return ctx.scheduleAfter(delay, std::move(fn)); } diff --git a/src/util/async/AnyOperation.hpp b/src/util/async/AnyOperation.hpp index 7328a5494..793e67a18 100644 --- a/src/util/async/AnyOperation.hpp +++ b/src/util/async/AnyOperation.hpp @@ -32,8 +32,8 @@ #include // TODO: In the future, perhaps cancel and requestStop should be combined into one. -// Users of the library should not care whether the operation is cancellable or stoppable - users just want to cancel -// it whatever that means internally. +// Users of the library should not care whether the operation is cancellable or stoppable - users +// just want to cancel it whatever that means internally. namespace util::async { @@ -48,7 +48,8 @@ public: * * @param operation The operation to wrap */ - /* implicit */ AnyOperation(impl::ErasedOperation&& operation) : operation_{std::move(operation)} + /* implicit */ AnyOperation(impl::ErasedOperation&& operation) + : operation_{std::move(operation)} { } @@ -74,7 +75,8 @@ public: /** * @brief Abort the operation * - * Used to cancel the timer for scheduled operations and request the operation to be stopped as soon as possible + * Used to cancel the timer for scheduled operations and request the operation to be stopped as + * soon as possible */ void abort() @@ -102,15 +104,17 @@ public: } } catch (std::bad_any_cast const& e) { - return std::unexpected{ExecutionError(fmt::format("{}", std::this_thread::get_id()), "Bad any cast")}; + return std::unexpected{ + ExecutionError(fmt::format("{}", std::this_thread::get_id()), "Bad any cast") + }; } } /** * @brief Force-invoke the operation * @note The action is scheduled on the underlying context/strand - * @warning The code of the user-provided action is expected to take care of thread-safety unless this operation is - * scheduled through a strand + * @warning The code of the user-provided action is expected to take care of thread-safety + * unless this operation is scheduled through a strand */ void invoke() diff --git a/src/util/async/AnyStrand.hpp b/src/util/async/AnyStrand.hpp index d60db3a31..d8fca9d77 100644 --- a/src/util/async/AnyStrand.hpp +++ b/src/util/async/AnyStrand.hpp @@ -92,14 +92,18 @@ public: static_assert(not std::is_same_v); return AnyOperation( // - pimpl_->execute([fn = std::forward(fn)](auto stopToken) mutable -> std::any { - if constexpr (std::is_void_v) { - std::invoke(std::forward(fn), std::move(stopToken)); - return {}; - } else { - return std::make_any(std::invoke(std::forward(fn), std::move(stopToken))); + pimpl_->execute( + [fn = std::forward(fn)](auto stopToken) mutable -> std::any { + if constexpr (std::is_void_v) { + std::invoke(std::forward(fn), std::move(stopToken)); + return {}; + } else { + return std::make_any( + std::invoke(std::forward(fn), std::move(stopToken)) + ); + } } - }) + ) ); } @@ -148,10 +152,12 @@ public: auto const millis = std::chrono::duration_cast(interval); return AnyOperation( // - pimpl_->executeRepeatedly(millis, [fn = std::forward(fn)] mutable -> std::any { - std::invoke(std::forward(fn)); - return {}; - }) + pimpl_->executeRepeatedly( + millis, [fn = std::forward(fn)] mutable -> std::any { + std::invoke(std::forward(fn)); + return {}; + } + ) ); } @@ -193,7 +199,10 @@ private: } [[nodiscard]] impl::ErasedOperation - execute(std::function fn, std::optional timeout) override + execute( + std::function fn, + std::optional timeout + ) override { return strand.execute(std::move(fn), timeout); } diff --git a/src/util/async/Concepts.hpp b/src/util/async/Concepts.hpp index 1bde21e6e..fa925edbd 100644 --- a/src/util/async/Concepts.hpp +++ b/src/util/async/Concepts.hpp @@ -33,7 +33,8 @@ namespace util::async { * @brief Tag type for identifying execution context types. * * Types that inherit from this tag can be detected using the SomeExecutionContext concept. - * This allows generic code to differentiate between raw Boost.Asio contexts and wrapped execution contexts. + * This allows generic code to differentiate between raw Boost.Asio contexts and wrapped execution + * contexts. */ struct ExecutionContextTag { virtual ~ExecutionContextTag() = default; @@ -190,7 +191,8 @@ concept SomeHandlerWith = requires(T fn) { template concept SomeStdDuration = requires { // Thank you Ed Catmur for this trick. - // See https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types + // See + // https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types []( // std::type_identity> ) {}(std::type_identity>()); diff --git a/src/util/async/Operation.hpp b/src/util/async/Operation.hpp index 8783219a4..42a5b3c63 100644 --- a/src/util/async/Operation.hpp +++ b/src/util/async/Operation.hpp @@ -99,9 +99,13 @@ struct BasicScheduledOperation : util::MoveTracker { typename CtxType::Timer timer; BasicScheduledOperation(auto& executor, auto delay, auto&& fn) - : timer(executor, delay, [state = state, fn = std::forward(fn)](auto ec) mutable { - state->emplace(fn(ec)); - }) + : timer( + executor, + delay, + [state = state, fn = std::forward(fn)](auto ec) mutable { + state->emplace(fn(ec)); + } + ) { } @@ -220,8 +224,9 @@ using ScheduledOperation = impl::BasicScheduledOperation; /** * @brief The `future` side of async operations that automatically repeat until aborted * - * @note The current implementation requires the user provided function to return void and to take no arguments. There - * is also no mechanism to request the repeating task to stop from inside of the user provided block of code. + * @note The current implementation requires the user provided function to return void and to take + * no arguments. There is also no mechanism to request the repeating task to stop from inside of the + * user provided block of code. * * @tparam CtxType The type of the execution context */ @@ -241,7 +246,8 @@ public: */ template RepeatingOperation(auto& executor, std::chrono::steady_clock::duration interval, FnType&& fn) - : repeat_(executor), action_([fn = std::forward(fn), &executor] { boost::asio::post(executor, fn); }) + : repeat_(executor) + , action_([fn = std::forward(fn), &executor] { boost::asio::post(executor, fn); }) { repeat_.start(interval, action_); } @@ -273,8 +279,8 @@ public: /** * @brief Force-invoke the operation * @note The action is scheduled on the underlying context/strand - * @warning The code of the user-provided action is expected to take care of thread-safety unless this operation is - * scheduled through a strand + * @warning The code of the user-provided action is expected to take care of thread-safety + * unless this operation is scheduled through a strand */ void invoke() diff --git a/src/util/async/context/BasicExecutionContext.hpp b/src/util/async/context/BasicExecutionContext.hpp index be8a6a200..145100818 100644 --- a/src/util/async/context/BasicExecutionContext.hpp +++ b/src/util/async/context/BasicExecutionContext.hpp @@ -47,7 +47,8 @@ /** * @brief This namespace implements an async framework built on top of execution contexts * - * There are multiple execution contexts available, each with its own set of features and trade-offs. + * There are multiple execution contexts available, each with its own set of features and + * trade-offs. * * @see util::async::CoroExecutionContext * @see util::async::PoolExecutionContext @@ -120,8 +121,8 @@ struct AsioPoolContext { * * This execution context is used as the base for all specialized execution contexts. * Return values are handled by capturing them and returning them packaged as std::expected. - * Exceptions may or may not be caught and handled depending on the error strategy. The default behavior is to catch and - * package them as the error channel of std::expected. + * Exceptions may or may not be caught and handled depending on the error strategy. The default + * behavior is to catch and package them as the error channel of std::expected. */ template < typename ContextType, @@ -138,7 +139,8 @@ class BasicExecutionContext : public ExecutionContextTag { public: /** @brief Whether operations on this execution context are noexcept */ - static constexpr bool kIS_NOEXCEPT = noexcept(ErrorHandlerType::wrap([](auto&) { throw 0; })) and + static constexpr bool kIS_NOEXCEPT = + noexcept(ErrorHandlerType::wrap([](auto&) { throw 0; })) and noexcept(ErrorHandlerType::catchAndAssert([] { throw 0; })); using ContextHolderType = ContextType; @@ -158,8 +160,12 @@ public: template using Operation = Operation>; - using Strand = impl:: - BasicStrand; + using Strand = impl::BasicStrand< + BasicExecutionContext, + StopSourceType, + DispatcherType, + TimerContextProvider, + ErrorHandlerType>; using Timer = typename ContextHolderType::Timer; @@ -205,7 +211,9 @@ public: std::optional timeout = std::nullopt ) noexcept(kIS_NOEXCEPT) { - if constexpr (not std::is_same_v) { + if constexpr (not std::is_same_v< + decltype(TimerContextProvider::getContext(*this)), + decltype(*this)>) { return TimerContextProvider::getContext(*this).scheduleAfter( delay, std::forward(fn), timeout ); @@ -220,7 +228,9 @@ public: if constexpr (std::is_void_v) { std::invoke(std::forward(fn), std::move(stopToken)); } else { - return std::invoke(std::forward(fn), std::move(stopToken)); + return std::invoke( + std::forward(fn), std::move(stopToken) + ); } }, timeout @@ -234,7 +244,8 @@ public: * @brief Schedule an operation on the execution context * * @param delay The delay after which the operation should be executed - * @param fn The block of code to execute with stop token as the first arg and cancellation flag as the second arg + * @param fn The block of code to execute with stop token as the first arg and cancellation flag + * as the second arg * @param timeout The optional timeout duration after which the operation will be cancelled * @return A scheduled stoppable operation that can be used to wait for the result */ @@ -245,7 +256,9 @@ public: std::optional timeout = std::nullopt ) noexcept(kIS_NOEXCEPT) { - if constexpr (not std::is_same_v) { + if constexpr (not std::is_same_v< + decltype(TimerContextProvider::getContext(*this)), + decltype(*this)>) { return TimerContextProvider::getContext(*this).scheduleAfter( delay, std::forward(fn), timeout ); @@ -257,11 +270,17 @@ public: [this, timeout, fn = std::forward(fn)](auto ec) mutable { return this->execute( [fn = std::forward(fn), - isAborted = (ec == boost::asio::error::operation_aborted)](auto stopToken) mutable { + isAborted = (ec == boost::asio::error::operation_aborted)]( + auto stopToken + ) mutable { if constexpr (std::is_void_v) { - std::invoke(std::forward(fn), std::move(stopToken), isAborted); + std::invoke( + std::forward(fn), std::move(stopToken), isAborted + ); } else { - return std::invoke(std::forward(fn), std::move(stopToken), isAborted); + return std::invoke( + std::forward(fn), std::move(stopToken), isAborted + ); } }, timeout @@ -280,12 +299,21 @@ public: * @return A repeating stoppable operation that can be used to wait for its cancellation */ [[nodiscard]] auto - executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto&& fn) noexcept(kIS_NOEXCEPT) + executeRepeatedly( + SomeStdDuration auto interval, + SomeHandlerWithoutStopToken auto&& fn + ) noexcept(kIS_NOEXCEPT) { - if constexpr (not std::is_same_v) { - return TimerContextProvider::getContext(*this).executeRepeatedly(interval, std::forward(fn)); + if constexpr (not std::is_same_v< + decltype(TimerContextProvider::getContext(*this)), + decltype(*this)>) { + return TimerContextProvider::getContext(*this).executeRepeatedly( + interval, std::forward(fn) + ); } else { - return RepeatedOperation(impl::extractAssociatedExecutor(*this), interval, std::forward(fn)); + return RepeatedOperation( + impl::extractAssociatedExecutor(*this), interval, std::forward(fn) + ); } } @@ -308,15 +336,18 @@ public: ErrorHandlerType::wrap([this, timeout, fn = std::forward(fn)]( auto& outcome, auto& stopSource, auto stopToken ) mutable { - [[maybe_unused]] auto timeoutHandler = - impl::getTimeoutHandleIfNeeded(TimerContextProvider::getContext(*this), timeout, stopSource); + [[maybe_unused]] auto timeoutHandler = impl::getTimeoutHandleIfNeeded( + TimerContextProvider::getContext(*this), timeout, stopSource + ); using FnRetType = std::decay_t>; if constexpr (std::is_void_v) { std::invoke(std::forward(fn), std::move(stopToken)); outcome.setValue(); } else { - outcome.setValue(std::invoke(std::forward(fn), std::move(stopToken))); + outcome.setValue( + std::invoke(std::forward(fn), std::move(stopToken)) + ); } }) ); @@ -330,7 +361,9 @@ public: * @return A stoppable operation that can be used to wait for the result */ [[nodiscard]] auto - execute(SomeHandlerWith auto&& fn, SomeStdDuration auto timeout) noexcept(kIS_NOEXCEPT) + execute(SomeHandlerWith auto&& fn, SomeStdDuration auto timeout) noexcept( + kIS_NOEXCEPT + ) { return execute( std::forward(fn), @@ -341,7 +374,8 @@ public: /** * @brief Schedule an operation on the execution context * - * @param fn The block of code to execute. Signature is `Type()` where `Type` is the return type. + * @param fn The block of code to execute. Signature is `Type()` where `Type` is the return + * type. * @return A unstoppable operation that can be used to wait for the result */ [[nodiscard]] auto @@ -423,20 +457,22 @@ public: * * This execution context uses `asio::spawn` to create a coroutine per executed operation. * The stop token that is sent to the lambda to execute is YieldContextStopSource::Token - * and is special in the way that each time your code checks `token.isStopRequested()` the coroutine will - * be suspended and other work such as timers and/or other operations in the queue will get a chance to run. - * This makes it possible to have 1 thread in the execution context and still be able to execute operations AND timers - * at the same time. + * and is special in the way that each time your code checks `token.isStopRequested()` the coroutine + * will be suspended and other work such as timers and/or other operations in the queue will get a + * chance to run. This makes it possible to have 1 thread in the execution context and still be able + * to execute operations AND timers at the same time. */ -using CoroExecutionContext = - BasicExecutionContext; +using CoroExecutionContext = BasicExecutionContext< + impl::AsioPoolContext, + impl::YieldContextStopSource, + impl::SpawnDispatchStrategy>; /** * @brief A asio::thread_pool-based execution context. * * This execution context uses `asio::post` to dispatch operations to the thread pool. - * Please note that this execution context can't handle timers and operations at the same time iff you have exactly 1 - * thread in the thread pool. + * Please note that this execution context can't handle timers and operations at the same time iff + * you have exactly 1 thread in the thread pool. */ using PoolExecutionContext = BasicExecutionContext; diff --git a/src/util/async/context/SyncExecutionContext.hpp b/src/util/async/context/SyncExecutionContext.hpp index 9b69b13e8..d178a26fe 100644 --- a/src/util/async/context/SyncExecutionContext.hpp +++ b/src/util/async/context/SyncExecutionContext.hpp @@ -95,10 +95,11 @@ struct SystemContextProvider { /** * @brief A synchronous execution context. Runs on the caller thread. * - * This execution context runs the operations on the same thread that requested the operation to run. - * Each operation must finish before the corresponding `execute` returns an operation object that can immediately be - * queried for value or error as it's guaranteed to have completed. Timer-based operations are scheduled via - * SystemExecutionContext, including those that are scheduled from within a strand. + * This execution context runs the operations on the same thread that requested the operation to + * run. Each operation must finish before the corresponding `execute` returns an operation object + * that can immediately be queried for value or error as it's guaranteed to have completed. + * Timer-based operations are scheduled via SystemExecutionContext, including those that are + * scheduled from within a strand. */ using SyncExecutionContext = BasicExecutionContext< impl::SameThreadContext, diff --git a/src/util/async/context/SystemExecutionContext.hpp b/src/util/async/context/SystemExecutionContext.hpp index 46d191646..c912718fc 100644 --- a/src/util/async/context/SystemExecutionContext.hpp +++ b/src/util/async/context/SystemExecutionContext.hpp @@ -26,8 +26,8 @@ namespace util::async { /** * @brief A execution context that runs tasks on a system thread pool of 1 thread. * - * This is useful for timers and system tasks that need to be scheduled on a exececution context that otherwise would - * not be able to support them (e.g. a synchronous execution context). + * This is useful for timers and system tasks that need to be scheduled on a exececution context + * that otherwise would not be able to support them (e.g. a synchronous execution context). */ class SystemExecutionContext { public: diff --git a/src/util/async/context/impl/Execution.hpp b/src/util/async/context/impl/Execution.hpp index ffc32cd45..d6ddf1baf 100644 --- a/src/util/async/context/impl/Execution.hpp +++ b/src/util/async/context/impl/Execution.hpp @@ -39,10 +39,13 @@ struct SpawnDispatchStrategy { if constexpr (SomeStoppableOutcome) { util::spawn( ctx.getExecutor(), - [outcome = std::forward(outcome), fn = std::forward(fn)](auto yield) mutable { + [outcome = std::forward(outcome), + fn = std::forward(fn)](auto yield) mutable { if constexpr (SomeStoppableOutcome) { auto& stopSource = outcome.getStopSource(); - std::invoke(std::forward(fn), outcome, stopSource, stopSource[yield]); + std::invoke( + std::forward(fn), outcome, stopSource, stopSource[yield] + ); } else { std::invoke(std::forward(fn), outcome); } @@ -51,7 +54,8 @@ struct SpawnDispatchStrategy { } else { boost::asio::post( ctx.getExecutor(), - [outcome = std::forward(outcome), fn = std::forward(fn)]() mutable { + [outcome = std::forward(outcome), + fn = std::forward(fn)]() mutable { std::invoke(std::forward(fn), outcome); } ); @@ -78,10 +82,14 @@ struct PostDispatchStrategy { auto op = outcome.getOperation(); boost::asio::post( - ctx.getExecutor(), [outcome = std::forward(outcome), fn = std::forward(fn)]() mutable { + ctx.getExecutor(), + [outcome = std::forward(outcome), + fn = std::forward(fn)]() mutable { if constexpr (SomeStoppableOutcome) { auto& stopSource = outcome.getStopSource(); - std::invoke(std::forward(fn), outcome, stopSource, stopSource.getToken()); + std::invoke( + std::forward(fn), outcome, stopSource, stopSource.getToken() + ); } else { std::invoke(std::forward(fn), outcome); } diff --git a/src/util/async/context/impl/Strand.hpp b/src/util/async/context/impl/Strand.hpp index dc060a325..d6b8c9658 100644 --- a/src/util/async/context/impl/Strand.hpp +++ b/src/util/async/context/impl/Strand.hpp @@ -51,8 +51,8 @@ public: using ContextHolderType = typename ParentContextType::ContextHolderType::Strand; using ExecutorType = typename ContextHolderType::Executor; using StopToken = typename StopSourceType::Token; - using Timer = - typename ParentContextType::ContextHolderType::Timer; // timers are associated with the parent context + using Timer = typename ParentContextType::ContextHolderType::Timer; // timers are associated + // with the parent context using RepeatedOperation = RepeatingOperation; BasicStrand(ParentContextType& parent, auto&& strand) @@ -86,14 +86,18 @@ public: std::invoke(std::forward(fn), std::move(stopToken)); outcome.setValue(); } else { - outcome.setValue(std::invoke(std::forward(fn), std::move(stopToken))); + outcome.setValue( + std::invoke(std::forward(fn), std::move(stopToken)) + ); } }) ); } [[nodiscard]] auto - execute(SomeHandlerWith auto&& fn, SomeStdDuration auto timeout) noexcept(kIS_NOEXCEPT) + execute(SomeHandlerWith auto&& fn, SomeStdDuration auto timeout) noexcept( + kIS_NOEXCEPT + ) { return execute( std::forward(fn), @@ -120,12 +124,21 @@ public: } [[nodiscard]] auto - executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto&& fn) noexcept(kIS_NOEXCEPT) + executeRepeatedly( + SomeStdDuration auto interval, + SomeHandlerWithoutStopToken auto&& fn + ) noexcept(kIS_NOEXCEPT) { - if constexpr (not std::is_same_v) { - return TimerContextProvider::getContext(*this).executeRepeatedly(interval, std::forward(fn)); + if constexpr (not std::is_same_v< + decltype(TimerContextProvider::getContext(*this)), + decltype(*this)>) { + return TimerContextProvider::getContext(*this).executeRepeatedly( + interval, std::forward(fn) + ); } else { - return RepeatedOperation(impl::extractAssociatedExecutor(*this), interval, std::forward(fn)); + return RepeatedOperation( + impl::extractAssociatedExecutor(*this), interval, std::forward(fn) + ); } } diff --git a/src/util/async/context/impl/Utils.hpp b/src/util/async/context/impl/Utils.hpp index f722f8361..9c38af4f3 100644 --- a/src/util/async/context/impl/Utils.hpp +++ b/src/util/async/context/impl/Utils.hpp @@ -44,7 +44,11 @@ inline constexpr struct AssociatedExecutorExtractor { template [[nodiscard]] constexpr auto -getTimeoutHandleIfNeeded(CtxType& ctx, SomeOptStdDuration auto timeout, SomeStopSource auto& stopSource) +getTimeoutHandleIfNeeded( + CtxType& ctx, + SomeOptStdDuration auto timeout, + SomeStopSource auto& stopSource +) { using TimerType = typename CtxType::Timer; std::optional timer; @@ -62,7 +66,8 @@ template outcomeForHandler(auto&& fn) { if constexpr (SomeHandlerWith) { - using FnRetType = std::decay_t>; + using FnRetType = + std::decay_t>; using RetType = std::expected; return StoppableOutcome(); diff --git a/src/util/async/impl/ErasedOperation.hpp b/src/util/async/impl/ErasedOperation.hpp index d42de490c..ecb97e991 100644 --- a/src/util/async/impl/ErasedOperation.hpp +++ b/src/util/async/impl/ErasedOperation.hpp @@ -119,7 +119,8 @@ private: ASSERT(false, "Called get() on an operation that does not support it"); std::unreachable(); } else { - // Note: return type of the operation was already wrapped to std::any by AnyExecutionContext + // Note: return type of the operation was already wrapped to std::any by + // AnyExecutionContext return operation.get(); } } @@ -127,9 +128,12 @@ private: void abort() override { - if constexpr (not SomeCancellableOperation and not SomeStoppableOperation and - not SomeAbortable) { - ASSERT(false, "Called abort() on an operation that can't be aborted, cancelled nor stopped"); + if constexpr (not SomeCancellableOperation and + not SomeStoppableOperation and not SomeAbortable) { + ASSERT( + false, + "Called abort() on an operation that can't be aborted, cancelled nor stopped" + ); } else { if constexpr (SomeAbortable) { operation.abort(); diff --git a/src/util/async/impl/ErrorHandling.hpp b/src/util/async/impl/ErrorHandling.hpp index c7002b7df..e02b2dbbe 100644 --- a/src/util/async/impl/ErrorHandling.hpp +++ b/src/util/async/impl/ErrorHandling.hpp @@ -36,24 +36,31 @@ struct DefaultErrorHandler { [[nodiscard]] static auto wrap(auto&& fn) noexcept { - return - [fn = std::forward(fn)](SomeOutcome auto& outcome, Args&&... args) mutable { - try { - std::invoke(std::forward(fn), outcome, std::forward(args)...); - } catch (std::exception const& e) { - outcome.setValue( - std::unexpected(ExecutionError{fmt::format("{}", std::this_thread::get_id()), e.what()}) - ); - } catch (...) { - outcome.setValue( - std::unexpected(ExecutionError{fmt::format("{}", std::this_thread::get_id()), "unknown"}) - ); - } - }; + return [fn = std::forward(fn)]( + SomeOutcome auto& outcome, Args&&... args + ) mutable { + try { + std::invoke(std::forward(fn), outcome, std::forward(args)...); + } catch (std::exception const& e) { + outcome.setValue( + std::unexpected( + ExecutionError{fmt::format("{}", std::this_thread::get_id()), e.what()} + ) + ); + } catch (...) { + outcome.setValue( + std::unexpected( + ExecutionError{fmt::format("{}", std::this_thread::get_id()), "unknown"} + ) + ); + } + }; } [[nodiscard]] static auto - catchAndAssert(auto&& fn) noexcept // note this is a lie when used with MockAssert (use MockAssertNoThrow) + catchAndAssert( + auto&& fn + ) noexcept // note this is a lie when used with MockAssert (use MockAssertNoThrow) { return [fn = std::forward(fn)] mutable { try { diff --git a/src/util/build/Build.cpp b/src/util/build/Build.cpp index 35a690e0d..5f7ace6f9 100644 --- a/src/util/build/Build.cpp +++ b/src/util/build/Build.cpp @@ -51,7 +51,8 @@ getClioVersionString() std::string const& getClioFullVersionString() { - static std::string const value = "clio-" + getClioVersionString(); // NOLINT(readability-identifier-naming) + static std::string const value = + "clio-" + getClioVersionString(); // NOLINT(readability-identifier-naming) return value; } diff --git a/src/util/config/Array.cpp b/src/util/config/Array.cpp index 4a07a0598..838ec51bc 100644 --- a/src/util/config/Array.cpp +++ b/src/util/config/Array.cpp @@ -60,7 +60,10 @@ std::optional Array::addNull(std::optional key) { if (not itemPattern_.isOptional() and not itemPattern_.hasValue()) { - return Error{key.value_or("Unknown_key"), "value for the array (or object field inside array) is required"}; + return Error{ + key.value_or("Unknown_key"), + "value for the array (or object field inside array) is required" + }; } elements_.push_back(itemPattern_); diff --git a/src/util/config/Array.hpp b/src/util/config/Array.hpp index a1c6edca2..7cdd125b2 100644 --- a/src/util/config/Array.hpp +++ b/src/util/config/Array.hpp @@ -48,7 +48,8 @@ public: Array(ConfigValue arg); /** - * @brief Extract array prefix from a key, For example for a key foo.[].bar the method will return foo.[] + * @brief Extract array prefix from a key, For example for a key foo.[].bar the method will + * return foo.[] * @note Provided key must contain '.[]' * @warning Be careful with string_view! Returned value is valid only while the key is valid * @@ -70,7 +71,8 @@ public: /** * @brief Add null value to the array - * @note The error will be returned if item pattern of the array is neither optional nor has a default value + * @note The error will be returned if item pattern of the array is neither optional nor has a + * default value * * @param key An optional key which will be used for error message only (if any) * @return An error if any or nullopt if the operation succeeded diff --git a/src/util/config/ArrayView.cpp b/src/util/config/ArrayView.cpp index 5d0733ae4..92cc7a5e7 100644 --- a/src/util/config/ArrayView.cpp +++ b/src/util/config/ArrayView.cpp @@ -39,7 +39,11 @@ ArrayView::ArrayView(std::string_view prefix, ClioConfigDefinition const& config ValueView ArrayView::valueAt(std::size_t idx) const { - ASSERT(clioConfig_.get().contains(prefix_), "Current string {} is a prefix, not a key of config", prefix_); + ASSERT( + clioConfig_.get().contains(prefix_), + "Current string {} is a prefix, not a key of config", + prefix_ + ); ConfigValue const& val = clioConfig_.get().asArray(prefix_).at(idx); return ValueView{val}; } diff --git a/src/util/config/ArrayView.hpp b/src/util/config/ArrayView.hpp index dcdec2b1e..1c682173c 100644 --- a/src/util/config/ArrayView.hpp +++ b/src/util/config/ArrayView.hpp @@ -112,7 +112,8 @@ public: * @brief Equality operator * * @param other Another ArrayIterator to compare - * @return true if iterators are pointing to the same element in the same ArrayView object, otherwise false + * @return true if iterators are pointing to the same element in the same ArrayView object, + * otherwise false */ bool operator==(ArrayIterator const& other) const diff --git a/src/util/config/ConfigConstraints.hpp b/src/util/config/ConfigConstraints.hpp index 211c4ca9f..bc658ca1b 100644 --- a/src/util/config/ConfigConstraints.hpp +++ b/src/util/config/ConfigConstraints.hpp @@ -113,7 +113,8 @@ public: protected: /** - * @brief Creates an error message for all constraints that must satisfy certain hard-coded values. + * @brief Creates an error message for all constraints that must satisfy certain hard-coded + * values. * * @tparam arrSize, the size of the array of hardcoded values * @param key The key to the value @@ -123,7 +124,11 @@ protected: */ template constexpr std::string - makeErrorMsg(std::string_view key, Value const& value, std::array arr) const + makeErrorMsg( + std::string_view key, + Value const& value, + std::array arr + ) const { // Extract the value from the variant auto const valueStr = std::visit([](auto const& v) { return fmt::format("{}", v); }, value); @@ -212,7 +217,9 @@ private: void print(std::ostream& stream) const override { - stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`.", kPORT_MIN, kPORT_MAX); + stream << fmt::format( + "The minimum value is `{}`. The maximum value is `{}`.", kPORT_MIN, kPORT_MAX + ); } static constexpr uint32_t kPORT_MIN = 1; @@ -258,7 +265,8 @@ private: }; /** - * @brief A constraint class to ensure the provided value is one of the specified values in an array. + * @brief A constraint class to ensure the provided value is one of the specified values in an + * array. * * @tparam arrSize The size of the array containing the valid values for the constraint */ @@ -266,12 +274,14 @@ template class OneOf final : public Constraint { public: /** - * @brief Constructs a constraint where the value must be one of the values in the provided array. + * @brief Constructs a constraint where the value must be one of the values in the provided + * array. * * @param key The key of the ConfigValue that has this constraint * @param arr The value that has this constraint must be of the values in arr */ - constexpr OneOf(std::string_view key, std::array arr) : key_{key}, arr_{arr} + constexpr OneOf(std::string_view key, std::array arr) + : key_{key}, arr_{arr} { } @@ -302,7 +312,9 @@ private: checkValueImpl(Value const& val) const override { namespace rg = std::ranges; - auto const check = [&val](std::string_view name) { return std::get(val) == name; }; + auto const check = [&val](std::string_view name) { + return std::get(val) == name; + }; if (rg::any_of(arr_, check)) return std::nullopt; @@ -480,16 +492,34 @@ static constinit OneOf gValidateProvider{"database.cassandra.provider", kPROVIDE static constinit PositiveDouble gValidatePositiveDouble{}; static constinit NumberValueConstraint gValidateNumMarkers{1, 256}; -static constinit NumberValueConstraint gValidateNumCursors{0, std::numeric_limits::max()}; +static constinit NumberValueConstraint gValidateNumCursors{ + 0, + std::numeric_limits::max() +}; // replication factor can be 0 -static constinit NumberValueConstraint gValidateReplicationFactor{0, std::numeric_limits::max()}; +static constinit NumberValueConstraint gValidateReplicationFactor{ + 0, + std::numeric_limits::max() +}; -static constinit NumberValueConstraint gValidateUint16{1, std::numeric_limits::max()}; +static constinit NumberValueConstraint gValidateUint16{ + 1, + std::numeric_limits::max() +}; -static constinit NumberValueConstraint gValidateUint32{1, std::numeric_limits::max()}; -static constinit NumberValueConstraint gValidateNonNegativeUint32{0, std::numeric_limits::max()}; -static constinit NumberValueConstraint gValidateApiVersion{rpc::kAPI_VERSION_MIN, rpc::kAPI_VERSION_MAX}; +static constinit NumberValueConstraint gValidateUint32{ + 1, + std::numeric_limits::max() +}; +static constinit NumberValueConstraint gValidateNonNegativeUint32{ + 0, + std::numeric_limits::max() +}; +static constinit NumberValueConstraint gValidateApiVersion{ + rpc::kAPI_VERSION_MIN, + rpc::kAPI_VERSION_MAX +}; static constinit RpcNameConstraint gRpcNameConstraint{}; } // namespace util::config diff --git a/src/util/config/ConfigDefinition.cpp b/src/util/config/ConfigDefinition.cpp index 430a8b34a..fd060c42e 100644 --- a/src/util/config/ConfigDefinition.cpp +++ b/src/util/config/ConfigDefinition.cpp @@ -68,7 +68,8 @@ ClioConfigDefinition::getObject(std::string_view prefix, std::optional(mapVal)) { ASSERT(std::get(mapVal).size() > idx.value(), "Index provided is out of scope"); - // we want to support getObject("array") and getObject("array.[]"), so we check if "[]" exists + // we want to support getObject("array") and getObject("array.[]"), so we check if "[]" + // exists if (!prefix.contains("[]")) return ObjectView{prefixWithDot + "[]", idx.value(), *this}; return ObjectView{prefix, idx.value(), *this}; @@ -88,7 +89,8 @@ ClioConfigDefinition::getArray(std::string_view prefix) const for (auto const& [mapKey, mapVal] : map_) { if (mapKey.starts_with(key)) { ASSERT( - std::holds_alternative(mapVal), "Trying to retrieve Object or ConfigValue, instead of an Array " + std::holds_alternative(mapVal), + "Trying to retrieve Object or ConfigValue, instead of an Array " ); return ArrayView{key, *this}; } @@ -106,7 +108,9 @@ ClioConfigDefinition::contains(std::string_view key) const bool ClioConfigDefinition::hasItemsWithPrefix(std::string_view key) const { - return std::ranges::any_of(map_, [&key](auto const& pair) { return pair.first.starts_with(key); }); + return std::ranges::any_of(map_, [&key](auto const& pair) { + return pair.first.starts_with(key); + }); } ValueView @@ -124,7 +128,9 @@ std::chrono::milliseconds ClioConfigDefinition::toMilliseconds(float value) { ASSERT(value >= 0.0f, "Floating point value of seconds must be non-negative, got: {}", value); - return std::chrono::milliseconds{std::lroundf(value * static_cast(util::kMILLISECONDS_PER_SECOND))}; + return std::chrono::milliseconds{ + std::lroundf(value * static_cast(util::kMILLISECONDS_PER_SECOND)) + }; } ValueView @@ -166,11 +172,12 @@ ClioConfigDefinition::parse(ConfigFileInterface const& config) arrayPrefixesToKeysMap[prefix].push_back(key); } - // if key doesn't exist in user config, makes sure it is marked as ".optional()" or has ".defaultValue()"" in - // ClioConfigDefinition above + // if key doesn't exist in user config, makes sure it is marked as ".optional()" or has + // ".defaultValue()"" in ClioConfigDefinition above if (!config.containsKey(key)) { if (std::holds_alternative(value)) { - if (!(std::get(value).isOptional() || std::get(value).hasValue())) + if (!(std::get(value).isOptional() || + std::get(value).hasValue())) listOfErrors.emplace_back(key, "key is required in user Config"); } continue; @@ -180,29 +187,31 @@ ClioConfigDefinition::parse(ConfigFileInterface const& config) "Value must be of type ConfigValue or Array" ); std::visit( - util::OverloadSet{// handle the case where the config value is a single element. - // attempt to set the value from the configuration for the specified key. - [&key, &config, &listOfErrors](ConfigValue& val) { - if (auto const maybeError = val.setValue(config.getValue(key), key); - maybeError.has_value()) { - listOfErrors.emplace_back(maybeError.value()); - } - }, - // handle the case where the config value is an array. - // iterate over each provided value in the array and attempt to set it for the key. - [&key, &config, &listOfErrors](Array& arr) { - for (auto const& val : config.getArray(key)) { - if (val.has_value()) { - if (auto const maybeError = arr.addValue(*val, key); maybeError.has_value()) { - listOfErrors.emplace_back(*maybeError); - } - } else { - if (auto const maybeError = arr.addNull(key); maybeError.has_value()) { - listOfErrors.emplace_back(*maybeError); - } - } - } - } + util::OverloadSet{ + // handle the case where the config value is a single element. + // attempt to set the value from the configuration for the specified key. + [&key, &config, &listOfErrors](ConfigValue& val) { + if (auto const maybeError = val.setValue(config.getValue(key), key); + maybeError.has_value()) { + listOfErrors.emplace_back(maybeError.value()); + } + }, + // handle the case where the config value is an array. + // iterate over each provided value in the array and attempt to set it for the key. + [&key, &config, &listOfErrors](Array& arr) { + for (auto const& val : config.getArray(key)) { + if (val.has_value()) { + if (auto const maybeError = arr.addValue(*val, key); + maybeError.has_value()) { + listOfErrors.emplace_back(*maybeError); + } + } else { + if (auto const maybeError = arr.addNull(key); maybeError.has_value()) { + listOfErrors.emplace_back(*maybeError); + } + } + } + } }, value ); @@ -212,8 +221,8 @@ ClioConfigDefinition::parse(ConfigFileInterface const& config) return listOfErrors; // The code above couldn't detect whether some fields in an array are missing. - // So to fix it for each array we determine it's size and add empty values if the field is optional - // or generate an error. + // So to fix it for each array we determine it's size and add empty values if the field is + // optional or generate an error. for (auto const& [_, keys] : arrayPrefixesToKeysMap) { size_t maxSize = 0; std::ranges::for_each(keys, [&](std::string_view key) { @@ -254,13 +263,19 @@ getClioConfig() { static ClioConfigDefinition kCLIO_CONFIG{ {{"database.type", - ConfigValue{ConfigType::String}.defaultValue("cassandra").withConstraint(gValidateCassandraName)}, - {"database.cassandra.contact_points", ConfigValue{ConfigType::String}.defaultValue("localhost")}, + ConfigValue{ConfigType::String} + .defaultValue("cassandra") + .withConstraint(gValidateCassandraName)}, + {"database.cassandra.contact_points", + ConfigValue{ConfigType::String}.defaultValue("localhost")}, {"database.cassandra.secure_connect_bundle", ConfigValue{ConfigType::String}.optional()}, - {"database.cassandra.port", ConfigValue{ConfigType::Integer}.withConstraint(gValidatePort).optional()}, + {"database.cassandra.port", + ConfigValue{ConfigType::Integer}.withConstraint(gValidatePort).optional()}, {"database.cassandra.keyspace", ConfigValue{ConfigType::String}.defaultValue("clio")}, {"database.cassandra.replication_factor", - ConfigValue{ConfigType::Integer}.defaultValue(3u).withConstraint(gValidateReplicationFactor)}, + ConfigValue{ConfigType::Integer}.defaultValue(3u).withConstraint( + gValidateReplicationFactor + )}, {"database.cassandra.table_prefix", ConfigValue{ConfigType::String}.optional()}, {"database.cassandra.max_write_requests_outstanding", ConfigValue{ConfigType::Integer}.defaultValue(10'000).withConstraint(gValidateUint32)}, @@ -269,7 +284,8 @@ getClioConfig() {"database.cassandra.threads", ConfigValue{ConfigType::Integer} .defaultValue( - static_cast(std::thread::hardware_concurrency()), "The number of available CPU cores." + static_cast(std::thread::hardware_concurrency()), + "The number of available CPU cores." ) .withConstraint(gValidateUint32)}, {"database.cassandra.core_connections_per_host", @@ -286,53 +302,79 @@ getClioConfig() {"database.cassandra.password", ConfigValue{ConfigType::String}.optional()}, {"database.cassandra.certfile", ConfigValue{ConfigType::String}.optional()}, {"database.cassandra.provider", - ConfigValue{ConfigType::String}.defaultValue("cassandra").withConstraint(gValidateProvider)}, + ConfigValue{ConfigType::String} + .defaultValue("cassandra") + .withConstraint(gValidateProvider)}, {"allow_no_etl", ConfigValue{ConfigType::Boolean}.defaultValue(false)}, - {"etl_sources.[].ip", Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidateIp)}}, - {"etl_sources.[].ws_port", Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidatePort)}}, - {"etl_sources.[].grpc_port", Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidatePort)}}, + {"etl_sources.[].ip", + Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidateIp)}}, + {"etl_sources.[].ws_port", + Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidatePort)}}, + {"etl_sources.[].grpc_port", + Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidatePort)}}, {"forwarding.cache_timeout", - ConfigValue{ConfigType::Double}.defaultValue(0.0).withConstraint(gValidatePositiveDouble)}, + ConfigValue{ConfigType::Double}.defaultValue(0.0).withConstraint( + gValidatePositiveDouble + )}, {"forwarding.request_timeout", - ConfigValue{ConfigType::Double}.defaultValue(10.0).withConstraint(gValidatePositiveDouble)}, + ConfigValue{ConfigType::Double}.defaultValue(10.0).withConstraint( + gValidatePositiveDouble + )}, {"rpc.cache_timeout", - ConfigValue{ConfigType::Double}.defaultValue(0.0).withConstraint(gValidatePositiveDouble)}, + ConfigValue{ConfigType::Double}.defaultValue(0.0).withConstraint( + gValidatePositiveDouble + )}, - {"num_markers", ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateNumMarkers)}, + {"num_markers", + ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateNumMarkers)}, {"dos_guard.whitelist.[]", Array{ConfigValue{ConfigType::String}.optional()}}, {"dos_guard.max_fetches", ConfigValue{ConfigType::Integer}.defaultValue(1000'000u).withConstraint(gValidateUint32)}, {"dos_guard.max_connections", ConfigValue{ConfigType::Integer}.defaultValue(20u).withConstraint(gValidateUint32)}, - {"dos_guard.max_requests", ConfigValue{ConfigType::Integer}.defaultValue(20u).withConstraint(gValidateUint32)}, + {"dos_guard.max_requests", + ConfigValue{ConfigType::Integer}.defaultValue(20u).withConstraint(gValidateUint32)}, {"dos_guard.sweep_interval", - ConfigValue{ConfigType::Double}.defaultValue(1.0).withConstraint(gValidatePositiveDouble)}, + ConfigValue{ConfigType::Double}.defaultValue(1.0).withConstraint( + gValidatePositiveDouble + )}, {"dos_guard.__ng_default_weight", - ConfigValue{ConfigType::Integer}.defaultValue(1).withConstraint(gValidateNonNegativeUint32)}, + ConfigValue{ConfigType::Integer}.defaultValue(1).withConstraint( + gValidateNonNegativeUint32 + )}, {"dos_guard.__ng_weights.[].method", Array{ConfigValue{ConfigType::String}.withConstraint(gRpcNameConstraint)}}, {"dos_guard.__ng_weights.[].weight", Array{ConfigValue{ConfigType::Integer}.withConstraint(gValidateNonNegativeUint32)}}, {"dos_guard.__ng_weights.[].weight_ledger_current", - Array{ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateNonNegativeUint32)}}, + Array{ + ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateNonNegativeUint32) + }}, {"dos_guard.__ng_weights.[].weight_ledger_validated", - Array{ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateNonNegativeUint32)}}, + Array{ + ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateNonNegativeUint32) + }}, {"workers", ConfigValue{ConfigType::Integer} - .defaultValue(std::thread::hardware_concurrency(), "The number of available CPU cores.") + .defaultValue( + std::thread::hardware_concurrency(), "The number of available CPU cores." + ) .withConstraint(gValidateUint32)}, {"server.ip", ConfigValue{ConfigType::String}.withConstraint(gValidateIp)}, {"server.port", ConfigValue{ConfigType::Integer}.withConstraint(gValidatePort)}, - {"server.max_queue_size", ConfigValue{ConfigType::Integer}.defaultValue(1000).withConstraint(gValidateUint32)}, + {"server.max_queue_size", + ConfigValue{ConfigType::Integer}.defaultValue(1000).withConstraint(gValidateUint32)}, {"server.local_admin", ConfigValue{ConfigType::Boolean}.optional()}, {"server.admin_password", ConfigValue{ConfigType::String}.optional()}, {"server.processing_policy", - ConfigValue{ConfigType::String}.defaultValue("parallel").withConstraint(gValidateProcessingPolicy)}, + ConfigValue{ConfigType::String} + .defaultValue("parallel") + .withConstraint(gValidateProcessingPolicy)}, {"server.parallel_requests_limit", ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateUint16)}, {"server.ws_max_sending_queue_size", @@ -344,21 +386,29 @@ getClioConfig() {"prometheus.enabled", ConfigValue{ConfigType::Boolean}.defaultValue(true)}, {"prometheus.compress_reply", ConfigValue{ConfigType::Boolean}.defaultValue(true)}, - {"io_threads", ConfigValue{ConfigType::Integer}.defaultValue(2).withConstraint(gValidateUint16)}, + {"io_threads", + ConfigValue{ConfigType::Integer}.defaultValue(2).withConstraint(gValidateUint16)}, - {"subscription_workers", ConfigValue{ConfigType::Integer}.defaultValue(1).withConstraint(gValidateUint32)}, + {"subscription_workers", + ConfigValue{ConfigType::Integer}.defaultValue(1).withConstraint(gValidateUint32)}, {"graceful_period", - ConfigValue{ConfigType::Double}.defaultValue(10.0).withConstraint(gValidatePositiveDouble)}, + ConfigValue{ConfigType::Double}.defaultValue(10.0).withConstraint( + gValidatePositiveDouble + )}, - {"cache.num_diffs", ConfigValue{ConfigType::Integer}.defaultValue(32).withConstraint(gValidateUint16)}, - {"cache.num_markers", ConfigValue{ConfigType::Integer}.defaultValue(48).withConstraint(gValidateUint16)}, + {"cache.num_diffs", + ConfigValue{ConfigType::Integer}.defaultValue(32).withConstraint(gValidateUint16)}, + {"cache.num_markers", + ConfigValue{ConfigType::Integer}.defaultValue(48).withConstraint(gValidateUint16)}, {"cache.num_cursors_from_diff", ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateNumCursors)}, {"cache.num_cursors_from_account", ConfigValue{ConfigType::Integer}.defaultValue(0).withConstraint(gValidateNumCursors)}, - {"cache.page_fetch_size", ConfigValue{ConfigType::Integer}.defaultValue(512).withConstraint(gValidateUint16)}, - {"cache.load", ConfigValue{ConfigType::String}.defaultValue("async").withConstraint(gValidateLoadMode)}, + {"cache.page_fetch_size", + ConfigValue{ConfigType::Integer}.defaultValue(512).withConstraint(gValidateUint16)}, + {"cache.load", + ConfigValue{ConfigType::String}.defaultValue("async").withConstraint(gValidateLoadMode)}, {"cache.file.path", ConfigValue{ConfigType::String}.optional()}, {"cache.file.max_sequence_age", ConfigValue{ConfigType::Integer}.defaultValue(5000)}, {"cache.file.async_save", ConfigValue{ConfigType::Boolean}.defaultValue(false)}, @@ -368,9 +418,13 @@ getClioConfig() {"log.channels.[].level", Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidateLogLevelName)}}, - {"log.level", ConfigValue{ConfigType::String}.defaultValue("info").withConstraint(gValidateLogLevelName)}, + {"log.level", + ConfigValue{ConfigType::String}.defaultValue("info").withConstraint( + gValidateLogLevelName + )}, - {"log.format", ConfigValue{ConfigType::String}.defaultValue(R"(%Y-%m-%d %H:%M:%S.%f %^%3!l:%n%$ - %v)")}, + {"log.format", + ConfigValue{ConfigType::String}.defaultValue(R"(%Y-%m-%d %H:%M:%S.%f %^%3!l:%n%$ - %v)")}, {"log.is_async", ConfigValue{ConfigType::Boolean}.defaultValue(true)}, @@ -378,34 +432,47 @@ getClioConfig() {"log.directory", ConfigValue{ConfigType::String}.optional()}, - {"log.rotation_size", ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(gValidateUint32)}, + {"log.rotation_size", + ConfigValue{ConfigType::Integer}.defaultValue(2048).withConstraint(gValidateUint32)}, - {"log.directory_max_files", ConfigValue{ConfigType::Integer}.defaultValue(25).withConstraint(gValidateUint32)}, + {"log.directory_max_files", + ConfigValue{ConfigType::Integer}.defaultValue(25).withConstraint(gValidateUint32)}, - {"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("none").withConstraint(gValidateLogTag)}, + {"log.tag_style", + ConfigValue{ConfigType::String}.defaultValue("none").withConstraint(gValidateLogTag)}, - {"extractor_threads", ConfigValue{ConfigType::Integer}.defaultValue(1u).withConstraint(gValidateUint32)}, + {"extractor_threads", + ConfigValue{ConfigType::Integer}.defaultValue(1u).withConstraint(gValidateUint32)}, {"read_only", ConfigValue{ConfigType::Boolean}.defaultValue(false)}, - {"start_sequence", ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateUint32)}, + {"start_sequence", + ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateUint32)}, - {"finish_sequence", ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateUint32)}, + {"finish_sequence", + ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateUint32)}, {"ssl_cert_file", ConfigValue{ConfigType::String}.optional()}, {"ssl_key_file", ConfigValue{ConfigType::String}.optional()}, {"api_version.default", - ConfigValue{ConfigType::Integer}.defaultValue(rpc::kAPI_VERSION_DEFAULT).withConstraint(gValidateApiVersion)}, + ConfigValue{ConfigType::Integer} + .defaultValue(rpc::kAPI_VERSION_DEFAULT) + .withConstraint(gValidateApiVersion)}, {"api_version.min", - ConfigValue{ConfigType::Integer}.defaultValue(rpc::kAPI_VERSION_MIN).withConstraint(gValidateApiVersion)}, + ConfigValue{ConfigType::Integer} + .defaultValue(rpc::kAPI_VERSION_MIN) + .withConstraint(gValidateApiVersion)}, {"api_version.max", - ConfigValue{ConfigType::Integer}.defaultValue(rpc::kAPI_VERSION_MAX).withConstraint(gValidateApiVersion)}, + ConfigValue{ConfigType::Integer} + .defaultValue(rpc::kAPI_VERSION_MAX) + .withConstraint(gValidateApiVersion)}, {"migration.full_scan_threads", ConfigValue{ConfigType::Integer}.defaultValue(2).withConstraint(gValidateUint32)}, - {"migration.full_scan_jobs", ConfigValue{ConfigType::Integer}.defaultValue(4).withConstraint(gValidateUint32)}, + {"migration.full_scan_jobs", + ConfigValue{ConfigType::Integer}.defaultValue(4).withConstraint(gValidateUint32)}, {"migration.cursors_per_job", ConfigValue{ConfigType::Integer}.defaultValue(100).withConstraint(gValidateUint32)}}, }; diff --git a/src/util/config/ConfigDefinition.hpp b/src/util/config/ConfigDefinition.hpp index 6109f55b5..5cab2fbca 100644 --- a/src/util/config/ConfigDefinition.hpp +++ b/src/util/config/ConfigDefinition.hpp @@ -222,7 +222,8 @@ private: getArrayIterator(std::string_view key) const { auto const fullKey = addBracketsForArrayKey(key); - auto const it = std::ranges::find_if(map_, [&fullKey](auto pair) { return pair.first == fullKey; }); + auto const it = + std::ranges::find_if(map_, [&fullKey](auto pair) { return pair.first == fullKey; }); ASSERT(it != map_.end(), "key {} does not exist in config", fullKey); ASSERT(std::holds_alternative(it->second), "Value of {} is not an array", fullKey); @@ -251,8 +252,8 @@ private: /** * @brief Full Clio Configuration definition. * - * Specifies which keys are valid in Clio Config and provides default values if user's do not specify one. Those - * without default values must be present in the user's config file. + * Specifies which keys are valid in Clio Config and provides default values if user's do not + * specify one. Those without default values must be present in the user's config file. */ ClioConfigDefinition& getClioConfig(); diff --git a/src/util/config/ConfigDescription.hpp b/src/util/config/ConfigDescription.hpp index 8299398c4..8903e1339 100644 --- a/src/util/config/ConfigDescription.hpp +++ b/src/util/config/ConfigDescription.hpp @@ -53,7 +53,8 @@ public: /** * @brief Constructs a new Clio Config Description based on pre-existing descriptions * - * Config Keys and it's corresponding descriptions are all predefined. Used to generate markdown file + * Config Keys and it's corresponding descriptions are all predefined. Used to generate markdown + * file */ constexpr ClioConfigDescription() = default; @@ -66,7 +67,8 @@ public: [[nodiscard]] static constexpr std::string_view get(std::string_view key) { - auto const itr = std::ranges::find_if(kCONFIG_DESCRIPTION, [&](auto const& v) { return v.key == key; }); + auto const itr = + std::ranges::find_if(kCONFIG_DESCRIPTION, [&](auto const& v) { return v.key == key; }); ASSERT(itr != kCONFIG_DESCRIPTION.end(), "Key {} doesn't exist in config", key); return itr->value; } @@ -85,14 +87,16 @@ public: // Validate the directory exists auto const dir = path.parent_path(); if (!dir.empty() && !fs::exists(dir)) { - return std::unexpected{ - fmt::format("Error: Directory '{}' does not exist or provided path is invalid", dir.string()) - }; + return std::unexpected{fmt::format( + "Error: Directory '{}' does not exist or provided path is invalid", dir.string() + )}; } std::ofstream file(path.string()); if (!file.is_open()) { - return std::unexpected{fmt::format("Failed to create file '{}': {}", path.string(), std::strerror(errno))}; + return std::unexpected{ + fmt::format("Failed to create file '{}': {}", path.string(), std::strerror(errno)) + }; } writeConfigDescriptionToFile(file); @@ -141,39 +145,48 @@ This document provides a list of all available Clio configuration properties in )"; static constexpr auto kCONFIG_DESCRIPTION = std::array{ - KV{ - .key = "database.type", - .value = - "Specifies the type of database used for storing and retrieving data required by the Clio server. Both " - "ScyllaDB and Cassandra can serve as backends for Clio; however, this value must be set to `cassandra`." - }, + KV{.key = "database.type", + .value = "Specifies the type of database used for storing and retrieving data required " + "by the Clio server. Both " + "ScyllaDB and Cassandra can serve as backends for Clio; however, this value " + "must be set to `cassandra`."}, KV{.key = "database.cassandra.contact_points", - .value = "A list of IP addresses or hostnames for the initial cluster nodes (Cassandra or ScyllaDB) that " - "the client connects to when establishing a database connection. If you're running Clio locally, " + .value = "A list of IP addresses or hostnames for the initial cluster nodes (Cassandra " + "or ScyllaDB) that " + "the client connects to when establishing a database connection. If you're " + "running Clio locally, " "set this value to `localhost` or `127.0.0.1`."}, KV{.key = "database.cassandra.secure_connect_bundle", - .value = "The configuration file that contains the necessary credentials and connection details for " + .value = "The configuration file that contains the necessary credentials and connection " + "details for " "securely connecting to a Cassandra database cluster."}, - KV{.key = "database.cassandra.port", .value = "The port number used to connect to the Cassandra database."}, + KV{.key = "database.cassandra.port", + .value = "The port number used to connect to the Cassandra database."}, KV{.key = "database.cassandra.keyspace", - .value = "The Cassandra keyspace to use for the database. If you don't provide a value, this is set to " + .value = "The Cassandra keyspace to use for the database. If you don't provide a value, " + "this is set to " "`clio` by default."}, KV{.key = "database.cassandra.replication_factor", - .value = "Represents the number of replicated nodes for ScyllaDB. For more details see [Fault Tolerance " - "Replication " - "Factor](https://university.scylladb.com/courses/scylla-essentials-overview/lessons/" - "high-availability/topic/fault-tolerance-replication-factor/)."}, + .value = + "Represents the number of replicated nodes for ScyllaDB. For more details see " + "[Fault Tolerance " + "Replication " + "Factor](https://university.scylladb.com/courses/scylla-essentials-overview/lessons/" + "high-availability/topic/fault-tolerance-replication-factor/)."}, KV{.key = "database.cassandra.table_prefix", - .value = "An optional field to specify a prefix for the Cassandra database table names."}, + .value = + "An optional field to specify a prefix for the Cassandra database table names."}, KV{.key = "database.cassandra.max_write_requests_outstanding", - .value = "Represents the maximum number of outstanding write requests. Write requests are API calls that " + .value = "Represents the maximum number of outstanding write requests. Write requests " + "are API calls that " "write to the database."}, KV{.key = "database.cassandra.max_read_requests_outstanding", - .value = - "Maximum number of outstanding read requests. Read requests are API calls that read from the database."}, + .value = "Maximum number of outstanding read requests. Read requests are API calls that " + "read from the database."}, KV{.key = "database.cassandra.threads", .value = "Represents the number of threads that will be used for database operations."}, - KV{.key = "database.cassandra.provider", .value = "The specific database backend provider we are using."}, + KV{.key = "database.cassandra.provider", + .value = "The specific database backend provider we are using."}, KV{.key = "database.cassandra.core_connections_per_host", .value = "The number of core connections per host for the Cassandra database."}, KV{.key = "database.cassandra.queue_size_io", @@ -181,116 +194,160 @@ This document provides a list of all available Clio configuration properties in KV{.key = "database.cassandra.write_batch_size", .value = "Represents the batch size for write operations in Cassandra."}, KV{.key = "database.cassandra.connect_timeout", - .value = "The maximum amount of time in seconds that the system waits for a database connection to be " + .value = "The maximum amount of time in seconds that the system waits for a database " + "connection to be " "established."}, KV{.key = "database.cassandra.request_timeout", - .value = "The maximum amount of time in seconds that the system waits for a request to be fetched from the " + .value = "The maximum amount of time in seconds that the system waits for a request to " + "be fetched from the " "database."}, - KV{.key = "database.cassandra.username", .value = "The username used for authenticating with the database."}, - KV{.key = "database.cassandra.password", .value = "The password used for authenticating with the database."}, + KV{.key = "database.cassandra.username", + .value = "The username used for authenticating with the database."}, + KV{.key = "database.cassandra.password", + .value = "The password used for authenticating with the database."}, KV{.key = "database.cassandra.certfile", - .value = "The path to the SSL/TLS certificate file used to establish a secure connection between the client " + .value = "The path to the SSL/TLS certificate file used to establish a secure " + "connection between the client " "and the Cassandra database."}, - KV{.key = "allow_no_etl", .value = "If set to `True`, allows Clio to start without any ETL source."}, + KV{.key = "allow_no_etl", + .value = "If set to `True`, allows Clio to start without any ETL source."}, KV{.key = "etl_sources.[].ip", .value = "The IP address of the ETL source."}, KV{.key = "etl_sources.[].ws_port", .value = "The WebSocket port of the ETL source."}, KV{.key = "etl_sources.[].grpc_port", .value = "The gRPC port of the ETL source."}, KV{.key = "forwarding.cache_timeout", - .value = "Specifies the timeout duration (in seconds) for the forwarding cache used in `rippled` " + .value = "Specifies the timeout duration (in seconds) for the forwarding cache used in " + "`rippled` " "communication. A value of `0` means disabling this feature."}, KV{.key = "forwarding.request_timeout", - .value = "Specifies the timeout duration (in seconds) for the forwarding request used in `rippled` " + .value = "Specifies the timeout duration (in seconds) for the forwarding request used " + "in `rippled` " "communication."}, KV{.key = "rpc.cache_timeout", - .value = "Specifies the timeout duration (in seconds) for RPC cache response to timeout. A value of `0` " + .value = "Specifies the timeout duration (in seconds) for RPC cache response to " + "timeout. A value of `0` " "means disabling this feature."}, - KV{.key = "num_markers", .value = "Specifies the number of coroutines used to download the initial ledger."}, - KV{.key = "dos_guard.whitelist.[]", .value = "The list of IP addresses to whitelist for DOS protection."}, - KV{.key = "dos_guard.max_fetches", .value = "The maximum number of fetch operations allowed by DOS guard."}, + KV{.key = "num_markers", + .value = "Specifies the number of coroutines used to download the initial ledger."}, + KV{.key = "dos_guard.whitelist.[]", + .value = "The list of IP addresses to whitelist for DOS protection."}, + KV{.key = "dos_guard.max_fetches", + .value = "The maximum number of fetch operations allowed by DOS guard."}, KV{.key = "dos_guard.max_connections", .value = "The maximum number of concurrent connections for a specific IP address."}, KV{.key = "dos_guard.max_requests", .value = "The maximum number of requests allowed for a specific IP address."}, - KV{.key = "dos_guard.sweep_interval", .value = "Interval in seconds for DOS guard to sweep(clear) its state."}, + KV{.key = "dos_guard.sweep_interval", + .value = "Interval in seconds for DOS guard to sweep(clear) its state."}, KV{.key = "workers", .value = "The number of threads used to process RPC requests."}, KV{.key = "server.ip", .value = "The IP address of the Clio HTTP server."}, KV{.key = "server.port", .value = "The port number of the Clio HTTP server."}, KV{.key = "server.max_queue_size", - .value = "The maximum size of the server's request queue. If set to `0`, this means there is no queue size " + .value = "The maximum size of the server's request queue. If set to `0`, this means " + "there is no queue size " "limit."}, KV{.key = "server.local_admin", - .value = "Indicates if requests from `localhost` are allowed to call Clio admin-only APIs. Note that this " + .value = "Indicates if requests from `localhost` are allowed to call Clio admin-only " + "APIs. Note that this " "setting cannot be enabled " "together with [server.admin_password](#serveradmin_password)."}, KV{.key = "server.admin_password", - .value = "The password for Clio admin-only APIs. Note that this setting cannot be enabled together with " + .value = "The password for Clio admin-only APIs. Note that this setting cannot be " + "enabled together with " "[server.local_admin](#serveradmin_password)."}, KV{.key = "server.processing_policy", - .value = "For the `sequent` policy, requests from a single client connection are processed one by one, with " - "the next request read only after the previous one is processed. For the `parallel` policy, Clio " - "will accept all requests and process them in parallel, sending a reply for each request as soon " + .value = "For the `sequent` policy, requests from a single client connection are " + "processed one by one, with " + "the next request read only after the previous one is processed. For the " + "`parallel` policy, Clio " + "will accept all requests and process them in parallel, sending a reply for " + "each request as soon " "as it is ready."}, KV{.key = "server.parallel_requests_limit", - .value = "This is an optional parameter, used only if the `processing_strategy` is `parallel`. It limits " - "the number of requests processed in parallel for a single client connection. If not specified, no " + .value = "This is an optional parameter, used only if the `processing_strategy` is " + "`parallel`. It limits " + "the number of requests processed in parallel for a single client connection. " + "If not specified, no " "limit is enforced."}, KV{.key = "server.ws_max_sending_queue_size", - .value = "Maximum queue size for sending subscription data to clients. This queue buffers data when a " + .value = "Maximum queue size for sending subscription data to clients. This queue " + "buffers data when a " "client is slow to receive it, ensuring delivery once the client is ready."}, KV{.key = "server.proxy.ips.[]", - .value = "List of proxy ip addresses. When Clio receives a request from proxy it will use " - "`Forwarded` value (if any) as client ip. When this option is used together with " - "`server.proxy.tokens` Clio will identify proxy by ip or by token."}, + .value = + "List of proxy ip addresses. When Clio receives a request from proxy it will use " + "`Forwarded` value (if any) as client ip. When this option is used together with " + "`server.proxy.tokens` Clio will identify proxy by ip or by token."}, KV{.key = "server.proxy.tokens.[]", - .value = "List of tokens in identifying request as a request from proxy. Token should be provided in " + .value = "List of tokens in identifying request as a request from proxy. Token should " + "be provided in " "`X-Proxy-Token` header, e.g. " "`X-Proxy-Token: '. When Clio receives a request from proxy " - "it will use 'Forwarded` value (if any) to get client ip. When this option is used together with " + "it will use 'Forwarded` value (if any) to get client ip. When this option is " + "used together with " "'server.proxy.ips' Clio will identify proxy by ip or by token."}, KV{.key = "prometheus.enabled", .value = "Enables or disables Prometheus metrics."}, - KV{.key = "prometheus.compress_reply", .value = "Enables or disables compression of Prometheus responses."}, + KV{.key = "prometheus.compress_reply", + .value = "Enables or disables compression of Prometheus responses."}, KV{.key = "io_threads", .value = "The number of input/output (I/O) threads. The value cannot be less than `1`."}, KV{.key = "subscription_workers", - .value = "The number of worker threads or processes that are responsible for managing and processing " + .value = "The number of worker threads or processes that are responsible for managing " + "and processing " "subscription-based tasks from `rippled`."}, KV{.key = "graceful_period", - .value = "The number of seconds the server waits to shutdown gracefully. If Clio does not shutdown " + .value = "The number of seconds the server waits to shutdown gracefully. If Clio does " + "not shutdown " "gracefully after the specified value, it will be killed instead."}, KV{.key = "cache.num_diffs", - .value = "The number of cursors generated is the number of changed (without counting deleted) objects in " - "the latest `cache.num_diffs` number of ledgers. Cursors are workers that load the ledger cache " + .value = "The number of cursors generated is the number of changed (without counting " + "deleted) objects in " + "the latest `cache.num_diffs` number of ledgers. Cursors are workers that load " + "the ledger cache " "from the position of markers concurrently. For more information, please read " "[README.md](../src/etl/README.md)."}, KV{.key = "cache.num_markers", - .value = "Specifies how many markers are placed randomly within the cache. These markers define the " - "positions on the ledger that will be loaded concurrently by the workers. The higher the number, " + .value = "Specifies how many markers are placed randomly within the cache. These " + "markers define the " + "positions on the ledger that will be loaded concurrently by the workers. The " + "higher the number, " "the more places within the cache we potentially cover."}, KV{.key = "cache.num_cursors_from_diff", - .value = "`cache.num_cursors_from_diff` number of cursors are generated by looking at the number of changed " - "objects in the most recent ledger. If number of changed objects in current ledger is not enough, " - "it will keep reading previous ledgers until it hit `cache.num_cursors_from_diff`. If set to `0`, " + .value = "`cache.num_cursors_from_diff` number of cursors are generated by looking at " + "the number of changed " + "objects in the most recent ledger. If number of changed objects in current " + "ledger is not enough, " + "it will keep reading previous ledgers until it hit " + "`cache.num_cursors_from_diff`. If set to `0`, " "the system defaults to generating cursors based on `cache.num_diffs`."}, KV{.key = "cache.num_cursors_from_account", - .value = "`cache.num_cursors_from_diff` of cursors are generated by reading accounts in `account_tx` table. " - "If set to `0`, the system defaults to generating cursors based on `cache.num_diffs`."}, - KV{.key = "cache.page_fetch_size", .value = "The number of ledger objects to fetch concurrently per marker."}, + .value = "`cache.num_cursors_from_diff` of cursors are generated by reading accounts in " + "`account_tx` table. " + "If set to `0`, the system defaults to generating cursors based on " + "`cache.num_diffs`."}, + KV{.key = "cache.page_fetch_size", + .value = "The number of ledger objects to fetch concurrently per marker."}, KV{.key = "cache.load", .value = "The strategy used for Cache loading."}, KV{.key = "cache.file.path", - .value = "The path to a file where cache will be saved to on shutdown and loaded from on startup. " - "If the file couldn't be read Clio will load cache as usual (from DB or from rippled)."}, + .value = "The path to a file where cache will be saved to on shutdown and loaded from " + "on startup. " + "If the file couldn't be read Clio will load cache as usual (from DB or from " + "rippled)."}, KV{.key = "cache.file.max_sequence_age", - .value = "Max allowed difference between the latest sequence in DB and in cache file. If the cache file is " + .value = "Max allowed difference between the latest sequence in DB and in cache file. " + "If the cache file is " "too old (contains too low latest sequence) Clio will reject using it."}, KV{.key = "cache.file.async_save", - .value = "When false, Clio waits for cache saving to finish before shutting down. When true, " - "cache saving runs in parallel with other shutdown operations."}, + .value = + "When false, Clio waits for cache saving to finish before shutting down. When true, " + "cache saving runs in parallel with other shutdown operations."}, KV{.key = "log.channels.[].channel", .value = "The name of the log channel."}, KV{.key = "log.channels.[].level", .value = "The log level for the specific log channel."}, KV{.key = "log.level", - .value = "The general logging level of Clio. This level is applied to all log channels that do not have an " + .value = "The general logging level of Clio. This level is applied to all log channels " + "that do not have an " "explicitly defined logging level."}, - KV{.key = "log.format", .value = R"(The format string for log messages using spdlog format patterns. + KV{.key = "log.format", + .value = R"(The format string for log messages using spdlog format patterns. Each of the variables expands like so: @@ -311,25 +368,34 @@ Documentation can be found at: ConfigFileJson::makeConfigFileJson(std::filesystem::path const& configFilePath) { try { - if (auto const in = std::ifstream(configFilePath.string(), std::ios::in | std::ios::binary); in) { + if (auto const in = std::ifstream(configFilePath.string(), std::ios::in | std::ios::binary); + in) { std::stringstream contents; contents << in.rdbuf(); auto const opts = boost::json::parse_options{.allow_comments = true}; @@ -101,7 +102,9 @@ ConfigFileJson::makeConfigFileJson(std::filesystem::path const& configFilePath) } catch (std::exception const& e) { return std::unexpected(Error{fmt::format( - "An error occurred while processing configuration file '{}': {}", configFilePath.string(), e.what() + "An error occurred while processing configuration file '{}': {}", + configFilePath.string(), + e.what() )}); } } @@ -177,12 +180,17 @@ ConfigFileJson::flattenJson(boost::json::object const& jsonRootObject) tasks.pop(); for (auto const& [key, value] : task.object) { - auto fullKey = - task.prefix.empty() ? std::string(key) : fmt::format("{}.{}", task.prefix, std::string_view{key}); + auto fullKey = task.prefix.empty() + ? std::string(key) + : fmt::format("{}.{}", task.prefix, std::string_view{key}); if (value.is_object()) { tasks.push( - Task{.object = value.as_object(), .prefix = std::move(fullKey), .arrayIndex = task.arrayIndex} + Task{ + .object = value.as_object(), + .prefix = std::move(fullKey), + .arrayIndex = task.arrayIndex + } ); } else if (value.is_array()) { fullKey += ".[]"; @@ -190,14 +198,23 @@ ConfigFileJson::flattenJson(boost::json::object const& jsonRootObject) if (std::ranges::all_of(array, [](auto const& v) { return v.is_primitive(); })) { jsonObject_[fullKey] = array; - } else if (std::ranges::all_of(array, [](auto const& v) { return v.is_object(); })) { + } else if (std::ranges::all_of(array, [](auto const& v) { + return v.is_object(); + })) { for (size_t i = 0; i < array.size(); ++i) { - tasks.push(Task{.object = array.at(i).as_object(), .prefix = fullKey, .arrayIndex = i}); + tasks.push( + Task{ + .object = array.at(i).as_object(), + .prefix = fullKey, + .arrayIndex = i + } + ); } } else { ASSERT( false, - "Arrays containing both values and objects are not supported. Please check the array {}", + "Arrays containing both values and objects are not supported. Please check " + "the array {}", fullKey ); } diff --git a/src/util/config/ConfigValue.hpp b/src/util/config/ConfigValue.hpp index e9f46e51c..0249bd378 100644 --- a/src/util/config/ConfigValue.hpp +++ b/src/util/config/ConfigValue.hpp @@ -77,7 +77,8 @@ public: * @brief Sets the value current ConfigValue given by the User's defined value * * @param value The value to set - * @param key The Config key associated with the value. Optional to include; Used for debugging message to user. + * @param key The Config key associated with the value. Optional to include; Used for debugging + * message to user. * @return optional Error if user tries to set a value of wrong type or not within a constraint */ [[nodiscard]] std::optional @@ -92,7 +93,8 @@ public: if (cons_.has_value()) { auto constraintCheck = cons_->get().checkConstraint(value); if (constraintCheck.has_value()) { - constraintCheck->error = fmt::format("{} {}", key.value_or("Unknown_key"), constraintCheck->error); + constraintCheck->error = + fmt::format("{} {}", key.value_or("Unknown_key"), constraintCheck->error); return constraintCheck; } } @@ -161,7 +163,8 @@ public: } /** - * @brief Sets the config value as optional, meaning the user doesn't have to provide the value in their config + * @brief Sets the config value as optional, meaning the user doesn't have to provide the value + * in their config * * @return Reference to this ConfigValue */ diff --git a/src/util/config/ObjectView.cpp b/src/util/config/ObjectView.cpp index 70419c1f3..da48c9ae5 100644 --- a/src/util/config/ObjectView.cpp +++ b/src/util/config/ObjectView.cpp @@ -39,7 +39,11 @@ ObjectView::ObjectView(std::string_view prefix, ClioConfigDefinition const& clio { } -ObjectView::ObjectView(std::string_view prefix, std::size_t arrayIndex, ClioConfigDefinition const& clioConfig) +ObjectView::ObjectView( + std::string_view prefix, + std::size_t arrayIndex, + ClioConfigDefinition const& clioConfig +) : prefix_{prefix}, arrayIndex_{arrayIndex}, clioConfig_{clioConfig} { } @@ -81,7 +85,9 @@ ObjectView::getArray(std::string_view key) const if (!fullKey.contains(".[]")) fullKey += ".[]"; - ASSERT(clioConfig_.get().hasItemsWithPrefix(fullKey), "Key {} does not exist in object", fullKey); + ASSERT( + clioConfig_.get().hasItemsWithPrefix(fullKey), "Key {} does not exist in object", fullKey + ); return clioConfig_.get().getArray(fullKey); } @@ -94,7 +100,9 @@ ObjectView::getFullKey(std::string_view key) const bool ObjectView::startsWithKey(std::string_view key) const { - return std::ranges::any_of(clioConfig_.get(), [&key](auto const& pair) { return pair.first.starts_with(key); }); + return std::ranges::any_of(clioConfig_.get(), [&key](auto const& pair) { + return pair.first.starts_with(key); + }); } } // namespace util::config diff --git a/src/util/config/ObjectView.hpp b/src/util/config/ObjectView.hpp index 895175e3d..0c6fb79bc 100644 --- a/src/util/config/ObjectView.hpp +++ b/src/util/config/ObjectView.hpp @@ -54,7 +54,11 @@ public: * @param arrayIndex The index of the array object element to view * @param clioConfig Reference to the ClioConfigDefinition containing all the configuration data */ - ObjectView(std::string_view prefix, std::size_t arrayIndex, ClioConfigDefinition const& clioConfig); + ObjectView( + std::string_view prefix, + std::size_t arrayIndex, + ClioConfigDefinition const& clioConfig + ); /** * @brief Checks if prefix_.key (fullkey) exists in ClioConfigDefinition @@ -103,8 +107,8 @@ public: } /** - * @brief Retrieves an ObjectView in ClioConfigDefinition with key that starts with prefix_.key. The view must be of - * type object + * @brief Retrieves an ObjectView in ClioConfigDefinition with key that starts with prefix_.key. + * The view must be of type object * * @param key The suffix of the key * @return An ObjectView representing the subset of configuration data @@ -113,8 +117,8 @@ public: getObject(std::string_view key) const; /** - * @brief Retrieves an ArrayView in ClioConfigDefinition with key that starts with prefix_.key. The view must be of - * type object + * @brief Retrieves an ArrayView in ClioConfigDefinition with key that starts with prefix_.key. + * The view must be of type object * * @param key The suffix of the key * @return An ObjectView representing the subset of configuration data diff --git a/src/util/config/ValueView.hpp b/src/util/config/ValueView.hpp index 6600d3edf..76a5624cd 100644 --- a/src/util/config/ValueView.hpp +++ b/src/util/config/ValueView.hpp @@ -175,7 +175,10 @@ public: ASSERT(type() == ConfigType::String, "Value type is not a string"); return asString(); } else if constexpr (std::is_floating_point_v) { - ASSERT(type() == ConfigType::Double || type() == ConfigType::Integer, "Value type is not a floating point"); + ASSERT( + type() == ConfigType::Double || type() == ConfigType::Integer, + "Value type is not a floating point" + ); return asDouble(); } diff --git a/src/util/log/Logger.cpp b/src/util/log/Logger.cpp index 28b6cab14..cc5f2f249 100644 --- a/src/util/log/Logger.cpp +++ b/src/util/log/Logger.cpp @@ -176,7 +176,9 @@ createConsoleSinks(bool logToConsole, std::string const& format) auto consoleSink = std::make_shared(); consoleSink->set_level(spdlog::level::trace); consoleSink->set_formatter( - std::make_unique(std::make_unique(format)) + std::make_unique( + std::make_unique(format) + ) ); sinks.push_back(std::move(consoleSink)); } @@ -218,7 +220,8 @@ LogService::createFileSink(FileLoggingParams const& params, std::string const& f * * @param config The configuration object containing log settings. * @param defaultSeverity The default severity level to use if not overridden. - * @return A map of channel names to their minimum severity levels, or an error message if parsing fails. + * @return A map of channel names to their minimum severity levels, or an error message if parsing + * fails. */ static std::expected, std::string> getMinSeverity(config::ClioConfigDefinition const& config, Severity defaultSeverity) @@ -229,11 +232,15 @@ getMinSeverity(config::ClioConfigDefinition const& config, Severity defaultSever auto const overrides = config.getArray("log.channels"); - for (auto it = overrides.begin(); it != overrides.end(); ++it) { + for (auto it = overrides.begin(); + it != overrides.end(); + ++it) { auto const& channelConfig = *it; auto const name = channelConfig.get("channel"); if (not std::ranges::contains(Logger::kCHANNELS, name)) { - return std::unexpected{fmt::format("Can't override settings for log channel {}: invalid channel", name)}; + return std::unexpected{ + fmt::format("Can't override settings for log channel {}: invalid channel", name) + }; } minSeverity[name] = getSeverityLevel(channelConfig.get("level")); @@ -243,7 +250,11 @@ getMinSeverity(config::ClioConfigDefinition const& config, Severity defaultSever } void -LogServiceState::init(bool isAsync, Severity defaultSeverity, std::vector const& sinks) +LogServiceState::init( + bool isAsync, + Severity defaultSeverity, + std::vector const& sinks +) { if (initialized_) { throw std::logic_error("LogServiceState is already initialized"); @@ -308,7 +319,11 @@ LogServiceState::registerLogger(std::string_view channel, std::optional logger; if (isAsync_) { logger = std::make_shared( - channelStr, sinks_.begin(), sinks_.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block + channelStr, + sinks_.begin(), + sinks_.end(), + spdlog::thread_pool(), + spdlog::async_overflow_policy::block ); } else { logger = std::make_shared(channelStr, sinks_.begin(), sinks_.end()); @@ -327,15 +342,16 @@ LogService::getSinks(config::ClioConfigDefinition const& config) { std::string const format = config.get("log.format"); - std::vector allSinks = createConsoleSinks(config.get("log.enable_console"), format); + std::vector allSinks = + createConsoleSinks(config.get("log.enable_console"), format); if (auto const logDir = config.maybeValue("log.directory"); logDir.has_value()) { std::filesystem::path const dirPath{logDir.value()}; if (not std::filesystem::exists(dirPath)) { if (std::error_code error; not std::filesystem::create_directories(dirPath, error)) { - return std::unexpected{ - fmt::format("Couldn't create logs directory '{}': {}", dirPath.string(), error.message()) - }; + return std::unexpected{fmt::format( + "Couldn't create logs directory '{}': {}", dirPath.string(), error.message() + )}; } } @@ -387,7 +403,8 @@ void LogService::shutdown() { if (initialized_ && isAsync_) { - // We run in async mode in production, so we need to make sure all logs are flushed before shutting down + // We run in async mode in production, so we need to make sure all logs are flushed before + // shutting down spdlog::shutdown(); } } @@ -454,7 +471,11 @@ Logger::~Logger() } } -Logger::Pump::Pump(std::shared_ptr logger, Severity sev, SourceLocationType const& loc) +Logger::Pump::Pump( + std::shared_ptr logger, + Severity sev, + SourceLocationType const& loc +) : logger_(std::move(logger)) , severity_(sev) , sourceLocation_(loc) diff --git a/src/util/log/Logger.hpp b/src/util/log/Logger.hpp index 9e7b61eb4..77b6ad7fa 100644 --- a/src/util/log/Logger.hpp +++ b/src/util/log/Logger.hpp @@ -59,7 +59,8 @@ class ClioConfigDefinition; } // namespace config /** - * @brief Skips evaluation of expensive argument lists if the given logger is disabled for the required severity level. + * @brief Skips evaluation of expensive argument lists if the given logger is disabled for the + * required severity level. * * Note: Currently this introduces potential shadowing (unlikely). */ @@ -121,7 +122,8 @@ class Logger { operator=(Pump&&) = delete; /** - * @brief Perfectly forwards any incoming data into the underlying stream if data should be logged. + * @brief Perfectly forwards any incoming data into the underlying stream if data should be + * logged. * * @tparam T Type of data to pump * @param data The data to pump @@ -257,7 +259,11 @@ protected: * @param sinks Vector of spdlog sinks to use for output */ static void - init(bool isAsync, Severity defaultSeverity, std::vector> const& sinks); + init( + bool isAsync, + Severity defaultSeverity, + std::vector> const& sinks + ); /** * @brief Whether the LogService is initialized or not @@ -268,7 +274,8 @@ protected: initialized(); /** - * @brief Whether the LogService has any sink. If there is no sink, logger will not log messages anywhere. + * @brief Whether the LogService has any sink. If there is no sink, logger will not log messages + * anywhere. * * @return true if the LogService has at least one sink */ @@ -303,10 +310,11 @@ protected: registerLogger(std::string_view channel, std::optional severity = std::nullopt); protected: - static bool isAsync_; // NOLINT(readability-identifier-naming) - static Severity defaultSeverity_; // NOLINT(readability-identifier-naming) - static std::vector> sinks_; // NOLINT(readability-identifier-naming) - static bool initialized_; // NOLINT(readability-identifier-naming) + static bool isAsync_; // NOLINT(readability-identifier-naming) + static Severity defaultSeverity_; // NOLINT(readability-identifier-naming) + static std::vector> + sinks_; // NOLINT(readability-identifier-naming) + static bool initialized_; // NOLINT(readability-identifier-naming) }; /** @@ -395,8 +403,9 @@ private: * @param config The configuration to parse sinks from * @return A vector of sinks on success, error message on failure */ - [[nodiscard]] static std::expected>, std::string> - getSinks(config::ClioConfigDefinition const& config); + [[nodiscard]] static std:: + expected>, std::string> + getSinks(config::ClioConfigDefinition const& config); struct FileLoggingParams { std::string logDir; diff --git a/src/util/prometheus/Gauge.hpp b/src/util/prometheus/Gauge.hpp index 7e90500ff..76372e806 100644 --- a/src/util/prometheus/Gauge.hpp +++ b/src/util/prometheus/Gauge.hpp @@ -31,7 +31,8 @@ namespace util::prometheus { /** - * @brief A prometheus gauge metric implementation. It can be increased, decreased or set to a value. + * @brief A prometheus gauge metric implementation. It can be increased, decreased or set to a + * value. * * @tparam NumberType The type of the value of the gauge */ diff --git a/src/util/prometheus/Histogram.hpp b/src/util/prometheus/Histogram.hpp index 3258c29b4..09dac574b 100644 --- a/src/util/prometheus/Histogram.hpp +++ b/src/util/prometheus/Histogram.hpp @@ -49,18 +49,27 @@ public: * * @tparam ImplType The type of the implementation of the histogram * @param name The name of the metric - * @param labelsString The labels of the metric in serialized format, e.g. {name="value",name2="value2"} + * @param labelsString The labels of the metric in serialized format, e.g. + * {name="value",name2="value2"} * @param buckets The buckets of the histogram - * @param impl The implementation of the histogram (has default value and need to be specified only for testing) + * @param impl The implementation of the histogram (has default value and need to be specified + * only for testing) */ template > requires std::same_as::ValueType> - AnyHistogram(std::string name, std::string labelsString, Buckets const& buckets, ImplType&& impl = ImplType{}) + AnyHistogram( + std::string name, + std::string labelsString, + Buckets const& buckets, + ImplType&& impl = ImplType{} + ) : MetricBase(std::move(name), std::move(labelsString)) , pimpl_(std::make_unique>(std::forward(impl))) { ASSERT(!buckets.empty(), "Histogram must have at least one bucket."); - ASSERT(std::is_sorted(buckets.begin(), buckets.end()), "Buckets for histogra must be sorted."); + ASSERT( + std::is_sorted(buckets.begin(), buckets.end()), "Buckets for histogra must be sorted." + ); pimpl_->setBuckets(buckets); } @@ -96,7 +105,11 @@ private: setBuckets(Buckets const& buckets) = 0; virtual void - serializeValue(std::string const& name, std::string const& labelsString, OStream&) const = 0; + serializeValue( + std::string const& name, + std::string const& labelsString, + OStream& + ) const = 0; }; template @@ -121,7 +134,11 @@ private: } void - serializeValue(std::string const& name, std::string const& labelsString, OStream& stream) const override + serializeValue( + std::string const& name, + std::string const& labelsString, + OStream& stream + ) const override { impl_.serializeValue(name, labelsString, stream); } diff --git a/src/util/prometheus/Http.hpp b/src/util/prometheus/Http.hpp index 4a49545c5..9dae34a39 100644 --- a/src/util/prometheus/Http.hpp +++ b/src/util/prometheus/Http.hpp @@ -35,6 +35,9 @@ namespace util::prometheus { * @return nullopt if the request shouldn't be handled, respoce for Prometheus otherwise */ std::optional> -handlePrometheusRequest(boost::beast::http::request const& req, bool isAdmin); +handlePrometheusRequest( + boost::beast::http::request const& req, + bool isAdmin +); } // namespace util::prometheus diff --git a/src/util/prometheus/Label.hpp b/src/util/prometheus/Label.hpp index 8fabd52aa..28c3bab40 100644 --- a/src/util/prometheus/Label.hpp +++ b/src/util/prometheus/Label.hpp @@ -41,7 +41,8 @@ public: operator<=>(Label const& rhs) const = default; /** - * @brief Serialize the label to a string in Prometheus format (e.g. name="value"). The value is escaped + * @brief Serialize the label to a string in Prometheus format (e.g. name="value"). The value is + * escaped * * @return The serialized label */ @@ -68,7 +69,8 @@ public: explicit Labels(std::vector