Skip to content

Commit

Permalink
Use MAX_CHALLENGES_WITH_CAPTCHA instead of CAPTCHA_CHALLENGES_REDUCTI…
Browse files Browse the repository at this point in the history
…ON_RATIO
  • Loading branch information
harryttd committed Sep 29, 2023
1 parent a5867ce commit 5b6c461
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 52 deletions.
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ MIN_TEZ=1
MAX_TEZ=6000

MIN_CHALLENGES=1
MAX_CHALLENGES=120
MAX_CHALLENGES=550
MAX_CHALLENGES_WITH_CAPTCHA=66
CHALLENGE_SIZE=2048
DIFFICULTY=4
CAPTCHA_CHALLENGES_REDUCTION_RATIO=0.88
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ Here's a general flow of how it works:
2. **Solving Challenges**: The user must solve the challenge by finding a correct solution. The complexity of the challenge can vary, and the number of challenges to be solved scales linearly with the amount of Tez requested.
3. **Verification & Receiving Tez**: Once the user submits a solution, the backend verifies it. If the solution is correct but there are more challenges to be solved, the user will be sent another challenge. This repeats until all challenges are solved correctly. Only then is the requested Tez granted to the user.

## Programmatic Faucet Usage

For programmatic usage of the faucet, we provide a `getTez.js` script located in the `/scripts` directory of the frontend repository. Please refer to it for more details on how to use it. This script can be run from a JavaScript program or directly from a shell. It interacts with the backend to request Tez, solve the required challenges, and verify the solutions.

Please note that the `getTez.js` script does not use CAPTCHA. Therefore, when using the programmatic faucet, more challenges can be given.

## Prerequisites

- **Node.js** v18
Expand All @@ -35,21 +41,21 @@ Optional:
- `MAX_BALANCE`: maximum address balance beyond which sending of XTZ is refused (default: `6000`)
- `MIN_TEZ`: Minimum amount of Tez that can be requested (default: `1`)
- `MAX_TEZ`: Maximum amount of Tez that can be requested (default: `6000`)
- `MAX_CHALLENGES`: Maximum number of challenges required for the maximum Tez request (default: `120`)
- `DIFFICULTY`: Difficulty level for challenges (default: `4`)
- `CHALLENGE_SIZE`: How many bytes the challenge string should be (default: `2048`)
- `MIN_CHALLENGES`: Minimum number of challenges required for the minimum Tez request (default: `1`)
- `DIFFICULTY`: Difficulty level for challenges (default: `5`)
- `CHALLENGE_SIZE`: How many bytes the challenge string should be (default: `32`)
- `CAPTCHA_CHALLENGES_REDUCTION_RATIO`: A percentage value between 0 and 1, indicating how much easier challenges should be when a captcha is used (default: `0.5`)
- `MAX_CHALLENGES`: Maximum number of challenges required for the maximum Tez request (default: `120`)
- `MAX_CHALLENGES_WITH_CAPTCHA`: Maximum number of challenges required for the maximum Tez request when a captcha is used (default: `66`)

### Configuring Challenges

The `MAX_CHALLENGES`, `MIN_CHALLENGES`, `CHALLENGE_SIZE`, `DIFFICULTY`, `MIN_TEZ`, `MAX_TEZ`, and `CAPTCHA_CHALLENGES_REDUCTION_RATIO` environment variables control the number and difficulty of the challenges that a user must solve to receive Tez.
The `MAX_CHALLENGES`, `MIN_CHALLENGES`, `CHALLENGE_SIZE`, `DIFFICULTY`, `MIN_TEZ`, `MAX_TEZ`, and `MAX_CHALLENGES_WITH_CAPTCHA` environment variables control the number and difficulty of the challenges that a user must solve to receive Tez.

The `DIFFICULTY` variable determines the complexity of each challenge. A higher value will make each challenge more difficult and time-consuming to solve.

The `MAX_CHALLENGES` and `MIN_CHALLENGES` variables determine the maximum and minimum number of challenges that a user must solve to receive the max and min amount of Tez, respectively. The actual number of challenges scales linearly with the amount of Tez requested. The proportion of the requested Tez to the maximum Tez (`MAX_TEZ`) is calculated, and the number of challenges is scaled based on this proportion. If a captcha is used, the number of challenges is reduced by a certain ratio (`CAPTCHA_CHALLENGES_REDUCTION_RATIO`).
The `MAX_CHALLENGES` and `MIN_CHALLENGES` variables determine the maximum and minimum number of challenges that a user must solve to receive the max and min amount of Tez, respectively. The actual number of challenges scales linearly with the amount of Tez requested. The proportion of the requested Tez to the maximum Tez (`MAX_TEZ` or `MAX_CHALLENGES_WITH_CAPTCHA` if captcha is used) is calculated, and the number of challenges is scaled based on this proportion.

For example, assume with a `DIFFICULTY` of 5 and `CHALLENGE_SIZE` of 32 the average time to find a solution is approximately 5 seconds. Therefore, if `MAX_TEZ` is set to 6000 and `MAX_CHALLENGES` is set to 120, it would take a user about 10 minutes (600 seconds) to receive 6000 Tez. If say `CAPTCHA_CHALLENGES_REDUCTION_RATIO=0.5`, then when using CAPTCHA it should take half the time to solve the challenges and receive Tez. The actual time may vary depending on the user's computational resources.
For example, assume with a `DIFFICULTY` of 4 and `CHALLENGE_SIZE` of 2048 the average time to find a solution is approximately 1.09 seconds when using the `getTez` script from the CLI or in a Node.js program, and approximately 4.6 seconds when solving challenges in the browser with the faucet frontend. Therefore, if `MAX_TEZ` is set to 6000 and `MAX_CHALLENGES` is set to 550, it would take a user about 10 minutes (600 seconds) to receive 6000 Tez when using the `getTez` script. With `MAX_CHALLENGES_WITH_CAPTCHA` set to 66, then when using CAPTCHA via the browser it should take about 5 minutes to solve the challenges and receive Tez. The actual time may vary a bit depending on the user's computational resources.

## Running the API

Expand Down Expand Up @@ -120,9 +126,3 @@ The endpoint verifies the solution by trying to regenerate it using the challeng
If the solution is correct but the required number of challenges have not yet been satisfied, a new challenge is generated and returned in the response.

If all challenges have been completed, the user's address is granted the requested amount of Tez. The transaction hash is returned to indicate the transfer was successful.

## Programmatic Faucet Usage

For programmatic usage of the faucet, we provide a `getTez.js` script located in the `/scripts` directory of the frontend repository. Please refer to it for more details on how to use it. This script can be run from a JavaScript program or directly from a shell. It interacts with the backend to request Tez, solve the required challenges, and verify the solutions.

Please note that the `getTez.js` script does not use CAPTCHA. Therefore, when using the programmatic faucet, challenges can be configured to be more difficult and require more of them to be solved.
51 changes: 25 additions & 26 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ const {
MAX_TEZ,
MIN_CHALLENGES,
MAX_CHALLENGES,
MAX_CHALLENGES_WITH_CAPTCHA,
CHALLENGE_SIZE,
DIFFICULTY,
CAPTCHA_CHALLENGES_REDUCTION_RATIO,
} = process.env

