Merge #9347: [0.13.2] wallet/rpc backports
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)
This commit is contained in:
commit
b711390895
|
@ -484,6 +484,23 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
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")
|
||||
|
|
|
@ -85,7 +85,7 @@ class SegWitTest(BitcoinTestFramework):
|
|||
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)
|
||||
|
@ -215,7 +215,6 @@ class SegWitTest(BitcoinTestFramework):
|
|||
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)):
|
||||
|
|
|
@ -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));
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ public:
|
|||
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; }
|
||||
|
|
Loading…
Reference in New Issue