Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
3001status = DatabaseStatus::FAILED_BAD_PATH;3002return nullptr;3003}3004return MakeDatabase(*wallet_path, options, status, error_string);3005}3007bool CWallet::LoadWalletArgs(std::shared_ptr<CWallet> wallet, const WalletContext& context, bilingual_str& error, std::vector<bilingual_str>& warnings)3008{3009interfaces::Chain* chain = context.chain;3010const ArgsManager& args = *Assert(context.args);3012if (!args.GetArg("-addresstype", "").empty()) {3013std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-addresstype", ""));3014if (!parsed) {3015error = strprintf(_("Unknown address type '%s'"), args.GetArg("-addresstype", ""));3016return false;3017}3018wallet->m_default_address_type = parsed.value();3019}3021if (!args.GetArg("-changetype", "").empty()) {3022std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-changetype", ""));3023if (!parsed) {3024error = strprintf(_("Unknown change type '%s'"), args.GetArg("-changetype", ""));3025return false;3026}3027wallet->m_default_change_type = parsed.value();3028}3030if (const auto arg{args.GetArg("-mintxfee")}) {3031std::optional<CAmount> min_tx_fee = ParseMoney(*arg);3032if (!min_tx_fee) {3033error = AmountErrMsg("mintxfee", *arg);3034return false;3035} else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {3036warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +3037_("This is the minimum transaction fee you pay on every transaction."));3038}3040wallet->m_min_fee = CFeeRate{min_tx_fee.value()};3041}3043if (const auto arg{args.GetArg("-maxapsfee")}) {3044const std::string& max_aps_fee{*arg};3045if (max_aps_fee == "-1") {3046wallet->m_max_aps_fee = -1;3047} else if (std::optional<CAmount> max_fee = ParseMoney(max_aps_fee)) {3048if (max_fee.value() > HIGH_APS_FEE) {3049warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +3050_("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));3051}3052wallet->m_max_aps_fee = max_fee.value();3053} else {3054error = AmountErrMsg("maxapsfee", max_aps_fee);3055return false;3056}3057}3059if (const auto arg{args.GetArg("-fallbackfee")}) {3060std::optional<CAmount> fallback_fee = ParseMoney(*arg);3061if (!fallback_fee) {3062error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-fallbackfee", *arg);3063return false;3064} else if (fallback_fee.value() > HIGH_TX_FEE_PER_KB) {3065warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +3066_("This is the transaction fee you may pay when fee estimates are not available."));3067}3068wallet->m_fallback_fee = CFeeRate{fallback_fee.value()};3069}3071// Disable fallback fee in case value was set to 0, enable if non-null value3072wallet->m_allow_fallback_fee = wallet->m_fallback_fee.GetFeePerK() != 0;3074if (const auto arg{args.GetArg("-discardfee")}) {3075std::optional<CAmount> discard_fee = ParseMoney(*arg);3076if (!discard_fee) {3077error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-discardfee", *arg);3078return false;3079} else if (discard_fee.value() > HIGH_TX_FEE_PER_KB) {3080warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +3081_("This is the transaction fee you may discard if change is smaller than dust at this level"));3082}3083wallet->m_discard_rate = CFeeRate{discard_fee.value()};3084}3086if (const auto arg{args.GetArg("-maxtxfee")}) {3087std::optional<CAmount> max_fee = ParseMoney(*arg);3088if (!max_fee) {3089error = AmountErrMsg("maxtxfee", *arg);3090return false;3091} else if (max_fee.value() > HIGH_MAX_TX_FEE) {3092warnings.push_back(strprintf(_("%s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));3093}3095if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {3096error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),3097"-maxtxfee", *arg, chain->relayMinFee().ToString());3098return false;3099}3101wallet->m_default_max_tx_fee = max_fee.value();3102}3104if (const auto arg{args.GetArg("-consolidatefeerate")}) {3105if (std::optional<CAmount> consolidate_feerate = ParseMoney(*arg)) {3106wallet->m_consolidate_feerate = CFeeRate(*consolidate_feerate);3107} else {3108error = AmountErrMsg("consolidatefeerate", *arg);3109return false;3110}3111}3113if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {3114warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +3115_("The wallet will avoid paying less than the minimum relay fee."));3116}3118wallet->m_confirm_target = args.GetIntArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);3119wallet->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);3120wallet->m_signal_rbf = DEFAULT_WALLET_RBF;3121if (auto value{args.GetBoolArg("-walletrbf")}) {3122warnings.push_back(_("-walletrbf is deprecated and will be fully removed in the next release."));3123wallet->m_signal_rbf = *value;3124}3126wallet->m_keypool_size = std::max(args.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{1});3127wallet->m_notify_tx_changed_script = args.GetArg("-walletnotify", "");3128wallet->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));3130return true;3131}3133std::shared_ptr<CWallet> CWallet::CreateNew(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bool born_encrypted, bilingual_str& error, std::vector<bilingual_str>& warnings)3134{3135interfaces::Chain* chain = context.chain;3136const std::string& walletFile = database->Filename();3138const auto start{SteadyClock::now()};3139// TODO: Can't use std::make_shared because we need a custom deleter but3140// should be possible to use std::allocate_shared.3141std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), FlushAndDeleteWallet);3143if (!LoadWalletArgs(walletInstance, context, error, warnings)) {3144return nullptr;3145}3147// Initialize version key.3148if(!WalletBatch(walletInstance->GetDatabase()).WriteVersion(CLIENT_VERSION)) {3149error = strprintf(_("Error creating %s: Could not write version metadata."), walletFile);3150return nullptr;3151}3152{3153LOCK(walletInstance->cs_wallet);3155// Init with passed flags.3156// Always set the cache upgrade flag as this feature is supported from the beginning.3157walletInstance->InitWalletFlags(wallet_creation_flags | WALLET_FLAG_LAST_HARDENED_XPUB_CACHED);3159// Only descriptor wallets can be created3160assert(walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));3162// Born encrypted wallets will have their keys generated later3163if (!born_encrypted) {3164walletInstance->SetupWalletGeneration();3165}3167if (chain) {3168std::optional<int> tip_height = chain->getHeight();3169if (tip_height) {3170walletInstance->SetLastBlockProcessed(*tip_height, chain->getBlockHash(*tip_height));3171}3172}3173}3175walletInstance->WalletLogPrintf("Wallet completed creation in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));3177// Try to top up keypool. No-op if the wallet is locked.3178walletInstance->TopUpKeyPool();3180if (chain && !AttachChain(walletInstance, *chain, /*rescan_required=*/false, error, warnings)) {3181walletInstance->DisconnectChainNotifications();3182return nullptr;3183}3185return walletInstance;3186}3188std::shared_ptr<CWallet> CWallet::LoadExisting(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, bilingual_str& error, std::vector<bilingual_str>& warnings)3189{3190interfaces::Chain* chain = context.chain;3191const std::string& walletFile = database->Filename();3193const auto start{SteadyClock::now()};3194std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), FlushAndDeleteWallet);3196if (!LoadWalletArgs(walletInstance, context, error, warnings)) {3197return nullptr;3198}3200// Load wallet3201auto nLoadWalletRet = walletInstance->PopulateWalletFromDB(error, warnings);3202bool rescan_required = nLoadWalletRet == DBErrors::NEED_RESCAN;3203if (nLoadWalletRet != DBErrors::LOAD_OK && nLoadWalletRet != DBErrors::NONCRITICAL_ERROR && !rescan_required) {3204return nullptr;3205}3207if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {3208for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {3209if (spk_man->HavePrivateKeys()) {3210warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));3211break;3212}3213}3214}3216walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));3218// Try to top up keypool. No-op if the wallet is locked.3219walletInstance->TopUpKeyPool();3221if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {3222walletInstance->DisconnectChainNotifications();3223return nullptr;3224}3226WITH_LOCK(walletInstance->cs_wallet, walletInstance->LogStats());3228return walletInstance;3229}3232bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interfaces::Chain& chain, const bool rescan_required, bilingual_str& error, std::vector<bilingual_str>& warnings)3233{3234LOCK(walletInstance->cs_wallet);3235// allow setting the chain if it hasn't been set already but prevent changing it3236assert(!walletInstance->m_chain || walletInstance->m_chain == &chain);3237walletInstance->m_chain = &chain;3239// Unless allowed, ensure wallet files are not reused across chains:3240if (!gArgs.GetBoolArg("-walletcrosschain", DEFAULT_WALLETCROSSCHAIN)) {3241WalletBatch batch(walletInstance->GetDatabase());3242CBlockLocator locator;3243if (batch.ReadBestBlock(locator) && locator.vHave.size() > 0 && chain.getHeight()) {3244// Wallet is assumed to be from another chain, if genesis block in the active3245// chain differs from the genesis block known to the wallet.3246if (chain.getBlockHash(0) != locator.vHave.back()) {3247error = Untranslated("Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");3248return false;3249}3250}