core: fix locktime handling#438
Conversation
| lockTime := matchTime.Add(time.Hour * 24).UTC().Unix() | ||
| if dbMatch.Side == order.Maker { | ||
| proof.Secret = encode.RandomBytes(32) | ||
| secretHash := sha256.Sum256(proof.Secret) | ||
| proof.SecretHash = secretHash[:] | ||
| lockTime = matchTime.Add(time.Hour * 48).UTC().Unix() |
There was a problem hiding this comment.
Yikes good catch. But I feel like we should have these two constant times somewhere in a common server-client package (no law that says these couldn't be 2 hr / 4 hr).
There was a problem hiding this comment.
I actually thought about making them DEX cfg variables.
There was a problem hiding this comment.
no law that says these couldn't be 2 hr / 4 hr
They need to guarantee (probabilistically) SwapConf confirmations within the taker's locktime. And since SwapConf is a variable, we need to be generous.
There was a problem hiding this comment.
Regarding making these constants, one reason I had in mind for making them dex cfg variables is to enable testing refund scenarios in #432.
An alternative would be declaring as var instead of const so the test code can change the values to something much shorter for test purposes.
A couple other reasons to consider making the locktimes dex cfg variables:
- If we make them dex cfg variables, it'd be easier for clients to know what's expected in terms of swap locktimes (just check the dex cfg to know what locktime to set). Short of that, we'd need to add those values to the spec so all parties know what's expected.
- Since
swapConfis a dex cfg variable, it'd also make sense to make the locktime similarly variable and we could add some validation code to ensure that the set locktimes are sane and generous.
There was a problem hiding this comment.
@itswisdomagain You make some good arguments for making lock times config settings. Let's consider that for future work.
|
@JoeGruffins Check the server logs please, if this is your local server. The error indicates that a response message from your client had a msg ID that did not match one of the known server initiated requests IDs. There is a preimage collection bug fixed in 700e145, but I don't think that's what happened. |
|
server logs: |
|
Are you able to reproduce this, @JoeGruffins? |
|
Smells like a bug, maybe a race, with the comms or auth routers registering a handler keyed by request id vs. a response coming back too fast. I didn't come across anything fishy though. |
|
I have not been able to reproduce that specific error yet, but I have been able to get "ghost orders" another way. Just firing them off pretty fast using dexcctl, I started getting this error: |
|
I have reproduced the COMMS error on master, just making a lot of orders. I'm not sure why it is happening sometimes. documented in #446 |
There was a problem hiding this comment.
Looks good, but I noticed a discrepancy in the 'match' route payload field names from the spec vs msgjson.Match, namely it's tserver in the struct tag and timestamp in the spec. The fields are also out of order, but that doesn't really matter. We can either revise the struct tags or sneak in a spec fix since it's not substantial. Either way, I feel like it would be a good idea to revise the spec's description of the time stamp to explicitly state that the lock times should be derived from that time. Maybe even refer to the 'match' payload from the atomic swap section of the spec.
| lockTime := matchTime.Add(dex.LockTimeTaker).UTC().Unix() | ||
| if dbMatch.Side == order.Maker { | ||
| proof.Secret = encode.RandomBytes(32) | ||
| secretHash := sha256.Sum256(proof.Secret) | ||
| proof.SecretHash = secretHash[:] | ||
| lockTime = matchTime.Add(dex.LockTimeMaker).UTC().Unix() |
There was a problem hiding this comment.
Regarding spec clarifications, I think we should also formalize the ms -> second translation of lock time from the match time. Seems to be a round down.
|
I've got a spec tweaks roundup branch working where I'll address the spec changes. |
| auth.AuditSig = audit.Sig | ||
| proof.CounterScript = audit.Contract | ||
| matchTime := encode.UnixTimeMilli(int64(auth.MatchStamp)) | ||
| reqLockTime := matchTime.Add(dex.LockTimeMaker).Truncate(time.Millisecond) // counterparty = maker, their locktime = 48 hours. |
There was a problem hiding this comment.
Shouldn't reqLockTime be second resolution, not millisecond?
Also, I feel like both client and server should perhaps be using the same function like NextSecond from dex or a common package to take a time or a ms stamp and return the next second. That way they can both be guaranteed to do the same thing with the match stamp.
There was a problem hiding this comment.
Shouldn't reqLockTime be second resolution, not millisecond?
Of course it should.
Also, I feel like both client and server should perhaps be using the same function like
NextSecondfromdexor a common package to take a time or a ms stamp and return the next second. That way they can both be guaranteed to do the same thing with the match stamp.
I'm not understanding the use of "next" here. Won't truncate be the "previous" second?
There was a problem hiding this comment.
"next" meaning the ceil operation or the opposite of truncate, round up I guess. But as long as everything is consistent it doesn't matter which direction up/down and I see that 9b39f6f makes it super clear now
i.e. in swap.go we now have
reqLockTime = encode.DropMilliseconds(stepInfo.match.matchTime.Add(dex.LockTimeMaker))and in client/core/trade.go we have
reqLockTime := encode.DropMilliseconds(matchTime.Add(dex.LockTimeMaker))which makes it super clear that the same thing is computed on both ends.


Locktime was not being set correctly. The server intentionally sets the
msgjson.Match.ServerTimebased on the match epoch so that locktime can be based off of a common point for both maker and taker. Plus, taker wasn't setting their locktime correctly when constructing the contract, which is now fixed.