This project is a test assignment and, as such, should be considered a learning exercise rather than a production-ready solution. The implementation, especially the Proof of Work (PoW) component, is conceptual and may not align with real-world best practices in cryptography or network security. Key points to note:
-
PoW Resource Consumption: The PoW mechanism implemented here may consume more resources than the request handler itself. This approach was chosen to fulfill the assignment's requirements and demonstrate the concept. In a real-world scenario, the resource consumption and efficiency of such a system would need careful evaluation and likely a different approach.
-
Level of Abstraction and Complexity: I've tried to keep a balance between the complexity needed for a production-ready application and a minimal solution that gets the job done. The result is what I might have developed as a proof-of-concept for a new service. It includes the basic code layout structure, an example of unit testing, fuzz testing, things like graceful shutdown, and basic build tooling.
This project implements a TCP server that provides quotes from a specified collection. To protect against DDoS attacks, the server uses a simple Proof of Work (PoW) challenge-response mechanism. Clients must solve a PoW challenge before receiving a quote.
cmd
: This directory contains the entry points for the server and client applications.pkg
: Houses the core packages used by applications.
Dockerfiles for building container images are located in their respective subdirectories under cmd
.
db.txt
: A text file serving as a simple database for storing quotes. This file is used by the server to retrieve quotes.
Provided examples should be run from the project root.
go run ./cmd/wow -h
Usage of wow:
-addr string
application network address (default ":1111")
-db string
database file (default "db.txt")
-difficulty int
challenge difficulty (default 4)
-timeout duration
connection idle timeout (default 3s)
Client provides an interface similar to ab
, you can specify the total number of requests and a concurrency level
using -n
and -c
flags.
To print the quotes to standard output, use -v
flag.
go run ./cmd/client -h
Usage of client:
-addr string
server address (default "localhost:1111")
-c int
request concurrency (default 1)
-n int
request number (default 1)
-v print quotes
- Go (version 1.21 or later)
go run ./cmd/wow
go run ./cmd/client -v -n 5 -c 3
Images should be built from the root directory of the project.
- Docker
docker build -f cmd/wow/Dockerfile -t wow .
docker build -f cmd/client/Dockerfile -t client .
docker run -p 1111:1111 wow
docker run --net=host client -v -n 3 -c 3
To test the failure scenario, you can use the telnet
application.
You might want to set a longer idle timeout for this test.
docker run -p 1111:1111 wow -timeout 30s
telnet localhost 1111
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get
4:Oz7FBPiu3tOE
12345
Connection closed by foreign host.
Server will print a warning for incorrect solution:
2024/02/04 17:05:07 WARN failed to verify solution error="incorrect solution \"12345\" for challange \"4:Oz7FBPiu3tOE\""
The client initiates the interaction by establishing a TCP connection to the server. The established connection may be reused to issue subsequent requests.
Upon establishing a connection, the client sends a get
command to the server to request a quote.
- The server responds to the
get
command by sending a PoW challenge. The challenge comprises a difficulty level and a random string, separated by a colon:
. - The client is required to compute a solution to the PoW challenge by finding a nonce. This nonce, when concatenated with the challenge string and hashed using SHA-256, should produce a hash with the specified number of leading zeros.
- The client then sends the computed nonce back to the server as the solution.
- Upon receiving the nonce, the server verifies the client's PoW solution.
- If the solution is valid, the server selects a quote from its database using a round-robin method and sends it to the client.
- The server indicates the end of the quote by sending an additional newline character, resulting in an empty line.
The server may terminate the connection if the client's PoW solution is incorrect or after a specified idle timeout period. The client can also close the connection.
- The client connects to the server.
- The client issues a
get
command. - The server sends a PoW challenge:
"4:abc123"
. - The client calculates and returns the solution:
"56789"
. - The server verifies the solution and sends a quote followed by an empty
line:
"hello, world\n--Brian Kernighan, Programming in C: A Tutorial\n\n"
. - The client closes the connection.
The database file is a simple text file.
- Each quote in the database file is separated by a blank line.
- A single quote can span multiple lines, allowing for longer quotes.
- The end of a quote is marked by a newline character, followed by a blank line.
- The file ends with a blank line following the last quote.
Here is an example illustrating the format of the db file:
The only true wisdom is in knowing you know nothing.
-- Socrates
The unexamined life is not worth living.
-- Socrates
To know, is to know that you know nothing. That is the meaning of true knowledge.
-- Socrates