-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Drop checkFinalTx and use Median Time Past to check finality of wallet transactions #17443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
jonatack
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for beginning with nits rather than concept review as I lack the time today to review this properly. A few grammar suggestions for clarity, if the fundamental changes are correct.
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK c9609737208a238984717d16e13f770ea350bb95. This seems like a good change because it should make checkFinalTx more accurate given current consensus rules, and also because it should make IsTrusted more conservative. Two suggestions for followup here or a later PR:
-
It could be good to add a new test for
CWallet::IsTrustedsetting a mock time and covering this edge case. I think this should not be too hard to implement as either a c++ or a python test -
Especially with #16426, I wonder if it would be better to delete the
interfaces::Chain::checkFinalTxmethod, and instead add aCWallet::CheckFinalTxmethod callingIsFinalTxwithm_last_block_processedheight and time, so the wallet uses a consistent tip and there aren't race conditions when the tip is changing. I previously suggested this in #16426 (comment)). This could also be added as another Chain interface TODO item if it is not worth the effort to implement now.
c960973 to
3af0df2
Compare
|
@ryanofsky Thanks for review! I went ahead on replaced About testing, I think a bit about it, it's quite hard because contrary to the consensus code where finality enforcement is going to change after softfork activation, wallet is always using current finality consensus rules. So that would need to have 2 versions of the wallet. I think that's an issue already known of our current wallet test framework.. |
3af0df2 to
01377a5
Compare
|
01377a5 Moved |
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 01377a55545beb03c6c0033f4bea483338855880 modulo some new travis failures in miner_tests.cpp. Various suggested changes since last review (thanks!)
01377a5 to
6fb938c
Compare
ariard
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for review @ryanofsky! Updated at 6fb938c with fixing travis build failure.
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 6fb938c78d1fed9e460775f772e276b473075965. No change since last review other than fixing travis include error. There is still a remaining travis error though:
wallet/wallet.cpp:3999:26: error: reading variable 'm_last_block_processed_height' requires holding mutex 'cs_wallet' [-Werror,-Wthread-safety-analysis]
return IsFinalTx(tx, m_last_block_processed_height + 1, m_last_block_median_time_past);
6fb938c to
6e10c40
Compare
6e10c40 to
ec73698
Compare
|
Updated bbdc8b5, extended both |
bbdc8b5 to
fa5b990
Compare
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conditional code review ACK fa5b990647baf7184d1fd610f9a747be3ed46127 if the NO_THREAD_SAFETY_ANALYSIS annotations can be removed, or at least documented (see comment below). Only changes since the last review are adding the annotations and fixing up some comments in the third commit message.
src/wallet/wallet.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Replace Chain::checkFinal by CWallet::CheckFinalWalletTx" (1f479751b2eaf6f17ae76334b72ebc5fd76d8956)
I think it'd be safer to just add AssertLockHeld statements if the compiler can't determine that a particular lock is held, than to disable safety analysis altogether. On my system, the following changes seem to work:
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 9d291f0b585..c702f90681d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1882,6 +1882,7 @@ bool CWalletTx::IsTrusted(interfaces::Chain::Lock& locked_chain) const
bool CWalletTx::IsTrusted(interfaces::Chain::Lock& locked_chain, std::set<uint256>& trusted_parents) const
{
// Quick answer in most cases
+ AssertLockHeld(pwallet->cs_wallet);
if (!pwallet->CheckFinalWalletTx(*tx)) return false;
int nDepth = GetDepthInMainChain();
if (nDepth >= 1) return true;
@@ -3967,6 +3968,7 @@ bool CWalletTx::IsImmatureCoinBase() const
bool CWalletTx::isFinal() const
{
+ AssertLockHeld(pwallet->cs_wallet);
return pwallet->CheckFinalWalletTx(*tx);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index acf0de45f1c..4ae39ba328a 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -477,8 +477,8 @@ public:
bool IsEquivalentTo(const CWalletTx& tx) const;
bool InMempool() const;
- bool IsTrusted(interfaces::Chain::Lock& locked_chain) const NO_THREAD_SAFETY_ANALYSIS;
- bool IsTrusted(interfaces::Chain::Lock& locked_chain, std::set<uint256>& trusted_parents) const NO_THREAD_SAFETY_ANALYSIS;
+ bool IsTrusted(interfaces::Chain::Lock& locked_chain) const;
+ bool IsTrusted(interfaces::Chain::Lock& locked_chain, std::set<uint256>& trusted_parents) const;
int64_t GetTxTime() const;
@@ -531,7 +531,7 @@ public:
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
bool IsImmatureCoinBase() const;
- bool isFinal() const NO_THREAD_SAFETY_ANALYSIS;
+ bool isFinal() const;
};
class COutput6e10c40e9507c2ff45d47ca863778fff85584b36
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you test on a Linux ? IIRC clang static analysis only work on MacOS. AssertLockHeld is lock checking at runtime
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you test on a Linux ? IIRC clang static analysis only work on MacOS.
AssertLockHeldis lock checking at runtime
AssertLockHeld does affect static analysis, because it sets the assert_exclusive_lock attribute, see https://clang.llvm.org/docs/ThreadSafetyAnalysis.html. I am testing on linux, and I am using clang and have static analysis enabled. The following change works fine for me with the asserts added, so still think NO_THREAD_SAFETY_ANALYSIS annotations are unneeded.
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -481,12 +481,12 @@ public:
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
// having to resolve the issue of member access into incomplete type CWallet.
- bool IsTrusted(interfaces::Chain::Lock& locked_chain) const NO_THREAD_SAFETY_ANALYSIS;
+ bool IsTrusted(interfaces::Chain::Lock& locked_chain) const;
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
// having to resolve the issue of member access into incomplete type CWallet.
- bool IsTrusted(interfaces::Chain::Lock& locked_chain, std::set<uint256>& trusted_parents) const NO_THREAD_SAFETY_ANALYSIS;
+ bool IsTrusted(interfaces::Chain::Lock& locked_chain, std::set<uint256>& trusted_parents) const;
int64_t GetTxTime() const;
@@ -543,7 +543,7 @@ public:
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
// having to resolve the issue of member access into incomplete type CWallet.
- bool isFinal() const NO_THREAD_SAFETY_ANALYSIS;
+ bool isFinal() const;
};fa5b990 to
9afb8dd
Compare
ariard
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated at 9afb8dd, thanks to your suggestions @ryanofsky, AssertLockHeld being disabled with default flags it's not going to be a performance hit, but will hit deadlock in Travis.
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 9afb8ddd1d9406a623d209bc5a4a5e955f0b806c. Only change since last review is to lock assertions, annotations, and comments
fjahr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 9afb8ddd1d9406a623d209bc5a4a5e955f0b806c
Reviewed code and ran tests locally. I think it's a good change both as an incremental step for wallet/node separation and for the fix on CheckFinalTx usage.
Just some grammar nits in a comment block. And, if you get around to it, I also saw two typos in the commit messages:
70cc88fa8bfcb3032ee8d63120921b8448b10e8e => mediam
f50723670e104457c21ca8b214e0b46bf6d23df2 => misuage
9afb8dd to
ba18c2c
Compare
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK b14e07b227f3830120e97f44b3d6ece55bf700c6. Just rebased since previous review
jonatack
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK / almost ACK b14e07b227f3830120e9 but this seems unfinished. The diff isn't large; best to not add TODOs and debt for later that can be done here, tie off the loose ends like #17443 (comment), and take care in the writing of the code docs and commit messages. Could use a test to be confident it's not adding a regression.
src/consensus/tx_check.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a20187d suggestion while moving this code
-bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
+bool IsFinalTx(const CTransaction& tx, int nBlockHeight, int64_t nBlockTime)
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice improvement here!
b14e07b to
808dc17
Compare
|
Thanks @ryanofsky and @jonatack for reviews, took most of your suggestion, specially with better comment for top message commit. |
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 808dc174b14fb7504c74a818ecaa2399258cf94e. Changes since last review: updating findBlock calls mostly as suggested (still not raising error on failure), updating commit messages, comments, thread annotations
src/wallet/wallet.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[wallet] Replace Chain::checkFinal by CWallet::CheckFinalWalletTx" (03870881969b12d8023716897ff674ec6ec3568e)
Travis error here:
In file included from interfaces/wallet.cpp:24:
./wallet/wallet.h:558:51: error: use of undeclared identifier 'cs_wallet'; did you mean 'pwallet'?
bool isFinal() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
^~~~~~~~~
pwallet
./threadsafety.h:31:79: note: expanded from macro 'EXCLUSIVE_LOCKS_REQUIRED'
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
^
./wallet/wallet.h:272:20: note: 'pwallet' declared here
const CWallet* pwallet;
Probably needs to say pwallet->cs_wallet not just cs_wallet
I wonder @ariard if you're able to test lock annotations locally since these errors seem to come up a lot. It shouldn't be hard to enable them. I just configure with ./configure CXX=clang++ --enable-debug --enable-werror for these
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing the same messages while building locally, the gcc 8.3 build is fine but the clang 6.0 debug/werror build errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Building with pwallet->cs_wallet halts with
./wallet/wallet.h:558:58: error: member access into incomplete type 'const CWallet'
bool isFinal() const EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet);
^
./wallet/fees.h:13:7: note: forward declaration of 'CWallet'
class CWallet;
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jonatack @ryanofsky You right I didn't the warning at first, was compiling with gcc locally. Okay in fact the issue hasn't been solved wrt to NO_THREAD_SAFETY_ANALYSIS.
Isn't the way to solve it cleanly would be to get CWalletTx its own lock instead of requiring CWallet one ? I don't see a better way to solve dependency declaration..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated dropping isFinal accessor on the advice of @ryanofsky
|
re-almost ACK 808dc17 the changes per |
|
I also see the build error locally (I use clang by default). Code looks good but will wait with a full review until the fix is up. |
Context-independent IsFinalTx doesn't rely on chain or mempool state so moving it to tx_check let it being used by wallet code without linking server code in following commits.
Extend Notifications::BlockConnected/BlockDisconnected with median_time_past parameter. Used in next commit.
By caching tip median time-past, wallet can do transactions finality calculation without accessing chain state. Fix misuage of CheckFinalTx, which was called with default flags argument by implementation of Chain::checkFinal, triggering finality evaluation based on GetAdjustedTime instead of consensus and standard rules of BIP 113.
nBlockTime semantic is selected using a bit-flags corresponding to current soft-fork rules. Comment around this bit-flags was previously ambiguous meaning that not soft-fork rules affecting nBlockTime was currently active, which is false since BIP113 deployement.
808dc17 to
d55ba31
Compare
|
Rebased and updated with fix at d55ba31. Thanks for your patience! |
|
🐙 This pull request conflicts with the target branch and needs rebase. |
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK d55ba31. No significant changes since last review, just replaced wtx.isFinal calls with wallet.CheckFinalWalletTx to work around thread annotation problems
| if (tip_height) { | ||
| walletInstance->m_last_block_processed = chain.getBlockHash(*tip_height); | ||
| walletInstance->m_last_block_processed_height = *tip_height; | ||
| chain.findBlock(walletInstance->m_last_block_processed, FoundBlock().mtpTime(walletInstance->m_last_block_median_time_past)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[wallet] Add m_last_block_mediam_time_past in CWallet" (1d2345b)
Suggest using CHECK_NONFATAL(chain.findBlock...) to catch a failure early if chain.findBlock returns not found for some reason
There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
1 similar comment
There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
|
If there is anything relevant that I missed, I think it might be best to open a fresh pull request. |
|
I agree this PR is not relevant anymore in its substantial parts. |
Replace
Chain::checkFinalTxbyCheckFinalWalletTxby caching best block median time past which is following BIP113 rule than time-locked transactions have nLockTime set to less than the median time of the previous block they're contained in.Fix misuage of CheckFinalTx, which was called with default flags
argument by implementation of Chain::checkFinal, triggering
finality evaluation based on GetAdjustedTime instead of consensus
and standard rules of BIP 113.
I think it should have been set at same time than d1c3762, to align wallet checks on the mempool ones.