Skip to content
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

client/trade: Return counterPartyConfirms error. #1595

Merged
merged 1 commit into from
Apr 28, 2022

Conversation

JoeGruffins
Copy link
Member

Because the return data cannot all be trusted if the method has an
error, return that error up to the caller rather than just logging and
returning with possibly false values.

For swaps using contracts it is ok for the swap to be status none, in
which case we cannot check the lock time or confirmations on chain yet.
Do not log an error in this case.

Checking the eth locktime would fail because expire was set to true even though checking the locktime failed. This error was not as helpful as the real error would have been. Also, there is no reason to log an error if the swap has not been mined because we cannot know anything about the counter party's swap without the on chain data.

@JoeGruffins
Copy link
Member Author

I really though I was on to something and reproducing #1561 , but it turns out it was just this. I am able to trade with short locktimes now. Yet unable to cause the init failures on demand. Or maybe it's just fixed for some reason.

@chappjc
Copy link
Member

chappjc commented Apr 25, 2022

Interesting. Makes perfect sense. I think I made this bug BTW.

You must have been seeing Counter-party's swap expired before we could broadcast our own logged before because the expired bool was true even though it didn't really know? Certainly looks like that could have happened without this change, as you said. That would be particularly problematic because in that case it switched match.MetaData.Proof.SelfRevoked = true

Thoughts if this bug can affect btc/dcr etc or just eth? Might need to put this bug fix in 0.4.3 since 79ccdd8 is on that branch. EDIT: looks like only with eth does it actually have to find the swap for LocktimeExpired to work, but still should get this fix in because if LocktimeExpired fails for any other reason (transient node RPC error), it would self-revoke!

Copy link
Member

@chappjc chappjc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent catch! And not too soon since this fix should get in 0.4.3. I definitely created this in #1548.

if !errors.Is(err, asset.ErrSwapNotInitiated) {
// No need to log an error if swap not initiated as this
// is expected for newly made swaps involving contracts.
t.dc.log.Errorf("Failed to get confirmations of the counter-party's swap %s (%s) "+
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static text part of this error is now mostly redundant since caller now has t.dc.log.Errorf("isSwappable: unable to get counter party confirms: %v", err) (or a variation with isRedeemable).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chappjc chappjc added this to the 0.4.3 milestone Apr 25, 2022
@JoeGruffins
Copy link
Member Author

Just rebased.

Because the return data cannot all be trusted if the method has an
error, return that error up to the caller rather than just logging and
returning with possibly false values.

For swaps using contracts it is ok for the swap to be status none, in
which case we cannot check the lock time or confirmations on chain yet.
Do not log an error in this case.
coin, t.wallets.toAsset.Symbol, match, t.UID(), err)
}
return
return fail(fmt.Errorf("failed to get confirmations of the counter-party's swap %s (%s) "+
"for match %s, order %v: %w",
coin, t.wallets.toAsset.Symbol, match, t.UID(), err))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we only return an error if !errors.Is(err, asset.ErrSwapNotInitiated)? Otherwise, just call it zero confs. That would capture the behavior from before, and this part doesn't appear to be related to the bug you're fixing.

Copy link
Member

@chappjc chappjc Apr 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, but the LocktimeExpired call above would have to error on ErrSwapNotInitiated because the zero-value for lockTime returned on error would be interpreted as "expired". Which means it would never be ErrSwapNotInitiated down here because it would have been so above (for ETH at least).

An alternative might be to change the expired logic to expired = !lockTime.IsZero() && time.Until(lockTime) < 0 so it never says expired=true when the lockTime is the zero value as is the case when LocktimeExpired has an error. But I think I agree with Joe's conclusion that bubbling up an error is the least error prone way to keep the caller from jumping to conclusions about the actual state of the contract when it is actually unknown.

If you have a specific diff @buck54321 we could talk over that? I would like to get this fix in today in one form or another, and we could push a commit onto this PR if there's a revision that looks good.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, but the LocktimeExpired call above would have to error on ErrSwapNotInitiated

I'm not suggesting changing anything up there. Just here to match previous behavior that wasn't broken.

Copy link
Member

@chappjc chappjc Apr 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand, but I'm saying "Which means it would never be ErrSwapNotInitiated down here because it would have been so above (for ETH at least)."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I must be misunderstanding your comment "only return an error if !errors.Is(err, asset.ErrSwapNotInitiated)". Because when I mentally apply the suggestion, it would return for any error like it is in the present revision of this PR because it can't be ErrSwapNotInitiated because we're now catching it above (same contract call inside wallet.LocktimeExpired).
Apologies if I'm being dense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're saying now. The ErrSwapNotInitiated check down here is pointless then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, eth should have already failed. I was going to do something like that at first, but after I was about to submit that pr I decided to do a little more that seems right to me and also fixes the bug. The returns should not be trusted if their is an error checking any of them, and the caller should be informed as of the reason of failure. The failure isn't that we are past locktime, the failure is that we couldn't check the locktime.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo was an easy bug to happen because of method design. Seeing the same thing in #1599 should just return errors and nil values on failure.

@chappjc chappjc merged commit c3327ea into decred:master Apr 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants