Engine changes

Add addr helpers (will be split off into own package)
Engine status updates (log and data dir display)
Use GetPairFormat for various exchanges instead of calling the config
QA fixes
Implement GCTRPC exchange deposit address handling
This commit is contained in:
Adrian Gallagher
2019-06-24 17:34:07 +10:00
parent 9ff4471a45
commit 1daaa66830
15 changed files with 247 additions and 78 deletions

100
engine/addr_helpers.go Normal file
View File

@@ -0,0 +1,100 @@
package engine
import (
"errors"
"strings"
"sync"
"github.com/thrasher-/gocryptotrader/currency"
)
// DepositAddressStore stores a list of exchange deposit addresses
type DepositAddressStore struct {
m sync.Mutex
Store map[string]map[string]string
}
// DepositAddressManager manages the exchange deposit address store
type DepositAddressManager struct {
Store DepositAddressStore
}
// vars related to the deposit address helpers
var (
ErrDepositAddressStoreIsNil = errors.New("deposit address store is nil")
ErrDepositAddressNotFound = errors.New("deposit address does not exist")
)
// Seed seeds the deposit address store
func (d *DepositAddressStore) Seed(coinData map[string]map[string]string) {
d.m.Lock()
defer d.m.Unlock()
if d.Store == nil {
d.Store = make(map[string]map[string]string)
}
for k, v := range coinData {
r := make(map[string]string)
for w, x := range v {
r[strings.ToUpper(w)] = x
}
d.Store[strings.ToUpper(k)] = r
}
}
// GetDepositAddress returns a deposit address based on the specified item
func (d *DepositAddressStore) GetDepositAddress(exchName string, item currency.Code) (string, error) {
d.m.Lock()
defer d.m.Unlock()
if len(d.Store) == 0 {
return "", ErrDepositAddressStoreIsNil
}
r, ok := d.Store[strings.ToUpper(exchName)]
if !ok {
return "", ErrExchangeNotFound
}
addr, ok := r[strings.ToUpper(item.String())]
if !ok {
return "", ErrDepositAddressNotFound
}
return addr, nil
}
// GetDepositAddresses returns a list of stored deposit addresses
func (d *DepositAddressStore) GetDepositAddresses(exchName string) (map[string]string, error) {
d.m.Lock()
defer d.m.Unlock()
if len(d.Store) == 0 {
return nil, ErrDepositAddressStoreIsNil
}
r, ok := d.Store[strings.ToUpper(exchName)]
if !ok {
return nil, ErrDepositAddressNotFound
}
return r, nil
}
// GetDepositAddressByExchange returns a deposit address for the specified exchange and cryptocurrency
// if it exists
func (d *DepositAddressManager) GetDepositAddressByExchange(exchName string, currencyItem currency.Code) (string, error) {
return d.Store.GetDepositAddress(exchName, currencyItem)
}
// GetDepositAddressesByExchange returns a list of cryptocurrency addresses for the specified
// exchange if they exist
func (d *DepositAddressManager) GetDepositAddressesByExchange(exchName string) (map[string]string, error) {
return d.Store.GetDepositAddresses(exchName)
}
// Sync synchronises all deposit addresses
func (d *DepositAddressManager) Sync() {
result := GetExchangeCryptocurrencyDepositAddresses()
d.Store.Seed(result)
}

View File

