diff --git a/src/seeder/bitcoin.cpp b/src/seeder/bitcoin.cpp
index 16ec2a7ec..ec3c7e9fc 100644
--- a/src/seeder/bitcoin.cpp
+++ b/src/seeder/bitcoin.cpp
@@ -1,278 +1,278 @@
 // Copyright (c) 2017-2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <seeder/bitcoin.h>
 
 #include <hash.h>
 #include <netbase.h>
 #include <seeder/db.h>
 #include <seeder/messagewriter.h>
 #include <serialize.h>
 #include <uint256.h>
+#include <util/time.h>
 
 #include <algorithm>
 
 #define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL
 
 void CSeederNode::Send() {
     if (sock == INVALID_SOCKET) {
         return;
     }
     if (vSend.empty()) {
         return;
     }
     int nBytes = send(sock, &vSend[0], vSend.size(), 0);
     if (nBytes > 0) {
         vSend.erase(vSend.begin(), vSend.begin() + nBytes);
     } else {
         close(sock);
         sock = INVALID_SOCKET;
     }
 }
 
 PeerMessagingState CSeederNode::ProcessMessage(std::string strCommand,
                                                CDataStream &recv) {
     // tfm::format(std::cout, "%s: RECV %s\n", ToString(you),
     // strCommand);
     if (strCommand == NetMsgType::VERSION) {
         int64_t nTime;
         CAddress addrMe;
         CAddress addrFrom;
         uint64_t nNonce = 1;
         uint64_t nServiceInt;
         recv >> nVersion >> nServiceInt >> nTime >> addrMe;
         you.nServices = ServiceFlags(nServiceInt);
         recv >> addrFrom >> nNonce;
         recv >> strSubVer;
         recv >> nStartingHeight;
 
         vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION));
         MessageWriter::WriteMessage(vSend, NetMsgType::VERACK);
         return PeerMessagingState::AwaitingMessages;
     }
 
     if (strCommand == NetMsgType::VERACK) {
         vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION));
         // tfm::format(std::cout, "\n%s: version %i\n", ToString(you),
         // nVersion);
         if (vAddr) {
             MessageWriter::WriteMessage(vSend, NetMsgType::GETADDR);
-            doneAfter = time(nullptr) + GetTimeout();
+            doneAfter = GetTime() + GetTimeout();
         } else {
-            doneAfter = time(nullptr) + 1;
+            doneAfter = GetTime() + 1;
         }
         return PeerMessagingState::AwaitingMessages;
     }
 
     if (strCommand == NetMsgType::ADDR && vAddr) {
         std::vector<CAddress> vAddrNew;
         recv >> vAddrNew;
         // tfm::format(std::cout, "%s: got %i addresses\n",
         // ToString(you),
         //        (int)vAddrNew.size());
-        int64_t now = time(nullptr);
+        int64_t now = GetTime();
         std::vector<CAddress>::iterator it = vAddrNew.begin();
         if (vAddrNew.size() > 1) {
             if (doneAfter == 0 || doneAfter > now + 1) {
                 doneAfter = now + 1;
             }
         }
         while (it != vAddrNew.end()) {
             CAddress &addr = *it;
             // tfm::format(std::cout, "%s: got address %s\n",
             // ToString(you),
             //        addr.ToString(), (int)(vAddr->size()));
             it++;
             if (addr.nTime <= 100000000 || addr.nTime > now + 600) {
                 addr.nTime = now - 5 * 86400;
             }
             if (addr.nTime > now - 604800) {
                 vAddr->push_back(addr);
             }
             // tfm::format(std::cout, "%s: added address %s (#%i)\n",
             // ToString(you),
             //        addr.ToString(), (int)(vAddr->size()));
             if (vAddr->size() > ADDR_SOFT_CAP) {
                 doneAfter = 1;
                 return PeerMessagingState::Finished;
             }
         }
         return PeerMessagingState::AwaitingMessages;
     }
 
     return PeerMessagingState::AwaitingMessages;
 }
 
 bool CSeederNode::ProcessMessages() {
     if (vRecv.empty()) {
         return false;
     }
 
     const CMessageHeader::MessageMagic netMagic = Params().NetMagic();
 
     do {
         CDataStream::iterator pstart = std::search(
             vRecv.begin(), vRecv.end(), BEGIN(netMagic), END(netMagic));
         uint32_t nHeaderSize =
             GetSerializeSize(CMessageHeader(netMagic), vRecv.GetVersion());
         if (vRecv.end() - pstart < nHeaderSize) {
             if (vRecv.size() > nHeaderSize) {
                 vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
             }
             break;
         }
         vRecv.erase(vRecv.begin(), pstart);
         std::vector<char> vHeaderSave(vRecv.begin(),
                                       vRecv.begin() + nHeaderSize);
         CMessageHeader hdr(netMagic);
         vRecv >> hdr;
         if (!hdr.IsValidWithoutConfig(netMagic)) {
             // tfm::format(std::cout, "%s: BAD (invalid header)\n",
             // ToString(you));
             ban = 100000;
             return true;
         }
         std::string strCommand = hdr.GetCommand();
         unsigned int nMessageSize = hdr.nMessageSize;
         if (nMessageSize > MAX_SIZE) {
             // tfm::format(std::cout, "%s: BAD (message too large)\n",
             // ToString(you));
             ban = 100000;
             return true;
         }
         if (nMessageSize > vRecv.size()) {
             vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
             break;
         }
         if (vRecv.GetVersion() >= 209) {
             uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
             if (memcmp(hash.begin(), hdr.pchChecksum,
                        CMessageHeader::CHECKSUM_SIZE) != 0) {
                 continue;
             }
         }
         CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize,
                          vRecv.GetType(), vRecv.GetVersion());
         vRecv.ignore(nMessageSize);
         if (ProcessMessage(strCommand, vMsg) == PeerMessagingState::Finished) {
             return true;
         }
         // tfm::format(std::cout, "%s: done processing %s\n",
         // ToString(you),
         //        strCommand);
     } while (1);
     return false;
 }
 
 CSeederNode::CSeederNode(const CService &ip, std::vector<CAddress> *vAddrIn)
     : sock(INVALID_SOCKET), vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0),
       nHeaderStart(-1), nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0),
       doneAfter(0), you(ip, ServiceFlags(NODE_NETWORK)) {
-    if (time(nullptr) > 1329696000) {
+    if (GetTime() > 1329696000) {
         vSend.SetVersion(209);
         vRecv.SetVersion(209);
     }
 }
 
 bool CSeederNode::Run() {
     // FIXME: This logic is duplicated with CConnman::ConnectNode for no
     // good reason.
     bool connected = false;
     proxyType proxy;
 
     if (you.IsValid()) {
         bool proxyConnectionFailed = false;
 
         if (GetProxy(you.GetNetwork(), proxy)) {
             sock = CreateSocket(proxy.proxy);
             if (sock == INVALID_SOCKET) {
                 return false;
             }
             connected = ConnectThroughProxy(
                 proxy, you.ToStringIP(), you.GetPort(), sock, nConnectTimeout,
                 &proxyConnectionFailed);
         } else {
             // no proxy needed (none set for target network)
             sock = CreateSocket(you);
             if (sock == INVALID_SOCKET) {
                 return false;
             }
             // no proxy needed (none set for target network)
             connected =
                 ConnectSocketDirectly(you, sock, nConnectTimeout, false);
         }
     }
 
     if (!connected) {
         // tfm::format(std::cout, "Cannot connect to %s\n",
         // ToString(you));
         CloseSocket(sock);
         return false;
     }
 
-    // Push version;
+    // Write version message
     uint64_t nLocalServices = 0;
     uint64_t nLocalNonce = BITCOIN_SEED_NONCE;
     CService myService;
     CAddress me(myService, ServiceFlags(NODE_NETWORK));
     std::string ver = "/bitcoin-cash-seeder:0.15/";
     MessageWriter::WriteMessage(vSend, NetMsgType::VERSION, PROTOCOL_VERSION,
-                                nLocalServices, time(nullptr), you, me,
-                                nLocalNonce, ver, GetRequireHeight());
+                                nLocalServices, GetTime(), you, me, nLocalNonce,
+                                ver, GetRequireHeight());
     Send();
 
     bool res = true;
     int64_t now;
-    while (now = time(nullptr), ban == 0 &&
-                                    (doneAfter == 0 || doneAfter > now) &&
-                                    sock != INVALID_SOCKET) {
+    while (now = GetTime(), ban == 0 && (doneAfter == 0 || doneAfter > now) &&
+                                sock != INVALID_SOCKET) {
         char pchBuf[0x10000];
         fd_set fdsetRecv;
         fd_set fdsetError;
         FD_ZERO(&fdsetRecv);
         FD_ZERO(&fdsetError);
         FD_SET(sock, &fdsetRecv);
         FD_SET(sock, &fdsetError);
         struct timeval wa;
         if (doneAfter) {
             wa.tv_sec = doneAfter - now;
             wa.tv_usec = 0;
         } else {
             wa.tv_sec = GetTimeout();
             wa.tv_usec = 0;
         }
         int ret = select(sock + 1, &fdsetRecv, nullptr, &fdsetError, &wa);
         if (ret != 1) {
             if (!doneAfter) {
                 res = false;
             }
             break;
         }
         int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0);
         int nPos = vRecv.size();
         if (nBytes > 0) {
             vRecv.resize(nPos + nBytes);
             memcpy(&vRecv[nPos], pchBuf, nBytes);
         } else if (nBytes == 0) {
             // tfm::format(std::cout, "%s: BAD (connection closed
             // prematurely)\n",
             //        ToString(you));
             res = false;
             break;
         } else {
             // tfm::format(std::cout, "%s: BAD (connection error)\n",
             // ToString(you));
             res = false;
             break;
         }
         ProcessMessages();
         Send();
     }
     if (sock == INVALID_SOCKET) {
         res = false;
     }
     close(sock);
     sock = INVALID_SOCKET;
     return (ban == 0) && res;
 }
diff --git a/src/seeder/db.cpp b/src/seeder/db.cpp
index e6140a06a..405b0681a 100644
--- a/src/seeder/db.cpp
+++ b/src/seeder/db.cpp
@@ -1,236 +1,238 @@
 // Copyright (c) 2017-2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <seeder/db.h>
 
