ProofOfWork gateway to simple tcp service.
1. Problem statement
Test task for Server Engineer
Design and implement “Word of Wisdom” tcp server.
• TCP server should be protected from DDOS attacks with the Prof of Work (https://en.wikipedia.org/wiki/Proof_of_work), the challenge-response protocol should be used.
• The choice of the POW algorithm should be explained.
• After Prof Of Work verification, server should send one of the quotes from “word of wisdom” book or any other collection of the quotes.
• Docker file should be provided both for the server and for the client that solves the POW challenge
2. How to run
2.1. Requirements
There are some issues, which I will fix shortly. https://github.com/svkior/powgwey/issues
Possibly can work everywhere on Linux/MacOS X, but tested on this config:
- OS: Mac OS X 12.5.1
- Docker Desktop 4.4.2+
- GNU Make 3.81
- curl 7.79.1
- code is compatible with golang 1.18.3
There is no needence for installing golang locally, need access to the Internet for a first fime
May be some issues when running on m1 mac's
2.2. List of all available commands
To list all of the available commands just type:
make help
2.3. Building base image
The base image is used by other images to build, lint, test and check software in containers.
make build-base
Builind server image:
make build-server
Building client image:
make build-client
2.4. Linter check
make lint
2.5. Passing tests
make test
2.6. Monitoring environment
TODO: Still not works https://github.com/svkior/powgwey/issues/31
make start-monitoring
2.7. Start server
make start-server
2.8. Start client
make start-client
2.9. Start load-test
If server is started we can run load test.
make start-loadtest
2.10. Update quotes from another repo
make update-quotes
3. Solution
3.1. Sequence diagram
WiP: https://github.com/svkior/powgwey/issues/20
sequenceDiagram
autonumber
participant C as Client
participant TCP as TCP Service
participant PoW as PoW Service
participant Q as Quotes Service
participant S as Storage
participant M as Monitoring
C->>TCP: TCP Connect
TCP->>TCP: Accept
TCP->>M: Increment Income
C->>TCP: PoW request
TCP->>PoW: PoW request
PoW->>M: Get 1m AVG Load
activate M
M-->>PoW: Current Load
deactivate M
activate PoW
PoW->>PoW: Generate Puzzle
PoW-->>TCP: Puzzle
deactivate PoW
TCP-->>C: Puzzle
activate C
C->>C: Solve
C->>TCP: Solution
deactivate C
TCP->>PoW: Solution
PoW->>PoW: Verify
alt Solution is correct
PoW-->>TCP: OK
activate TCP
TCP->>Q: GetRandomQuote
Q->>S: GetRandomQuote
S-->>Q: Quote
Q-->>TCP: Quote
TCP-->>C: Quote
deactivate TCP
TCP->>M: Increment Success
TCP->>M: time of processing success
else Solution is incorrect
PoW-->>TCP: Not OK
TCP->>M: Increment Failed
TCP->>M: time of processing Failed
end
TCP-->>C: Close connection
3.2. Common way of configuration of all service components
I choosed viper.
3.3. Quotes
I've taked quotes from different repo on github.
Permlink is : https://raw.githubusercontent.com/msramalho/json-tv-quotes/master/quotes.json
Service component "quotes" is located in server_internal/services folder
- configuration of this component is located in server_internal/config/quotes
3.4. Quotes Model
Component model:
I've taked quotes from different repo on github.
Permlink is : https://raw.githubusercontent.com/msramalho/json-tv-quotes/master/quotes.json
Service component "quotes" is located in server_internal/services folder
- configuration of this component is located in server_internal/config/quotes
Component model:
- NewQuotesService
- quotesService:
- Init() Initialize component
- Shutdown() Shutdown component
- GetQuote() Get Quote
It can be assumed that in a highly loaded project, the payload will take some time.
Let's limit the fictitious load of the variable QUOTES_PROCESSING_TIME
We will create a work queue from QUOTES_WORKERS
3.5. TCP Server Component
According to https://github.com/svkior/powgwey/issues/12 I decided to implement No8.
Because for gaming industry the most important feature is a lattency.
Second important is maximum throughput.
If we can provide lattency, we can spend more mony for servers.
3.6. PoW Algritm
Descisions: https://github.com/svkior/powgwey/issues/15
I've found article https://users.soe.ucsc.edu/~abadi/Papers/memory-longer-acm.pdf and
Memory-bound PoW is better because memory access performance is less sensitive to hardware and should generally work on both low and high-end hardware. In addition, it is expected that the performance of such an algorithm will be less sensitive to an increase in processor speed.
General design matches a proposed one where Server generates a random x0 and applies F() to it k times resulting in xk.
Client knows all information about the parameters of algorithm except the x0 and is expected to try all different paths towards x0.
When x0 is found, Client compares a checksum of a sequence to the checksum of a valid sequence received from the Server. When checksum matches, solution is found. Is checksums don't match, client goes for another sequence until valid is found.
3.7. Function F()
Implementation of F() will greatly affect difficulty and efficiency of an algorithm.
It is desirable that there are x and x', where F(x)=F(x'). This requires client to traverse both paths to check sequences, increasing required work.
In addition, it's required that calling inverted F() is slower that accessing inversion table, encouraging client to use memory instead of CPU.
There is possibillity to change current implementation of F() if needed.
3.8. Challenge difficulty
Difficulty of this PoW can be configured with two parameters k and n.
k represents a number of times F() is applied. Increasing this parameter will result in longer sequences and will affect both Client and Server
n represents a range of possible values, which will be in a range [0, 2^n). Increasing it will mostly affect Client and not a Server, since Client will have to generate a larger inversion table and process more sequences, while Server will just generate a larger numbers.
TODO: https://github.com/svkior/powgwey/issues/36
4. Server environment variables
###############################################
# -=(* TCP SERVER CONFIG *)=-
###############################################
SRV_PORT=8000
SRV_HOST=0.0.0.0
SRV_NET_READ_TIMEOUT=1s
SRV_NET_WRITE_TIMEOUT=1s
###############################################
# -=(* QUOTES STORAGE COMPONENT CONFIG *)=-
###############################################
# Fiction processing time of getting quotes
SRV_QUOTES_PROCESSING_TIME=0.3s
# Filepath of quotes database
SRV_QUOTES_FILEPATH=/opt/user/data/movies.json
###############################################
# -=(* QUOTES SERVICE COMPONENT CONFIG *)=-
###############################################
# Number of workers in Quotes workers queue
SRV_QUOTES_WORKERS=100
5. Client command lines
We have single parameter for describing connection string.
client -server=127.0.0.1:8000