Skip to content

Commit

Permalink
Merge #9347: [0.13.2] wallet/rpc backports
Browse files Browse the repository at this point in the history
49a612f [qa] Don't set unknown rpcserialversion (MarcoFalke)
c365556 Complain when unknown rpcserialversion is specified (Pieter Wuille)
f5d606e Return txid even if ATMP fails for new transaction (Pieter Wuille)
35174a0 Make RelayWalletTransaction attempt to AcceptToMemoryPool. (Gregory Maxwell)
a0f7ece Update for OpenSSL 1.1 API (Gregory Maxwell)
43bcfca [Wallet] Bugfix: FRT: don't terminate when keypool is empty (Jonas Schnelli)
0cc07f8 [QA] add fundrawtransaction test on a locked wallet with empty keypool (Jonas Schnelli)
  • Loading branch information
laanwj committed Dec 19, 2016
2 parents 03b6f62 + 49a612f commit b711390
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 33 deletions.
17 changes: 17 additions & 0 deletions qa/rpc-tests/fundrawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,23 @@ def run_test(self):
self.is_network_split=False
self.sync_all()

# drain the keypool
self.nodes[1].getnewaddress()
inputs = []
outputs = {self.nodes[0].getnewaddress():1.1}
rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
# fund a transaction that requires a new key for the change output
# creating the key must be impossible because the wallet is locked
try:
fundedTx = self.nodes[1].fundrawtransaction(rawTx)
raise AssertionError("Wallet unlocked without passphrase")
except JSONRPCException as e:
assert('Keypool ran out' in e.error['message'])

#refill the keypool
self.nodes[1].walletpassphrase("test", 100)
self.nodes[1].walletlock()

try:
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
raise AssertionError("Wallet unlocked without passphrase")
Expand Down
3 changes: 1 addition & 2 deletions qa/rpc-tests/segwit.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def setup_chain(self):
def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness", "-rpcserialversion=0"]))
self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=2"]))
self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"]))
self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
connect_nodes(self.nodes[1], 0)
connect_nodes(self.nodes[2], 1)
Expand Down Expand Up @@ -215,7 +215,6 @@ def run_test(self):
assert_equal(len(segwit_tx_list), 5)

print("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
# Note: node1 has version 2, which is simply >0 and will catch future upgrades in tests
assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
for i in range(len(segwit_tx_list)):
Expand Down
5 changes: 4 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort()));
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy"));
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE));
strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(>0) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION));
strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION));
strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect"));
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
Expand Down Expand Up @@ -986,6 +986,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
return InitError("rpcserialversion must be non-negative.");

if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
return InitError("unknown rpcserialversion requested.");

nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);

fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
Expand Down
20 changes: 15 additions & 5 deletions src/qt/paymentrequestplus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,24 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
std::string data_to_verify; // Everything but the signature
rcopy.SerializeToString(&data_to_verify);

EVP_MD_CTX ctx;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context.");
#else
EVP_MD_CTX _ctx;
EVP_MD_CTX *ctx;
ctx = &_ctx;
#endif
EVP_PKEY *pubkey = X509_get_pubkey(signing_cert);
EVP_MD_CTX_init(&ctx);
if (!EVP_VerifyInit_ex(&ctx, digestAlgorithm, NULL) ||
!EVP_VerifyUpdate(&ctx, data_to_verify.data(), data_to_verify.size()) ||
!EVP_VerifyFinal(&ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) {
EVP_MD_CTX_init(ctx);
if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, NULL) ||
!EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) ||
!EVP_VerifyFinal(ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) {
throw SSLVerifyError("Bad signature, invalid payment request.");
}
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
EVP_MD_CTX_free(ctx);
#endif

// OpenSSL API for getting human printable strings from certs is baroque.
int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, NULL, 0);
Expand Down
32 changes: 20 additions & 12 deletions src/wallet/test/crypto_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,19 @@ bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char>
int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
vchCiphertext = std::vector<unsigned char> (nCLen);

EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();

if (!ctx) return false;

bool fOk = true;

EVP_CIPHER_CTX_init(&ctx);
if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
EVP_CIPHER_CTX_cleanup(&ctx);
EVP_CIPHER_CTX_init(ctx);
if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
EVP_CIPHER_CTX_cleanup(ctx);

EVP_CIPHER_CTX_free(ctx);

if (!fOk) return false;

Expand All @@ -66,15 +70,19 @@ bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial

vchPlaintext = CKeyingMaterial(nPLen);

EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();

if (!ctx) return false;

bool fOk = true;

EVP_CIPHER_CTX_init(&ctx);
if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
EVP_CIPHER_CTX_cleanup(&ctx);
EVP_CIPHER_CTX_init(ctx);
if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
EVP_CIPHER_CTX_cleanup(ctx);

EVP_CIPHER_CTX_free(ctx);

if (!fOk) return false;

Expand Down
30 changes: 18 additions & 12 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1442,16 +1442,19 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = *(item.second);

LOCK(mempool.cs);
wtx.AcceptToMemoryPool(false, maxTxFee);
CValidationState state;
wtx.AcceptToMemoryPool(false, maxTxFee, state);
}
}

bool CWalletTx::RelayWalletTransaction()
{
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0)
{
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
CValidationState state;
/* GetDepthInMainChain already catches known conflicts. */
if (InMempool() || AcceptToMemoryPool(false, maxTxFee, state)) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
RelayTransaction((CTransaction)*this);
return true;
Expand Down Expand Up @@ -2290,7 +2293,11 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CPubKey vchPubKey;
bool ret;
ret = reservekey.GetReservedKey(vchPubKey);
assert(ret); // should never fail, as we just unlocked
if (!ret)
{
strFailReason = _("Keypool ran out, please call keypoolrefill first");
return false;
}

scriptChange = GetScriptForDestination(vchPubKey.GetID());
}
Expand Down Expand Up @@ -2477,14 +2484,14 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)

if (fBroadcastTransactions)
{
CValidationState state;
// Broadcast
if (!wtxNew.AcceptToMemoryPool(false, maxTxFee))
{
// This must not fail. The transaction has already been signed and recorded.
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false;
if (!wtxNew.AcceptToMemoryPool(false, maxTxFee, state)) {
LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason());
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else {
wtxNew.RelayWalletTransaction();
}
wtxNew.RelayWalletTransaction();
}
}
return true;
Expand Down Expand Up @@ -3590,8 +3597,7 @@ int CMerkleTx::GetBlocksToMaturity() const
}


bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee, CValidationState& state)
{
CValidationState state;
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
}
2 changes: 1 addition & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class CMerkleTx : public CTransaction
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
int GetBlocksToMaturity() const;
/** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee);
bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee, CValidationState& state);
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
Expand Down

0 comments on commit b711390

Please sign in to comment.