aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp7
-rw-r--r--src/wallet/rpcwallet.cpp82
-rw-r--r--src/wallet/test/wallet_tests.cpp60
-rw-r--r--src/wallet/wallet.cpp26
-rw-r--r--src/wallet/walletdb.h1
5 files changed, 124 insertions, 52 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 14c2e31d9..d55cc68dc 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -167,6 +167,11 @@ void ImportScript(const CScript& script, const string& strLabel, bool isRedeemSc
if (!pwalletMain->HaveCScript(script) && !pwalletMain->AddCScript(script))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
ImportAddress(CBitcoinAddress(CScriptID(script)), strLabel);
+ } else {
+ CTxDestination destination;
+ if (ExtractDestination(script, destination)) {
+ pwalletMain->SetAddressBook(destination, strLabel, "receive");
+ }
}
}
@@ -195,6 +200,8 @@ UniValue importaddress(const UniValue& params, bool fHelp)
"4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
"If you have the full public key, you should call importpubkey instead of this.\n"
+ "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
+ "as change, and not show up in many RPCs.\n"
"\nExamples:\n"
"\nImport a script with rescan\n"
+ HelpExampleCli("importaddress", "\"myscript\"") +
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 2d4e95911..8538f880f 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1011,6 +1011,85 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp)
return CBitcoinAddress(innerID).ToString();
}
+class Witnessifier : public boost::static_visitor<bool>
+{
+public:
+ CScriptID result;
+
+ bool operator()(const CNoDestination &dest) const { return false; }
+
+ bool operator()(const CKeyID &keyID) {
+ CPubKey pubkey;
+ if (pwalletMain && pwalletMain->GetPubKey(keyID, pubkey)) {
+ CScript basescript;
+ basescript << ToByteVector(pubkey) << OP_CHECKSIG;
+ CScript witscript = GetScriptForWitness(basescript);
+ pwalletMain->AddCScript(witscript);
+ result = CScriptID(witscript);
+ return true;
+ }
+ return false;
+ }
+
+ bool operator()(const CScriptID &scriptID) {
+ CScript subscript;
+ if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) {
+ int witnessversion;
+ std::vector<unsigned char> witprog;
+ if (subscript.IsWitnessProgram(witnessversion, witprog)) {
+ result = scriptID;
+ return true;
+ }
+ CScript witscript = GetScriptForWitness(subscript);
+ pwalletMain->AddCScript(witscript);
+ result = CScriptID(witscript);
+ return true;
+ }
+ return false;
+ }
+};
+
+UniValue addwitnessaddress(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() < 1 || params.size() > 1)
+ {
+ string msg = "addwitnessaddress \"address\"\n"
+ "\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
+ "It returns the witness script.\n"
+
+ "\nArguments:\n"
+ "1. \"address\" (string, required) An address known to the wallet\n"
+
+ "\nResult:\n"
+ "\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n"
+ "}\n"
+ ;
+ throw runtime_error(msg);
+ }
+
+ {
+ LOCK(cs_main);
+ if (!IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()) && !GetBoolArg("-walletprematurewitness", false)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Segregated witness not enabled on network");
+ }
+ }
+
+ CBitcoinAddress address(params[0].get_str());
+ if (!address.IsValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+
+ Witnessifier w;
+ CTxDestination dest = address.Get();
+ bool ret = boost::apply_visitor(w, dest);
+ if (!ret) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet");
+ }
+
+ return CBitcoinAddress(w.result).ToString();
+}
struct tallyitem
{
@@ -2451,7 +2530,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
// parse hex string from parameter
CTransaction origTx;
- if (!DecodeHexTx(origTx, params[0].get_str()))
+ if (!DecodeHexTx(origTx, params[0].get_str(), true))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
if (origTx.vout.size() == 0)
@@ -2491,6 +2570,7 @@ static const CRPCCommand commands[] =
{ "hidden", "resendwallettransactions", &resendwallettransactions, true },
{ "wallet", "abandontransaction", &abandontransaction, false },
{ "wallet", "addmultisigaddress", &addmultisigaddress, true },
+ { "wallet", "addwitnessaddress", &addwitnessaddress, true },
{ "wallet", "backupwallet", &backupwallet, true },
{ "wallet", "dumpprivkey", &dumpprivkey, true },
{ "wallet", "dumpwallet", &dumpwallet, true },
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 387b22358..c6c505898 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -27,7 +27,7 @@ typedef set<pair<const CWalletTx*,unsigned int> > CoinSet;
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
-static CWallet wallet;
+static const CWallet wallet;
static vector<COutput> vCoins;
static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
@@ -188,11 +188,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// empty the wallet and start again, now with fractions of a cent, to test small change avoidance
empty_wallet();
- add_coin(0.1*MIN_CHANGE);
- add_coin(0.2*MIN_CHANGE);
- add_coin(0.3*MIN_CHANGE);
- add_coin(0.4*MIN_CHANGE);
- add_coin(0.5*MIN_CHANGE);
+ add_coin(MIN_CHANGE * 1 / 10);
+ add_coin(MIN_CHANGE * 2 / 10);
+ add_coin(MIN_CHANGE * 3 / 10);
+ add_coin(MIN_CHANGE * 4 / 10);
+ add_coin(MIN_CHANGE * 5 / 10);
// try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
// we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
@@ -207,8 +207,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// if we add more small coins:
- add_coin(0.6*MIN_CHANGE);
- add_coin(0.7*MIN_CHANGE);
+ add_coin(MIN_CHANGE * 6 / 10);
+ add_coin(MIN_CHANGE * 7 / 10);
// and try again to make 1.0 * MIN_CHANGE
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
@@ -229,9 +229,9 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// sometimes it will fail, and so we use the next biggest coin:
empty_wallet();
- add_coin(0.5 * MIN_CHANGE);
- add_coin(0.6 * MIN_CHANGE);
- add_coin(0.7 * MIN_CHANGE);
+ add_coin(MIN_CHANGE * 5 / 10);
+ add_coin(MIN_CHANGE * 6 / 10);
+ add_coin(MIN_CHANGE * 7 / 10);
add_coin(1111 * MIN_CHANGE);
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin
@@ -239,9 +239,9 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0)
empty_wallet();
- add_coin(0.4 * MIN_CHANGE);
- add_coin(0.6 * MIN_CHANGE);
- add_coin(0.8 * MIN_CHANGE);
+ add_coin(MIN_CHANGE * 4 / 10);
+ add_coin(MIN_CHANGE * 6 / 10);
+ add_coin(MIN_CHANGE * 8 / 10);
add_coin(1111 * MIN_CHANGE);
BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount
@@ -249,17 +249,17 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// test avoiding small change
empty_wallet();
- add_coin(0.05 * MIN_CHANGE);
- add_coin(1 * MIN_CHANGE);
- add_coin(100 * MIN_CHANGE);
+ add_coin(MIN_CHANGE * 5 / 100);
+ add_coin(MIN_CHANGE * 1);
+ add_coin(MIN_CHANGE * 100);
// trying to make 100.01 from these three coins
- BOOST_CHECK( wallet.SelectCoinsMinConf(100.01 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 101.05 * MIN_CHANGE); // we should get all coins
+ BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
- BOOST_CHECK( wallet.SelectCoinsMinConf(99.9 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@@ -310,7 +310,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// add 75 cents in small change. not enough to make 90 cents,
// then try making 90 cents. there are multiple competing "smallest bigger" coins,
// one of which should be picked at random
- add_coin( 5*CENT); add_coin(10*CENT); add_coin(15*CENT); add_coin(20*CENT); add_coin(25*CENT);
+ add_coin(5 * CENT);
+ add_coin(10 * CENT);
+ add_coin(15 * CENT);
+ add_coin(20 * CENT);
+ add_coin(25 * CENT);
fails = 0;
for (int i = 0; i < RANDOM_REPEATS; i++)
@@ -345,20 +349,6 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
-
- empty_wallet();
-
- // Test trimming
- for (int i = 0; i < 100; i++)
- add_coin(10 * COIN);
- for (int i = 0; i < 100; i++)
- add_coin(1000 * COIN);
-
- BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
- // We need all 100 larger coins and exactly one small coin.
- // Superfluous small coins must be trimmed from the set:
- BOOST_CHECK_EQUAL(nValueRet, 100010 * COIN);
- BOOST_CHECK_EQUAL(setCoinsRet.size(), 101);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 723b2ecef..a0095ebd9 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1879,16 +1879,6 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
}
-
- //Reduces the approximate best subset by removing any inputs that are smaller than the surplus of nTotal beyond nTargetValue.
- for (unsigned int i = 0; i < vValue.size(); i++)
- {
- if (vfBest[i] && (nBest - vValue[i].first) >= nTargetValue )
- {
- vfBest[i] = false;
- nBest -= vValue[i].first;
- }
- }
}
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
@@ -2334,33 +2324,37 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
{
bool signSuccess;
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
- CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
+ SignatureData sigdata;
if (sign)
- signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes);
+ signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata);
else
- signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes);
+ signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata);
if (!signSuccess)
{
strFailReason = _("Signing transaction failed");
return false;
+ } else {
+ UpdateTransaction(txNew, nIn, sigdata);
}
+
nIn++;
}
- unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
+ unsigned int nBytes = GetVirtualTransactionSize(txNew);
// Remove scriptSigs if we used dummy signatures for fee calculation
if (!sign) {
BOOST_FOREACH (CTxIn& vin, txNew.vin)
vin.scriptSig = CScript();
+ txNew.wit.SetNull();
}
// Embed the constructed transaction data in wtxNew.
*static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
// Limit size
- if (nBytes >= MAX_STANDARD_TX_SIZE)
+ if (GetTransactionCost(txNew) >= MAX_STANDARD_TX_COST)
{
strFailReason = _("Transaction too large");
return false;
@@ -3209,7 +3203,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
- strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after bip32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
+ strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 71b0ff26d..d083722dd 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -7,6 +7,7 @@
#define BITCOIN_WALLET_WALLETDB_H
#include "amount.h"
+#include "primitives/transaction.h"
#include "wallet/db.h"
#include "key.h"