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

server: app config and asset drivers system #81

Merged
merged 2 commits into from
Jan 15, 2020

Conversation

chappjc
Copy link
Member

@chappjc chappjc commented Nov 18, 2019

The primary changes in this PR are:

  • 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 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 comms.Link as an input argument to auth.respHandler.f to match the handler in other Request functions.
  • 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. NOTE: The key storage scheme still needs to be implemented properly with encryption and/or PEM encoding.
  • 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.
  • Remove the Time field from order.UserMatch and msgjson.Match.

@chappjc chappjc changed the title Server app server: app config and asset drivers system Nov 18, 2019
server/cmd/dcrdex/main.go Outdated Show resolved Hide resolved
@buck54321
Copy link
Member

buck54321 commented Dec 6, 2019

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 /server/asset/ module for the plugins to import, and probably a couple of dcrd dependency versions will have to be locked down too.

@chappjc chappjc force-pushed the server-app branch 3 times, most recently from b8a2441 to 5617e7c Compare December 20, 2019 20:41
server/dex/dex.go Outdated Show resolved Hide resolved
server/dex/dex.go Outdated Show resolved Hide resolved
server/dex/dex.go Outdated Show resolved Hide resolved
@chappjc chappjc force-pushed the server-app branch 2 times, most recently from d3250d0 to d3a84cb Compare January 1, 2020 15:08
Copy link
Member Author

@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.

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.

Comment on lines +15 to +16
"decred.org/dcrdex/dex"
dexsrv "decred.org/dcrdex/server/dex"
Copy link
Member Author

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.

Comment on lines +16 to +33
// 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
}
Copy link
Member Author

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.

Copy link
Member Author

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)
Copy link
Member Author

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
Copy link
Member Author

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)
Copy link
Member Author

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.

Copy link
Member

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.

@chappjc chappjc marked this pull request as ready for review January 2, 2020 16:41
server/dex/dex.go Outdated Show resolved Hide resolved
@chappjc chappjc force-pushed the server-app branch 2 times, most recently from 1ee15ae to 531b152 Compare January 6, 2020 17:36
Copy link
Member

@buck54321 buck54321 left a 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.

server/asset/btc/btc.go Outdated Show resolved Hide resolved
dex/market.go Show resolved Hide resolved
server/asset/btc/btc.go Outdated Show resolved Hide resolved
Comment on lines +706 to +718
var wg sync.WaitGroup
shutdown := func() {
cancel()
wg.Wait()
}
wg.Add(1)
go func() {
btc.Run(ctx)
wg.Done()
}()
Copy link
Member

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?

Copy link
Member Author

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.

@@ -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) {
Copy link
Member

@buck54321 buck54321 Jan 7, 2020

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.

Copy link
Member Author

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.

server/dex/dex.go Outdated Show resolved Hide resolved
server/dex/dex.go Outdated Show resolved Hide resolved
server/dex/dex.go Outdated Show resolved Hide resolved
server/market/market.go Outdated Show resolved Hide resolved
server/cmd/dcrdex/main.go Outdated Show resolved Hide resolved
server/market/market_test.go Outdated Show resolved Hide resolved
server/cmd/dcrdex/config.go Outdated Show resolved Hide resolved
server/cmd/dcrdex/config.go Outdated Show resolved Hide resolved
@chappjc
Copy link
Member Author

chappjc commented Jan 8, 2020

I just restored several commits that I accidentally nuked when rebasing.

@chappjc chappjc force-pushed the server-app branch 2 times, most recently from 0382458 to 25ef991 Compare January 13, 2020 16:14
@chappjc chappjc requested a review from buck54321 January 13, 2020 16:17
Copy link
Member

@buck54321 buck54321 left a 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/asset/btc/btc.go Outdated Show resolved Hide resolved
server/auth/auth.go Outdated Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
server/cmd/dcrdex/config.go Outdated Show resolved Hide resolved
server/market/market.go Outdated Show resolved Hide resolved
Comment on lines 145 to 148
// WaitForEpochOpen waits until the start of epoch processing.
func (m *Market) WaitForEpochOpen() {
<-m.running
}
Copy link
Member

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.

Copy link
Member Author

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.

server/market/market.go Show resolved Hide resolved
server/market/market.go Outdated Show resolved Hide resolved
dex/runner.go Show resolved Hide resolved
Copy link
Member

@buck54321 buck54321 left a 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.

server/dex/dex.go Outdated Show resolved Hide resolved
Comment on lines +299 to +300
bookSources := make(map[string]market.BookSource, len(cfg.Markets))
marketTunnels := make(map[string]market.MarketTunnel, len(cfg.Markets))
Copy link
Member

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)
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member

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.

Comment on lines 105 to 107
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."`
Copy link
Member

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.

Copy link
Member Author

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.

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))
Copy link
Member

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.
@chappjc chappjc merged commit 5bf9082 into decred:master Jan 15, 2020
@chappjc chappjc deleted the server-app branch January 15, 2020 16:17
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.

2 participants