rippled
ValidatorSite_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright 2016 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/misc/ValidatorSite.h>
21 #include <ripple/basics/Slice.h>
22 #include <ripple/basics/base64.h>
23 #include <ripple/basics/strHex.h>
24 #include <ripple/protocol/HashPrefix.h>
25 #include <ripple/protocol/PublicKey.h>
26 #include <ripple/protocol/SecretKey.h>
27 #include <ripple/protocol/Sign.h>
28 #include <ripple/protocol/digest.h>
29 #include <ripple/protocol/jss.h>
30 #include <boost/algorithm/string/join.hpp>
31 #include <boost/algorithm/string/predicate.hpp>
32 #include <boost/asio.hpp>
33 #include <boost/range/adaptor/transformed.hpp>
34 #include <chrono>
35 #include <test/jtx.h>
36 #include <test/jtx/TrustedPublisherServer.h>
37 #include <test/unit_test/FileDirGuard.h>
38 
39 namespace ripple {
40 namespace test {
41 namespace detail {
42 constexpr const char*
44 {
45  return R"vl({
46  "public_key": "ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734",
47  "manifest": "JAAAAAFxIe0md6v/0bM6xvvDBitx8eg5fBUF4cQsZNEa0bKP9z9HNHMh7V0AnEi5D4odY9X2sx+cY8B3OHNjJvMhARRPtTHmWnAhdkDFcg53dAQS1WDMQDLIs2wwwHpScrUnjp1iZwwTXVXXsaRxLztycioto3JgImGdukXubbrjeqCNU02f7Y/+6w0BcBJA3M0EOU+39hmB8vwfgernXZIDQ1+o0dnuXjX73oDLgsacwXzLBVOdBpSAsJwYD+nW8YaSacOHEsWaPlof05EsAg==",
48  "blob" : "eyJzZXF1ZW5jZSI6MzcsImV4cGlyYXRpb24iOjU5NDE3MjgwMCwidmFsaWRhdG9ycyI6W3sidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ0OUY4RUI4MDcxRTI2RDRFMDY3MjM4RDYyRDY3Q0E2RUJGQjI5OEI0QTcyRENGQUQ1MzZBN0VDODkyNUM1MTlCIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMUorT3VBY2VKdFRnWnlPTll0WjhwdXY3S1l0S2N0ejYxVGFuN0lrbHhSbTNNaEFvZ01tUVRSQUZLLyttL1hXUWZKdlhUZU1jYWl5RjZna2hnQXNzZExPY2lJZGtZd1JBSWdOeFlhdkpQeUhBTnV4b2dRWTdSTkJQOXRab2daSnhGMXdacXptNGEzN0dnQ0lCT3ZiZVE4K1A0NkNDSWN5NFpDWkE1clpaKzkzSDBhS0paUTMrSUEwT091Y0JKQUFTVHBRS3RFSmtlcXdIeitqS1dOdldsMHNIUlFaU1NKdVlpTXl5VWE3eXRwc2V2Nk5Hb0ZuMWJOcFlUZ3ZzYVB4b3o3dkhza0RoMlo2Z2ViU0RDUkNBPT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEODEwOEY3RDlFRTc3OURDMTA3NUVDM0NGOEVCOTAwNERERjg0Q0QwQTBGRjU3NzVDOUUzNzVDQ0FDREFBMzAyMiIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTJCQ1BmWjduZWR3UWRldzgrT3VRQk4zNFROQ2cvMWQxeWVOMXpLemFvd0luTWhBbHZQSkFOUWNSVVNOVVIrTmxadW80a0dwWUY4bDlwSFBQMVpST09VY05ZUmRrWXdSQUlnUldaWnVKTEFmM1NOTUdvRnlnVWx1K2VBRDUxWm9IRk1jeW9pY24wV0t1Y0NJR3c0bjljVkRQT0JHQzh3bEpEeTkyODJ4OVJkT3dvMWNvMmcrTlpsYy9ETmNCSkFLSmhLL2FtNkw3S0U0NTBOVnpocFZWb0w4T0ZNbzBtRnhrOEJERzZRTzJjU05NTjNPeXdmNDBEK0lsZXM5TFh4eHZ2UEI2Z1dTbVBsd0Y3ZE5SOUdBUT09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDdFM0JBRkY5MDFERTUyNUIwMEIyQzFGRTE5QUY0NDlBMDgwQjVGMzEwMEM2RUMxODJDODY3QUY2MUY3MTBGRkQiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUxK082LzVBZDVTV3dDeXdmNFpyMFNhQ0F0Zk1RREc3QmdzaG5yMkgzRVAvWE1oQTUrR0RKaDJBcFdLQ2gyTjVvbXg0RkFPRkVxWE1qcXkxSEo1RTdXQTNGck9ka2N3UlFJaEFNUmV6d2pUQUwzNWpwamoxNWpxb0hVdlJtNys3aUhwVTQ3YUtFNkhFQ2haQWlCU01JWmFNV3Y2cU5KSG5pWXBzWUh4NE9QUHBCb0NNTWRNVkFHZkZpOWZLM0FTUUUwVFlpSXNHdjAveWxwcUdFQmlMa2syWGpyQTgrK0FrenByOXZjVHRya0hpRERvMGNIS085bVJVTEFYZXNSck95RmI1UWNPMGwwVnN3ZXZENWpsc3drPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ0NUU4MEEwNEQ3OUNCOURGMDBBRUJEODZEQ0RDMTY4NkQ2NDE5RUE5RTVFMEU3MUYxQTgxN0UwOEI1MDc2QTU1IiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMUY2QW9FMTV5NTN3Q3V2WWJjM0JhRzFrR2VxZVhnNXg4YWdYNEl0UWRxVlhNaEF4Wm8xNTdwY0I5ZGU2U21rN2hvSzN3TkNBcjRhRlp0ZkFQaTdDRTRtTkpsZGtjd1JRSWhBTGxWalhDZml5L210WEJXc050Nzd0NGpLY05FQnBSVjh6ditTcFU1bENoMEFpQmE4dm84eHhwdmlZbGY0emRHK25RaEIyT2dma1FaWlBNSE90N0NhWHpYZ1hBU1FMOE81cDA4M21nNEtLTDh1WmZNYVVxZGd6dUowR3RhMWx5VVdQY3RUUEN4WTEzNVh3SytuSkFkRnNJVUZOSjlNUGpucENtU2pZVnpWYTZNNS9uQWNBST0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVERDhDODg2NDI3OTVDRTY5QzVCNzgwRTAxNzAyQzM3MEY5NTA3RDBCNjQ0MzNGMTdFRkU3MEYyNjM3QTQwQURCNyIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTNZeUlaQ2VWem1uRnQ0RGdGd0xEY1BsUWZRdGtRejhYNytjUEpqZWtDdHQzTWhBbkZmcityOUJYZHNYRS9jQmxKTXlkL1hzTzFBNVhFWUNjdHJzdkxFWCtEbWRrY3dSUUloQU5SY1JNZzlTQVhvYU92SERaMmF2OVJ6RWFaYVZFTmZRaVZnc2krT3gzRjBBaUIyc25TSU9tNmM0L2luYnRVMFVtV0xRVHp1d2tPZFVGUElCOEF4OGRtR3VIQVNRTVVJZlhNajk2a2NGVFNKbk1GQy9tVy9BUThiS1hrRnJyazBDVVRGRkt3ZUVqVHErU1RyRmk2cUxMMk1UN252ZUd4c1hCQ2d6dGpjMHFHYXM5S0ZXZ009In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREJERUI5MDFGN0M3NUQwRTIwQzZDNDJBRjAzQkUwREE0MDM3N0FGMTkzOUExOEIzQ0IzNjc5NjYxREQ1RjlGNzQiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUyOTY1QWZmSFhRNGd4c1FxOER2ZzJrQTNldkdUbWhpenl6WjVaaDNWK2ZkSE1oQWczY3lLTlBNUHFLZ1I3a0lpN2MvOEdML1lnZEJ0ZzRtU0FXdndtYWV2Vkdka1l3UkFJZ1d6RzhHcVlnM1lwd0RzOHhYYTlYcUxIc3M3NktUMnVBSFJoVVhGVlVxQ1FDSUcyRXZiRktueGV6UmQ5Y3BQSFN0MzJIWEsrUDQrYUwzcDIrdnFsQ3hSUjljQkpBYm9YVG1ZVGF5b2NBM3pmOWRXRVh0eWFlT0dDMWs1V2RZVVJ6UGxlZXZ2YWxSNHhWb1h6czM4aUdQeEZyL3BBOW5MK000ZHV1MEdLQ0hsVmlyK2ZCQWc9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURBMTc4NzFFNzJCMEM1NzBBQzQzNDVDNjBDRjAyQUZCQkI3NDBBNjMxQjdBRDBFMUU1NzMyMTY1NzREOUFFQTAyIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMmhlSEhuS3d4WENzUTBYR0RQQXErN3QwQ21NYmV0RGg1WE1oWlhUWnJxQW5NaEFvanl1emd0cmVRa3hRajhwckh4T3NiRGNGNWZ1NFhYYjBLeEVML1BxNUhoZGtjd1JRSWhBTmZQRExaUDQ3YUNXd3Q1a0JucDc1QnV1Q2dwOWM0QmZKUGQ2NlNGQ3c2MUFpQUp2ZWdCdnZQSXJlYytYT1N6S1JmaTV1dVhXeHRsOUV5cjJhUEJZWHZiUkhBU1FNVUxZRW83YmVSZm9VQ25qazFzVFl5WTkxdExJR0xnbm5hV1hoVW04MCt6czVJR2VnazhxaWpLQXRCT011QkM3MWxBQjRLaEpjK2RCMnJwTU9GYzVndz0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVERjQ2RUUyN0FEMEUxQTcxNEFGRUNEQTgxNkVBQjcxMTQ2MTRGQ0I5MkQwQ0I0RDk3QjZBODhFRDQzNDM0QUZDOSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTMwYnVKNjBPR25GSy9zMm9GdXEzRVVZVS9Ma3RETFRaZTJxSTdVTkRTdnlYTWhBdzBBVFdqVlR0NEZmZUtPN2t2NmZGZ2QvZ28yK2Q1QlN5VWNVUm1SV25UdGRrY3dSUUloQU13T2dEZWM3UVlZTm5nc3BnOTB3RXZWYnNvaDJ1eDE0UlBUdytHSGFYTmxBaUFMZ2ZFc3orQUY0ZXlYL1k1aTQ0VnJGakZGSU1XVWZPWmFRSnRzeHRlTTFYQVNRTE9hRjB0MlpwcVZLZDhKRVNRVlkrelU1NjdpQUFHMmFtVFBaeDk1ODc1UzlBNlBsK2tINVRHSE1BZVdqZ1dTcWZoM20ySEJKWDdOSWNYYjk4dnk5QUE9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDZFNEM0MUU1OUZGQkVCNTE3MjZFNTQ0Njg1MDJGRTY0MzcyMzhGQTc4RUE1MTYzNEU3QkYwRDA5MTcxQUVFOEYiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUxdVRFSGxuL3ZyVVhKdVZFYUZBdjVrTnlPUHA0NmxGalRudncwSkZ4cnVqM01oQXV6dEdXYi9PaTEvVjVtNWR1aldyOUhtYktSeUs0WFlrK2ttdUZQU2dBRnJka1l3UkFJZ2ZRK0JnWFg2UWJsWnk0SDA1bzdHUFNJd3FTN1FRUlVXN2RxRjU0SUFpaU1DSUg0WGZMdzk1NmlFYW94Wk9rN0tjdGluMlg5aE1mYUxON3d5czl5QVVGb1pjQkpBdWVFaTg0WFIzTGwxR0xKV2FuVzFnMU1kVWovMFBBeEpidzZFRVFSdUczemRudVJITlhsZDZVWkFiSWtWY1AwenRmcXVsQnpqYmNzTERPS0ZFaWNTQmc9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURCNkZDOEU4MDNFRThFREMyNzkzRjFFQzkxN0IyRUU0MUQzNTI1NTYxOERFQjkxRDNGOUIxRkM4OUI3NUQ0NTM5IiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMjIvSTZBUHVqdHduay9Ic2tYc3U1QjAxSlZZWTNya2RQNXNmeUp0MTFGT1hNaEE4VmR2SEZ5U2NCeVFHVFlOR2VPdkIwKzY3Z1dhcWVmY2Z2Ums1K0t3Z1YxZGtZd1JBSWdaRnVsTy9BaU1vY3puZzZpLzRCa2Z6VDdqOWx4RjRQUDF1ZmdyT1FhSjhzQ0lCWC9FOFpicG43dFdxZ0F5TnlXcFZQa2hGbWFVTXFFcnk4V29VVDFmZEdRY0JKQXY1MVJxSnhnZy9Wcm5yWndpTEsyRGMwQ0tiaUxQTzVISjRaTXNqZFBUMmdSYzk3cldrQVh1VjJMNlBORk81OXh5dW9hWm1TTWxaWXZxU0dQcGZGN0J3PT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVENjkxMzAzOTkyRkVDNjRFNkJDNEJBQ0QzNkFFNkU1QUVEQzIzRjI4NjFCNkQ4RUZCOUZENzdFRTNFQURFMzQzNSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTFwRXdPWkwreGs1cnhMck5OcTV1V3UzQ1B5aGh0dGp2dWYxMzdqNnQ0ME5YTWhBaTJBWEpRZ28vSnVXM3I3Zi82Q2NWc0dOMVltSWoxMUdpSUVTSEJuUVNrOGRrY3dSUUloQU5DREVReW1yZDZ2ZVQzb3VhY0Y2ZmhCcjV3THczR21YZzFyTUNMVnZCelpBaUE4dVdRK3RxZDQ2V21mQmV4alNCUTJKZDZVQUdkckh2amNDUTJaZ1Nvb0NuQVNRRmtIbCtENy9VM1dCeVlQMzg0K3BjRkRmMkdpNFdJUkhWVG81OGNxZGs1Q0Rpd2MxVDByRG9MaG1vNDFhM2YrZHNmdGZ3UjRhTW13RmNQWExucmpyQUk9In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREFEMTY2NjdGMDE4NUREQkI3RkE2NUIyMkY0QjdEMzEwQkY1QzNFMkQ5QjgyM0ZCMDZBM0E0MUFGOEFDODNCQzEiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUydEZtWi9BWVhkdTMrbVd5TDB0OU1RdjF3K0xadUNQN0JxT2tHdmlzZzd3WE1oQXF3ZUUzUElTM0U0NEtoTXFLakt0YmtCZThIOEdiaXVvQVhBWURSb1ZSSG9ka1l3UkFJZ2FnR2tYdG93VXliZGx0S29qdjBsdnZmbHJsUTlJUm5QT2pla0Y2MGlIemdDSUNnNlpvY0lNemtVdXZPOTFCRW9ybUlXbVg0Ry9NR1QyenJvNkkvUHZCOFhjQkpBY0pMWGt0L3cva2N3RXZOaVptaTJpMm5NbjF3aVAzTFM5TkpqQlBqdThLRkxBTWcwTzl5ZFFUNjdVL0FMWU9lVFBUTzIvaTJZdzlPU2xpYnRxaGd6REE9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURDMjQ1MDI3QTUyRUU1MzE4MDk1NTk4RUMzQUI2NUZGNEEzQjlGOTQyOEUxMEIyRjNDNkYzOURFMTVBMTVDOTBBIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllM0NSUUo2VXU1VEdBbFZtT3c2dGwvMG83bjVRbzRRc3ZQRzg1M2hXaFhKQ25NaEEvOC85cktVZEE2MWovZklFUC9jcUxweEJsbUloUDJyZzFkN05hRVB5S1YrZGtjd1JRSWhBSXhFME0vRko1MHZmWlc2ZlBweTR5Q1p1bVk5bjBvYnJPb2pVa2ptNTVhMEFpQmo1Nk8wTXBvcEdvWTlIeEMvKzR3Tk8zNkhvN0U5Q1FlSHNuS3JlRGRzQVhBU1FJWVVkODFqYmlWVWxFVDRkR29HMnArY2YrMkdxRVhYNWZKTVNTeVgvcWUwWGZSNGNPKzRxbGdtak1RZENSREJXQUJIVnZkTi95WnlpL3JMMmMrV3JRYz0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVENDI0NkFBM0FFOUQyOTg2Mzk0NDgwMENDQTkxODI5RTQ0NDc0OThBMjBDRDlDMzk3M0E2QjU5MzQ2Qzc1QUI5NSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTFDUnFvNjZkS1lZNVJJQU15cEdDbmtSSFNZb2d6Wnc1YzZhMWswYkhXcmxYTWhBa20xbHowYzhRWFdmSjliMXZCNzJkTGFidzh3WUlkOE10bnBzSEhCRUM4cGRrWXdSQUlnUWxiNkhKNTNoc1RBZlZpZCtBT2RCVnZNRjdyYWhJS05MQkhVZ241MnpCRUNJR0xVcUZ1OGExQUFIUkpjVm9uS1lFbm1oSndiQ1hMbitqZTduYTFXRDEvb2NCSkFFNHZmdnJHU21aQzJ1QVVHbU01ZElCdG9TZ0VVZXkrMlZsZURZRXNjZTk0dHhZY2pSOFo3UUxOYWxpRDh3L2JENS9odllROG1lVjFXZzFqSkZOZTBDQT09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDJDMTQ2OEI0QTExRDI4MUY5M0VGMzM3Qzk1RTRBMDhERjAwMDBGREVGQjZEMEVBOUJDMDVGQkQ1RDYxQTFGNUEiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUwc0ZHaTBvUjBvSDVQdk0zeVY1S0NOOEFBUDN2dHREcW04QmZ2VjFob2ZXbk1oQWtNVW1DRDJhUG1nRkREUm1pbXZTaWNTSVNjdzZZTnI0MkR3NFJBZHdyT0Fka2N3UlFJaEFKRk9ITWc2cVRHOHY2MGRocmVuWVlrNmN3T2FSWHEwUk5tTGp5eUNpejVsQWlBZFUwWWtEVUpRaG5OOFJ5OHMrNnpUSkxpTkxidE04b08vY0xudXJWcFJNM0FTUUdBTGFySEFzSmtTWlF0R2RNMkFhUi9qb0ZLL2poRFU1NytsK1JTWWpyaS95ZEUyMERhS2Fud2tNRW9WbEJUZzdsWDRoWWpFbm1rcW83M3dJdGhMT0FRPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRURBNTRDODVGOTEyMTlGRDI1OTEzNEI2QjEyNkFENjRBRTcyMDRCODFERDQwNTI1MTA2NTdFMUE1Njk3MjQ2QUQyIiwibWFuaWZlc3QiOiJKQUFBQUFKeEllMmxUSVg1RWhuOUpaRTB0ckVtcldTdWNnUzRIZFFGSlJCbGZocFdseVJxMG5NaEFsOGNKZXJQdit2bzFCSzYxMXhWVHBHeGpqci9DdXhQVGdVOFVSTTRlVFo1ZGtZd1JBSWdkSzNjUVYyWS92aVpuZS9QYm9LU0tld25nVHVJTjJNNmM4YXp3cWMyMHVVQ0lBYzZHb05UK1AyWUJ5NDlnZGF1NFA3eVN3V29RWDVuZjlkUXhpUWF2NXdJY0JKQXFpQ0swZDZRUlpTcGlWSHA4TzlubEtYQ1NFaHNpU05jV2NFRm0vZkdoSkFuQU4wT3Y5SElOSWQxcHhyQm4yZEtSZWdMVHZZRzNCcGJ6Ly9ITGdFZERBPT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEOUFFNEY1ODg3QkEwMjlFQjdDMDg4NDQ4NkQyM0NGMjgxOTc1Rjc3M0Y0NEJEMjEzMDU0MjE5ODgyQzQxMUNDNyIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTJhNVBXSWU2QXA2M3dJaEVodEk4OG9HWFgzYy9STDBoTUZRaG1JTEVFY3gzTWhBbUcyemd2OEZCWnNaSlU4YVBhcHdvOWNJcVF2NC9NU1Mxb1ZBNWVWTWl3TGRrWXdSQUlnRitMT2U0ZVkwZ3A5dHRxaDJnbnYrejc1T3FMeU9RTXBHUEFMZ20rTnRPc0NJQ0RYQlpWUHRwcm1CRGtCSmtQRlNuRTU1RDllS1lSSDh6L2lZMUV0cE5wbGNCSkFBREVXR1ZUODBPd2hkMWxoMkpzVS9vWmxtZU5GNVdON1l2bEI4bGxFeGFSS0VWQytHVzlXZytpTklRM3JtVjdQOGFOYVZ1YWFiRzAwZk9na2d6TmhEdz09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFREE4RDI5RjQwQ0VCMjg5OTU2MTc2NDFBM0JDNDI2OTJFMURFODgzMjE0RjYxMkZCQjYyMDg3QTE0OEU1RjZGOUEiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUybzBwOUF6cktKbFdGMlFhTzhRbWt1SGVpRElVOWhMN3RpQ0hvVWpsOXZtbk1oQW5ZblA3RWc2VmdObkVVVFJFMjlkNjRqUVQvaUJjV1RRdE5yVXp5RDZNSitka2N3UlFJaEFPRXNWNWFuVGtsb1NtVFpSYmltTXlCS3FIb0pZWGNCQmU4bExpUFlDN21VQWlBejJhTk9wZlEvMUx5Y1dsb0lNdmRoeHppbnE1WDdVYXMvdU9TYjl3aDhkM0FTUUxWa2ZwVy9HTzZ3ZFQ2QXV1U0o1NlR0TTM0M3BETkgraVN6eGx0SWZkclBpVXhUNXJmNGsyMWxRUXVQQ2xYbTkrU2ZLckNpVVhaSzdkajAvR1dUWVFnPSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQzOEIwMjg4RUEyNDBCNENERUMxOEExQTYyODlFQjQ5MDA3RTRFQkMwREU5NDQ4MDNFQjdFRjE0MUM1NjY0MDczIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMDRzQ2lPb2tDMHpld1lvYVlvbnJTUUIrVHJ3TjZVU0FQcmZ2RkJ4V1pBYzNNaEFnT0tjdkl1Y2hhbHJady9nbFR1T3hWM0lPQ2Nwb3J4TUI3SnFBVnVwazFlZGtjd1JRSWhBT3ZSenBlK0lZWksxTXlJbklRWjg3SnZQMko4U0lYQ1haTVBCQ2RJVEJhbUFpQVNhdkpYaTlwd3M4ckRESlN4aEdNbG1FN3pJNWJTQThpdnRSQzlMZ3ErVVhBU1FEbDNlb3FMSUQrRVRKTk0remJNdXZ3dmNIRUl4ZUJaa1o5ZnA1akp2Nk9DVFB3bGo0VEpTdXkxYXZFV3FVWVMycml2NUR2bDJoYUZVb0NIZjR5YXdBQT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVERUUxMERDMzZBQ0Q5OTVDOEUwRTg2RTNDRDJGQkY4MzAxQTRBQzJCODg0N0I2MUExOTM1REU0OTczQjQwN0MwRSIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTN1RU53MnJObVZ5T0RvYmp6UysvZ3dHa3JDdUlSN1lhR1RYZVNYTzBCOERuTWhBbVgwdmI3aitsZ0JqRmpiTjlSbEE4Nko3QU8yVm42SExxdU8zYWlzSzRtd2RrWXdSQUlnZnhCTG43aTRqZy9kaTBVMjVxNmtJYlZmVHpxYkEwU0NwUTBJNTdUT0ZrY0NJRk10SlFwRU5qQjJLMkVtdkJIUHZOY3d1U1BjM3ZzRWVxRTJyTkovY1Q1RGNCSkFmNjhYUEZ1NVJqQ2VMZ3BGSk03UEtGTGdvVjhlMW54TzVld2pxOVErVEFFR25GeVMwSU93ZjZwT090SVZNZFZlWHUxdjZwNGZoWFFrZGloSHQxeDZBZz09In0seyJ2YWxpZGF0aW9uX3B1YmxpY19rZXkiOiJFRDU4M0VDRDA2QzNCNzM2OTk4MEU2NUM3OEM0NDBBNTI5MzAwRjU1N0VEODEyNTYyODNGN0RENUFBMzUxM0EzMzQiLCJtYW5pZmVzdCI6IkpBQUFBQUZ4SWUxWVBzMEd3N2MybVlEbVhIakVRS1VwTUE5VmZ0Z1NWaWcvZmRXcU5ST2pOSE1oQXl1VW56WloxbjIvR2FUbUUxbTdIL3Y5WWxaeURFd0hZM2dTSFVBM0lDTDlka1l3UkFJZ0h4MlBIdmlkb04rNXlHOVdlQVMyazdud0lNOGFqeFFXNndqdnQ4a0JlbkFDSUROeFFQUWtEeURKSDlzZVM1QzYybUFhclFtZ2lOODlZUzNqaE50bnZFSXFjQkpBajdKaDBLYWMrYUpkcG9lcHUvK2VKS25uRlE3WUJ5WkI4ZU1aK1NTMXpMaEUrbGlwLzQ5cXFWTmNwQXhFcWZhR3R4SnpvREREMS9RYnVVN05PU1BrQ2c9PSJ9LHsidmFsaWRhdGlvbl9wdWJsaWNfa2V5IjoiRUQ5NUM1MTcyQjJBRDdEMzk0MzRFRUJDNDM2QjY1QjNCQjdFNThENUMxQ0VGQzgyMEI2OTcyQUNBRDc3NkUyODZBIiwibWFuaWZlc3QiOiJKQUFBQUFGeEllMlZ4UmNyS3RmVGxEVHV2RU5yWmJPN2ZsalZ3Yzc4Z2d0cGNxeXRkMjRvYW5NaEFpcWNSZGUzTVFaMDc1ZmE0Wk5OeVJhWUpHTWRCTmtCbm4zYlFyS3NlQkRRZGtZd1JBSWdVK0xmY0U3MURQVnJPK0t0VUJqUTlEMnUway9QcjdsdWtPMW5QUmo2aFNBQ0lETkxZQy9KRmdvYkNzSWEwQkd3KzZiVW5PdzltZVUzRmRYZ1I3UTdTb3FKY0JKQVhRYWtPb1FuUHAzcGNMTDd6ZEtDUFVYNGIrL0ZDOVVuaHFwK085eFFGblJhQ1dWR21rNU1KT0lNczRXT1FkcE0xajNPZ1NzQUJtUnVDWFl2d28vbkR3PT0ifSx7InZhbGlkYXRpb25fcHVibGljX2tleSI6IkVEOTAxNjNEMkJGMEI3Nzg4OTA0QzRBNDExOEQ3RDk2ODkyMEU4NDdEODhCNzkxNzgzOTA4MzdERTNDQTI2MTU2MiIsIm1hbmlmZXN0IjoiSkFBQUFBRnhJZTJRRmowcjhMZDRpUVRFcEJHTmZaYUpJT2hIMkl0NUY0T1FnMzNqeWlZVlluTWhBNzJWVFJpR2hrSkJ0cWdHSER6SGo3WWJDNitOc0VLckZITnVFL0xPM1RuNWRrWXdSQUlnZjhzK2ZZdDBsbHJLUTJxaVdQbkdtYjZxSlBvZThPbkNNM1ZTMjlYS2JZWUNJSEdubEo0T1RzMmRYdWdPNkJ0bzYzTnBEdnZxSitXSXdkWUtxWjZCaUJmemNCSkFHdk50a29nNHBmRTVkWlJ3bWljODdaQmVldW5PaDRZcEwwU0VSZHhXajQzQ3M5ODE1ekZKdVp5c1NhVVgyUi92ZEUyVktxdlNncXF0REVuck1vMm9Bdz09In1dfQ==",
49  "signature" : "9FF30EDC4DED7ABCD0D36389B7C716EED4B5E4F043902853534EBAC7BE966BB3813D5CF25E4DADA5E657CCF019FFD11847FD3CC44B5559A6FCEEE4C3DCFF8D0E",
50  "version": 1
51 }
52 )vl";
53 }
54 
55 auto constexpr default_expires = std::chrono::seconds{3600};
56 } // namespace detail
57 
58 class ValidatorSite_test : public beast::unit_test::suite
59 {
60 private:
62 
63  void
65  {
66  testcase("Config Load");
67 
68  using namespace jtx;
69 
70  Env env(*this);
71  auto trustedSites =
72  std::make_unique<ValidatorSite>(env.app(), env.journal);
73 
74  // load should accept empty sites list
75  std::vector<std::string> emptyCfgSites;
76  BEAST_EXPECT(trustedSites->load(emptyCfgSites));
77 
78  // load should accept valid validator site uris
79  std::vector<std::string> cfgSites({
80  "http://ripple.com/", "http://ripple.com/validators",
81  "http://ripple.com:8080/validators",
82  "http://207.261.33.37/validators",
83  "http://207.261.33.37:8080/validators",
84  "https://ripple.com/validators",
85  "https://ripple.com:443/validators",
86  "file:///etc/opt/ripple/validators.txt",
87  "file:///C:/Lib/validators.txt"
88 #if !_MSC_VER
89  ,
90  "file:///"
91 #endif
92  });
93  BEAST_EXPECT(trustedSites->load(cfgSites));
94 
95  // load should reject validator site uris with invalid schemes
96  std::vector<std::string> badSites({"ftp://ripple.com/validators"});
97  BEAST_EXPECT(!trustedSites->load(badSites));
98 
99  badSites[0] = "wss://ripple.com/validators";
100  BEAST_EXPECT(!trustedSites->load(badSites));
101 
102  badSites[0] = "ripple.com/validators";
103  BEAST_EXPECT(!trustedSites->load(badSites));
104 
105  // Host names are not supported for file URLs
106  badSites[0] = "file://ripple.com/vl.txt";
107  BEAST_EXPECT(!trustedSites->load(badSites));
108 
109  // Even local host names are not supported for file URLs
110  badSites[0] = "file://localhost/home/user/vl.txt";
111  BEAST_EXPECT(!trustedSites->load(badSites));
112 
113  // Nor IP addresses
114  badSites[0] = "file://127.0.0.1/home/user/vl.txt";
115  BEAST_EXPECT(!trustedSites->load(badSites));
116 
117  // File URL path can not be empty
118  badSites[0] = "file://";
119  BEAST_EXPECT(!trustedSites->load(badSites));
120 
121 #if _MSC_VER // Windows paths strip off the leading /, leaving the path empty
122  // File URL path can not be a directory
123  // (/ is the only path we can reasonably assume is a directory)
124  badSites[0] = "file:///";
125  BEAST_EXPECT(!trustedSites->load(badSites));
126 #endif
127  }
128 
130  {
133  bool ssl;
134  bool failFetch = false;
135  bool failApply = false;
136  int serverVersion = 1;
139  };
140  void
142  {
143  testcase << "Fetch list - "
144  << boost::algorithm::join(
145  paths |
146  boost::adaptors::transformed(
147  [](FetchListConfig const& cfg) {
148  return cfg.path +
149  (cfg.ssl ? " [https]" : " [http]");
150  }),
151  ", ");
152  using namespace jtx;
153 
154  Env env(*this);
155  auto& trustedKeys = env.app().validators();
156 
157  test::StreamSink sink;
158  beast::Journal journal{sink};
159 
160  PublicKey emptyLocalKey;
161  std::vector<std::string> emptyCfgKeys;
162  struct publisher
163  {
164  publisher(FetchListConfig const& c) : cfg{c}
165  {
166  }
169  std::string uri;
170  FetchListConfig const& cfg;
171  bool isRetry;
172  };
173  std::vector<publisher> servers;
174 
175  auto constexpr listSize = 20;
176  std::vector<std::string> cfgPublishers;
177 
178  for (auto const& cfg : paths)
179  {
180  servers.push_back(cfg);
181  auto& item = servers.back();
182  item.isRetry = cfg.path == "/bad-resource";
183  item.list.reserve(listSize);
184  while (item.list.size() < listSize)
185  item.list.push_back(TrustedPublisherServer::randomValidator());
186 
187  item.server = std::make_unique<TrustedPublisherServer>(
188  env.app().getIOService(),
189  item.list,
190  env.timeKeeper().now() + cfg.expiresFromNow,
191  cfg.ssl,
192  cfg.serverVersion);
193  cfgPublishers.push_back(strHex(item.server->publisherPublic()));
194 
195  std::stringstream uri;
196  uri << (cfg.ssl ? "https://" : "http://")
197  << item.server->local_endpoint() << cfg.path;
198  item.uri = uri.str();
199  }
200 
201  BEAST_EXPECT(
202  trustedKeys.load(emptyLocalKey, emptyCfgKeys, cfgPublishers));
203 
204  using namespace std::chrono_literals;
205  auto sites = std::make_unique<ValidatorSite>(env.app(), journal, 2s);
206 
208  for (auto const& u : servers)
209  uris.push_back(u.uri);
210  sites->load(uris);
211  sites->start();
212  sites->join();
213 
214  auto const jv = sites->getJson();
215  for (auto const& u : servers)
216  {
217  for (auto const& val : u.list)
218  {
219  BEAST_EXPECT(
220  trustedKeys.listed(val.masterPublic) != u.cfg.failApply);
221  BEAST_EXPECT(
222  trustedKeys.listed(val.signingPublic) != u.cfg.failApply);
223  }
224 
225  Json::Value myStatus;
226  for (auto const& vs : jv[jss::validator_sites])
227  if (vs[jss::uri].asString().find(u.uri) != std::string::npos)
228  myStatus = vs;
229  BEAST_EXPECTS(
230  myStatus[jss::last_refresh_message].asString().empty() !=
231  u.cfg.failFetch,
232  to_string(myStatus) + "\n" + sink.messages().str());
233 
234  if (!u.cfg.msg.empty())
235  {
236  BEAST_EXPECTS(
237  sink.messages().str().find(u.cfg.msg) != std::string::npos,
238  sink.messages().str());
239  }
240 
241  if (u.cfg.expectedRefreshMin)
242  {
243  BEAST_EXPECTS(
244  myStatus[jss::refresh_interval_min].asInt() ==
245  u.cfg.expectedRefreshMin,
246  to_string(myStatus));
247  }
248 
249  if (u.cfg.failFetch)
250  {
251  using namespace std::chrono;
252  log << " -- Msg: "
253  << myStatus[jss::last_refresh_message].asString()
254  << std::endl;
255  std::stringstream nextRefreshStr{
256  myStatus[jss::next_refresh_time].asString()};
257  system_clock::time_point nextRefresh;
258  date::from_stream(nextRefreshStr, "%Y-%b-%d %T", nextRefresh);
259  BEAST_EXPECT(!nextRefreshStr.fail());
260  auto now = system_clock::now();
261  BEAST_EXPECTS(
262  nextRefresh <= now + (u.isRetry ? seconds{30} : minutes{5}),
263  "Now: " + to_string(now) + ", NR: " + nextRefreshStr.str());
264  }
265  }
266  }
267 
268  void
270  {
271  testcase << "File list - " << paths[0].first
272  << (paths.size() > 1 ? ", " + paths[1].first : "");
273 
274  using namespace jtx;
275 
276  Env env(*this);
277 
278  test::StreamSink sink;
279  beast::Journal journal{sink};
280 
281  struct publisher
282  {
283  std::string uri;
284  std::string expectMsg;
285  bool shouldFail;
286  };
287  std::vector<publisher> servers;
288 
289  for (auto const& cfg : paths)
290  {
291  servers.push_back({});
292  auto& item = servers.back();
293  item.shouldFail = !cfg.second.empty();
294  item.expectMsg = cfg.second;
295 
296  std::stringstream uri;
297  uri << "file://" << cfg.first;
298  item.uri = uri.str();
299  }
300 
301  auto sites = std::make_unique<ValidatorSite>(env.app(), journal);
302 
304  for (auto const& u : servers)
305  uris.push_back(u.uri);
306  sites->load(uris);
307  sites->start();
308  sites->join();
309 
310  for (auto const& u : servers)
311  {
312  auto const jv = sites->getJson();
313  Json::Value myStatus;
314  for (auto const& vs : jv[jss::validator_sites])
315  if (vs[jss::uri].asString().find(u.uri) != std::string::npos)
316  myStatus = vs;
317  BEAST_EXPECTS(
318  myStatus[jss::last_refresh_message].asString().empty() !=
319  u.shouldFail,
320  to_string(myStatus));
321  if (u.shouldFail)
322  {
323  BEAST_EXPECTS(
324  sink.messages().str().find(u.expectMsg) !=
325  std::string::npos,
326  sink.messages().str());
327  log << " -- Msg: "
328  << myStatus[jss::last_refresh_message].asString()
329  << std::endl;
330  }
331  }
332  }
333 
334  void
336  {
337  auto fullPath = [](detail::FileDirGuard const& guard) {
338  auto absPath = absolute(guard.file()).string();
339  if (absPath.front() != '/')
340  absPath.insert(absPath.begin(), '/');
341  return absPath;
342  };
343  {
344  // Create a file with a real validator list
346  *this, "test_val", "vl.txt", detail::realValidatorContents());
347  // Create a file with arbitrary content
348  detail::FileDirGuard hello(
349  *this, "test_val", "helloworld.txt", "Hello, world!");
350  // Create a file with malformed Json
352  *this,
353  "test_val",
354  "json.txt",
355  R"json({ "version": 2, "extra" : "value" })json");
356  auto const goodPath = fullPath(good);
357  auto const helloPath = fullPath(hello);
358  auto const jsonPath = fullPath(json);
359  auto const missingPath = jsonPath + ".bad";
360  testFileList({
361  {goodPath, ""},
362  {helloPath,
363  "Unable to parse JSON response from file://" + helloPath},
364  {jsonPath,
365  "Missing fields in JSON response from file://" + jsonPath},
366  {missingPath, "Problem retrieving from file://" + missingPath},
367  });
368  }
369  }
370 
371 public:
372  void
373  run() override
374  {
375  testConfigLoad();
376 
377  for (auto ssl : {true, false})
378  {
379  // fetch single site
380  testFetchList({{"/validators", "", ssl}});
381  // fetch multiple sites
382  testFetchList({{"/validators", "", ssl}, {"/validators", "", ssl}});
383  // fetch single site with single redirects
384  testFetchList({{"/redirect_once/301", "", ssl}});
385  testFetchList({{"/redirect_once/302", "", ssl}});
386  testFetchList({{"/redirect_once/307", "", ssl}});
387  testFetchList({{"/redirect_once/308", "", ssl}});
388  // one redirect, one not
390  {{"/validators", "", ssl}, {"/redirect_once/302", "", ssl}});
391  // fetch single site with undending redirect (fails to load)
393  {{"/redirect_forever/301",
394  "Exceeded max redirects",
395  ssl,
396  true,
397  true}});
398  // two that redirect forever
400  {{"/redirect_forever/307",
401  "Exceeded max redirects",
402  ssl,
403  true,
404  true},
405  {"/redirect_forever/308",
406  "Exceeded max redirects",
407  ssl,
408  true,
409  true}});
410  // one undending redirect, one not
412  {{"/validators", "", ssl},
413  {"/redirect_forever/302",
414  "Exceeded max redirects",
415  ssl,
416  true,
417  true}});
418  // invalid redir Location
420  {{"/redirect_to/ftp://invalid-url/302",
421  "Invalid redirect location",
422  ssl,
423  true,
424  true}});
426  {{"/redirect_to/file://invalid-url/302",
427  "Invalid redirect location",
428  ssl,
429  true,
430  true}});
431  // invalid json
433  {{"/validators/bad",
434  "Unable to parse JSON response",
435  ssl,
436  true,
437  true}});
438  // error status returned
440  {{"/bad-resource", "returned bad status", ssl, true, true}});
441  // location field missing
443  {{"/redirect_nolo/308",
444  "returned a redirect with no Location",
445  ssl,
446  true,
447  true}});
448  // json fields missing
450  {{"/validators/missing",
451  "Missing fields in JSON response",
452  ssl,
453  true,
454  true}});
455  // timeout
456  testFetchList({{"/sleep/3", "took too long", ssl, true, true}});
457  // bad manifest version
459  {{"/validators", "Unsupported version", ssl, false, true, 4}});
460  using namespace std::chrono_literals;
461  // get old validator list
463  {{"/validators",
464  "Stale validator list",
465  ssl,
466  false,
467  true,
468  1,
469  0s}});
470  // force an out-of-range expiration value
472  {{"/validators",
473  "Invalid validator list",
474  ssl,
475  false,
476  true,
477  1,
479  // verify refresh intervals are properly clamped
481  {{"/validators/refresh/0",
482  "",
483  ssl,
484  false,
485  false,
486  1,
488  1}}); // minimum of 1 minute
490  {{"/validators/refresh/10",
491  "",
492  ssl,
493  false,
494  false,
495  1,
497  10}}); // 10 minutes is fine
499  {{"/validators/refresh/2000",
500  "",
501  ssl,
502  false,
503  false,
504  1,
506  60 * 24}}); // max of 24 hours
507  }
508  testFileURLs();
509  }
510 };
511 
513 
514 } // namespace test
515 } // namespace ripple
ripple::test::jtx::json
Inject raw JSON.
Definition: jtx_json.h:31
ripple::test::ValidatorSite_test::testConfigLoad
void testConfigLoad()
Definition: ValidatorSite_test.cpp:64
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
std::string
STL class.
ripple::test::ValidatorSite_test::FetchListConfig::ssl
bool ssl
Definition: ValidatorSite_test.cpp:133
ripple::ValidatorSite
Definition: ValidatorSite.h:67
std::pair
std::string::reserve
T reserve(T... args)
std::vector< std::string >
std::chrono::seconds
ripple::test::ValidatorSite_test::testFileURLs
void testFileURLs()
Definition: ValidatorSite_test.cpp:335
std::stringstream
STL class.
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:141
ripple::test::jtx::Env::timeKeeper
ManualTimeKeeper & timeKeeper()
Definition: Env.h:250
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:238
std::vector::back
T back(T... args)
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::test::ValidatorSite_test::FetchListConfig::expectedRefreshMin
int expectedRefreshMin
Definition: ValidatorSite_test.cpp:138
ripple::test::detail::realValidatorContents
constexpr const char * realValidatorContents()
Definition: ValidatorSite_test.cpp:43
std::vector::push_back
T push_back(T... args)
ripple::test::ValidatorSite_test::testFetchList
void testFetchList(std::vector< FetchListConfig > const &paths)
Definition: ValidatorSite_test.cpp:141
Json::Value::maxInt
static const Int maxInt
Definition: json_value.h:159
ripple::test::ValidatorSite_test::testFileList
void testFileList(std::vector< std::pair< std::string, std::string >> const &paths)
Definition: ValidatorSite_test.cpp:269
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
chrono
ripple::test::TrustedPublisherServer::Validator
Definition: TrustedPublisherServer.h:92
ripple::test::ValidatorSite_test::FetchListConfig::serverVersion
int serverVersion
Definition: ValidatorSite_test.cpp:136
ripple::test::ValidatorSite_test::FetchListConfig::path
std::string path
Definition: ValidatorSite_test.cpp:131
ripple::test::jtx::paths
Set Paths, SendMax on a JTx.
Definition: paths.h:32
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::test::TrustedPublisherServer::randomValidator
static Validator randomValidator()
Definition: TrustedPublisherServer.h:128
ripple::test::ValidatorSite_test::FetchListConfig::failFetch
bool failFetch
Definition: ValidatorSite_test.cpp:134
ripple::test::detail::default_expires
constexpr auto default_expires
Definition: ValidatorSite_test.cpp:55
ripple::Application::validators
virtual ValidatorList & validators()=0
ripple::Application::getIOService
virtual boost::asio::io_service & getIOService()=0
ripple::test::StreamSink
Definition: SuiteJournal.h:110
ripple::test::StreamSink::messages
std::stringstream const & messages() const
Definition: SuiteJournal.h:130
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::endl
T endl(T... args)
ripple::test::ValidatorSite_test
Definition: ValidatorSite_test.cpp:58
ripple::test::ValidatorSite_test::FetchListConfig
Definition: ValidatorSite_test.cpp:129
ripple::test::ValidatorSite_test::FetchListConfig::expiresFromNow
std::chrono::seconds expiresFromNow
Definition: ValidatorSite_test.cpp:137
ripple::test::ValidatorSite_test::run
void run() override
Definition: ValidatorSite_test.cpp:373
ripple::test::ValidatorSite_test::FetchListConfig::failApply
bool failApply
Definition: ValidatorSite_test.cpp:135
std::stringstream::str
T str(T... args)
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
ripple::test::detail::FileDirGuard
Write a file in a directory and remove when done.
Definition: FileDirGuard.h:110
ripple::test::ManualTimeKeeper::now
time_point now() const override
Returns the estimate of wall time, in network time.
Definition: ManualTimeKeeper.cpp:37
ripple::test::ValidatorSite_test::FetchListConfig::msg
std::string msg
Definition: ValidatorSite_test.cpp:132
std::unique_ptr
STL class.
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:114
Json::Value
Represents a JSON value.
Definition: json_value.h:145
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
std::chrono