const env = {
Expand All @@ -23,53 +23,52 @@ const env = {
MAX_BALANCE: MAX_BALANCE ? Number(MAX_BALANCE) : 6000,
MIN_TEZ: MIN_TEZ ? Number(MIN_TEZ) : 1,
MAX_TEZ: MAX_TEZ ? Number(MAX_TEZ) : 6000,
MIN_CHALLENGES: MIN_CHALLENGES ? Number(MIN_CHALLENGES) : 1,
MAX_CHALLENGES: MAX_CHALLENGES ? Number(MAX_CHALLENGES) : 550,
CHALLENGE_SIZE: CHALLENGE_SIZE ? Number(CHALLENGE_SIZE) : 2048,
DIFFICULTY: DIFFICULTY ? Number(DIFFICULTY) : 4,
CAPTCHA_CHALLENGES_REDUCTION_RATIO: CAPTCHA_CHALLENGES_REDUCTION_RATIO
? Number(CAPTCHA_CHALLENGES_REDUCTION_RATIO)
: 0.88,
MIN_CHALLENGES: MIN_CHALLENGES ? Number(MIN_CHALLENGES) : 1,
MAX_CHALLENGES: MAX_CHALLENGES ? Number(MAX_CHALLENGES) : 550,
MAX_CHALLENGES_WITH_CAPTCHA: MAX_CHALLENGES_WITH_CAPTCHA
? Number(MAX_CHALLENGES_WITH_CAPTCHA)
: 66,
}

const vars: (keyof typeof env)[] = [
"CAPTCHA_CHALLENGES_REDUCTION_RATIO",
"CHALLENGE_SIZE",
"DIFFICULTY",
"MAX_BALANCE",
"MAX_TEZ",
"MIN_TEZ",
"MAX_CHALLENGES",
"CHALLENGE_SIZE",
"DIFFICULTY",
"MIN_CHALLENGES",
"MAX_CHALLENGES",
"MAX_CHALLENGES_WITH_CAPTCHA",
]

vars.forEach((v) => {
const value: any = env[v]
if (isNaN(value)) throw new Error(`Env var ${v} must be a number.`)

if (["CHALLENGE_SIZE", "DIFFICULTY"].includes(v)) {
if (value <= 0) {
throw new Error(`Env var ${v} must be greater than 0.`)
}
if (
[
"CHALLENGE_SIZE",
"DIFFICULTY",
"MIN_CHALLENGES",
"MAX_CHALLENGES",
"MAX_CHALLENGES_WITH_CAPTCHA",
].includes(v)
) {
if (value <= 0) {
throw new Error(`Env var ${v} must be greater than 0.`)
}
}
})

if (
env.CAPTCHA_CHALLENGES_REDUCTION_RATIO < 0 ||
env.CAPTCHA_CHALLENGES_REDUCTION_RATIO >= 1
) {
throw new Error(
"Env var CAPTCHA_CHALLENGES_REDUCTION_RATIO must be >= 0 and < 1."
)
}

if (
env.MAX_CHALLENGES < env.MIN_CHALLENGES ||
env.MIN_CHALLENGES <= 0 ||
env.MAX_CHALLENGES <= 0
env.MAX_CHALLENGES_WITH_CAPTCHA < env.MIN_CHALLENGES
) {
throw new Error(
"Env vars MAX_CHALLENGES and MIN_CHALLENGES must be greater than 0 and MAX_CHALLENGES must be greater than or equal to MIN_CHALLENGES."
`Env vars MAX_CHALLENGES and MAX_CHALLENGES_WITH_CAPTCHA must be
greater than or equal to MIN_CHALLENGES.`
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ declare global {
MAX_TEZ: string
MIN_CHALLENGES: string
MAX_CHALLENGES: string
MAX_CHALLENGES_WITH_CAPTCHA: string
CHALLENGE_SIZE: string
DIFFICULTY: string
CAPTCHA_CHALLENGES_REDUCTION_RATIO: string
}
}
}
Expand Down
14 changes: 4 additions & 10 deletions src/pow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,15 @@ const determineDifficulty = () => {
}

const determineChallengesNeeded = (amount: number, usedCaptcha: boolean) => {
const { MIN_TEZ, MAX_TEZ, MIN_CHALLENGES, MAX_CHALLENGES, } = env
const { MIN_TEZ, MAX_TEZ, MIN_CHALLENGES, MAX_CHALLENGES, MAX_CHALLENGES_WITH_CAPTCHA } = env

// Calculate the proportion of the requested Tez to the maximum Tez
const tezProportion = (amount - MIN_TEZ) / (MAX_TEZ - MIN_TEZ)

// Calculate the base number of challenges based on the Tez proportion
let baseChallenges = tezProportion * (MAX_CHALLENGES - MIN_CHALLENGES) + MIN_CHALLENGES
// Calculate the base number of challenges based on the Tez proportion and whether a captcha was used
const maxChallenges = usedCaptcha ? MAX_CHALLENGES_WITH_CAPTCHA : MAX_CHALLENGES
const challengesNeeded = Math.ceil(tezProportion * (maxChallenges - MIN_CHALLENGES) + MIN_CHALLENGES)

// If a captcha was used, reduce the number of challenges
if (usedCaptcha) {
baseChallenges *= (1 - env.CAPTCHA_CHALLENGES_REDUCTION_RATIO)
}

// Round the number of challenges to the nearest whole number
const challengesNeeded = Math.ceil(baseChallenges)
return challengesNeeded
}

Expand Down

0 comments on commit 5b6c461

Please sign in to comment.