This project is the implementation of the proposal: Drand for Cartesi
Drand enables us to offer pseudo random numbers to Cartesi DApps in a simple manner.
Drand is a distributed randomness beacon daemon written in Golang. Linked drand nodes collectively produce publicly verifiable, unbiased and unpredictable random values at fixed intervals using bilinear pairings and threshold cryptography. Drand is used by various projects such as Filecoin, The League of Entropy and Heliax.
- Rust ^1.78.0
- Install rust with rustup. https://www.rust-lang.org/tools/install
- Install node and install packages
- Build rust and npm packages
Self container middleware: You can use cartesi CLI to compile using Docker. Install cartesi CLI follow this steps: https://docs.cartesi.io/cartesi-rollups/1.3/quickstart/
Consult this for more info: https://docs.sunodo.io/guide/deploying/deploying-application
sequenceDiagram
autonumber
box dApp Frontend
actor Bob
actor Alice
end
box Off-chain
participant API
end
participant L1 & Rollups
box Cartesi Machine
participant Middleware
participant Random
participant dApp as dApp Backend
end
Bob->>L1 & Rollups: Bob's input
activate L1 & Rollups
L1 & Rollups->>Middleware: Bob's input
activate Middleware
loop Every clock
L1 & Rollups --> Middleware: Waiting for beacon
end
Middleware->>dApp: Bob's input
activate dApp
dApp->>Random: request random
activate Random
Random->>Middleware: flag to hold on next inputs
Alice->>L1 & Rollups: Alice Input
activate L1 & Rollups
L1 & Rollups->>Middleware: Alice Input
activate Middleware
Middleware ->> Middleware: save input (hold flag)
API->>L1 & Rollups: Drand's beacon
L1 & Rollups->>Middleware: Drand's beacon
Middleware->>Random: Drand's beacon
Random-->>dApp: random response
dApp-->>Middleware: ok Bob
deactivate dApp
Middleware-->>L1 & Rollups: ok Bob
deactivate Middleware
L1 & Rollups-->>Bob: ok Bob
deactivate L1 & Rollups
Middleware->>dApp: Alice's input
activate dApp
dApp-->>Middleware: ok Alice
deactivate dApp
Middleware-->>L1 & Rollups: ok Alice
L1 & Rollups-->>Alice: ok Alice
deactivate Random
deactivate Middleware
deactivate L1 & Rollups
Bob initiates a new random number process by sending an input to the Cartesi Rollups. The frontend is unaware of whether the DApp backend inside the Cartesi Machine will require a random number. As needed, the DApp backend will request a random number from the Random Server. The Random Server will then signal the Convenience Middleware to hold all subsequent inputs until the beacon arrives.
The Convenience API will periodically inspect the Cartesi Machine to check if there are any inputs awaiting a beacon. When the Convenience API detects an input waiting for a random number, it will request the latest beacon from the Drand network and send it to the Cartesi Rollups.
The Random Server will calculate the creation time of the beacon by subtracting a safe number of seconds to prevent any prior knowledge of the beacon by the user. Within this safe time, it will load the pending random requests sent before that timestamp and respond with a generated seed. Finally, the DApp will receive that seed to generate a random number.
When an input backend execution requesting a random number arrives, it will force any subsequent inputs (whether they require a random number or not) to be stored until the next Drand beacon arrives. This rule ensures the correct sequence of input execution.
We know that the user’s DApp calls the rollup server, we change the arrow direction to make the problem easier to think about. In reality, DApps will call our middleware and our middleware will call the rollup server.
The DApp’s owner can run an instance of the Convenience API to provide this random number functionality.
The middleware provides 2 endpoints
/finish Replace the Rollup's finish endpoint with this one. Example: http://localhost:8080/finish
/random?timestamp=[timestamp] Call this one to get a seed from Drand. Example: http://localhost:8080/random?timestamp=1692129529 It will return 404 when the seed isn't available.
With cartesi instance:
cartesi build
cartesi run
Start the middleware:
cd convenience-middleware/
cargo run
Start the drand-provider:
cd convenience-drand-provider/
npm ci && npm run dev
Run this smoke test:
export TIMESTAMP=`date +%s`
curl http://localhost:8080/random?timestamp=${TIMESTAMP}
sleep 10
curl http://localhost:8080/random?timestamp=${TIMESTAMP}
sleep 10
curl http://localhost:8080/random?timestamp=${TIMESTAMP}
Run the rollups:
cartesi build
cartesi run
To run the blackjack frontend:
cd dapp-blackjack
npm ci && npm start
The update_drand_config
endpoint allows you to update the configuration for Drand. This endpoint accepts HTTP PUT requests and expects a JSON payload containing the necessary configuration parameters.
- Endpoint URL:
http://localhost:8080/update_drand_config
- HTTP Method: PUT
The endpoint requires a JSON payload with the following parameters:
{
"DRAND_PUBLIC_KEY": "a0b862a7527fee3a731bcb59280ab6abd62d5c0b6ea03dc4ddf6612fdfc9d01f01c31542541771903475eb1ec6615f8d0df0b8b6dce385811d6dcf8cbefb8759e5e616a3dfd054c928940766d9a5b9db91e3b697e5d70a975181e007f87fca5e",
"DRAND_PERIOD": 3,
"DRAND_GENESIS_TIME": 1677685200,
"DRAND_SAFE_SECONDS": 5
}
- DRAND_PUBLIC_KEY (string): The public key for Drand.
- DRAND_GENESIS_TIME (integer): The genesis time for Drand.
- DRAND_SAFE_SECONDS (integer): The safe seconds for Drand.
- DRAND_PERIOD (integer): The period for Drand.
curl -X PUT http://localhost:8080/update_drand_config \
-H "Content-Type: application/json" \
-d '{
"DRAND_PUBLIC_KEY": "a0b862a7527fee3a731bcb59280ab6abd62d5c0b6ea03dc4ddf6612fdfc9d01f01c31542541771903475eb1ec6615f8d0df0b8b6dce385811d6dcf8cbefb8759e5e616a3dfd054c928940766d9a5b9db91e3b697e5d70a975181e007f87fca5e",
"DRAND_PERIOD": 3,
"DRAND_GENESIS_TIME": 1677685200,
"DRAND_SAFE_SECONDS": 5
}'
The endpoint responds with an appropriate HTTP status code. A successful update will return a 200 OK
status code.
In case of an error, the endpoint will return an appropriate HTTP status code along with an error message in the response body.