+#include <util/time.h>
+
 #include <cstdlib>
 
 void SeederAddrInfo::Update(bool good) {
-    int64_t now = time(nullptr);
+    int64_t now = GetTime();
     if (ourLastTry == 0) {
         ourLastTry = now - MIN_RETRY;
     }
     int age = now - ourLastTry;
     lastTry = now;
     ourLastTry = now;
     total++;
     if (good) {
         success++;
         ourLastSuccess = now;
     }
     stat2H.Update(good, age, 3600 * 2);
     stat8H.Update(good, age, 3600 * 8);
     stat1D.Update(good, age, 3600 * 24);
     stat1W.Update(good, age, 3600 * 24 * 7);
     stat1M.Update(good, age, 3600 * 24 * 30);
     int64_t ign = GetIgnoreTime();
     if (ign && (ignoreTill == 0 || ignoreTill < ign + now)) {
         ignoreTill = ign + now;
     }
     //  tfm::format(std::cout, "%s: got %s result: success=%i/%i;
     //  2H:%.2f%%-%.2f%%(%.2f) 8H:%.2f%%-%.2f%%(%.2f) 1D:%.2f%%-%.2f%%(%.2f)
     //  1W:%.2f%%-%.2f%%(%.2f) \n", ToString(ip), good ? "good" : "bad",
     //  success, total, 100.0 * stat2H.reliability, 100.0 * (stat2H.reliability
     //  + 1.0 - stat2H.weight), stat2H.count, 100.0 * stat8H.reliability, 100.0
     //  * (stat8H.reliability + 1.0 - stat8H.weight), stat8H.count, 100.0 *
     //  stat1D.reliability, 100.0 * (stat1D.reliability + 1.0 - stat1D.weight),
     //  stat1D.count, 100.0 * stat1W.reliability, 100.0 * (stat1W.reliability
     //  + 1.0 - stat1W.weight), stat1W.count);
 }
 
 bool CAddrDb::Get_(CServiceResult &ip, int &wait) {
-    int64_t now = time(nullptr);
+    int64_t now = GetTime();
     size_t tot = unkId.size() + ourId.size();
     if (tot == 0) {
         wait = 5;
         return false;
     }
 
     do {
         size_t rnd = rand() % tot;
         int ret;
         if (rnd < unkId.size()) {
             std::set<int>::iterator it = unkId.end();
             it--;
             ret = *it;
             unkId.erase(it);
         } else {
             ret = ourId.front();
-            if (time(nullptr) - idToInfo[ret].ourLastTry < MIN_RETRY) {
+            if (GetTime() - idToInfo[ret].ourLastTry < MIN_RETRY) {
                 return false;
             }
             ourId.pop_front();
         }
 
         if (idToInfo[ret].ignoreTill && idToInfo[ret].ignoreTill < now) {
             ourId.push_back(ret);
             idToInfo[ret].ourLastTry = now;
         } else {
             ip.service = idToInfo[ret].ip;
             ip.ourLastSuccess = idToInfo[ret].ourLastSuccess;
             break;
         }
     } while (1);
 
     nDirty++;
     return true;
 }
 
 int CAddrDb::Lookup_(const CService &ip) {
     if (ipToId.count(ip)) {
         return ipToId[ip];
     }
     return -1;
 }
 
 void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV,
                     int blocks) {
     int id = Lookup_(addr);
     if (id == -1) {
         return;
     }
     unkId.erase(id);
     banned.erase(addr);
     SeederAddrInfo &info = idToInfo[id];
     info.clientVersion = clientV;
     info.clientSubVersion = clientSV;
     info.blocks = blocks;
     info.Update(true);
     if (info.IsReliable() && goodId.count(id) == 0) {
         goodId.insert(id);
         //    tfm::format(std::cout, "%s: good; %i good nodes now\n",
         //    ToString(addr), (int)goodId.size());
     }
     nDirty++;
     ourId.push_back(id);
 }
 
 void CAddrDb::Bad_(const CService &addr, int ban) {
     int id = Lookup_(addr);
     if (id == -1) {
         return;
     }
     unkId.erase(id);
     SeederAddrInfo &info = idToInfo[id];
     info.Update(false);
-    uint32_t now = time(nullptr);
+    uint32_t now = GetTime();
     int ter = info.GetBanTime();
     if (ter) {
         //    tfm::format(std::cout, "%s: terrible\n", ToString(addr));
         if (ban < ter) {
             ban = ter;
         }
     }
     if (ban > 0) {
         //    tfm::format(std::cout, "%s: ban for %i seconds\n",
         //    ToString(addr), ban);
         banned[info.ip] = ban + now;
         ipToId.erase(info.ip);
         goodId.erase(id);
         idToInfo.erase(id);
     } else {
         if (/*!info.IsReliable() && */ goodId.count(id) == 1) {
             goodId.erase(id);
             //      tfm::format(std::cout, "%s: not good; %i good nodes left\n",
             //      ToString(addr), (int)goodId.size());
         }
         ourId.push_back(id);
     }
     nDirty++;
 }
 
 void CAddrDb::Add_(const CAddress &addr, bool force) {
     if (!force && !addr.IsRoutable()) {
         return;
     }
     CService ipp(addr);
     if (banned.count(ipp)) {
         time_t bantime = banned[ipp];
         if (force || (bantime < time(nullptr) && addr.nTime > bantime)) {
             banned.erase(ipp);
         } else {
             return;
         }
     }
     if (ipToId.count(ipp)) {
         SeederAddrInfo &ai = idToInfo[ipToId[ipp]];
         if (addr.nTime > ai.lastTry || ai.services != addr.nServices) {
             ai.lastTry = addr.nTime;
             ai.services |= addr.nServices;
             //      tfm::format(std::cout, "%s: updated\n",
             //      ToString(addr));
         }
         if (force) {
             ai.ignoreTill = 0;
         }
         return;
     }
 
     SeederAddrInfo ai;
     ai.ip = ipp;
     ai.services = addr.nServices;
     ai.lastTry = addr.nTime;
     ai.ourLastTry = 0;
     ai.total = 0;
     ai.success = 0;
     int id = nId++;
     idToInfo[id] = ai;
     ipToId[ipp] = id;
     //  tfm::format(std::cout, "%s: added\n", ToString(ipp),
     //  ipToId[ipp]);
     unkId.insert(id);
     nDirty++;
 }
 
 void CAddrDb::GetIPs_(std::set<CNetAddr> &ips, uint64_t requestedFlags,
                       uint32_t max, const bool *nets) {
     if (goodId.size() == 0) {
         int id = -1;
         if (ourId.size() == 0) {
             if (unkId.size() == 0) {
                 return;
             }
             id = *unkId.begin();
         } else {
             id = *ourId.begin();
         }
 
         if (id >= 0 &&
             (idToInfo[id].services & requestedFlags) == requestedFlags) {
             ips.insert(idToInfo[id].ip);
         }
         return;
     }
 
     std::vector<int> goodIdFiltered;
     for (auto &id : goodId) {
         if ((idToInfo[id].services & requestedFlags) == requestedFlags) {
             goodIdFiltered.push_back(id);
         }
     }
 
     if (!goodIdFiltered.size()) {
         return;
     }
 
     if (max > goodIdFiltered.size() / 2) {
         max = goodIdFiltered.size() / 2;
     }
 
     if (max < 1) {
         max = 1;
     }
 
     std::set<int> ids;
     while (ids.size() < max) {
         ids.insert(goodIdFiltered[rand() % goodIdFiltered.size()]);
     }
 
     for (auto &id : ids) {
         CService &ip = idToInfo[id].ip;
         if (nets[ip.GetNetwork()]) {
             ips.insert(ip);
         }
     }
 }
diff --git a/src/seeder/db.h b/src/seeder/db.h
index 9bc210eb4..ed825fefe 100644
--- a/src/seeder/db.h
+++ b/src/seeder/db.h
@@ -1,458 +1,459 @@
 // Copyright (c) 2017-2019 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_SEEDER_DB_H
 #define BITCOIN_SEEDER_DB_H
 
 #include <chainparams.h>
 #include <netbase.h>
 #include <protocol.h>
 #include <seeder/bitcoin.h>
 #include <seeder/util.h>
 #include <sync.h>