@@ -0,0 +1,64 @@
package engine
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency"
)
const (
testBTCAddress = "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX"
)
func TestSeed(t *testing.T) {
var d DepositAddressStore
u := map[string]map[string]string{
"BITSTAMP": map[string]string{
"BTC": testBTCAddress,
},
}
d.Seed(u)
r, err := d.GetDepositAddress("BITSTAMP", currency.BTC)
if err != nil {
t.Error("unexpected result")
}
if r != testBTCAddress {
t.Error("unexpected result")
}
}
func TestGetDepositAddress(t *testing.T) {
var d DepositAddressStore
_, err := d.GetDepositAddress("", currency.BTC)
if err != ErrDepositAddressStoreIsNil {
t.Error("non-error on non-existent exchange")
}
d.Store = map[string]map[string]string{
"BITSTAMP": map[string]string{
"BTC": testBTCAddress,
},
}
_, err = d.GetDepositAddress("", currency.BTC)
if err != ErrExchangeNotFound {
t.Error("non-error on non-existent exchange")
}
var r string
r, err = d.GetDepositAddress("BiTStAmP", currency.NewCode("bTC"))
if err != nil {
t.Error("unexpected err: ", err)
}
if r != testBTCAddress {
t.Error("unexpected BTC address: ", r)
}
_, err = d.GetDepositAddress("BiTStAmP", currency.LTC)
if err != ErrDepositAddressNotFound {
t.Error("unexpected err: ", err)
}
}

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"os"
"os/signal"
"path"
"sync"
"syscall"
"time"
@@ -25,20 +24,20 @@ import (
// Engine contains configuration, portfolio, exchange & ticker data and is the
// overarching type across this code base.
type Engine struct {
Config *config.Config
Portfolio *portfolio.Base
Exchanges []exchange.IBotExchange
ExchangeCurrencyPairManager *ExchangeCurrencyPairSyncer
NTPManager ntpManager
ConnectionManager connectionManager
OrderManager orderManager
PortfolioManager portfolioManager
CommsManager commsManager
Shutdown chan struct{}
Settings Settings
CryptocurrencyDepositAddresses map[string]map[string]string
Uptime time.Time
ServicesWG sync.WaitGroup
Config *config.Config
Portfolio *portfolio.Base
Exchanges []exchange.IBotExchange
ExchangeCurrencyPairManager *ExchangeCurrencyPairSyncer
NTPManager ntpManager
ConnectionManager connectionManager
OrderManager orderManager
PortfolioManager portfolioManager
CommsManager commsManager
DepositAddressManager *DepositAddressManager
Shutdown chan struct{}
Settings Settings
Uptime time.Time
ServicesWG sync.WaitGroup
}
// Vars for engine
@@ -62,8 +61,6 @@ func New() (*Engine, error) {
return nil, fmt.Errorf("failed to load config. Err: %s", err)
}
b.CryptocurrencyDepositAddresses = make(map[string]map[string]string)
return &b, nil
}
@@ -75,7 +72,7 @@ func NewFromSettings(settings *Settings) (*Engine, error) {
var b Engine
b.Config = &config.Cfg
log.Debugf("Loading config file %s..\n", settings.ConfigFile)
log.Debugf("Loading config file %s...\n", settings.ConfigFile)
err := b.Config.LoadConfig(settings.ConfigFile)
if err != nil {
return nil, fmt.Errorf("failed to load config. Err: %s", err)
@@ -93,8 +90,11 @@ func NewFromSettings(settings *Settings) (*Engine, error) {
b.Settings.ConfigFile = settings.ConfigFile
b.Settings.DataDir = settings.DataDir
b.Settings.LogFile = path.Join(log.LogPath, log.Logger.File)
b.CryptocurrencyDepositAddresses = make(map[string]map[string]string)
if *log.Logger.Enabled {
b.Settings.LogFile = log.LogPath
log.Debugf("Using log file: %s.\n", log.LogPath)
}
err = utils.AdjustGoMaxProcs(settings.GoMaxProcs)
if err != nil {
@@ -102,9 +102,7 @@ func NewFromSettings(settings *Settings) (*Engine, error) {
}
b.handleInterrupt()
ValidateSettings(&b, settings)
return &b, nil
}
@@ -157,6 +155,7 @@ func ValidateSettings(b *Engine, s *Settings) {
b.Settings.EnableNTPClient = s.EnableNTPClient
b.Settings.EnableOrderManager = s.EnableOrderManager
b.Settings.EnableExchangeSyncManager = s.EnableExchangeSyncManager
b.Settings.EnableDepositAddressManager = s.EnableDepositAddressManager
b.Settings.EnableTickerSyncing = s.EnableTickerSyncing
b.Settings.EnableOrderbookSyncing = s.EnableOrderbookSyncing
b.Settings.EnableExchangeAutoPairUpdates = s.EnableExchangeAutoPairUpdates
@@ -228,6 +227,7 @@ func PrintSettings(s *Settings) {
log.Debugf("\t Event manager sleep delay: %v", s.EventManagerDelay)
log.Debugf("\t Enable order manager: %v", s.EnableOrderManager)
log.Debugf("\t Enable exchange sync manager: %v", s.EnableExchangeSyncManager)
log.Debugf("\t Enable deposit address manager: %v\n", s.EnableDepositAddressManager)
log.Debugf("\t Enable ticker syncing: %v", s.EnableTickerSyncing)
log.Debugf("\t Enable orderbook syncing: %v", s.EnableOrderbookSyncing)
log.Debugf("\t Enable websocket routine: %v\n", s.EnableWebsocketRoutine)
@@ -277,6 +277,7 @@ func (e *Engine) Start() {
e.Uptime = time.Now()
log.Debugf("Bot '%s' started.\n", e.Config.Name)
log.Debugf("Using data dir: %s\n", e.Settings.DataDir)
enabledExchanges := e.Config.CountEnabledExchanges()
if e.Settings.EnableAllExchanges {
@@ -331,8 +332,6 @@ func (e *Engine) Start() {
log.Warn("currency updater system failed to start", err)
}
e.CryptocurrencyDepositAddresses = GetExchangeCryptocurrencyDepositAddresses()
if e.Settings.EnableGRPC {
go StartRPCServer()
}
@@ -352,6 +351,11 @@ func (e *Engine) Start() {
}
}
if e.Settings.EnableDepositAddressManager {
e.DepositAddressManager = new(DepositAddressManager)
e.DepositAddressManager.Sync()
}
if e.Settings.EnableOrderManager {
if err = e.OrderManager.Start(); err != nil {
log.Errorf("Order manager unable to start: %v", err)

View File

@@ -21,6 +21,7 @@ type Settings struct {
EnableDeprecatedRPC bool
EnableCommsRelayer bool
EnableExchangeSyncManager bool
EnableDepositAddressManager bool
EnableTickerSyncing bool
EnableOrderbookSyncing bool
EnableEventManager bool

View File

@@ -629,15 +629,34 @@ func GetCryptocurrenciesByExchange(exchangeName string, enabledExchangesOnly, en
return cryptocurrencies, nil
}
// GetCryptocurrencyDepositAddressesByExchange returns the cryptocurrency deposit addresses for a particular exchange
func GetCryptocurrencyDepositAddressesByExchange(exchName string) (map[string]string, error) {
if Bot.DepositAddressManager != nil {
return Bot.DepositAddressManager.GetDepositAddressesByExchange(exchName)
}
result := GetExchangeCryptocurrencyDepositAddresses()
r, ok := result[exchName]
if !ok {
return nil, ErrExchangeNotFound
}
return r, nil
}
// GetExchangeCryptocurrencyDepositAddress returns the cryptocurrency deposit address for a particular
// exchange
func GetExchangeCryptocurrencyDepositAddress(exchName string, item currency.Code) (string, error) {
func GetExchangeCryptocurrencyDepositAddress(exchName, accountID string, item currency.Code) (string, error) {
if Bot.DepositAddressManager != nil {
return Bot.DepositAddressManager.GetDepositAddressByExchange(exchName, item)
}
exch := GetExchangeByName(exchName)
if exch == nil {
return "", ErrExchangeNotFound
}
return exch.GetDepositAddress(item, "")
return exch.GetDepositAddress(item, accountID)
}
// GetExchangeCryptocurrencyDepositAddresses obtains an exchanges deposit cryptocurrency list
@@ -649,7 +668,6 @@ func GetExchangeCryptocurrencyDepositAddresses() map[string]map[string]string {
continue
}
exchName := Bot.Exchanges[x].GetName()
if !Bot.Exchanges[x].GetAuthenticatedAPISupport(exchange.RestAuthentication) {
if Bot.Settings.Verbose {
log.Debugf("GetExchangeCryptocurrencyDepositAddresses: Skippping %s due to disabled authenticated API support.", exchName)
@@ -679,40 +697,18 @@ func GetExchangeCryptocurrencyDepositAddresses() map[string]map[string]string {
return result
}
// GetDepositAddressByExchange returns a deposit address for the specified exchange and cryptocurrency
// if it exists
func GetDepositAddressByExchange(exchName string, currencyItem currency.Code) string {
for x, y := range Bot.CryptocurrencyDepositAddresses {
if exchName == x {
addr, ok := y[currencyItem.String()]
if ok {
return addr
}
}
}
return ""
}
// GetDepositAddressesByExchange returns a list of cryptocurrency addresses for the specified
// exchange if they exist
func GetDepositAddressesByExchange(exchName string) map[string]string {
for x, y := range Bot.CryptocurrencyDepositAddresses {
if exchName == x {
return y
}
}
return nil
}
// WithdrawCryptocurrencyFundsByExchange withdraws the desired cryptocurrency and amount to a desired cryptocurrency address
func WithdrawCryptocurrencyFundsByExchange(exchName string) (string, error) {
func WithdrawCryptocurrencyFundsByExchange(exchName string, req *exchange.CryptoWithdrawRequest) (string, error) {
if req == nil {
return "", errors.New("crypto withdraw request param is nil")
}
exch := GetExchangeByName(exchName)
if exch == nil {
return "", ErrExchangeNotFound
}
// TO-DO: FILL
return exch.WithdrawCryptocurrencyFunds(&exchange.CryptoWithdrawRequest{})
return exch.WithdrawCryptocurrencyFunds(req)
}
// FormatCurrency is a method that formats and returns a currency pair

View File

@@ -64,8 +64,6 @@ func (o *orderManager) Start() error {
log.Debugln("Order manager starting...")
// test param
o.cfg.CancelOrdersOnShutdown = true
o.shutdown = make(chan struct{})
o.orderStore.Orders = make(map[string][]exchange.OrderDetail)
go o.run()

View File

@@ -727,7 +727,8 @@ func (s *RPCServer) GetCryptocurrencyDepositAddresses(ctx context.Context, r *gc
return nil, errors.New("exchange is not loaded/doesn't exist")
}
return &gctrpc.GetCryptocurrencyDepositAddressesResponse{}, common.ErrNotYetImplemented
result, err := GetCryptocurrencyDepositAddressesByExchange(r.Exchange)
return &gctrpc.GetCryptocurrencyDepositAddressesResponse{Addresses: result}, err
}
// GetCryptocurrencyDepositAddress returns a cryptocurrency deposit address
@@ -738,7 +739,7 @@ func (s *RPCServer) GetCryptocurrencyDepositAddress(ctx context.Context, r *gctr
return nil, errors.New("exchange is not loaded/doesn't exist")
}
addr, err := exch.GetDepositAddress(currency.NewCode(r.Cryptocurrency), "")
addr, err := GetExchangeCryptocurrencyDepositAddress(r.Exchange, "", currency.NewCode(r.Cryptocurrency))
return &gctrpc.GetCryptocurrencyDepositAddressResponse{Address: addr}, err
}