Skip to content

Commit d8fe643

Browse files
committed
more fields
1 parent cde2700 commit d8fe643

File tree

7 files changed

+112
-11
lines changed

7 files changed

+112
-11
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
ALTER TABLE request
2-
DROP COLUMN gas_used;
2+
DROP COLUMN gas_used;
3+
ALTER TABLE request
4+
DROP COLUMN gas_limit;
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1+
-- U256 max value is 78 digits, so 100 is a safe upper bound
12
ALTER TABLE request
2-
ADD COLUMN gas_used VARCHAR(100); -- U256 max value is 78 digits, so 100 is a safe upper bound
3+
ADD COLUMN gas_used VARCHAR(100);
4+
ALTER TABLE request
5+
ADD COLUMN gas_limit VARCHAR(100) NOT NULL;

apps/fortuna/src/api/explorer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ use {
1616
#[derive(Debug, serde::Serialize, serde::Deserialize, IntoParams)]
1717
#[into_params(parameter_in=Query)]
1818
pub struct ExplorerQueryParams {
19-
/// Only return logs that are newer or equal to this timestamp.
19+
/// Only return logs that are newer or equal to this timestamp. Timestamp is in ISO 8601 format with UTC timezone.
2020
#[param(value_type = Option<String>, example = "2023-10-01T00:00:00Z")]
2121
pub min_timestamp: Option<DateTime<Utc>>,
22-
/// Only return logs that are older or equal to this timestamp.
22+
/// Only return logs that are older or equal to this timestamp. Timestamp is in ISO 8601 format with UTC timezone.
2323
#[param(value_type = Option<String>, example = "2033-10-01T00:00:00Z")]
2424
pub max_timestamp: Option<DateTime<Utc>>,
2525
/// The query string to search for. This can be a transaction hash, sender address, or sequence number.

apps/fortuna/src/history.rs

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ use {
22
crate::api::ChainId,
33
anyhow::Result,
44
chrono::{DateTime, NaiveDateTime},
5-
ethers::{core::utils::hex::ToHex, prelude::TxHash, types::{Address, U256}},
5+
ethers::{
6+
core::utils::hex::ToHex,
7+
prelude::TxHash,
8+
types::{Address, U256},
9+
utils::keccak256,
10+
},
611
serde::Serialize,
712
serde_with::serde_as,
813
sqlx::{migrate, Pool, Sqlite, SqlitePool},
@@ -17,6 +22,7 @@ use {
1722
pub enum RequestEntryState {
1823
Pending,
1924
Completed {
25+
/// The block number of the reveal transaction.
2026
reveal_block_number: u64,
2127
/// The transaction hash of the reveal transaction.
2228
#[schema(example = "0xfe5f880ac10c0aae43f910b5a17f98a93cdd2eb2dce3a5ae34e5827a3a071a32", value_type = String)]
@@ -28,7 +34,12 @@ pub enum RequestEntryState {
2834
/// The gas used for the reveal transaction in the smallest unit of the chain.
2935
/// For example, if the native currency is ETH, this will be in wei.
3036
#[schema(example = "567890", value_type = String)]
37+
#[serde(with = "crate::serde::u256")]
3138
gas_used: U256,
39+
/// The combined random number generated from the user and provider contributions.
40+
#[schema(example = "a905ab56567d31a7fda38ed819d97bc257f3ebe385fc5c72ce226d3bb855f0fe")]
41+
#[serde_as(as = "serde_with::hex::Hex")]
42+
combined_random_number: [u8; 32],
3243
},
3344
Failed {
3445
reason: String,
@@ -56,6 +67,11 @@ pub struct RequestStatus {
5667
/// The transaction hash of the request transaction.
5768
#[schema(example = "0x5a3a984f41bb5443f5efa6070ed59ccb25edd8dbe6ce7f9294cf5caa64ed00ae", value_type = String)]
5869
pub request_tx_hash: TxHash,
70+
/// Gas limit for the callback in the smallest unit of the chain.
71+
/// For example, if the native currency is ETH, this will be in wei.
72+
#[schema(example = "500000", value_type = String)]
73+
#[serde(with = "crate::serde::u256")]
74+
pub gas_limit: U256,
5975
/// The user contribution to the random number.
6076
#[schema(example = "a905ab56567d31a7fda38ed819d97bc257f3ebe385fc5c72ce226d3bb855f0fe")]
6177
#[serde_as(as = "serde_with::hex::Hex")]
@@ -66,6 +82,18 @@ pub struct RequestStatus {
6682
pub state: RequestEntryState,
6783
}
6884

85+
impl RequestStatus {
86+
pub fn generate_combined_random_number(
87+
user_random_number: &[u8; 32],
88+
provider_random_number: &[u8; 32],
89+
) -> [u8; 32] {
90+
let mut concat: [u8; 96] = [0; 96]; // last 32 bytes are for the block hash which is not used here
91+
concat[0..32].copy_from_slice(user_random_number);
92+
concat[32..64].copy_from_slice(provider_random_number);
93+
keccak256(&concat)
94+
}
95+
}
96+
6997
#[derive(Clone, Debug, Serialize, ToSchema, PartialEq)]
7098
struct RequestRow {
7199
chain_id: String,
@@ -78,6 +106,7 @@ struct RequestRow {
78106
request_tx_hash: String,
79107
user_random_number: String,
80108
sender: String,
109+
gas_limit: String,
81110
reveal_block_number: Option<i64>,
82111
reveal_tx_hash: Option<String>,
83112
provider_random_number: Option<String>,
@@ -98,6 +127,8 @@ impl TryFrom<RequestRow> for RequestStatus {
98127
let user_random_number = hex::FromHex::from_hex(row.user_random_number)?;
99128
let request_tx_hash = row.request_tx_hash.parse()?;
100129
let sender = row.sender.parse()?;
130+
let gas_limit = U256::from_dec_str(&row.gas_limit)
131+
.map_err(|_| anyhow::anyhow!("Failed to parse gas limit"))?;
101132

102133
let state = match row.state.as_str() {
103134
"Pending" => RequestEntryState::Pending,
@@ -116,16 +147,20 @@ impl TryFrom<RequestRow> for RequestStatus {
116147
))?;
117148
let provider_random_number: [u8; 32] =
118149
hex::FromHex::from_hex(provider_random_number)?;
119-
let gas_used = row.gas_used.ok_or(anyhow::anyhow!(
120-
"Gas used is missing for completed request"
121-
))?;
150+
let gas_used = row
151+
.gas_used
152+
.ok_or(anyhow::anyhow!("Gas used is missing for completed request"))?;
122153
let gas_used = U256::from_dec_str(&gas_used)
123154
.map_err(|_| anyhow::anyhow!("Failed to parse gas used"))?;
124155
RequestEntryState::Completed {
125156
reveal_block_number,
126157
reveal_tx_hash,
127158
provider_random_number,
128159
gas_used,
160+
combined_random_number: Self::generate_combined_random_number(
161+
&user_random_number,
162+
&provider_random_number,
163+
),
129164
}
130165
}
131166
"Failed" => RequestEntryState::Failed {
@@ -150,6 +185,7 @@ impl TryFrom<RequestRow> for RequestStatus {
150185
request_tx_hash,
151186
user_random_number,
152187
sender,
188+
gas_limit,
153189
})
154190
}
155191
}
@@ -208,12 +244,13 @@ impl History {
208244
let chain_id = new_status.chain_id;
209245
let request_tx_hash: String = new_status.request_tx_hash.encode_hex();
210246
let provider: String = new_status.provider.encode_hex();
247+
let gas_limit = new_status.gas_limit.to_string();
211248
let result = match new_status.state {
212249
RequestEntryState::Pending => {
213250
let block_number = new_status.request_block_number as i64;
214251
let sender: String = new_status.sender.encode_hex();
215252
let user_random_number: String = new_status.user_random_number.encode_hex();
216-
sqlx::query!("INSERT INTO request(chain_id, provider, sequence, created_at, last_updated_at, state, request_block_number, request_tx_hash, user_random_number, sender) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
253+
sqlx::query!("INSERT INTO request(chain_id, provider, sequence, created_at, last_updated_at, state, request_block_number, request_tx_hash, user_random_number, sender, gas_limit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
217254
chain_id,
218255
provider,
219256
sequence,
@@ -223,15 +260,18 @@ impl History {
223260
block_number,
224261
request_tx_hash,
225262
user_random_number,
226-
sender)
263+
sender,
264+
gas_limit
265+
)
227266
.execute(pool)
228267
.await
229268
}
230269
RequestEntryState::Completed {
231270
reveal_block_number,
232271
reveal_tx_hash,
233272
provider_random_number,
234-
gas_used
273+
gas_used,
274+
combined_random_number: _,
235275
} => {
236276
let reveal_block_number = reveal_block_number as i64;
237277
let reveal_tx_hash: String = reveal_tx_hash.encode_hex();
@@ -429,6 +469,7 @@ mod test {
429469
user_random_number: [20; 32],
430470
sender: Address::random(),
431471
state: RequestEntryState::Pending,
472+
gas_limit: U256::from(500_000),
432473
}
433474
}
434475

@@ -443,6 +484,10 @@ mod test {
443484
reveal_tx_hash,
444485
provider_random_number: [40; 32],
445486
gas_used: U256::from(567890),
487+
combined_random_number: RequestStatus::generate_combined_random_number(
488+
&status.user_random_number,
489+
&[40; 32],
490+
),
446491
};
447492
History::update_request_status(&history.pool, status.clone()).await;
448493

@@ -494,6 +539,10 @@ mod test {
494539
reveal_tx_hash,
495540
provider_random_number: [40; 32],
496541
gas_used: U256::from(567890),
542+
combined_random_number: RequestStatus::generate_combined_random_number(
543+
&status.user_random_number,
544+
&[40; 32],
545+
),
497546
};
498547
History::update_request_status(&history.pool, status.clone()).await;
499548
let mut failed_status = status.clone();
@@ -527,6 +576,26 @@ mod test {
527576
assert_eq!(logs, vec![status.clone()]);
528577
}
529578

579+
#[tokio::test]
580+
async fn test_generate_combined_random_number() {
581+
let user_random_number = hex::FromHex::from_hex(
582+
"0000000000000000000000006c8ac03d388d5572f77aca84573628ee87a7a4da",
583+
)
584+
.unwrap();
585+
let provider_random_number = hex::FromHex::from_hex(
586+
"deeb67cb894c33f7b20ae484228a9096b51e8db11461fcb0975c681cf0875d37",
587+
)
588+
.unwrap();
589+
let combined_random_number = RequestStatus::generate_combined_random_number(
590+
&user_random_number,
591+
&provider_random_number,
592+
);
593+
let expected_combined_random_number: [u8; 32] = hex::FromHex::from_hex(
594+
"1c26ffa1f8430dc91cb755a98bf37ce82ac0e2cfd961e10111935917694609d5",
595+
)
596+
.unwrap();
597+
assert_eq!(combined_random_number, expected_combined_random_number,);
598+
}
530599

531600
#[tokio::test]
532601
async fn test_history_filter_irrelevant_logs() {

apps/fortuna/src/keeper/process_event.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub async fn process_event_with_backoff(
5151
sender: event.requestor,
5252
user_random_number: event.user_random_number,
5353
state: RequestEntryState::Pending,
54+
gas_limit,
5455
};
5556
history.add(&status);
5657

@@ -93,6 +94,10 @@ pub async fn process_event_with_backoff(
9394
reveal_tx_hash: result.receipt.transaction_hash,
9495
provider_random_number: provider_revelation,
9596
gas_used: result.receipt.gas_used.unwrap_or_default(),
97+
combined_random_number: RequestStatus::generate_combined_random_number(
98+
&event.user_random_number,
99+
&provider_revelation,
100+
),
96101
};
97102
history.add(&status);
98103
tracing::info!(

apps/fortuna/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ pub mod config;
55
pub mod eth_utils;
66
pub mod history;
77
pub mod keeper;
8+
pub mod serde;
89
pub mod state;

apps/fortuna/src/serde.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
pub mod u256 {
2+
use {
3+
ethers::types::U256,
4+
serde::{de::Error, Deserialize, Deserializer, Serializer},
5+
};
6+
7+
pub fn serialize<S>(b: &U256, s: S) -> Result<S::Ok, S::Error>
8+
where
9+
S: Serializer,
10+
{
11+
s.serialize_str(b.to_string().as_str())
12+
}
13+
14+
pub fn deserialize<'de, D>(d: D) -> Result<U256, D::Error>
15+
where
16+
D: Deserializer<'de>,
17+
{
18+
let s: String = Deserialize::deserialize(d)?;
19+
U256::from_dec_str(s.as_str()).map_err(|err| D::Error::custom(err.to_string()))
20+
}
21+
}

0 commit comments

Comments
 (0)