+#include <util/time.h>
 #include <version.h>
 
 #include <cmath>
 #include <cstdint>
 #include <deque>
 #include <map>
 #include <set>
 #include <vector>
 
 #define MIN_RETRY 1000
 
 #define REQUIRE_VERSION 70001
 
 static inline int GetRequireHeight() {
     return Params().Checkpoints().mapCheckpoints.rbegin()->first;
 }
 
 static inline std::string ToString(const CService &ip) {
     std::string str = ip.ToString();
     while (str.size() < 22) {
         str += ' ';
     }
     return str;
 }
 
 class CAddrStat {
 private:
     float weight;
     float count;
     float reliability;
 
 public:
     CAddrStat() : weight(0), count(0), reliability(0) {}
 
     void Update(bool good, int64_t age, double tau) {
         double f = exp(-age / tau);
         reliability = reliability * f + (good ? (1.0 - f) : 0);
         count = count * f + 1;
         weight = weight * f + (1.0 - f);
     }
 
     ADD_SERIALIZE_METHODS;
 
     template <typename Stream, typename Operation>
     inline void SerializationOp(Stream &s, Operation ser_action) {
         READWRITE(weight);
         READWRITE(count);
         READWRITE(reliability);
     }
 
     friend class SeederAddrInfo;
 };
 
 class CAddrReport {
 public:
     CService ip;
     int clientVersion;
     int blocks;
     double uptime[5];
     std::string clientSubVersion;
     int64_t lastSuccess;
     bool fGood;
     uint64_t services;
 };
 
 class SeederAddrInfo {
 private:
     CService ip;
     uint64_t services;
     int64_t lastTry;
     int64_t ourLastTry;
     int64_t ourLastSuccess;
     int64_t ignoreTill;
     CAddrStat stat2H;
     CAddrStat stat8H;
     CAddrStat stat1D;
     CAddrStat stat1W;
     CAddrStat stat1M;
     int clientVersion;
     int blocks;
     int total;
     int success;
     std::string clientSubVersion;
 
 public:
     SeederAddrInfo()
         : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0),
           ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {}
 
     CAddrReport GetReport() const {
         CAddrReport ret;
         ret.ip = ip;
         ret.clientVersion = clientVersion;
         ret.clientSubVersion = clientSubVersion;
         ret.blocks = blocks;
         ret.uptime[0] = stat2H.reliability;
         ret.uptime[1] = stat8H.reliability;
         ret.uptime[2] = stat1D.reliability;
         ret.uptime[3] = stat1W.reliability;
         ret.uptime[4] = stat1M.reliability;
         ret.lastSuccess = ourLastSuccess;
         ret.fGood = IsReliable();
         ret.services = services;
         return ret;
     }
 
     bool IsReliable() const {
         if (ip.GetPort() != GetDefaultPort()) {
             return false;
         }
         if (!(services & NODE_NETWORK)) {
             return false;
         }
         if (!ip.IsRoutable()) {
             return false;
         }
         if (clientVersion && clientVersion < REQUIRE_VERSION) {
             return false;
         }
         if (blocks && blocks < GetRequireHeight()) {
             return false;
         }
 
         if (total <= 3 && success * 2 >= total) {
             return true;
         }
 
         if (stat2H.reliability > 0.85 && stat2H.count > 2) {
             return true;
         }
         if (stat8H.reliability > 0.70 && stat8H.count > 4) {
             return true;
         }
         if (stat1D.reliability > 0.55 && stat1D.count > 8) {
             return true;
         }
         if (stat1W.reliability > 0.45 && stat1W.count > 16) {
             return true;
         }
         if (stat1M.reliability > 0.35 && stat1M.count > 32) {
             return true;
         }
 
         return false;
     }
 
     int64_t GetBanTime() const {
         if (IsReliable()) {
             return 0;
         }
         if (clientVersion && clientVersion < 31900) {
             return 604800;
         }
         if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 &&
             stat1M.count > 32) {
             return 30 * 86400;
         }
         if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 &&
             stat1W.count > 16) {
             return 7 * 86400;
         }
         if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 &&
             stat1D.count > 8) {
             return 1 * 86400;
         }
         return 0;
     }
 
     int64_t GetIgnoreTime() const {
         if (IsReliable()) {
             return 0;
         }
         if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 &&
             stat1M.count > 2) {
             return 10 * 86400;
         }
         if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 &&
             stat1W.count > 2) {
             return 3 * 86400;
         }
         if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 &&
             stat1D.count > 2) {
             return 8 * 3600;
         }
         if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 &&
             stat8H.count > 2) {
             return 2 * 3600;
         }
         return 0;
     }
 
     void Update(bool good);
 
     friend class CAddrDb;
 
     ADD_SERIALIZE_METHODS;
 
     template <typename Stream, typename Operation>
     inline void SerializationOp(Stream &s, Operation ser_action) {
         uint8_t version = 4;
         READWRITE(version);
         READWRITE(ip);
         READWRITE(services);
         READWRITE(lastTry);
         uint8_t tried = ourLastTry != 0;
         READWRITE(tried);
         if (!tried) {
             return;
         }
 
         READWRITE(ourLastTry);
         READWRITE(ignoreTill);
         READWRITE(stat2H);
         READWRITE(stat8H);
         READWRITE(stat1D);
         READWRITE(stat1W);
         if (version >= 1) {
             READWRITE(stat1M);
         } else if (!ser_action.ForRead()) {
             *((CAddrStat *)(&stat1M)) = stat1W;
         }
         READWRITE(total);
         READWRITE(success);
         READWRITE(clientVersion);
         if (version >= 2) {
             READWRITE(clientSubVersion);
         }
         if (version >= 3) {
             READWRITE(blocks);
         }
         if (version >= 4) {
             READWRITE(ourLastSuccess);
         }
     }
 };
 
 class CAddrDbStats {
 public:
     int nBanned;
     int nAvail;
     int nTracked;
     int nNew;
     int nGood;
     int nAge;
 };
 
 struct CServiceResult {
     CService service;
     bool fGood;
     int nBanTime;
     int nHeight;
     int nClientV;
     std::string strClientV;
     int64_t ourLastSuccess;
 };
 
 /**
  *             seen nodes
  *            /          \
  * (a) banned nodes       available nodes--------------
  *                       /       |                     \
  *               tracked nodes   (b) unknown nodes   (e) active nodes
  *              /           \
  *     (d) good nodes   (c) non-good nodes
  */
 class CAddrDb {
 private:
     mutable RecursiveMutex cs;
     // number of address id's
     int nId;
     // map address id to address info (b,c,d,e)
     std::map<int, SeederAddrInfo> idToInfo;
     // map ip to id (b,c,d,e)
     std::map<CService, int> ipToId;
     // sequence of tried nodes, in order we have tried connecting to them (c,d)
     std::deque<int> ourId;
     // set of nodes not yet tried (b)
     std::set<int> unkId;
     // set of good nodes  (d, good e)
     std::set<int> goodId;
     int nDirty;
 
 protected:
     // internal routines that assume proper locks are acquired
     // add an address
     void Add_(const CAddress &addr, bool force);
     // get an IP to test (must call Good_ or Bad_ on result afterwards)
     bool Get_(CServiceResult &ip, int &wait);
     // mark an IP as good (must have been returned by Get_)
     void Good_(const CService &ip, int clientV, std::string clientSV,
                int blocks);
     // mark an IP as bad (and optionally ban it) (must have been returned by
     // Get_)
     void Bad_(const CService &ip, int ban);
     // look up id of an IP
     int Lookup_(const CService &ip);
     // get a random set of IPs (shared lock only)
     void GetIPs_(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
                  const bool *nets);
 
 public:
     // nodes that are banned, with their unban time (a)
     std::map<CService, int64_t> banned;
 
     void GetStats(CAddrDbStats &stats) const {
         LOCK(cs);
         stats.nBanned = banned.size();
         stats.nAvail = idToInfo.size();
         stats.nTracked = ourId.size();
         stats.nGood = goodId.size();
         stats.nNew = unkId.size();
         if (ourId.size() > 0) {
-            stats.nAge = time(nullptr) - idToInfo.at(ourId.at(0)).ourLastTry;
+            stats.nAge = GetTime() - idToInfo.at(ourId.at(0)).ourLastTry;
         } else {
             stats.nAge = 0;
         }
     }
 
     void ResetIgnores() {
         for (std::map<int, SeederAddrInfo>::iterator it = idToInfo.begin();
              it != idToInfo.end(); it++) {
             (*it).second.ignoreTill = 0;
         }
     }
 
     std::vector<CAddrReport> GetAll() {
         std::vector<CAddrReport> ret;
         LOCK(cs);
         for (std::deque<int>::const_iterator it = ourId.begin();
              it != ourId.end(); it++) {
             const SeederAddrInfo &info = idToInfo[*it];
             if (info.success > 0) {
                 ret.push_back(info.GetReport());
             }
         }
         return ret;
     }
 
     // serialization code
     // format:
     //   nVersion (0 for now)
     //   n (number of ips in (b,c,d))
     //   SeederAddrInfo[n]
     //   banned
     // acquires a shared lock (this does not suffice for read mode, but we
     // assume that only happens at startup, single-threaded) this way, dumping
     // does not interfere with GetIPs_, which is called from the DNS thread
     template <typename Stream> void Serialize(Stream &s) const {
         LOCK(cs);
 
         int nVersion = 0;
         s << nVersion;
 
         CAddrDb *db = const_cast<CAddrDb *>(this);
         int n = ourId.size() + unkId.size();
         s << n;
         for (std::deque<int>::const_iterator it = ourId.begin();
              it != ourId.end(); it++) {
             std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
             s << (*ci).second;
         }
         for (std::set<int>::const_iterator it = unkId.begin();
              it != unkId.end(); it++) {
             std::map<int, SeederAddrInfo>::iterator ci = db->idToInfo.find(*it);
             s << (*ci).second;
         }
         s << banned;
     }
 
     template <typename Stream> void Unserialize(Stream &s) {
         LOCK(cs);
 
         int nVersion;
         s >> nVersion;
 
         CAddrDb *db = const_cast<CAddrDb *>(this);
         db->nId = 0;
         int n;
         s >> n;
         for (int i = 0; i < n; i++) {
             SeederAddrInfo info;
             s >> info;
             if (!info.GetBanTime()) {
                 int id = db->nId++;
                 db->idToInfo[id] = info;
                 db->ipToId[info.ip] = id;
                 if (info.ourLastTry) {
                     db->ourId.push_back(id);
                     if (info.IsReliable()) {
                         db->goodId.insert(id);
                     }
                 } else {
                     db->unkId.insert(id);
                 }
             }
         }
         db->nDirty++;
 
         s >> banned;
     }
 
     void Add(const CAddress &addr, bool fForce = false) {
         LOCK(cs);
         Add_(addr, fForce);
     }
 
     void Add(const std::vector<CAddress> &vAddr, bool fForce = false) {
         LOCK(cs);
         for (size_t i = 0; i < vAddr.size(); i++) {
             Add_(vAddr[i], fForce);
         }
     }
 
     void GetMany(std::vector<CServiceResult> &ips, int max, int &wait) {
         LOCK(cs);
         while (max > 0) {
             CServiceResult ip = {};
             if (!Get_(ip, wait)) {
                 return;
             }
             ips.push_back(ip);
             max--;
         }
     }
 
     void ResultMany(const std::vector<CServiceResult> &ips) {
         LOCK(cs);
         for (size_t i = 0; i < ips.size(); i++) {
             if (ips[i].fGood) {
                 Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV,
                       ips[i].nHeight);
             } else {
                 Bad_(ips[i].service, ips[i].nBanTime);
             }
         }
     }
 
     void GetIPs(std::set<CNetAddr> &ips, uint64_t requestedFlags, uint32_t max,
                 const bool *nets) {
         LOCK(cs);
         GetIPs_(ips, requestedFlags, max, nets);
     }
 };
 
 #endif // BITCOIN_SEEDER_DB_H
