aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/bitcoin-conf.md2
-rw-r--r--src/bitcoin-chainstate.cpp2
-rw-r--r--src/chain.h6
-rw-r--r--src/consensus/params.h5
-rw-r--r--src/kernel/chainstatemanager_opts.h4
-rw-r--r--src/net_processing.cpp8
-rw-r--r--src/node/miner.cpp4
-rw-r--r--src/outputtype.h1
-rw-r--r--src/primitives/block.h6
-rw-r--r--src/protocol.cpp7
-rw-r--r--src/timedata.cpp4
-rw-r--r--src/timedata.h2
-rw-r--r--src/validation.cpp7
-rw-r--r--src/validation.h4
-rw-r--r--src/wallet/wallet.cpp11
-rw-r--r--src/wallet/wallet.h5
-rw-r--r--src/wallet/wallettool.cpp2
-rwxr-xr-xtest/functional/wallet_encryption.py18
18 files changed, 57 insertions, 41 deletions
diff --git a/doc/bitcoin-conf.md b/doc/bitcoin-conf.md
index acd767f234..1ebfb4c1de 100644
--- a/doc/bitcoin-conf.md
+++ b/doc/bitcoin-conf.md
@@ -6,6 +6,8 @@ All command-line options (except for `-?`, `-help`, `-version` and `-conf`) may
Changes to the configuration file while `bitcoind` or `bitcoin-qt` is running only take effect after restarting.
+Users should never make any configuration changes which they do not understand. Furthermore, users should always be wary of accepting any configuration changes provided to them by another source (even if they believe that they do understand them).
+
## Configuration File Format
The configuration file is a plain text file and consists of `option=value` entries, one per line. Leading and trailing whitespaces are removed.
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index 87f18371b1..7312ae45d4 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -82,7 +82,7 @@ int main(int argc, char* argv[])
// SETUP: Chainstate
const ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
- .adjusted_time_callback = static_cast<int64_t (*)()>(GetTime),
+ .adjusted_time_callback = NodeClock::now,
};
ChainstateManager chainman{chainman_opts};
diff --git a/src/chain.h b/src/chain.h
index 1c5cd3f1f6..cc1d9e2d22 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -12,6 +12,7 @@
#include <primitives/block.h>
#include <sync.h>
#include <uint256.h>
+#include <util/time.h>
#include <vector>
@@ -275,6 +276,11 @@ public:
*/
bool HaveTxsDownloaded() const { return nChainTx != 0; }
+ NodeSeconds Time() const
+ {
+ return NodeSeconds{std::chrono::seconds{nTime}};
+ }
+
int64_t GetBlockTime() const
{
return (int64_t)nTime;
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 794e0f5383..7c35222713 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -8,6 +8,7 @@
#include <uint256.h>
+#include <chrono>
#include <limits>
#include <map>
@@ -109,6 +110,10 @@ struct Params {
bool fPowNoRetargeting;
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
+ std::chrono::seconds PowTargetSpacing() const
+ {
+ return std::chrono::seconds{nPowTargetSpacing};
+ }
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
/** The best chain should have at least this much work */
uint256 nMinimumChainWork;
diff --git a/src/kernel/chainstatemanager_opts.h b/src/kernel/chainstatemanager_opts.h
index 510a1f9edc..520d0e8e75 100644
--- a/src/kernel/chainstatemanager_opts.h
+++ b/src/kernel/chainstatemanager_opts.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
#define BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
+#include <util/time.h>
+
#include <cstdint>
#include <functional>
@@ -19,7 +21,7 @@ namespace kernel {
*/
struct ChainstateManagerOpts {
const CChainParams& chainparams;
- const std::function<int64_t()> adjusted_time_callback{nullptr};
+ const std::function<NodeClock::time_point()> adjusted_time_callback{nullptr};
};
} // namespace kernel
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index b39412158f..b83034463d 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1151,7 +1151,7 @@ bool PeerManagerImpl::TipMayBeStale()
bool PeerManagerImpl::CanDirectFetch()
{
- return m_chainman.ActiveChain().Tip()->GetBlockTime() > GetAdjustedTime() - m_chainparams.GetConsensus().nPowTargetSpacing * 20;
+ return m_chainman.ActiveChain().Tip()->Time() > GetAdjustedTime() - m_chainparams.GetConsensus().PowTargetSpacing() * 20;
}
static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -4913,7 +4913,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (!state.fSyncStarted && CanServeBlocks(*peer) && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today.
- if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
+ if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->Time() > GetAdjustedTime() - 24h) {
const CBlockIndex* pindexStart = m_chainman.m_best_header;
/* If possible, start at the block preceding the currently
best known header. This ensures that we always get a
@@ -4933,7 +4933,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling
// to maintain precision
std::chrono::microseconds{HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER} *
- (GetAdjustedTime() - m_chainman.m_best_header->GetBlockTime()) / consensusParams.nPowTargetSpacing
+ Ticks<std::chrono::seconds>(GetAdjustedTime() - m_chainman.m_best_header->Time()) / consensusParams.nPowTargetSpacing
);
nSyncStarted++;
}
@@ -5250,7 +5250,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Check for headers sync timeouts
if (state.fSyncStarted && state.m_headers_sync_timeout < std::chrono::microseconds::max()) {
// Detect whether this is a stalling initial-headers-sync peer
- if (m_chainman.m_best_header->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) {
+ if (m_chainman.m_best_header->Time() <= GetAdjustedTime() - 24h) {
if (current_time > state.m_headers_sync_timeout && nSyncStarted == 1 && (m_num_preferred_download_peers - state.fPreferredDownload >= 1)) {
// Disconnect a peer (without NetPermissionFlags::NoBan permission) if it is our only sync peer,
// and we have others we could be using instead.
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index 9db10feae4..f04742deeb 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -30,7 +30,7 @@ namespace node {
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
int64_t nOldTime = pblock->nTime;
- int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());
+ int64_t nNewTime{std::max<int64_t>(pindexPrev->GetMedianTimePast() + 1, TicksSinceEpoch<std::chrono::seconds>(GetAdjustedTime()))};
if (nOldTime < nNewTime) {
pblock->nTime = nNewTime;
@@ -133,7 +133,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblock->nVersion = gArgs.GetIntArg("-blockversion", pblock->nVersion);
}
- pblock->nTime = GetAdjustedTime();
+ pblock->nTime = TicksSinceEpoch<std::chrono::seconds>(GetAdjustedTime());
m_lock_time_cutoff = pindexPrev->GetMedianTimePast();
int nPackagesSelected = 0;
diff --git a/src/outputtype.h b/src/outputtype.h
index be5fd62b80..c59262591b 100644
--- a/src/outputtype.h
+++ b/src/outputtype.h
@@ -27,7 +27,6 @@ static constexpr auto OUTPUT_TYPES = std::array{
OutputType::P2SH_SEGWIT,
OutputType::BECH32,
OutputType::BECH32M,
- OutputType::UNKNOWN,
};
std::optional<OutputType> ParseOutputType(const std::string& str);
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 2d10853607..76aba6c899 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -9,6 +9,7 @@
#include <primitives/transaction.h>
#include <serialize.h>
#include <uint256.h>
+#include <util/time.h>
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
@@ -52,6 +53,11 @@ public:
uint256 GetHash() const;
+ NodeSeconds Time() const
+ {
+ return NodeSeconds{std::chrono::seconds{nTime}};
+ }
+
int64_t GetBlockTime() const
{
return (int64_t)nTime;
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 139405170b..bdd1cc2aff 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -199,12 +199,7 @@ static std::string serviceFlagToStr(size_t bit)
// Not using default, so we get warned when a case is missing
}
- std::ostringstream stream;
- stream.imbue(std::locale::classic());
- stream << "UNKNOWN[";
- stream << "2^" << bit;
- stream << "]";
- return stream.str();
+ return strprintf("UNKNOWN[2^%u]", bit);
}
std::vector<std::string> serviceFlagsToStr(uint64_t flags)
diff --git a/src/timedata.cpp b/src/timedata.cpp
index ceee08e68c..fe9a5fbed7 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -32,9 +32,9 @@ int64_t GetTimeOffset()
return nTimeOffset;
}
-int64_t GetAdjustedTime()
+NodeClock::time_point GetAdjustedTime()
{
- return GetTime() + GetTimeOffset();
+ return NodeClock::now() + std::chrono::seconds{GetTimeOffset()};
}
#define BITCOIN_TIMEDATA_MAX_SAMPLES 200
diff --git a/src/timedata.h b/src/timedata.h
index cfe5111644..669a571f47 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -75,7 +75,7 @@ public:
/** Functions to keep track of adjusted P2P time */
int64_t GetTimeOffset();
-int64_t GetAdjustedTime();
+NodeClock::time_point GetAdjustedTime();
void AddTimeData(const CNetAddr& ip, int64_t nTime);
/**
diff --git a/src/validation.cpp b/src/validation.cpp
index d276cea2f7..dc90b53746 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -3441,7 +3441,7 @@ std::vector<unsigned char> ChainstateManager::GenerateCoinbaseCommitment(CBlock&
* in ConnectBlock().
* Note that -reindex-chainstate skips the validation that happens here!
*/
-static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const ChainstateManager& chainman, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
+static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const ChainstateManager& chainman, const CBlockIndex* pindexPrev, NodeClock::time_point now) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
assert(pindexPrev != nullptr);
@@ -3469,8 +3469,9 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-too-old", "block's timestamp is too early");
// Check timestamp
- if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
+ if (block.Time() > now + std::chrono::seconds{MAX_FUTURE_BLOCK_TIME}) {
return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", "block timestamp too far in the future");
+ }
// Reject blocks with outdated version
if ((block.nVersion < 2 && DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_HEIGHTINCB)) ||
@@ -3831,7 +3832,7 @@ bool TestBlockValidity(BlockValidationState& state,
CChainState& chainstate,
const CBlock& block,
CBlockIndex* pindexPrev,
- const std::function<int64_t()>& adjusted_time_callback,
+ const std::function<NodeClock::time_point()>& adjusted_time_callback,
bool fCheckPOW,
bool fCheckMerkleRoot)
{
diff --git a/src/validation.h b/src/validation.h
index 324074aee9..5b71318687 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -336,7 +336,7 @@ bool TestBlockValidity(BlockValidationState& state,
CChainState& chainstate,
const CBlock& block,
CBlockIndex* pindexPrev,
- const std::function<int64_t()>& adjusted_time_callback,
+ const std::function<NodeClock::time_point()>& adjusted_time_callback,
bool fCheckPOW = true,
bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -840,7 +840,7 @@ private:
const CChainParams m_chainparams;
- const std::function<int64_t()> m_adjusted_time_callback;
+ const std::function<NodeClock::time_point()> m_adjusted_time_callback;
//! Internal helper for ActivateSnapshot().
[[nodiscard]] bool PopulateAndValidateSnapshot(
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 752aad2378..3d989d90f8 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1526,16 +1526,20 @@ bool CWallet::LoadWalletFlags(uint64_t flags)
return true;
}
-bool CWallet::AddWalletFlags(uint64_t flags)
+void CWallet::InitWalletFlags(uint64_t flags)
{
LOCK(cs_wallet);
+
// We should never be writing unknown non-tolerable wallet flags
assert(((flags & KNOWN_WALLET_FLAGS) >> 32) == (flags >> 32));
+ // This should only be used once, when creating a new wallet - so current flags are expected to be blank
+ assert(m_wallet_flags == 0);
+
if (!WalletBatch(GetDatabase()).WriteWalletFlags(flags)) {
throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
}
- return LoadWalletFlags(flags);
+ if (!LoadWalletFlags(flags)) assert(false);
}
// Helper for producing a max-sized low-S low-R signature (eg 71 bytes)
@@ -2832,7 +2836,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
walletInstance->SetMinVersion(FEATURE_LATEST);
- walletInstance->AddWalletFlags(wallet_creation_flags);
+ walletInstance->InitWalletFlags(wallet_creation_flags);
// Only create LegacyScriptPubKeyMan when not descriptor wallet
if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
@@ -3446,7 +3450,6 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
- if (t == OutputType::UNKNOWN) continue;
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
if (IsCrypted()) {
if (IsLocked()) {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3a46d0a987..934811dee1 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -806,8 +806,9 @@ public:
bool IsWalletFlagSet(uint64_t flag) const override;
/** overwrite all flags by the given uint64_t
- returns false if unknown, non-tolerable flags are present */
- bool AddWalletFlags(uint64_t flags);
+ flags must be uninitialised (or 0)
+ only known flags may be present */
+ void InitWalletFlags(uint64_t flags);
/** Loads the flags into the wallet. (used by LoadWallet) */
bool LoadWalletFlags(uint64_t flags);
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index 769175b5a8..e991bc0814 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -34,7 +34,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag
LOCK(wallet_instance->cs_wallet);
wallet_instance->SetMinVersion(FEATURE_LATEST);
- wallet_instance->AddWalletFlags(wallet_creation_flags);
+ wallet_instance->InitWalletFlags(wallet_creation_flags);
if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index 0c9106f800..37c1c4bff3 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -9,8 +9,7 @@ import time
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_raises_rpc_error,
- assert_greater_than,
- assert_greater_than_or_equal,
+ assert_equal,
)
@@ -76,21 +75,18 @@ class WalletEncryptionTest(BitcoinTestFramework):
self.log.info('Check a timeout less than the limit')
MAX_VALUE = 100000000
- expected_time = int(time.time()) + MAX_VALUE - 600
+ now = int(time.time())
+ self.nodes[0].setmocktime(now)
+ expected_time = now + MAX_VALUE - 600
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600)
- # give buffer for walletpassphrase, since it iterates over all encrypted keys
- expected_time_with_buffer = time.time() + MAX_VALUE - 600
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
- assert_greater_than_or_equal(actual_time, expected_time)
- assert_greater_than(expected_time_with_buffer, actual_time)
+ assert_equal(actual_time, expected_time)
self.log.info('Check a timeout greater than the limit')
- expected_time = int(time.time()) + MAX_VALUE - 1
+ expected_time = now + MAX_VALUE
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000)
- expected_time_with_buffer = time.time() + MAX_VALUE
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
- assert_greater_than_or_equal(actual_time, expected_time)
- assert_greater_than(expected_time_with_buffer, actual_time)
+ assert_equal(actual_time, expected_time)
if __name__ == '__main__':