Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Refactor pricenode #7

Merged
merged 201 commits into from
Apr 17, 2018
Merged
Show file tree
Hide file tree
Changes from 178 commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
213a8f3
Move bisq.pricenode.{Main => app.Main}
cbeams Jan 25, 2018
15be897
Extract Pricenode class from Main
cbeams Jan 25, 2018
0dbb878
Extract Main.initLog method
cbeams Jan 25, 2018
99c7d8b
Wire and inject PriceRequestService from within Main
cbeams Jan 25, 2018
cbf2df4
Extract Environment utility class
cbeams Jan 25, 2018
6bc7665
Wire and inject FeeRequestService from within Main
cbeams Jan 25, 2018
aa86199
Move log init and version loading from Main to Pricenode
cbeams Jan 25, 2018
4d55e8a
Make fields private and final where appropriate
cbeams Jan 25, 2018
f797162
Wire and inject BtcFeesProvider from within Main
cbeams Jan 25, 2018
bf54408
Make FeeRequestService#requestIntervalMs optional
cbeams Jan 25, 2018
2ad083d
Remove temporary Pricenode.Config class
cbeams Jan 25, 2018
63e9700
Remove unnecessary static initializer from Main
cbeams Jan 25, 2018
948f8f1
Wire and inject price providers from within Main
cbeams Jan 25, 2018
2053f1e
Decouple constructing PriceRequestService from starting it
cbeams Jan 25, 2018
3201503
Extract Pricenode.mapRoutesAndStart method
cbeams Jan 25, 2018
def6da8
Rename Pricenode.{initLog => initLogging}
cbeams Jan 25, 2018
e70dcd6
Move bisq.pricenode.{app => util}.Environment
cbeams Jan 25, 2018
1c32534
Extract bisq.pricenode.util.Version class
cbeams Jan 25, 2018
5b0edab
Consolidate request logging with Spark.before("/*")
cbeams Jan 25, 2018
832db42
Inline private Pricenode.handleGet* methods
cbeams Jan 26, 2018
d358bdc
Add AGPL header where missing
cbeams Jan 26, 2018
28b9e43
Configure IDEA to add AGPL header to Java sources
cbeams Jan 26, 2018
502f1f8
Refactor Environment#{doWithOptionalVar => getOptionalVar}
cbeams Feb 3, 2018
b3cdace
Rename bisq.{pricenode => price}
cbeams Feb 3, 2018
dc4a4b2
Rename bisq.price.{app => node}
cbeams Feb 3, 2018
19cb583
Remove reference to Pricenode from Version
cbeams Feb 3, 2018
966dfc2
Rename bisq.price.{node => app}.*
cbeams Feb 5, 2018
d681cc5
Rename bisq.price.{fee => mining}
cbeams Feb 5, 2018
00f662e
Rename b.p.mining.Fee{Request => Estimation}Service
cbeams Feb 5, 2018
3c3780d
Reflect {pricenode => price} change in IDEA import config
cbeams Feb 5, 2018
b1d7e5b
Introduce FeeEstimationProvider interface
cbeams Feb 5, 2018
f3075bc
Rename BtcFeesProvider => BitcoinFees
cbeams Feb 5, 2018
b9d4590
Load BitcoinFees by SPI via ServiceLoader
cbeams Feb 5, 2018
9330449
Allow FeeEstimationService to configure itself
cbeams Feb 5, 2018
b5d7eb0
Allow Pricenode to configure itself
cbeams Feb 5, 2018
d182b49
Rename bisq.price.{price => spot}
cbeams Feb 5, 2018
e551ba7
Rename PriceRequestService => ExchangeRateService
cbeams Feb 5, 2018
5f63d96
Rename PriceData => ExchangeRateData
cbeams Feb 5, 2018
bb3cede
Introduce ExchangeRateProvider SPI
cbeams Feb 5, 2018
0cc2376
Allow BitcoinAverage(Local|Global) to configure itself
cbeams Feb 5, 2018
563a55d
Rename BtcAverageProvider => AbstractBitcoinAverage
cbeams Feb 6, 2018
a72bdef
Rename CoinmarketcapProvider => CoinMarketCap
cbeams Feb 6, 2018
f85c3a7
Rename PoloniexProvider => Poloniex
cbeams Feb 6, 2018
6721c2f
Nest BitcoinAverage(Local|Global) as inner classes
cbeams Feb 6, 2018
ba8fb42
Push functionality from ExchangeRateService into BitcoinAverage.Local
cbeams Feb 6, 2018
cb94448
Simplify field names in BitcoinAverage.Local
cbeams Feb 6, 2018
d6c713d
Rename Local.{requestBtcAverageLocalPrices => requestAndCache}
cbeams Feb 6, 2018
bae028a
Move ExchangeRateService.BTCAVERAGE_LOCAL_PROVIDER => Local.PROVIDER_…
cbeams Feb 6, 2018
f5b4efa
Remove unnecessary BitcoinAverage.Local#count field
cbeams Feb 6, 2018
b75b673
Remove unnecessary commented lines from BitcoinAverage.Local
cbeams Feb 6, 2018
f980047
Extract ExchangeRateService => BitcoinAverage.Global
cbeams Feb 6, 2018
3cbfb8a
Assign provider fields to their specific types
cbeams Feb 6, 2018
9c02a4a
Extract ExchangeRateService => Poloniex
cbeams Feb 6, 2018
9daee4d
Extract ExchangeRateService => CoinMarketCap
cbeams Feb 6, 2018
0373be3
Make ExchangeRateService stateless and immutable
cbeams Feb 6, 2018
03a628b
Filter outdated prices once per ExchangeRateService request
cbeams Feb 6, 2018
de4b98b
Extract AbstractExchangeRateProvider base class
cbeams Feb 6, 2018
f37f4d3
Remove obsolete FIXMEs
cbeams Feb 6, 2018
1cc4d07
Isolate JSON processing within web layer
cbeams Feb 6, 2018
511edf6
Derive debug timestamp/count values directly from data
cbeams Feb 6, 2018
eb1a295
Push debug prefix property into ExchangeRateProvider
cbeams Feb 6, 2018
9757b13
Rename local variables for clarity of purpose
cbeams Feb 6, 2018
c19cefa
Pull up methods into ExchangeRateProvider SPI
cbeams Feb 6, 2018
1f9b44c
Process generically a Set<ExchangeRateProvider>
cbeams Feb 6, 2018
445d782
Rename local variable for simplicity
cbeams Feb 6, 2018
b6d7fd9
Add comment on 'btcAverageTs' special handling
cbeams Feb 6, 2018
0078cba
Simplify adding each provider's data to allData
cbeams Feb 6, 2018
aa62aad
Extract explanatory methods in ExchangeRateService
cbeams Feb 6, 2018
c41e4e7
Rename ExchangeRateProvider#get{DebugPrefix => MetadataPrefix}
cbeams Feb 6, 2018
43e5f2a
Service load, order, and configure List<ExchangeRateProvider>
cbeams Feb 6, 2018
c962af1
Pull members up into AbstractExchangeRateProvider
cbeams Feb 7, 2018
c06acbb
Fix AbstractExchangeRateProvider Logger name
cbeams Feb 7, 2018
7269369
Pull requestAndCache method up to AbstractExchangeRateProvider
cbeams Feb 7, 2018
473969c
Tune AbstractExchangeRateProvider#requestAndCache logging
cbeams Feb 7, 2018
4ae8779
Simplify ExchangeRateProvider#getData generics
cbeams Feb 7, 2018
c805415
Isolate caching behavior within new CachingExchangeRateProvider
cbeams Feb 7, 2018
bf1e8a3
Remove ExchangeRateProvider#getData and use #request
cbeams Feb 7, 2018
6c81d12
Eliminate explicit ExchangeRateProvider#getOrder property
cbeams Feb 7, 2018
bb4602c
Rename CachingExchangeRateData#{requestIntervalMs => ttl}
cbeams Feb 7, 2018
b87f4aa
Use Duration vs Long values for TTL
cbeams Feb 7, 2018
22a96b6
Inline CachingExchangeRateProvider#timer field
cbeams Feb 7, 2018
f2aa335
Declare protected fields above private fields
cbeams Feb 7, 2018
3f61d7f
Extract explanatory CachingExchangeRateProvider#ttlFor method
cbeams Feb 7, 2018
09afcd7
Simplify BitcoinAverage secretKey management
cbeams Feb 7, 2018
7f6a431
Pull configure method up to AbstractExchangeRateProvider
cbeams Feb 7, 2018
7a60359
Move abstract ExchangeRateService types to new support package
cbeams Feb 7, 2018
b569464
Extract Altcoins utility class
cbeams Feb 7, 2018
b9c525f
Pull up common BitcoinAverage#doRequestForCaching implementation
cbeams Feb 7, 2018
d732184
Simplify declaration of BitcoinAverage.(Local|Global) types
cbeams Feb 7, 2018
a7902a5
Inline unnecessary BitcoinAverage#getMap method
cbeams Feb 7, 2018
afaff31
Move BitcoinAverage#getHeader method down
cbeams Feb 7, 2018
7dc37aa
Refactor BitcoinAverage#doRequestForCaching for readability
cbeams Feb 7, 2018
8ab9145
Extract BitcoinAverage#getTimestampFromAllTickerData method
cbeams Feb 7, 2018
2ffc05d
Flatten declaration of BitcoinAverage constructor
cbeams Feb 7, 2018
9e8ce07
Parameterize BitcoinAverage API path
cbeams Feb 7, 2018
9de5307
Refactor to use XChange BitcoinAverage library
cbeams Feb 7, 2018
2346085
Refactor BitcoinAverage API auth signature creation
cbeams Feb 8, 2018
b14e72c
Refactor BitcoinAverage for readability
cbeams Feb 8, 2018
44ca9ac
Refactor to use XChange CoinMarketCap library
cbeams Feb 8, 2018
5710415
Refactor CoinMarketCap for style
cbeams Feb 8, 2018
99a50d0
Refactor Poloniex for style
cbeams Feb 8, 2018
314d4ab
Refactor to use XChange Poloniex library
cbeams Feb 9, 2018
3e32ffb
Reformat to 4-space continuation indents
cbeams Feb 9, 2018
f7927f9
Remove ExchangeRateService#removeOutdatedPrices
cbeams Feb 9, 2018
c1bc990
Rename ExchangeRateData => ExchangeRate
cbeams Feb 9, 2018
8d23e93
Simplify naming of ExchangeRate fields
cbeams Feb 9, 2018
3e84b0d
Add ExchangeRate convenience constructor
cbeams Feb 9, 2018
c57a1a3
Rename ExchangeRateProvider#{getProviderSymbol => getName}
cbeams Feb 9, 2018
4db05f4
Document ExchangeRate
cbeams Feb 9, 2018
34dd139
Rename ExchangeRateService#{addData => addExchangeRates}
cbeams Feb 9, 2018
f9e8307
Rename ExchangeRateProvider#{getMetadataPrefix => getPrefix}
cbeams Feb 9, 2018
ef721eb
Return Set<ExchangeRate> from ExchangeRateProvider#request
cbeams Feb 9, 2018
24cd258
Refactor ExchangeRateProvider loops to stream pipelines
cbeams Feb 9, 2018
5e06ec3
Refactor ExchangeRateService for clarity and style
cbeams Feb 9, 2018
3f30f20
Make ExchangeRateProvider extend Supplier<Set<ExchangeRate>>
cbeams Feb 11, 2018
3ef1998
Update field names in ExchangeRateProvider implementations
cbeams Feb 11, 2018
dee5b37
Refactor to lambda expression in ExchangeRateService
cbeams Feb 11, 2018
fbefa2f
Fix null response from /getAllMarketPrices
cbeams Feb 11, 2018
81be033
Replace Gson serialization with Jackson
cbeams Feb 11, 2018
d69ae4a
Use String.format for clarity
cbeams Feb 11, 2018
5a67f54
Eliminate the need for BitcoinAverage API keys
cbeams Feb 11, 2018
4951989
Remove now-obsolete ExchangeRateProvider#configure hook
cbeams Feb 11, 2018
b137048
Revert "Remove now-obsolete ExchangeRateProvider#configure hook"
cbeams Feb 12, 2018
d741dbc
Revert "Eliminate the need for BitcoinAverage API keys"
cbeams Feb 12, 2018
875b2cf
Add TODO.md to capture remaining work
cbeams Feb 12, 2018
c0eb50a
Improve error handling
cbeams Feb 12, 2018
5dec7ec
Remove legacy log initialization logic
cbeams Feb 12, 2018
96a98fd
Migrate runtime and configuration to Spring
cbeams Feb 12, 2018
696021b
Fix R10 port binding issue on Heroku
cbeams Feb 12, 2018
58cd243
Fix incompatible JSON serialization in /getAllMarketPrices
cbeams Feb 12, 2018
1cb7b31
Extract spot.ExchangeRateController from app.Pricenode
cbeams Feb 12, 2018
50e0c81
Extract mining.FeeEstimationController from app.Pricenode
cbeams Feb 12, 2018
3adbb24
Extract util.VersionController from app.Pricenode
cbeams Feb 12, 2018
7e9c9c1
Extract common controller logging to WebConfig
cbeams Feb 12, 2018
d91f4b1
Remove TODO for refactoring to @Controller classes
cbeams Feb 12, 2018
72c84a1
Fix incompatible data handling in ExchangeRateService
cbeams Feb 13, 2018
e5e4a9c
Simplify invocation of lifecycle start/stop methods
cbeams Feb 13, 2018
c234628
Rename CachingExchangeRateProvider#{doGetForCache => doGet}
cbeams Feb 13, 2018
9c0bcc0
Sort mutable fields after final fields
cbeams Feb 13, 2018
7f2f5a3
Refactor FeeEstimationProvider to extend Supplier<Long>
cbeams Feb 13, 2018
79538d6
Introduce bisq.price.PriceProvider base class
cbeams Feb 13, 2018
707b196
Refactor FeeEstimationProvider to extend PriceProvider<Long>
cbeams Feb 14, 2018
2dc30d3
Rename mining.{FeeEstimation* => FeeRate*}
cbeams Feb 14, 2018
2c77008
Introduce and refactor to FeeRate value object
cbeams Feb 14, 2018
2f0b0fb
Simplify FeeRateService#getFees
cbeams Feb 14, 2018
cd76471
Configure IDEA to create package-private classes by default
cbeams Feb 14, 2018
e5bf166
Introduce FixedFeeRateProvider and DASH/DOGE/LTC implementations
cbeams Feb 14, 2018
fc79856
Push /getParams endpoint into BitcoinFeeRateProvider$Controller
cbeams Feb 14, 2018
5f9541a
Refactor BitcoinFeeRateProvider for clarity
cbeams Feb 14, 2018
1350b47
Make classes package-private where appropriate
cbeams Feb 14, 2018
ae74368
Restore original order of BitcoinAverage ctor params
cbeams Feb 14, 2018
ba51fe5
Remove AGPL license header from configuration files
cbeams Feb 14, 2018
1228167
Replace WebConfig with PriceController base class
cbeams Feb 14, 2018
aefc452
Add TODOs
cbeams Feb 14, 2018
af5002c
Remove use of io.bisq.common.util.MathUtils
cbeams Feb 14, 2018
cce8020
Upgrade to bisq-exchange:network:v0.6.5
cbeams Feb 14, 2018
9929284
Replace bisq-network HttpClient w/ Spring RestTemplate
cbeams Feb 14, 2018
b34e785
Remove unused Logback IDEA import layout entry
cbeams Feb 14, 2018
efca8c3
Fix formatting in spot.ExchangeRate
cbeams Feb 14, 2018
5e7989e
Remove use of Gson and refactor BitcoinFeeRateProvider
cbeams Feb 14, 2018
1c7e72c
Customize startup banner
cbeams Feb 15, 2018
64f51ee
Derive version from latest git tag
cbeams Feb 15, 2018
69618cf
Add detailed Git metadata to /info endpoint
cbeams Feb 15, 2018
52c207d
Revert "Add detailed Git metadata to /info endpoint"
cbeams Feb 15, 2018
7de26d7
Configure Heroku to handle Git-based app version
cbeams Feb 15, 2018
c858e27
Enable Travis CI
cbeams Feb 15, 2018
513d9dd
Remove redundant FeeRateProvider#log field
cbeams Feb 15, 2018
a41d94f
Remove alternative Bitcoin fee rate provider comments
cbeams Feb 15, 2018
fcb46f5
Run PriceProvider#timer instances as daemon threads
cbeams Feb 16, 2018
7a4fd67
Make PriceProvider implement Spring's SmartLifecycle
cbeams Feb 16, 2018
30dcaaf
Document PriceProvider#start
cbeams Feb 16, 2018
26a0247
Revert to simple version management
cbeams Feb 16, 2018
ea99368
Read version from classpath:version.txt
cbeams Feb 16, 2018
c14bdf2
Add TODO
cbeams Feb 16, 2018
34d6909
Update README
cbeams Feb 16, 2018
5f2a7a8
Support a ~/.config/bisq.properties config file
cbeams Feb 16, 2018
6089480
Use 2 5 3 params by default
cbeams Feb 16, 2018
0af9900
Make VersionController extend PriceController
cbeams Feb 19, 2018
206c398
Change fee rate params from '2 5 3' => '1 5 2'
cbeams Feb 22, 2018
3df25dd
Rename PriceProvider#{ttl => refreshInterval}
cbeams Feb 22, 2018
bf3056a
Remove BitcoinFeeRateProvider#capacity parameter
cbeams Feb 22, 2018
a87d652
Change max blocks from 5 => 2
cbeams Feb 26, 2018
9f5cf6a
Enable Travis CI Slack notifications
cbeams Mar 9, 2018
4c476ec
Rename groupid {io.bisq => network.bisq}
cbeams Mar 12, 2018
b62855f
Repackage {io.bisq.common => bisq.common}
cbeams Mar 12, 2018
f42d9fa
Organize imports with common layout (bisq-network/style#2)
cbeams Mar 14, 2018
5650ae6
Move bisq.{common => core}.locale
cbeams Mar 14, 2018
d53300d
Reduce Travis CI Slack notification frequency
cbeams Mar 15, 2018
1a6a601
Fix syntax error in Travis CI config
cbeams Mar 15, 2018
c61ca98
Re-introduce custom tor-binary Maven repository
cbeams Mar 16, 2018
123f2f3
Normalize .idea/codeStyles/*.xml EOF newlines
cbeams Mar 16, 2018
02edfef
Preserve blank lines in .properties files
cbeams Mar 16, 2018
f22814d
Wrap lines automatically at 120 character margin
cbeams Mar 16, 2018
9ebf7d6
Add visual guide at 90-character Javadoc margin
cbeams Mar 16, 2018
b8980fc
Use 'master' tor-binary Maven repository
cbeams Mar 21, 2018
ca65c30
Increase Gradle HTTP timeouts from 30 => 120 seconds
cbeams Mar 22, 2018
d46365f
Enable Travis CI Gradle dependency caching
cbeams Mar 22, 2018
286baf4
Disable IDEA wrap on typing
cbeams Mar 23, 2018
f544007
Revert "Enable Travis CI Gradle dependency caching"
cbeams Apr 5, 2018
47115f6
Do not qualify members with 'this' unless required
cbeams Apr 17, 2018
a271dcb
Add Javadoc to key components
cbeams Apr 17, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ root = true
[*]
indent_style = space
indent_size = 4
continuation_indent_size = 8
continuation_indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
Expand Down
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Vim
*.swp

# IDEA
.idea
*.iml
out

# Gradle
build
.gradle
out

# Heroku
.heroku/
.jdk/
.profile.d/
tor/
20 changes: 14 additions & 6 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions .idea/fileTemplates/includes/File Header.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/fileTemplates/internal/AnnotationType.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/fileTemplates/internal/Class.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/fileTemplates/internal/Enum.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/fileTemplates/internal/Interface.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
language: java
jdk: oraclejdk8
2 changes: 1 addition & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
web: if [ "$HIDDEN" == true ]; then ./tor/bin/run_tor build/install/bisq-pricenode/bin/bisq-pricenode 2 5 3; else build/install/bisq-pricenode/bin/bisq-pricenode 2 5 3; fi
web: if [ "$HIDDEN" == true ]; then ./tor/bin/run_tor java -jar -Dserver.port=$PORT build/libs/bisq-pricenode.jar 2 5 3; else java -jar -Dserver.port=$PORT build/libs/bisq-pricenode.jar 2 5 3; fi
1 change: 1 addition & 0 deletions README-HEROKU.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Deploy on Heroku
Run the following commands:

heroku create
heroku buildpacks:add heroku/gradle
heroku config:set BITCOIN_AVG_PUBKEY=[your pubkey] BITCOIN_AVG_PRIVKEY=[your privkey]
git push heroku master
curl https://your-app-123456.herokuapp.com/getAllMarketPrices
Expand Down
71 changes: 51 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,85 @@ bisq-pricenode
Overview
--------

The Bisq price relay node ("pricenode" for short) is a simple HTTP service that fetches data from third-party price providers and relays that data to Bisq exchange clients on request. Available prices include:
The Bisq pricenode is a simple HTTP service that fetches, transforms and relays data from third-party price providers to Bisq exchange clients on request. Available prices include:

- BTC exchange rates, available at `/getAllMarketPrices`, and
- BTC mining fees, available at `/getFees`
- Bitcoin exchange rates, available at `/getAllMarketPrices`, and
- Bitcoin, Litecoin, Dash, and Dogecoin mining fee rates, available at `/getFees`
Copy link
Contributor

Choose a reason for hiding this comment

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

Dogecoin is not supported anymore, Code is still left just in case, but no plans to re-enable it...

Copy link
Contributor Author

@cbeams cbeams Feb 21, 2018

Choose a reason for hiding this comment

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

  • @cbeams: Prune dead Doge code in a fashion friendly to a future git revert

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I'm deferring this to a separate issue, as it's not part of refactoring, per se. See #9.


Price relays are deployed as Tor hidden services. This is not because the location of these nodes needs to be kept secret, but rather so that Bisq exchange clients do not need to exit the Tor network in order to get price data.
Pricenodes are deployed in production as Tor hidden services. This is not because the location of these nodes needs to be kept secret, but rather so that Bisq exchange clients do not need to exit the Tor network in order to get price data.

Anyone can run a price relay, but a relay must be _discoverable_ in order for it to do any good. For exchange clients to discover your relay, its .onion address must be (a) hard coded in the Bisq exchange client's `ProviderRepository` class or (b) specified explicitly via the exchange client's `--providers` command line option.
Anyone can run a pricenode, but it must be _discoverable_ in order for it to do any good. For exchange clients to discover your pricenode, its .onion address must be hard-coded in the Bisq exchange client's `ProvidersRepository` class. Alternatively, users can point explicitly to given pricenode (or set of pricenodes) with the exchange client's `--providers` command line option.

Price relays can be run anywhere Java and Tor binaries can be run. Instructions below cover deployment on localhost and Heroku, but nothing in principle prevents these nodes from being run across a broader selection of platforms and regions. Note however that the exchange client is currently naive about selecting price relays (it does so once randomly at startup), but this could be improved in various ways to accommodate a larger number of better-distributed nodes.
Pricenodes can be deployed anywhere Java and Tor binaries can be run. Instructions below cover deployment on localhost, and instructions [how to deploy on Heroku](README-HEROKU.md) are also available.

Price relays should be cheap to run with regard to both time and money. The application itself is non-resource intensive and can be run on the low-end of most providers' paid tiers, and possibly even on some providers' free tiers.
Pricenodes should be cheap to run with regard to both time and money. The application itself is non-resource intensive and can be run on the low-end of most providers' paid tiers.

A price relay operator's main responsibilities are to ensure their node(s) are available and up-to-date. Releases are currently source-only, with the assumption that most operators will favor Git-based "push to deploy" workflows. To stay up to date with releases, operators can [subscribe to this repository's releases.atom feed](https://github.com/bisq-network/pricenode/releases.atom).
A [pricenode operator](https://github.com/bisq-network/roles/issues/5)'s main responsibilities are to ensure their node(s) are available and up-to-date. Releases are currently source-only, with the assumption that most operators will favor Git-based "push to deploy" workflows. To stay up to date with releases, operators can [subscribe to this repository's releases.atom feed](https://github.com/bisq-network/pricenode/releases.atom) and/or get notifications in the `#pricenode` Slack channel.

Operating a production price relay is a valuable service to the Bisq network. Accordingly, operators should issue BSQ compensation requests that cover their time and money costs.
Operating a production pricenode is a valuable service to the Bisq network, and operators should issue BSQ compensation requests accordingly.


Prerequisites
Prerequisites for running a pricenode
--------

To run a price relay, you will need:
To run a pricenode, you will need:

- [BitcoinAverage API keys](https://bitcoinaverage.com/en/plans). Free plans are fine for local development or personal nodes; paid plans should be used for well-known production nodes.
- [Tor Browser](https://www.torproject.org/projects/torbrowser.html.en) to verify .onion URLs.
- JDK 8 if you want to build and run a node locally.
- The `tor` binary (e.g. `brew install tor`) if you want to run a hidden service locally.


Deploy Locally
How to deploy locally
--------

Run the following commands:
### Configure

Export the following properties as environment variables, e.g.:

$ export BITCOIN_AVG_PUBKEY=[your pubkey]
$ export BITCOIN_AVG_PRIVKEY=[your privkey]

Or add them to your `bisq.properties` config file, e.g.:

$ echo BITCOIN_AVG_PUBKEY=[your pubkey] >> $HOME/.config/bisq.properties
$ echo BITCOIN_AVG_PRIVKEY=[your privkey] >> $HOME/.config/bisq.properties

> TIP: Using the `bisq.properties` config file has the advantage of not needing to specify environment variables in your IDE. Running the app and running tests will "just work" regardless where and how you run them.

### Build

./gradlew assemble

### Run

java -jar ./build/libs/bisq-pricenode.jar [capacity] [max-blocks] [request-interval-mins]

### Test

To manually test endpoints, run each of the following:

./gradlew installDist
BITCOIN_AVG_PUBKEY=[your pubkey] BITCOIN_AVG_PRIVKEY=[your privkey] ./build/install/bisq-pricenode/bin/bisq-pricenode [capacity] [max-blocks] [request-interval-mins]
curl http://localhost:8080/getAllMarketPrices
curl http://localhost:8080/getFees
curl http://localhost:8080/getParams
curl http://localhost:8080/getVersion
curl http://localhost:8080/info

### Run as Tor hidden service

To register the node as a Tor hidden service, run:
With your pricenode running at localhost:8080, run:

tor -f torrc

Wait for the process to report that it is "100% bootstrapped", then copy your newly-generated .onion address:

export PRICENODE_ONION=$(cat build/tor-hidden-service/hostname)

When the process reports that it is "100% bootstrapped", leave the process running, copy your newly-generated .onion address from `build/tor-hidden-service/hostname` and then open http://$YOUR_ONION/getAllMarketPrices in your Tor Browser. You should see the same response as produced in the `curl` request above.
Test the endpoints of your hidden service via curl with the --socks5-proxy option:

> NOTE: It may take a few minutes for your new .onion address to get registered and become resolvable. Registration of Tor hidden service descriptors can take some time.
curl --socks5-hostname 127.0.0.1:9050 http://$PRICENODE_ONION/getAllMarketPrices


Deploy Elsewhere
How to deploy elsewhere
--------

- [README-HEROKU.md](README-HEROKU.md)
20 changes: 20 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Refactorings

The list of stuff remaining to complete the PR at https://github.com/bisq-network/pricenode/pull/7

- Document provider implementations w/ links to API docs, etc
- Add integration tests
- Document / discuss how operators should (ideally) operate their pricenodes on a push-to-deploy model, e.g. how it's done on Heroku

## Non-refactorings

Most or all of these will become individual issues / PRs. Just capturing them here for convenience now. Not all may make sense.

- Deprecate existing get* endpoints (e.g. /getAllMarketPrices) in favor of '/exchange-rates', '/fee-estimate;
- Eliminate dependency on bisq-core (only real need now is CurrencyUtil for list of supported coins)
- Remove command line args for fee estimation params; hard-code these values and update them via commits, not via one-off changes by each operator
- Remove 'getParams' in favor of Boot actuator endpoint
- Update bisq-network/exchange to refer to 'provider' as 'pricenode'
- Invert the dependency arrangement. Move 'ProviderRepository' et al from bisq-network/exchange here into
bisq-network/pricenode and have bisq-network/exchange depend on it as a client lib
- Save bandwidth and be idiomatic by not pretty-printing json returned from /getAllMarketPrices et al
22 changes: 13 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
plugins {
id "java"
id "application"
id "org.springframework.boot" version "1.5.10.RELEASE"
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

mainClassName = "bisq.pricenode.Main"
version = "0.7.0"
version = file("src/main/resources/version.txt").text

jar.manifest.attributes(
"Implementation-Title": rootProject.name,
"Implementation-Version": version)
"Implementation-Title": rootProject.name,
"Implementation-Version": version)

jar.archiveName "${rootProject.name}.jar"

repositories {
jcenter()
maven { url "https://jitpack.io" }
maven { url "https://raw.githubusercontent.com/JesusMcCloud/tor-binary/testrelease/release/" }
}

dependencies {
compile("com.github.bisq-network.bisq-exchange:core:v0.6.4")
compile("com.sparkjava:spark-core:2.5.2")
compile("com.github.bisq-network.bisq-exchange:common:v0.6.5")
compile("org.knowm.xchange:xchange-bitcoinaverage:4.3.3")
compile("org.knowm.xchange:xchange-coinmarketcap:4.3.3")
compile("org.knowm.xchange:xchange-poloniex:4.3.3")
compile("org.springframework.boot:spring-boot-starter-web:1.5.10.RELEASE")
compile("org.springframework.boot:spring-boot-starter-actuator")
}

task stage {
dependsOn installDist
dependsOn assemble
}
51 changes: 51 additions & 0 deletions src/main/java/bisq/price/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.price;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UncheckedIOException;

import java.util.Properties;

@SpringBootApplication
public class Main {

public static void main(String[] args) {
new SpringApplicationBuilder(Main.class)
.properties(bisqProperties())
.run(args);
}

private static Properties bisqProperties() {
Properties props = new Properties();
File propsFile = new File(System.getenv("HOME"), ".config/bisq.properties");
if (propsFile.exists()) {
try {
props.load(new FileInputStream(propsFile));
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
return props;
}
}
35 changes: 35 additions & 0 deletions src/main/java/bisq/price/PriceController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.price;

import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class PriceController {

protected final Logger log = LoggerFactory.getLogger(this.getClass());
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason why not use Lombok annotations for logger? (@slf4j)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. It's because I've left Lombok out of the new project altogether. We briefly discussed this when I initially extracted the pricenode module here into its own repository. But it bears treating again here:

I was the one who originally brought Lombok into the Bisq codebase in its early days. I had been—and in many ways still am—a fan of Lombok annotations. They work wonders for getting rid of line noise, especially with regard to eliminating the need to manually code getters and setters and eliminating the need to generate and maintain hashCode, equals and toString methods. It also gets rid of the need to specify a Logger for every class. Lombok is wonderful for all those reasons and more.

The problem is that it violates the principle of least surprise for the majority of Java developers that come across Lombok-annotated classes. They see a strange beast, adorned with @Data, or @Value or @EqualsAndHashCode and/or, indeed @Slf4j annotations. They see no getters or setters declared within these classes, but then do see getters and setters being called on their instances. Slowly, and probably painfully, they realize what Lombok is and what it's doing: it's generating these elements at the bytecode level using a Java Agent-based annotation processor.

Sometimes people are forced abruptly into figuring this out because they try to import Bisq into IDEA or elsewhere, and they see compilation errors. Then they realize, painfully, that they need a Lombok plugin for their IDE. They find and install it, they rebuild and everything is OK. But it was frustrating getting there.

I was a fairly big champion of Lombok coming from the world of mostly closed-source enterprise projects, where it's a reasonable tradeoff to use something like Lombok widely within your organization, to document it in your new employee onboarding docs and be done with it. The cost of getting a closed, well-paid team on the same page about this is low, and the benefits fairly high.

I think that cost/benefit ratio changes with a project like Bisq. I think it's important that Bisq's components be as simple, understandable and idiomatic as possible. I want any highly experienced Java developer to take one look at a repository like this and feel right at home, instantly able to reason about what's going on, instantly able to be productive. To me, that means using stock-standard Java. It means using widely accepted naming conventions and patterns like those found in Domain Driven Design. It means using well-known, well-supported, thriving open source infrastructure like Spring Boot and the rest of the Spring family provide. It means striving for a situation where any competent Java developer can clone any of our repositories, run a single build command or import a project directly into their IDE of choice and have everything "just work".

Keeping Lombok around in new Bisq repositories just doesn't live up to this standard for me. Lombok is something that's great for a closed, fixed-size team, but is a barrier to entry if you're trying to build an open, global, amorphous team like the Bisq DAO. We want to make the process of contribution as smooth as possible for everyone—especially new people. I just don't see the convenience Lombok offers as being worth it anymore with these goals in mind.

P.S. Other issues can crop up with Lombok, too, especially where new language-level Java features are involved. I can't cite specific examples off the top of my head, but more than once, I've had to deal with Lombok being unable to modify or otherwise deal with certain bytecode. I remember problems coming up around Java 5 as well as around Java 8 if memory serves. We want to adopt Java 9 here as soon as possible, and the fewer annotation processors and agents, etc we have is probably for the better.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree to most points and I also prefer to stick with plain java instead of too much magical frameworks where someone who is not familiar with need to first learn about it.
Basically the 2 main exceptions for me was Guice and Lombok just because both add that much value to not need boilerplate code that I think its worth it. For the price project I don't care so much as there are not a ton of use cases for Lombok but in the Bisq app it would re-introduce a lot of boilerplate code. Furthermore Lombok is pretty simple to understand (how to use it - not how it works behind the scenes).
But I agree to the concerns regarding Java version update issues.
Furthermore I prefer also to keep that magic and framework usage limited for security reasons. It is easier to add a vulnerability from a 3rd party framework (as we had in the past with Java serialization - there are Apache commons classes which are vulnerable for hijacks, we did not use those classes but who know if another 3rd party lib uses it...).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got that, thanks. And to be clear, I am not suggesting that we back Lombok out of the existing bisq-network/exchange repository. This is just where new stuff (or newly extracted) stuff is involved.


@ModelAttribute
public void logRequest(HttpServletRequest request) {
log.info("Incoming {} request from: {}", request.getServletPath(), request.getHeader("User-Agent"));
}
}
Loading