diff --git a/src/seeder/dns.cpp b/src/seeder/dns.cpp
index bee54f874..a6e57a8f9 100644
--- a/src/seeder/dns.cpp
+++ b/src/seeder/dns.cpp
@@ -1,679 +1,680 @@
 // Copyright (c) 2017-2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <seeder/dns.h>
 
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <strings.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <util/time.h>
 
 #include <cctype>
 #include <cstdbool>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 #include <ctime>
 
 #define BUFLEN 512
 
 #if defined IP_RECVDSTADDR
 #define DSTADDR_SOCKOPT IP_RECVDSTADDR
 #define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_addr)))
 #define dstaddr(x) (CMSG_DATA(x))
 #elif defined IPV6_PKTINFO
 #define DSTADDR_SOCKOPT IPV6_PKTINFO
 #define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_pktinfo)))
 #define dstaddr(x) (&(((struct in6_pktinfo *)(CMSG_DATA(x)))->ipi6_addr))
 #else
 #error "can't determine socket option"
 #endif
 
 union control_data {
     struct cmsghdr cmsg;
     uint8_t data[DSTADDR_DATASIZE];
 };
 
 typedef enum {
     CLASS_IN = 1,
     QCLASS_ANY = 255,
 } dns_class;
 
 typedef enum {
     TYPE_A = 1,
     TYPE_NS = 2,
     TYPE_CNAME = 5,
     TYPE_SOA = 6,
     TYPE_MX = 15,
     TYPE_AAAA = 28,
     TYPE_SRV = 33,
     QTYPE_ANY = 255
 } dns_type;
 
 enum class DNSResponseCode : uint8_t {
     OK = 0,
     FORMAT_ERROR = 1,
     SERVER_FAILURE = 2,
     NAME_ERROR = 3,
     NOT_IMPLEMENTED = 4,
     REFUSED = 5,
 };
 
 ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend,
                            const uint8_t *inbuf, char *buf, size_t bufsize) {
     if (bufsize == 0) {
         return ParseNameStatus::OutputBufferError;
     }
     size_t bufused = 0;
     int init = 1;
     do {
         if (*inpos == inend) {
             return ParseNameStatus::InputError;
         }
         // read length of next component
         int octet = *((*inpos)++);
         if (octet == 0) {
             buf[bufused] = 0;
             return ParseNameStatus::OK;
         }
         // add dot in output
         if (!init) {
             if (bufused == bufsize - 1) {
                 return ParseNameStatus::OutputBufferError;
             }
             buf[bufused++] = '.';
         } else {
             init = 0;
         }
         // handle references
         if ((octet & 0xC0) == 0xC0) {
             if (*inpos == inend) {
                 return ParseNameStatus::InputError;
             }
             int ref = ((octet - 0xC0) << 8) + *((*inpos)++);
             if (ref < 0 || ref >= (*inpos) - inbuf - 2) {
                 return ParseNameStatus::InputError;
             }
             const uint8_t *newbuf = inbuf + ref;
             return parse_name(&newbuf, (*inpos) - 2, inbuf, buf + bufused,
                               bufsize - bufused);
         }
         if (octet > MAX_LABEL_LENGTH) {
             return ParseNameStatus::InputError;
         }
         // The maximum size of a query name is 255. The buffer must have
         // room for the null-character at the end of the buffer after writing
         // the label.
         if (octet + bufused > MAX_QUERY_NAME_LENGTH) {
             return ParseNameStatus::InputError;
         }
         // copy label
         while (octet) {
             if (*inpos == inend) {
                 return ParseNameStatus::InputError;
             }
             if (bufused == bufsize - 1) {
                 return ParseNameStatus::OutputBufferError;
             }
             int c = *((*inpos)++);
             if (c == '.') {
                 return ParseNameStatus::InputError;
             }
             octet--;
             buf[bufused++] = c;
         }
     } while (1);
 }
 
 int write_name(uint8_t **outpos, const uint8_t *outend, const char *name,
                int offset) {
     while (*name != 0) {
         const char *dot = strchr(name, '.');
         const char *fin = dot;
         if (!dot) {
             fin = name + strlen(name);
         }
         if (fin - name > MAX_LABEL_LENGTH) {
             return -1;
         }
         if (fin == name) {
             return -3;
         }
         if (outend - *outpos < fin - name + 2) {
             return -2;
         }
         *((*outpos)++) = fin - name;
         memcpy(*outpos, name, fin - name);
         *outpos += fin - name;
         if (!dot) {
             break;
         }
         name = dot + 1;
     }
     if (offset < 0) {
         // no reference
         if (outend == *outpos) {
             return -2;
         }
         *((*outpos)++) = 0;
     } else {
         if (outend - *outpos < 2) {
             return -2;
         }
         *((*outpos)++) = (offset >> 8) | 0xC0;
         *((*outpos)++) = offset & 0xFF;
     }
     return 0;
 }
 
 static int write_record(uint8_t **outpos, const uint8_t *outend,
                         const char *name, int offset, dns_type typ,
                         dns_class cls, int ttl) {
     uint8_t *oldpos = *outpos;
     int error = 0;
     // name
     int ret = write_name(outpos, outend, name, offset);
     if (ret) {
         error = ret;
         goto error;
     }
     if (outend - *outpos < 8) {
         error = -4;
         goto error;
     }
     // type
     *((*outpos)++) = typ >> 8;
     *((*outpos)++) = typ & 0xFF;
     // class
     *((*outpos)++) = cls >> 8;
     *((*outpos)++) = cls & 0xFF;
     // ttl
     *((*outpos)++) = (ttl >> 24) & 0xFF;
     *((*outpos)++) = (ttl >> 16) & 0xFF;
     *((*outpos)++) = (ttl >> 8) & 0xFF;
     *((*outpos)++) = ttl & 0xFF;
     return 0;
 error:
     *outpos = oldpos;
     return error;
 }
 
 static int write_record_a(uint8_t **outpos, const uint8_t *outend,
                           const char *name, int offset, dns_class cls, int ttl,
                           const addr_t *ip) {
     if (ip->v != 4) {
         return -6;
     }
     uint8_t *oldpos = *outpos;
     int error = 0;
     int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl);
     if (ret) {
         return ret;
     }
     if (outend - *outpos < 6) {
         error = -5;
         goto error;
     }
     // rdlength
     *((*outpos)++) = 0;
     *((*outpos)++) = 4;
     // rdata
     for (int i = 0; i < 4; i++) {
         *((*outpos)++) = ip->data.v4[i];
     }
     return 0;
 error:
     *outpos = oldpos;
     return error;
 }
 
 static int write_record_aaaa(uint8_t **outpos, const uint8_t *outend,
                              const char *name, int offset, dns_class cls,
                              int ttl, const addr_t *ip) {
     if (ip->v != 6) {
         return -6;
     }
     uint8_t *oldpos = *outpos;
     int error = 0;
     int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl);
     if (ret) {
         return ret;
     }
     if (outend - *outpos < 6) {
         error = -5;
         goto error;
     }
     // rdlength
     *((*outpos)++) = 0;
     *((*outpos)++) = 16;
     // rdata
     for (int i = 0; i < 16; i++) {
         *((*outpos)++) = ip->data.v6[i];
     }
     return 0;
 error:
     *outpos = oldpos;
     return error;
 }
 
 static int write_record_ns(uint8_t **outpos, const uint8_t *outend,
                            const char *name, int offset, dns_class cls, int ttl,
                            const char *ns) {
     uint8_t *oldpos = *outpos;
     int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl);
     if (ret) {
         return ret;
     }
 
     // Predeclare to avoid jumping over declaration.
     uint8_t *curpos;
 
     int error = 0;
     if (outend - *outpos < 2) {
         error = -5;
         goto error;
     }
 
     (*outpos) += 2;
     curpos = *outpos;
     ret = write_name(outpos, outend, ns, -1);
     if (ret) {
         error = ret;
         goto error;
     }
 
     curpos[-2] = (*outpos - curpos) >> 8;
     curpos[-1] = (*outpos - curpos) & 0xFF;
     return 0;
 
 error:
     *outpos = oldpos;
     return error;
 }
 
 static int write_record_soa(uint8_t **outpos, const uint8_t *outend,
                             const char *name, int offset, dns_class cls,
                             int ttl, const char *mname, const char *rname,
                             uint32_t serial, uint32_t refresh, uint32_t retry,
                             uint32_t expire, uint32_t minimum) {
     uint8_t *oldpos = *outpos;
     int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl);
     if (ret) {
         return ret;
     }
 
     // Predeclare variable to not jump over declarations.
     uint8_t *curpos;
 
     int error = 0;
     if (outend - *outpos < 2) {
         error = -5;
         goto error;
     }
 
     (*outpos) += 2;
     curpos = *outpos;
     ret = write_name(outpos, outend, mname, -1);
     if (ret) {
         error = ret;
         goto error;
     }
 
     ret = write_name(outpos, outend, rname, -1);
     if (ret) {
         error = ret;
         goto error;
     }
 
     if (outend - *outpos < 20) {
         error = -5;
         goto error;
     }
 
     *((*outpos)++) = (serial >> 24) & 0xFF;
     *((*outpos)++) = (serial >> 16) & 0xFF;
     *((*outpos)++) = (serial >> 8) & 0xFF;
     *((*outpos)++) = serial & 0xFF;
     *((*outpos)++) = (refresh >> 24) & 0xFF;
     *((*outpos)++) = (refresh >> 16) & 0xFF;
     *((*outpos)++) = (refresh >> 8) & 0xFF;
     *((*outpos)++) = refresh & 0xFF;
     *((*outpos)++) = (retry >> 24) & 0xFF;
     *((*outpos)++) = (retry >> 16) & 0xFF;
     *((*outpos)++) = (retry >> 8) & 0xFF;
     *((*outpos)++) = retry & 0xFF;
     *((*outpos)++) = (expire >> 24) & 0xFF;
     *((*outpos)++) = (expire >> 16) & 0xFF;
     *((*outpos)++) = (expire >> 8) & 0xFF;
     *((*outpos)++) = expire & 0xFF;
     *((*outpos)++) = (minimum >> 24) & 0xFF;
     *((*outpos)++) = (minimum >> 16) & 0xFF;
     *((*outpos)++) = (minimum >> 8) & 0xFF;
     *((*outpos)++) = minimum & 0xFF;
     curpos[-2] = (*outpos - curpos) >> 8;
     curpos[-1] = (*outpos - curpos) & 0xFF;
     return 0;
 
 error:
     *outpos = oldpos;
     return error;
 }
 
 static ssize_t dnshandle(dns_opt_t *opt, const uint8_t *inbuf, size_t insize,
                          uint8_t *outbuf) {
     DNSResponseCode responseCode = DNSResponseCode::OK;
     if (insize < 12) {
         // DNS header
         return -1;
     }
 
     // Predeclare various variables to avoid jumping over declarations.
     int have_ns = 0;
     int max_auth_size = 0;
     int nquestion = 0;
 
     // copy id
     outbuf[0] = inbuf[0];
     outbuf[1] = inbuf[1];
     // copy flags;
     outbuf[2] = inbuf[2];
     outbuf[3] = inbuf[3];
     // clear response code
     outbuf[3] &= ~15;
     // check qr
     if (inbuf[2] & 128) {
         /* tfm::format(std::cout, "Got response?\n"); */
         responseCode = DNSResponseCode::FORMAT_ERROR;
         goto error;
     }
 
     // check opcode
     if (((inbuf[2] & 120) >> 3) != 0) {
         /* tfm::format(std::cout, "Opcode nonzero?\n"); */
         responseCode = DNSResponseCode::NOT_IMPLEMENTED;
         goto error;
     }
 
     // unset TC
     outbuf[2] &= ~2;
     // unset RA
     outbuf[3] &= ~128;
     // check questions
     nquestion = (inbuf[4] << 8) + inbuf[5];
     if (nquestion == 0) {
         /* tfm::format(std::cout, "No questions?\n"); */
         responseCode = DNSResponseCode::OK;
         goto error;
     }
 
     if (nquestion > 1) {
         /* tfm::format(std::cout, "Multiple questions %i?\n", nquestion); */
         responseCode = DNSResponseCode::NOT_IMPLEMENTED;
         goto error;
     }
 
     {
         const uint8_t *inpos = inbuf + 12;
         const uint8_t *inend = inbuf + insize;
         char name[MAX_QUERY_NAME_BUFFER_LENGTH];
         int offset = inpos - inbuf;
         ParseNameStatus ret = parse_name(&inpos, inend, inbuf, name,
                                          MAX_QUERY_NAME_BUFFER_LENGTH);
         if (ret == ParseNameStatus::InputError) {
             responseCode = DNSResponseCode::FORMAT_ERROR;
             goto error;
         }
 
         if (ret == ParseNameStatus::OutputBufferError) {
             responseCode = DNSResponseCode::REFUSED;
             goto error;
         }
 
         int namel = strlen(name), hostl = strlen(opt->host);
         if (strcasecmp(name, opt->host) &&
             (namel < hostl + 2 || name[namel - hostl - 1] != '.' ||
              strcasecmp(name + namel - hostl, opt->host))) {
             responseCode = DNSResponseCode::REFUSED;
             goto error;
         }
 
         if (inend - inpos < 4) {
             responseCode = DNSResponseCode::FORMAT_ERROR;
             goto error;
         }
 
         // copy question to output
         memcpy(outbuf + 12, inbuf + 12, inpos + 4 - (inbuf + 12));
         // set counts
         outbuf[4] = 0;
         outbuf[5] = 1;
         outbuf[6] = 0;
         outbuf[7] = 0;
         outbuf[8] = 0;
         outbuf[9] = 0;
         outbuf[10] = 0;
         outbuf[11] = 0;
         // set qr
         outbuf[2] |= 128;
 
         int typ = (inpos[0] << 8) + inpos[1];
         int cls = (inpos[2] << 8) + inpos[3];
         inpos += 4;
 
         uint8_t *outpos = outbuf + (inpos - inbuf);
         uint8_t *outend = outbuf + BUFLEN;
 
         //   tfm::format(std::cout, "DNS: Request host='%s' type=%i class=%i\n",
         //   name, typ, cls);
 
         // calculate max size of authority section
 
         if (!((typ == TYPE_NS || typ == QTYPE_ANY) &&
               (cls == CLASS_IN || cls == QCLASS_ANY))) {
             // authority section will be necessary, either NS or SOA
             uint8_t *newpos = outpos;
             write_record_ns(&newpos, outend, "", offset, CLASS_IN, 0, opt->ns);
             max_auth_size = newpos - outpos;
 
             newpos = outpos;
             write_record_soa(&newpos, outend, "", offset, CLASS_IN, opt->nsttl,
-                             opt->ns, opt->mbox, time(NULL), 604800, 86400,
+                             opt->ns, opt->mbox, GetTime(), 604800, 86400,
                              2592000, 604800);
             if (max_auth_size < newpos - outpos) {
                 max_auth_size = newpos - outpos;
             }
             //    tfm::format(std::cout, "Authority section will claim %i bytes
             //    max\n", max_auth_size);
         }
 
         // Answer section
 
         // NS records
         if ((typ == TYPE_NS || typ == QTYPE_ANY) &&
             (cls == CLASS_IN || cls == QCLASS_ANY)) {
             int ret2 = write_record_ns(&outpos, outend - max_auth_size, "",
                                        offset, CLASS_IN, opt->nsttl, opt->ns);
             //    tfm::format(std::cout, "wrote NS record: %i\n", ret2);
             if (!ret2) {
                 outbuf[7]++;
                 have_ns++;
             }
         }
 
         // SOA records
         if ((typ == TYPE_SOA || typ == QTYPE_ANY) &&
             (cls == CLASS_IN || cls == QCLASS_ANY) && opt->mbox) {
             int ret2 =
                 write_record_soa(&outpos, outend - max_auth_size, "", offset,
                                  CLASS_IN, opt->nsttl, opt->ns, opt->mbox,
-                                 time(NULL), 604800, 86400, 2592000, 604800);
+                                 GetTime(), 604800, 86400, 2592000, 604800);
             //    tfm::format(std::cout, "wrote SOA record: %i\n", ret2);
             if (!ret2) {
                 outbuf[7]++;
             }
         }
 
         // A/AAAA records
         if ((typ == TYPE_A || typ == TYPE_AAAA || typ == QTYPE_ANY) &&
             (cls == CLASS_IN || cls == QCLASS_ANY)) {
             addr_t addr[32];
             int naddr = opt->cb((void *)opt, name, addr, 32,
                                 typ == TYPE_A || typ == QTYPE_ANY,
                                 typ == TYPE_AAAA || typ == QTYPE_ANY);
             int n = 0;
             while (n < naddr) {
                 int mustbreak = 1;
                 if (addr[n].v == 4) {
                     mustbreak = write_record_a(&outpos, outend - max_auth_size,
                                                "", offset, CLASS_IN,
                                                opt->datattl, &addr[n]);
                 } else if (addr[n].v == 6) {
                     mustbreak = write_record_aaaa(
                         &outpos, outend - max_auth_size, "", offset, CLASS_IN,
                         opt->datattl, &addr[n]);
                 }
 
                 //      tfm::format(std::cout, "wrote A record: %i\n",
                 //      mustbreak);
                 if (mustbreak) {
                     break;
                 }
 
                 n++;
                 outbuf[7]++;
             }
         }
 
         // Authority section
         if (!have_ns && outbuf[7]) {
             int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN,
                                        opt->nsttl, opt->ns);
             //    tfm::format(std::cout, "wrote NS record: %i\n", ret2);
             if (!ret2) {
                 outbuf[9]++;
             }
         } else if (!outbuf[7]) {
             // Didn't include any answers, so reply with SOA as this is a
             // negative response. If we replied with NS above we'd create a bad
             // horizontal referral loop, as the NS response indicates where the
             // resolver should try next.
             int ret2 = write_record_soa(
                 &outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns,
-                opt->mbox, time(NULL), 604800, 86400, 2592000, 604800);
+                opt->mbox, GetTime(), 604800, 86400, 2592000, 604800);
             //    tfm::format(std::cout, "wrote SOA record: %i\n", ret2);
             if (!ret2) {
                 outbuf[9]++;
             }
         }
 
         // set AA
         outbuf[2] |= 4;
 
         return outpos - outbuf;
     }
 
 error:
     // set response code
     outbuf[3] |= uint8_t(responseCode) & 0xF;
     // set counts
     outbuf[4] = 0;
     outbuf[5] = 0;
     outbuf[6] = 0;
     outbuf[7] = 0;
     outbuf[8] = 0;
     outbuf[9] = 0;
     outbuf[10] = 0;
     outbuf[11] = 0;
     return 12;
 }
 
 static int listenSocket = -1;
 
 int dnsserver(dns_opt_t *opt) {
     struct sockaddr_in6 si_other;
     int senderSocket = -1;
     senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
     if (senderSocket == -1) {
         return -3;
     }
 
     int replySocket;
     if (listenSocket == -1) {
         struct sockaddr_in6 si_me;
         if ((listenSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
             listenSocket = -1;
             return -1;
         }
         replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
         if (replySocket == -1) {
             close(listenSocket);
             return -1;
         }
         int sockopt = 1;
         setsockopt(listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &sockopt,
                    sizeof sockopt);
         memset((char *)&si_me, 0, sizeof(si_me));
         si_me.sin6_family = AF_INET6;
         si_me.sin6_port = htons(opt->port);
         si_me.sin6_addr = in6addr_any;
         if (bind(listenSocket, (struct sockaddr *)&si_me, sizeof(si_me)) ==
             -1) {
             return -2;
         }
     }
 
     uint8_t inbuf[BUFLEN], outbuf[BUFLEN];
     struct iovec iov[1] = {
         {
             .iov_base = inbuf,
             .iov_len = sizeof(inbuf),
         },
     };
 
     union control_data cmsg;
     msghdr msg;
     msg.msg_name = &si_other;
     msg.msg_namelen = sizeof(si_other);
     msg.msg_iov = iov;
     msg.msg_iovlen = 1;
     msg.msg_control = &cmsg;
     msg.msg_controllen = sizeof(cmsg);
 
     for (; 1; ++(opt->nRequests)) {
         ssize_t insize = recvmsg(listenSocket, &msg, 0);
         //    uint8_t *addr = (uint8_t*)&si_other.sin_addr.s_addr;
         //    tfm::format(std::cout, "DNS: Request %llu from %i.%i.%i.%i:%i of
         //    %i bytes\n", (unsigned long long)(opt->nRequests), addr[0],
         //    addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
         if (insize <= 0) {
             continue;
         }
 
         ssize_t ret = dnshandle(opt, inbuf, insize, outbuf);
         if (ret <= 0) {
             continue;
         }
 
         bool handled = false;
         for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
              hdr = CMSG_NXTHDR(&msg, hdr)) {
             if (hdr->cmsg_level == IPPROTO_IP &&
                 hdr->cmsg_type == DSTADDR_SOCKOPT) {
                 msg.msg_iov[0].iov_base = outbuf;
                 msg.msg_iov[0].iov_len = ret;
                 sendmsg(listenSocket, &msg, 0);
                 msg.msg_iov[0].iov_base = inbuf;
                 msg.msg_iov[0].iov_len = sizeof(inbuf);
                 handled = true;
             }
         }
         if (!handled) {
             sendto(listenSocket, outbuf, ret, 0, (struct sockaddr *)&si_other,
                    sizeof(si_other));
         }
     }
     return 0;
 }
diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp
index e654fa316..583cf1f74 100644
--- a/src/seeder/main.cpp
+++ b/src/seeder/main.cpp
@@ -1,582 +1,582 @@
 // Copyright (c) 2017-2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <chainparams.h>
 #include <clientversion.h>
 #include <fs.h>
 #include <logging.h>
 #include <protocol.h>
 #include <seeder/bitcoin.h>
 #include <seeder/db.h>
 #include <seeder/dns.h>
 #include <streams.h>
 #include <util/strencodings.h>
 #include <util/system.h>
+#include <util/time.h>
 #include <util/translation.h>
 
 #include <algorithm>
 #include <atomic>
 #include <cinttypes>
 #include <csignal>
 #include <cstdlib>
 #include <functional>
 #include <pthread.h>
 
 const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
 
 static const int CONTINUE_EXECUTION = -1;
 
 static const int DEFAULT_NUM_THREADS = 96;
 static const int DEFAULT_PORT = 53;
 static const int DEFAULT_NUM_DNS_THREADS = 4;
 static const bool DEFAULT_WIPE_BAN = false;
 static const bool DEFAULT_WIPE_IGNORE = false;
 static const std::string DEFAULT_EMAIL = "";
 static const std::string DEFAULT_NAMESERVER = "";
 static const std::string DEFAULT_HOST = "";
 static const std::string DEFAULT_TOR_PROXY = "";
 static const std::string DEFAULT_IPV4_PROXY = "";
 static const std::string DEFAULT_IPV6_PROXY = "";
 
 class CDnsSeedOpts {
 public:
     int nThreads;
     int nPort;
     int nDnsThreads;
     bool fWipeBan;
     bool fWipeIgnore;
     std::string mbox;
     std::string ns;
     std::string host;
     std::string tor;
     std::string ipv4_proxy;
     std::string ipv6_proxy;
     std::set<uint64_t> filter_whitelist;
 
     CDnsSeedOpts()
         : nThreads(DEFAULT_NUM_THREADS), nPort(DEFAULT_PORT),
           nDnsThreads(DEFAULT_NUM_DNS_THREADS), fWipeBan(DEFAULT_WIPE_BAN),
           fWipeIgnore(DEFAULT_WIPE_IGNORE), mbox(DEFAULT_EMAIL),
           ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), tor(DEFAULT_TOR_PROXY),
           ipv4_proxy(DEFAULT_IPV4_PROXY), ipv6_proxy(DEFAULT_IPV6_PROXY) {}
 
     int ParseCommandLine(int argc, char **argv) {
         SetupSeederArgs();
         std::string error;
         if (!gArgs.ParseParameters(argc, argv, error)) {
             tfm::format(std::cerr, "Error parsing command line arguments: %s\n",
                         error);
             return EXIT_FAILURE;
         }
         if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
             std::string strUsage =
                 PACKAGE_NAME " Seeder " + FormatFullVersion() + "\n";
             if (HelpRequested(gArgs)) {
                 strUsage +=
                     "\nUsage: bitcoin-seeder -host=<host> -ns=<ns> "
                     "[-mbox=<mbox>] [-threads=<threads>] [-port=<port>]\n\n" +
                     gArgs.GetHelpMessage();
             }
 
             tfm::format(std::cout, "%s", strUsage);
             return EXIT_SUCCESS;
         }
 
         nThreads = gArgs.GetArg("-threads", DEFAULT_NUM_THREADS);
         nPort = gArgs.GetArg("-port", DEFAULT_PORT);
         nDnsThreads = gArgs.GetArg("-dnsthreads", DEFAULT_NUM_DNS_THREADS);
         fWipeBan = gArgs.GetBoolArg("-wipeban", DEFAULT_WIPE_BAN);
         fWipeIgnore = gArgs.GetBoolArg("-wipeignore", DEFAULT_WIPE_IGNORE);
         mbox = gArgs.GetArg("-mbox", DEFAULT_EMAIL);
         ns = gArgs.GetArg("-ns", DEFAULT_NAMESERVER);
         host = gArgs.GetArg("-host", DEFAULT_HOST);
         tor = gArgs.GetArg("-onion", DEFAULT_TOR_PROXY);
         ipv4_proxy = gArgs.GetArg("-proxyipv4", DEFAULT_IPV4_PROXY);
         ipv6_proxy = gArgs.GetArg("-proxyipv6", DEFAULT_IPV6_PROXY);
         SelectParams(gArgs.GetChainName());
 
         if (gArgs.IsArgSet("-filter")) {
             // Parse whitelist additions
             std::string flagString = gArgs.GetArg("-filter", "");
             size_t flagstartpos = 0;
             while (flagstartpos < flagString.size()) {
                 size_t flagendpos = flagString.find_first_of(',', flagstartpos);
                 uint64_t flag = atoi64(flagString.substr(
                     flagstartpos, (flagendpos - flagstartpos)));
                 filter_whitelist.insert(flag);
                 if (flagendpos == std::string::npos) {
                     break;
                 }
                 flagstartpos = flagendpos + 1;
             }
         }
         if (filter_whitelist.empty()) {
             filter_whitelist.insert(NODE_NETWORK);
             filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM);
             filter_whitelist.insert(NODE_NETWORK | NODE_XTHIN);
             filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM | NODE_XTHIN);
         }
         return CONTINUE_EXECUTION;
     }
 
 private:
     void SetupSeederArgs() {
         SetupHelpOptions(gArgs);
         gArgs.AddArg("-help-debug",
                      "Show all debugging options (usage: --help -help-debug)",
                      ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
 
         SetupChainParamsBaseOptions();
 
         gArgs.AddArg("-version", "Print version and exit",
                      ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         gArgs.AddArg("-host=<host>", "Hostname of the DNS seed",
                      ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         gArgs.AddArg("-ns=<ns>", "Hostname of the nameserver",
                      ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         gArgs.AddArg("-mbox=<mbox>", "E-Mail address reported in SOA records",
                      ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         gArgs.AddArg("-threads=<threads>",
                      "Number of crawlers to run in parallel (default 96)",
                      ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         gArgs.AddArg("-dnsthreads=<threads>",
                      "Number of DNS server threads (default 4)",
                      ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         gArgs.AddArg("-port=<port>", "UDP port to listen on (default 53)",
                      ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
         gArgs.AddArg("-onion=<ip:port>", "Tor proxy IP/Port",
                      ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
         gArgs.AddArg("-proxyipv4=<ip:port>", "IPV4 SOCKS5 proxy IP/Port",
                      ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
         gArgs.AddArg("-proxyipv6=<ip:port>", "IPV6 SOCKS5 proxy IP/Port",
                      ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
         gArgs.AddArg("-filter=<f1,f2,...>",
                      "Allow these flag combinations as filters",
                      ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
         gArgs.AddArg("-wipeban", "Wipe list of banned nodes",
                      ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
         gArgs.AddArg("-wipeignore", "Wipe list of ignored nodes",
                      ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     }
 };
 
 extern "C" {
 #include <seeder/dns.h>
 }
 
 CAddrDb db;
 
 extern "C" void *ThreadCrawler(void *data) {
     int *nThreads = (int *)data;
     do {
         std::vector<CServiceResult> ips;
         int wait = 5;
         db.GetMany(ips, 16, wait);
-        int64_t now = time(nullptr);
+        int64_t now = GetTime();
         if (ips.empty()) {
             wait *= 1000;
             wait += rand() % (500 * *nThreads);
             Sleep(wait);
             continue;
         }
 
         std::vector<CAddress> addr;
         for (size_t i = 0; i < ips.size(); i++) {
             CServiceResult &res = ips[i];
             res.nBanTime = 0;
             res.nClientV = 0;
             res.nHeight = 0;
             res.strClientV = "";
             bool getaddr = res.ourLastSuccess + 86400 < now;
             try {
                 CSeederNode node(res.service, getaddr ? &addr : nullptr);
                 bool ret = node.Run();
                 if (!ret) {
                     res.nBanTime = node.GetBan();
                 } else {
                     res.nBanTime = 0;
                 }
                 res.nClientV = node.GetClientVersion();
                 res.strClientV = node.GetClientSubVersion();
                 res.nHeight = node.GetStartingHeight();
                 // tfm::format(std::cout, "%s: %s!!!\n", cip.ToString(),
                 // ret ? "GOOD" : "BAD");
                 res.fGood = ret;
             } catch (std::ios_base::failure &e) {
                 res.nBanTime = 0;
                 res.fGood = false;
             }
         }
 
         db.ResultMany(ips);
         db.Add(addr);
     } while (1);
     return nullptr;
 }
 
 extern "C" uint32_t GetIPList(void *thread, char *requestedHostname,
                               addr_t *addr, uint32_t max, uint32_t ipv4,
                               uint32_t ipv6);
 
 class CDnsThread {
 public:
     struct FlagSpecificData {
         int nIPv4, nIPv6;
         std::vector<addr_t> cache;
         time_t cacheTime;
         unsigned int cacheHits;
         FlagSpecificData() : nIPv4(0), nIPv6(0), cacheTime(0), cacheHits(0) {}
     };
 
     dns_opt_t dns_opt; // must be first
     const int id;
     std::map<uint64_t, FlagSpecificData> perflag;
     std::atomic<uint64_t> dbQueries;
     std::set<uint64_t> filterWhitelist;
 
     void cacheHit(uint64_t requestedFlags, bool force = false) {
         static bool nets[NET_MAX] = {};
         if (!nets[NET_IPV4]) {
             nets[NET_IPV4] = true;
             nets[NET_IPV6] = true;
         }
-        time_t now = time(nullptr);
+        int64_t now = GetTime();
         FlagSpecificData &thisflag = perflag[requestedFlags];
         thisflag.cacheHits++;
         if (force ||
             thisflag.cacheHits * 400 >
                 (thisflag.cache.size() * thisflag.cache.size()) ||
             (thisflag.cacheHits * thisflag.cacheHits * 20 >
                  thisflag.cache.size() &&
              (now - thisflag.cacheTime > 5))) {
             std::set<CNetAddr> ips;
             db.GetIPs(ips, requestedFlags, 1000, nets);
             dbQueries++;
             thisflag.cache.clear();
             thisflag.nIPv4 = 0;
             thisflag.nIPv6 = 0;
             thisflag.cache.reserve(ips.size());
             for (auto &ip : ips) {
                 struct in_addr addr;
                 struct in6_addr addr6;
                 if (ip.GetInAddr(&addr)) {
                     addr_t a;
                     a.v = 4;
                     memcpy(&a.data.v4, &addr, 4);
                     thisflag.cache.push_back(a);
                     thisflag.nIPv4++;
                 } else if (ip.GetIn6Addr(&addr6)) {
                     addr_t a;
                     a.v = 6;
                     memcpy(&a.data.v6, &addr6, 16);
                     thisflag.cache.push_back(a);
                     thisflag.nIPv6++;
                 }
             }
             thisflag.cacheHits = 0;
             thisflag.cacheTime = now;
         }
     }
 
     CDnsThread(CDnsSeedOpts *opts, int idIn) : id(idIn) {
         dns_opt.host = opts->host.c_str();
         dns_opt.ns = opts->ns.c_str();
         dns_opt.mbox = opts->mbox.c_str();
         dns_opt.datattl = 3600;
         dns_opt.nsttl = 40000;
         dns_opt.cb = GetIPList;
         dns_opt.port = opts->nPort;
         dns_opt.nRequests = 0;
         dbQueries = 0;
         perflag.clear();
         filterWhitelist = opts->filter_whitelist;
     }
 
     void run() { dnsserver(&dns_opt); }
 };
 
 extern "C" uint32_t GetIPList(void *data, char *requestedHostname, addr_t *addr,
                               uint32_t max, uint32_t ipv4, uint32_t ipv6) {
     CDnsThread *thread = (CDnsThread *)data;
 
     uint64_t requestedFlags = 0;
     int hostlen = strlen(requestedHostname);
     if (hostlen > 1 && requestedHostname[0] == 'x' &&
         requestedHostname[1] != '0') {
         char *pEnd;
         uint64_t flags = (uint64_t)strtoull(requestedHostname + 1, &pEnd, 16);
         if (*pEnd == '.' && pEnd <= requestedHostname + 17 &&
             std::find(thread->filterWhitelist.begin(),
                       thread->filterWhitelist.end(),
                       flags) != thread->filterWhitelist.end()) {
             requestedFlags = flags;
         } else {
             return 0;
         }
     } else if (strcasecmp(requestedHostname, thread->dns_opt.host)) {
         return 0;
     }
     thread->cacheHit(requestedFlags);
     auto &thisflag = thread->perflag[requestedFlags];
     uint32_t size = thisflag.cache.size();
     uint32_t maxmax = (ipv4 ? thisflag.nIPv4 : 0) + (ipv6 ? thisflag.nIPv6 : 0);
     if (max > size) {
         max = size;
     }
     if (max > maxmax) {
         max = maxmax;
     }
     uint32_t i = 0;
     while (i < max) {
         uint32_t j = i + (rand() % (size - i));
         do {
             bool ok = (ipv4 && thisflag.cache[j].v == 4) ||
                       (ipv6 && thisflag.cache[j].v == 6);
             if (ok) {
                 break;
             }
             j++;
             if (j == size) {
                 j = i;
             }
         } while (1);
         addr[i] = thisflag.cache[j];
         thisflag.cache[j] = thisflag.cache[i];
         thisflag.cache[i] = addr[i];
         i++;
     }
     return max;
 }
 
 std::vector<CDnsThread *> dnsThread;
 
 extern "C" void *ThreadDNS(void *arg) {
     CDnsThread *thread = (CDnsThread *)arg;
     thread->run();
     return nullptr;
 }
 
 int StatCompare(const CAddrReport &a, const CAddrReport &b) {
     if (a.uptime[4] == b.uptime[4]) {
         if (a.uptime[3] == b.uptime[3]) {
             return a.clientVersion > b.clientVersion;
         } else {
             return a.uptime[3] > b.uptime[3];
         }
     } else {
         return a.uptime[4] > b.uptime[4];
     }
 }
 
 extern "C" void *ThreadDumper(void *) {
     int count = 0;
     do {
         // First 100s, than 200s, 400s, 800s, 1600s, and then 3200s forever
         Sleep(100000 << count);
         if (count < 5) {
             count++;
         }
 
         {
             std::vector<CAddrReport> v = db.GetAll();
             sort(v.begin(), v.end(), StatCompare);
             FILE *f = fsbridge::fopen("dnsseed.dat.new", "w+");
             if (f) {
                 {
                     CAutoFile cf(f, SER_DISK, CLIENT_VERSION);
                     cf << db;
                 }
                 rename("dnsseed.dat.new", "dnsseed.dat");
             }
             fsbridge::ofstream d{"dnsseed.dump"};
             tfm::format(
                 d, "# address                                        good  "
                    "lastSuccess    %%(2h)   %%(8h)   %%(1d)   %%(7d)  "
                    "%%(30d)  blocks      svcs  version\n");
             double stat[5] = {0, 0, 0, 0, 0};
             for (CAddrReport rep : v) {
                 tfm::format(
                     d,
                     "%-47s  %4d  %11" PRId64
                     "  %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%%  %6i  %08" PRIx64
                     "  %5i \"%s\"\n",
                     rep.ip.ToString(), (int)rep.fGood, rep.lastSuccess,
                     100.0 * rep.uptime[0], 100.0 * rep.uptime[1],
                     100.0 * rep.uptime[2], 100.0 * rep.uptime[3],
                     100.0 * rep.uptime[4], rep.blocks, rep.services,
                     rep.clientVersion, rep.clientSubVersion);
                 stat[0] += rep.uptime[0];
                 stat[1] += rep.uptime[1];
                 stat[2] += rep.uptime[2];
                 stat[3] += rep.uptime[3];
                 stat[4] += rep.uptime[4];
             }
             fsbridge::ofstream ff{"dnsstats.log", std::ios_base::app};
-            tfm::format(ff, "%llu %g %g %g %g %g\n",
-                        (unsigned long long)(time(nullptr)), stat[0], stat[1],
-                        stat[2], stat[3], stat[4]);
+            tfm::format(ff, "%llu %g %g %g %g %g\n", GetTime(), stat[0],
+                        stat[1], stat[2], stat[3], stat[4]);
         }
     } while (1);
     return nullptr;
 }
 
 extern "C" void *ThreadStats(void *) {
     bool first = true;
     do {
         char c[256];
         time_t tim = time(nullptr);
         struct tm *tmp = localtime(&tim);
         strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp);
         CAddrDbStats stats;
         db.GetStats(stats);
         if (first) {
             first = false;
             tfm::format(std::cout, "\n\n\n\x1b[3A");
         } else {
             tfm::format(std::cout, "\x1b[2K\x1b[u");
         }
         tfm::format(std::cout, "\x1b[s");
         uint64_t requests = 0;
         uint64_t queries = 0;
         for (unsigned int i = 0; i < dnsThread.size(); i++) {
             requests += dnsThread[i]->dns_opt.nRequests;
             queries += dnsThread[i]->dbQueries;
         }
         tfm::format(
             std::cout,
             "%s %i/%i available (%i tried in %is, %i new, %i active), %i "
             "banned; %llu DNS requests, %llu db queries\n",
             c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge,
             stats.nNew, stats.nAvail - stats.nTracked - stats.nNew,
             stats.nBanned, (unsigned long long)requests,
             (unsigned long long)queries);
         Sleep(1000);
     } while (1);
     return nullptr;
 }
 
 const static unsigned int MAX_HOSTS_PER_SEED = 128;
 
 extern "C" void *ThreadSeeder(void *) {
     do {
         for (const std::string &seed : Params().DNSSeeds()) {
             std::vector<CNetAddr> ips;
             LookupHost(seed.c_str(), ips, MAX_HOSTS_PER_SEED, true);
             for (auto &ip : ips) {
                 db.Add(CAddress(CService(ip, GetDefaultPort()), ServiceFlags()),
                        true);
             }
         }
         Sleep(1800000);
     } while (1);
     return nullptr;
 }
 
 int main(int argc, char **argv) {
     // The logger dump everything on the console by default.
     LogInstance().m_print_to_console = true;
 
     signal(SIGPIPE, SIG_IGN);
     setbuf(stdout, nullptr);
     CDnsSeedOpts opts;
     int parseResults = opts.ParseCommandLine(argc, argv);
     if (parseResults != CONTINUE_EXECUTION) {
         return parseResults;
     }
 
     tfm::format(std::cout, "Supporting whitelisted filters: ");
     for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin();
          it != opts.filter_whitelist.end(); it++) {
         if (it != opts.filter_whitelist.begin()) {
             tfm::format(std::cout, ",");
         }
         tfm::format(std::cout, "0x%lx", (unsigned long)*it);
     }
     tfm::format(std::cout, "\n");
     if (!opts.tor.empty()) {
         CService service(LookupNumeric(opts.tor.c_str(), 9050));
         if (service.IsValid()) {
             tfm::format(std::cout, "Using Tor proxy at %s\n",
                         service.ToStringIPPort());
             SetProxy(NET_ONION, proxyType(service));
         }
     }
     if (!opts.ipv4_proxy.empty()) {
         CService service(LookupNumeric(opts.ipv4_proxy.c_str(), 9050));
         if (service.IsValid()) {
             tfm::format(std::cout, "Using IPv4 proxy at %s\n",
                         service.ToStringIPPort());
             SetProxy(NET_IPV4, proxyType(service));
         }
     }
     if (!opts.ipv6_proxy.empty()) {
         CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050));
         if (service.IsValid()) {
             tfm::format(std::cout, "Using IPv6 proxy at %s\n",
                         service.ToStringIPPort());
             SetProxy(NET_IPV6, proxyType(service));
         }
     }
     bool fDNS = true;
     tfm::format(std::cout, "Using %s.\n", gArgs.GetChainName());
     if (opts.ns.empty()) {
         tfm::format(std::cout, "No nameserver set. Not starting DNS server.\n");
         fDNS = false;
     }
     if (fDNS && opts.host.empty()) {
         tfm::format(std::cerr, "No hostname set. Please use -h.\n");
         return EXIT_FAILURE;
     }
     if (fDNS && opts.mbox.empty()) {
         tfm::format(std::cerr, "No e-mail address set. Please use -m.\n");
         return EXIT_FAILURE;
     }
     FILE *f = fsbridge::fopen("dnsseed.dat", "r");
     if (f) {
         tfm::format(std::cout, "Loading dnsseed.dat...");
         CAutoFile cf(f, SER_DISK, CLIENT_VERSION);
         cf >> db;
         if (opts.fWipeBan) {
             db.banned.clear();
             tfm::format(std::cout, "Ban list wiped...");
         }
         if (opts.fWipeIgnore) {
             db.ResetIgnores();
             tfm::format(std::cout, "Ignore list wiped...");
         }
         tfm::format(std::cout, "done\n");
     }
     pthread_t threadDns, threadSeed, threadDump, threadStats;
     if (fDNS) {
         tfm::format(std::cout,
                     "Starting %i DNS threads for %s on %s (port %i)...",
                     opts.nDnsThreads, opts.host, opts.ns, opts.nPort);
         dnsThread.clear();
         for (int i = 0; i < opts.nDnsThreads; i++) {
             dnsThread.push_back(new CDnsThread(&opts, i));
             pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]);
             tfm::format(std::cout, ".");
             Sleep(20);
         }
         tfm::format(std::cout, "done\n");
     }
     tfm::format(std::cout, "Starting seeder...");
     pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr);
     tfm::format(std::cout, "done\n");
     tfm::format(std::cout, "Starting %i crawler threads...", opts.nThreads);
     pthread_attr_t attr_crawler;
     pthread_attr_init(&attr_crawler);
     pthread_attr_setstacksize(&attr_crawler, 0x20000);
     for (int i = 0; i < opts.nThreads; i++) {
         pthread_t thread;
         pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads);
     }
     pthread_attr_destroy(&attr_crawler);
     tfm::format(std::cout, "done\n");
     pthread_create(&threadStats, nullptr, ThreadStats, nullptr);
     pthread_create(&threadDump, nullptr, ThreadDumper, nullptr);
     void *res;
     pthread_join(threadDump, &res);
     return EXIT_SUCCESS;
 }
diff --git a/src/seeder/test/message_writer_tests.cpp b/src/seeder/test/message_writer_tests.cpp
index d2c642754..a4c8551c4 100644
--- a/src/seeder/test/message_writer_tests.cpp
+++ b/src/seeder/test/message_writer_tests.cpp
@@ -1,95 +1,95 @@
 // Copyright (c) 2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <hash.h>
 #include <primitives/block.h>
 #include <protocol.h>
 #include <seeder/messagewriter.h>
 #include <streams.h>
 #include <version.h>
 
 #include <boost/test/unit_test.hpp>
 
 #include <string>
 #include <vector>
 
 BOOST_AUTO_TEST_SUITE(message_writer_tests)
 
 template <typename... Args>
 static void CheckMessage(CDataStream &expectedMessage, std::string command,
                          Args &&... args) {
     CDataStream message(SER_NETWORK, PROTOCOL_VERSION);
     MessageWriter::WriteMessage(message, command, std::forward<Args>(args)...);
     BOOST_CHECK_EQUAL(message.size(), expectedMessage.size());
     for (size_t i = 0; i < message.size(); i++) {
         BOOST_CHECK_EQUAL(message[i], expectedMessage[i]);
     }
 }
 
 BOOST_AUTO_TEST_CASE(simple_header_and_payload_message_writer_test) {
     SelectParams(CBaseChainParams::MAIN);
-    uint64_t now = time(nullptr);
+    int64_t now = GetTime();
     uint64_t nonce = 0;
     uint64_t serviceFlags = uint64_t(ServiceFlags(NODE_NETWORK));
     CService service;
     CAddress addrTo(service, ServiceFlags(NODE_NETWORK));
     CAddress addrFrom(service, ServiceFlags(NODE_NETWORK));
     std::string user_agent = "/bitcoin-cash-seeder:0.15/";
     int start_height = 1;
 
     CDataStream versionPayload(SER_NETWORK, PROTOCOL_VERSION);
     versionPayload << PROTOCOL_VERSION << serviceFlags << now << addrTo
                    << addrFrom << nonce << user_agent << start_height;
 
     CMessageHeader versionhdr(Params().NetMagic(), NetMsgType::VERSION,
                               versionPayload.size());
     uint256 hash = Hash(versionPayload.data(),
                         versionPayload.data() + versionPayload.size());
     memcpy(versionhdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
 
     CDataStream expectedVersion(SER_NETWORK, PROTOCOL_VERSION);
     expectedVersion << versionhdr;
     expectedVersion += versionPayload;
 
     CheckMessage(expectedVersion, NetMsgType::VERSION, PROTOCOL_VERSION,
                  serviceFlags, now, addrTo, addrFrom, nonce, user_agent,
                  start_height);
 }
 
 BOOST_AUTO_TEST_CASE(header_empty_payload_message_writer_test) {
     SelectParams(CBaseChainParams::MAIN);
     CMessageHeader verackHeader(Params().NetMagic(), NetMsgType::VERACK, 0);
     CDataStream expectedVerack(SER_NETWORK, PROTOCOL_VERSION);
     // This is an empty payload, but is still necessary for the checksum
     std::vector<uint8_t> payload;
     uint256 hash = Hash(payload.data(), payload.data() + payload.size());
     memcpy(verackHeader.pchChecksum, hash.begin(),
            CMessageHeader::CHECKSUM_SIZE);
     expectedVerack << verackHeader;
 
     CheckMessage(expectedVerack, NetMsgType::VERACK);
 }
 
 BOOST_AUTO_TEST_CASE(write_getheaders_message_test) {
     SelectParams(CBaseChainParams::MAIN);
     CDataStream payload(SER_NETWORK, PROTOCOL_VERSION);
     BlockHash bhash(uint256S(
         "0000000099f5509b5f36b1926bcf82b21d936ebeadee811030dfbbb7fae915d7"));
     std::vector<BlockHash> vlocator(1, bhash);
     CBlockLocator locatorhash(vlocator);
     payload << locatorhash << uint256();
     uint256 hash = Hash(payload.data(), payload.data() + payload.size());
 
     CMessageHeader msgHeader(Params().NetMagic(), NetMsgType::GETHEADERS,
                              payload.size());
     memcpy(msgHeader.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
 
     CDataStream expectedMsg(SER_NETWORK, PROTOCOL_VERSION);
     expectedMsg << msgHeader;
     expectedMsg += payload;
 
     CheckMessage(expectedMsg, NetMsgType::GETHEADERS, locatorhash, uint256());
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/seeder/test/p2p_messaging_tests.cpp b/src/seeder/test/p2p_messaging_tests.cpp
index e3b087704..c4436bd76 100644
--- a/src/seeder/test/p2p_messaging_tests.cpp
+++ b/src/seeder/test/p2p_messaging_tests.cpp
@@ -1,133 +1,132 @@
 // Copyright (c) 2019 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <chainparams.h>
 #include <protocol.h>
 #include <seeder/bitcoin.h>
 #include <seeder/db.h>
 #include <seeder/test/util.h>
 #include <serialize.h>
 #include <streams.h>
 #include <util/system.h>
 #include <version.h>
 
 #include <boost/test/unit_test.hpp>
 
 #include <memory>
 #include <ostream>
 #include <string>
 #include <vector>
 
 std::ostream &operator<<(std::ostream &os, const PeerMessagingState &state) {
     os << to_integral(state);
     return os;
 }
 
 class TestCSeederNode : public CSeederNode {
 public:
     TestCSeederNode(const CService &service, std::vector<CAddress> *vAddrIn)
         : CSeederNode(service, vAddrIn) {
         SelectParams(CBaseChainParams::REGTEST);
     }
 
     void TestProcessMessage(const std::string &strCommand, CDataStream &message,
                             PeerMessagingState expectedState) {
         PeerMessagingState ret =
             CSeederNode::ProcessMessage(strCommand, message);
         BOOST_CHECK_EQUAL(ret, expectedState);
     }
 };
 
 static const unsigned short SERVICE_PORT = 18444;
 
 struct SeederTestingSetup {
     SeederTestingSetup() {
         CNetAddr ip;
         ip.SetInternal("bitcoin.test");
         CService service = {ip, SERVICE_PORT};
         vAddr.emplace_back(service, ServiceFlags());
         testNode = std::make_unique<TestCSeederNode>(service, &vAddr);
     }
 
     std::vector<CAddress> vAddr;
     std::unique_ptr<TestCSeederNode> testNode;
 };
 
 BOOST_FIXTURE_TEST_SUITE(p2p_messaging_tests, SeederTestingSetup)
 
 static CDataStream
 CreateVersionMessage(int64_t now, CAddress addrTo, CAddress addrFrom,
                      int32_t start_height, uint32_t nVersion,
                      uint64_t nonce = 0,
                      std::string user_agent = "/bitcoin-cash-seeder:0.15/") {
     CDataStream payload(SER_NETWORK, 0);
     payload.SetVersion(nVersion);
     ServiceFlags serviceflags = ServiceFlags(NODE_NETWORK);
     payload << nVersion << uint64_t(serviceflags) << now << addrTo << addrFrom
             << nonce << user_agent << start_height;
     return payload;
 }
 
 static const int SEEDER_INIT_VERSION = 0;
 
 BOOST_AUTO_TEST_CASE(seeder_node_version_test) {
     CService serviceFrom;
     CAddress addrFrom(serviceFrom, ServiceFlags(NODE_NETWORK));
 
-    CDataStream versionMessage =
-        CreateVersionMessage(time(nullptr), vAddr[0], addrFrom,
-                             GetRequireHeight(), INIT_PROTO_VERSION);
+    CDataStream versionMessage = CreateVersionMessage(
+        GetTime(), vAddr[0], addrFrom, GetRequireHeight(), INIT_PROTO_VERSION);
 
     // Verify the version is set as the initial value
     BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(),
                       SEEDER_INIT_VERSION);
     testNode->TestProcessMessage(NetMsgType::VERSION, versionMessage,
                                  PeerMessagingState::AwaitingMessages);
     // Verify the version has been updated
     BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(),
                       versionMessage.GetVersion());
 }
 
 static CDataStream CreateAddrMessage(std::vector<CAddress> sendAddrs,
                                      uint32_t nVersion = INIT_PROTO_VERSION) {
     CDataStream payload(SER_NETWORK, 0);
     payload.SetVersion(nVersion);
     payload << sendAddrs;
     return payload;
 }
 
 BOOST_AUTO_TEST_CASE(seeder_node_addr_test) {
     // vAddrs starts with 1 entry.
     std::vector<CAddress> sendAddrs(ADDR_SOFT_CAP - 1, vAddr[0]);
 
     // Happy path
     // addrs are added normally to vAddr until ADDR_SOFT_CAP is reached.
     // Add addrs up to the soft cap.
     CDataStream addrMessage = CreateAddrMessage(sendAddrs);
     BOOST_CHECK_EQUAL(1, vAddr.size());
     testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
                                  PeerMessagingState::AwaitingMessages);
     BOOST_CHECK_EQUAL(ADDR_SOFT_CAP, vAddr.size());
 
     // ADDR_SOFT_CAP is exceeded
     sendAddrs.resize(1);
     addrMessage = CreateAddrMessage(sendAddrs);
     testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
                                  PeerMessagingState::Finished);
     BOOST_CHECK_EQUAL(ADDR_SOFT_CAP + 1, vAddr.size());
 
     // Test the seeder's behavior after ADDR_SOFT_CAP addrs
     // Only one addr per ADDR message will be added, the rest are ignored
     size_t expectedSize = vAddr.size() + 1;
     for (size_t i = 1; i < 10; i++) {
         sendAddrs.resize(i, sendAddrs[0]);
         addrMessage = CreateAddrMessage(sendAddrs);
         testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage,
                                      PeerMessagingState::Finished);
         BOOST_CHECK_EQUAL(expectedSize, vAddr.size());
         ++expectedSize;
     }
 }
 
 BOOST_AUTO_TEST_SUITE_END()