-
Notifications
You must be signed in to change notification settings - Fork 102
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
server: app config and asset drivers system #81
Conversation
Related to this work: Plugin-style asset backends are still a goal. From the little bit I've played with them, I think it'll be easier to start that work once we have a tagged |
b8a2441
to
5617e7c
Compare
d3250d0
to
d3a84cb
Compare
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.
There is a good deal of unfinished work here, primarily around the DEX manager and the handling of the subsystems it starts and is supposed to be managing, but there is a lot that is ready for review and should be merged.
"decred.org/dcrdex/dex" | ||
dexsrv "decred.org/dcrdex/server/dex" |
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.
Renaming "decred.org/dcrdex/server/dex" might be desirable.
// privkeyFile, err := os.OpenFile("dexprivkey.pem", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) | ||
// if err != nil { | ||
// return err | ||
// } | ||
// defer privkeyFile.Close() | ||
|
||
// err = pem.Encode(privkeyFile, &pem.Block{ | ||
// Type: "EC PRIVATE KEY", | ||
// Bytes: secPrivKey.Serialize(), | ||
// }) | ||
// if err != nil { | ||
// return err | ||
// } | ||
|
||
err = ioutil.WriteFile("dexprivkey", secPrivKey.Serialize(), 0600) | ||
if err != nil { | ||
return err | ||
} |
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.
It would be nice if the openssl command could be used to generate the secp256k1 keys in a format the dcrdex can read. We can read PEM, but the way openssl encodes the curve parameters and the public key in the same element is not clear to me yet. We would also want to write in a similar way so openssl could inspect the keys. This will take more work and it's not a show stopper, so I've just fallen back to unstructured binary files.
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.
cspp does this so I will look into the approach there and follow up on this.
epochNote.Seq = seq | ||
epochNote.MarketID = book.name | ||
t := uint64(u.order.Time()) | ||
epochNote.Epoch = t - t%r.epochLen | ||
epochNote.Epoch = uint64(u.epochIdx) |
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.
The source of the order feed knows this info, so now we just send it so the BookRouter does not have to know epoch durations or inspect order time stamps.
auth AuthManager | ||
assets map[uint32]*asset.BackedAsset | ||
tunnels map[string]MarketTunnel | ||
mbBuffer float64 |
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.
Provided by the market's MarketTunnel now.
Send(account.AccountID, *msgjson.Message) | ||
Request(account.AccountID, *msgjson.Message, func(comms.Link, *msgjson.Message)) | ||
Penalize(account.AccountID, *order.Match, order.MatchStatus) |
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.
The reason for providing order.Match and order.MatchStatus isn't clear, but the implementation in the auth
package just requires the account.Rule
.
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.
It's not clear to me what will be needed here either. Good for now.
1ee15ae
to
531b152
Compare
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.
It's Alive!!!
This review is just a first pass, but it's looking really good.
var wg sync.WaitGroup | ||
shutdown := func() { | ||
cancel() | ||
wg.Wait() | ||
} | ||
wg.Add(1) | ||
go func() { | ||
btc.Run(ctx) | ||
wg.Done() | ||
}() |
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.
Does it make sense to use a StartStopWaiter
here and in tests in general?
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.
I was sort of using the test as an example of direct usage without StartStopWaiter, but I suppose the type itself is the example.
server/asset/dcr/dcr.go
Outdated
@@ -155,6 +165,15 @@ func (dcr *DCRBackend) CheckAddress(addr string) bool { | |||
return err == nil | |||
} | |||
|
|||
func (dcr *DCRBackend) UnspentCoinDetails(coinID []byte) (addr string, val uint64, confs int64, err error) { |
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.
UnspentDetails
was just a guess, and it's now unused other than here and a test. You can just change the method signature instead of wrapping it.
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.
Unless you object, I think it would be good to keep the UTXO version available although obv not part of the DEXAsset interface. ba76c77 docs UnspentCoinDetails, tests it directly, and renames UnspentDetails to UTXODetails.
I just restored several commits that I accidentally nuked when rebasing. |
0382458
to
25ef991
Compare
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.
Second pass. Looking good.
server/market/market.go
Outdated
// WaitForEpochOpen waits until the start of epoch processing. | ||
func (m *Market) WaitForEpochOpen() { | ||
<-m.running | ||
} |
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.
This appears to be used for testing only. Looks like it can be unexported at least.
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.
My initial thought was it would be helpful to delay the startup of other subsystems such as the comms.Server or perhaps the BookRouter, but really the OrderRouter will get error messages back from the Market's epoch processing loop that would be just as good as what the OrderRouter would provide to the client if it had known the market(s) were not yet running before submitting the orders for processing.
Delaying the start of the Server might be helpful eventually but I also don't think that's critical.
unexporting as suggested.
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.
Just the pprof issue and it's a go for me.
bookSources := make(map[string]market.BookSource, len(cfg.Markets)) | ||
marketTunnels := make(map[string]market.MarketTunnel, len(cfg.Markets)) |
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.
I'm considering changing the OrderRouterConfig.Markets
field and NewBookRouter
argument to []*Market
and just converting to the MarketTunnel
and BookSource
interfaces internally. I can follow up.
// return err | ||
// } | ||
|
||
err = ioutil.WriteFile("dexprivkey", secPrivKey.Serialize(), 0600) |
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.
What do you think about adding a network identifier to the filename?
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.
Possibly, although all of this key management is going to change. But my thoughts about genkey are that you'd run it and them move/rename it to wherever depending on your needs. I'd like to revisit this idea when we code up encrypted keys properly.
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.
I guess it's actually the regfeexpub
that is network-versioned. The private key is fine.
server/cmd/dcrdex/config.go
Outdated
HTTPProfile bool `long:"httpprof" short:"p" description:"Start HTTP profiler."` | ||
HTTPProfPath string `long:"httpprofprefix" description:"URL path prefix for the HTTP profiler."` | ||
CPUProfile string `long:"cpuprofile" description:"File for CPU profiling."` |
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.
Description of default behavior would be helpful, e.g. port 9232
Also, when I try to set httpprofprefix
, I get some kind of recursion issue.
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.
Ah, this doesn't work with http.DefaultServeMux
. I'm removing HTTPProfPath
since it was of limited use.
server/cmd/dcrdex/main.go
Outdated
profPath := opts.HTTPProfPath | ||
log.Warnf("Starting the HTTP profiler on path %s.", profPath) | ||
// http pprof uses http.DefaultServeMux | ||
http.Handle("/", http.RedirectHandler(profPath+"/debug/pprof/", http.StatusSeeOther)) |
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.
Does profPath
need to be applied to the first argument here too?
server/dex package with the DEX (manager) type that starts and manages all of the server subsystems. Notable changes: - Create a DEX type in the new decred.org/dcrdex/server/dex package. - Create a driver system for the asset package and the different backends (drivers). This allows the main app (or a future dex package) to enable backends by name. This is similar to how sql drivers are implemented in and for the "database/sql" standard lib. - Create a similar driver system for the db package. - Define the structure of markets.json and create a parser, loadMarkets. - Introduce the dcrdex CLI app. - Introduce the dex.Runner interface that all DEX subsystems must implement with a Run(context.Context) method - Introduce the dex.StartStopWaiter type, which wraps a dex.Runner to provide the familiar Start/Stop/WaitForShutdown methods. - Change all server subsystems to dex.Runners. - Add db/driver/pg.ActiveMatches to get all active swaps for a given user. This is used by the AuthManager for the client connect message. - Add the MarketBuyBuffer setting to each MarketInfo as this can be different for each market. - Similarly allow epoch duration to be different for each Market. - Implement server/asset/dcr.UnspentCoinDetails for FeeChecker. - Several fixes for the outpoint=>coinID changes, and other interface-implementation mismatches such as swap.AuthManager.Penalize and MarketTunnel.CoinLocked. - Add Close() to DEXArchivist interface. - Add epochIdx to bookUpdateSignal so that the BookRouter does not need to compute the epoch index from server time and an epoch duration. - dex package: add Network.String and NetFromString - Remove dex.Asset.SwapSize - coinlock: Add (*DEXCoinLocker).AssetLocker - Remove the Time field from msgjson.Match and order.UserMatch - market: Remove EpochDuration from BookRouterConfig. Epoch duration may be set per-market. Add epochIdx to bookUpdateSignal, and set bookUpdateSignal.epochIdx in Market.notifyNewOrder. The epochIdx is only used in BookRouter for epochAction (not book and unbookAction). Include mbBuffer and epoch dur in market config. - market: Add EpochDuration() to MarketTunnel. - Remove startEpoch from connect response and AuthManager config. The start epoch for a market must be provided in the 'config' route response (handler not yet implemented). - market: Start at the next epoch by default. - matcher: Avoid seeding a PRNG if len(queue)<2. - btc: Add a note about reorg detection and move a log line. - Reduce reg fee confirm requirement from 6 to 4. Note about the Run(ctx) pattern and dex.StartStopWaiter: Instead of NewMarket starting the main loop in a goroutine automatically this creates Run, SetStartEpochIdx, and Start (wrapping the former). Run and Start are synchronous, so they should be launched inside goroutines (not as goroutines) defined by the caller. A context is passed to Run/Start rather than the constructor. The Market is stopped by cancelling the context.Context. A context.Context and context.CancelFun are no longer Market fields; they are passed around in a somewhat tedious but idiomatic fasion that I fought against initially and now reluctantly accept. Most subsystems are changed into dex.Runners.
NOTE: The key storage scheme still needs to be implemented properly with encryption and/or PEM encoding! Add a CLI app server/cmd/genkey for generating a public and private key for dex message signing, dumping them to unstructured binary files. The private key is used by DEX.
The primary changes in this PR are:
DEX
type in the newdecred.org/dcrdex/server/dex
package.asset
package and the different backends (drivers). This allows the main app (or a futuredex
package) to enable backends by name. This is similar to how sql drivers are implemented in and for the "database/sql" standard lib.db
package.loadMarkets
).dcrdex
CLI app.dex.Runner
interface that all DEX subsystems must implement with aRun(context.Context)
methoddex.StartStopWaiter
type, which wraps adex.Runner
to provide the familiar Start/Stop/WaitForShutdown methods.dex.Runner
s.db/driver/pg.ActiveMatches
to get all active swaps for a given user. This is used by theAuthManager
for the client connect message.comms.Link
as an input argument toauth.respHandler.f
to match the handler in otherRequest
functions.server/cmd/genkey
for generating a public and private key for dex message signing, dumping them to unstructured binary files. The private key is used byDEX
. NOTE: The key storage scheme still needs to be implemented properly with encryption and/or PEM encoding.MarketBuyBuffer
setting to eachMarketInfo
as this can be different for each market.Market
.epochIdx
tobookUpdateSignal
so that theBookRouter
does not need to compute the epoch index from server time and an epoch duration.