aboutsummaryrefslogtreecommitdiff
path: root/src/common/messages.cpp
blob: 5fe3e9e4d864521082d8913c2b7bf2f82993debd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <common/messages.h>

#include <common/types.h>
#include <policy/fees.h>
#include <node/types.h>
#include <tinyformat.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/translation.h>

#include <cassert>
#include <map>
#include <string>
#include <utility>
#include <vector>

using node::TransactionError;
using util::Join;

namespace common {
std::string StringForFeeReason(FeeReason reason)
{
    static const std::map<FeeReason, std::string> fee_reason_strings = {
        {FeeReason::NONE, "None"},
        {FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"},
        {FeeReason::FULL_ESTIMATE, "Target 85% Threshold"},
        {FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"},
        {FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"},
        {FeeReason::MEMPOOL_MIN, "Mempool Min Fee"},
        {FeeReason::PAYTXFEE, "PayTxFee set"},
        {FeeReason::FALLBACK, "Fallback fee"},
        {FeeReason::REQUIRED, "Minimum Required Fee"},
    };
    auto reason_string = fee_reason_strings.find(reason);

    if (reason_string == fee_reason_strings.end()) return "Unknown";

    return reason_string->second;
}

const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap()
{
    static const std::vector<std::pair<std::string, FeeEstimateMode>> FEE_MODES = {
        {"unset", FeeEstimateMode::UNSET},
        {"economical", FeeEstimateMode::ECONOMICAL},
        {"conservative", FeeEstimateMode::CONSERVATIVE},
    };
    return FEE_MODES;
}

std::string FeeModeInfo(const std::pair<std::string, FeeEstimateMode>& mode, std::string& default_info)
{
    switch (mode.second) {
        case FeeEstimateMode::UNSET:
            return strprintf("%s means no mode set (%s). \n", mode.first, default_info);
        case FeeEstimateMode::ECONOMICAL:
            return strprintf("%s estimates use a shorter time horizon, making them more\n"
                   "responsive to short-term drops in the prevailing fee market. This mode\n"
                   "potentially returns a lower fee rate estimate.\n", mode.first);
        case FeeEstimateMode::CONSERVATIVE:
            return strprintf("%s estimates use a longer time horizon, making them\n"
                   "less responsive to short-term drops in the prevailing fee market. This mode\n"
                   "potentially returns a higher fee rate estimate.\n", mode.first);
        default:
            // Other modes apart from the ones handled are fee rate units; they should not be clarified.
            assert(false);
    }
}

std::string FeeModesDetail(std::string default_info)
{
    std::string info;
    for (const auto& fee_mode : FeeModeMap()) {
        info += FeeModeInfo(fee_mode, default_info);
    }
    return strprintf("%s \n%s", FeeModes(", "), info);
}

std::string FeeModes(const std::string& delimiter)
{
    return Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; });
}

std::string InvalidEstimateModeErrorMessage()
{
    return "Invalid estimate_mode parameter, must be one of: \"" + FeeModes("\", \"") + "\"";
}

bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode)
{
    auto searchkey = ToUpper(mode_string);
    for (const auto& pair : FeeModeMap()) {
        if (ToUpper(pair.first) == searchkey) {
            fee_estimate_mode = pair.second;
            return true;
        }
    }
    return false;
}

bilingual_str PSBTErrorString(PSBTError err)
{
    switch (err) {
        case PSBTError::MISSING_INPUTS:
            return Untranslated("Inputs missing or spent");
        case PSBTError::SIGHASH_MISMATCH:
            return Untranslated("Specified sighash value does not match value stored in PSBT");
        case PSBTError::EXTERNAL_SIGNER_NOT_FOUND:
            return Untranslated("External signer not found");
        case PSBTError::EXTERNAL_SIGNER_FAILED:
            return Untranslated("External signer failed to sign");
        case PSBTError::UNSUPPORTED:
            return Untranslated("Signer does not support PSBT");
        // no default case, so the compiler can warn about missing cases
    }
    assert(false);
}

bilingual_str TransactionErrorString(const TransactionError err)
{
    switch (err) {
        case TransactionError::OK:
            return Untranslated("No error");
        case TransactionError::MISSING_INPUTS:
            return Untranslated("Inputs missing or spent");
        case TransactionError::ALREADY_IN_UTXO_SET:
            return Untranslated("Transaction outputs already in utxo set");
        case TransactionError::MEMPOOL_REJECTED:
            return Untranslated("Transaction rejected by mempool");
        case TransactionError::MEMPOOL_ERROR:
            return Untranslated("Mempool internal error");
        case TransactionError::MAX_FEE_EXCEEDED:
            return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)");
        case TransactionError::MAX_BURN_EXCEEDED:
            return Untranslated("Unspendable output exceeds maximum configured by user (maxburnamount)");
        case TransactionError::INVALID_PACKAGE:
            return Untranslated("Transaction rejected due to invalid package");
        // no default case, so the compiler can warn about missing cases
    }
    assert(false);
}

bilingual_str ResolveErrMsg(const std::string& optname, const std::string& strBind)
{
    return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
}

bilingual_str InvalidPortErrMsg(const std::string& optname, const std::string& invalid_value)
{
    return strprintf(_("Invalid port specified in %s: '%s'"), optname, invalid_value);
}

bilingual_str AmountHighWarn(const std::string& optname)
{
    return strprintf(_("%s is set very high!"), optname);
}

bilingual_str AmountErrMsg(const std::string& optname, const std::string& strValue)
{
    return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue);
}
} // namespace common