1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
use serde_derive::{Deserialize, Serialize};
/// Configuration for oracle duties.
///
/// This struct defines the parameters that control how oracle duties are scheduled,
/// executed, and finalized within the system.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct OracleDutyConfig {
/// The number of validators assigned to each oracle duty.
pub validators_per_duty: u32,
/// The number of consensus rounds to wait before an oracle request is issued.
pub oracle_request_delay: u32,
/// The size of the window (in rounds) during which oracle updates are collected.
/// Must be an odd number.
pub collection_window_size: u32,
/// The number of rounds to wait after the proposal round before the duty is considered committed.
pub commitment_buffer: u32,
/// Max size of oracle output in bytes.
pub max_oracle_output_size: u32,
}
impl Default for OracleDutyConfig {
fn default() -> Self {
Self {
// 3-validator committees gives us 99.996% success rate leveraging TEE guarantees
validators_per_duty: Self::DEFAULT_VALIDATORS_PER_DUTY,
// Time to execute an oracle, determined experimentally
oracle_request_delay: 6,
// ±1 round around proposal round (3 total rounds)
collection_window_size: 3,
// 3 rounds (150ms) provide adequate collection time with acceptable latency
commitment_buffer: 3,
// Safe size for the default number of validators.
max_oracle_output_size: Self::DEFAULT_MAX_ORACLE_OUTPUT_SIZE,
}
}
}
impl OracleDutyConfig {
/// Safe max size limit for the default number of validators.
pub const DEFAULT_MAX_ORACLE_OUTPUT_SIZE: u32 = 10 * 1024;
/// A reasonably safe value to make one-off oracles succeed with >22 bits of security.
/// This value is based on the example from the Rialo whitepaper, that is N = 130, D = 43.
pub const ONE_OFF_VALIDATORS_PER_DUTY: u32 = 13;
/// A small value for oracles that is reasonably cheap.
/// Note that by itself it doesn't provide a response reliably enough
/// and needs retries in case of failure..
pub const DEFAULT_VALIDATORS_PER_DUTY: u32 = 5;
/// Most oracles should complete within a few blocks.
pub const DEFAULT_ORACLE_REQUEST_DELAY: u32 = 6;
/// The minimum allowed delay for oracle requests, in consensus rounds.
pub const MIN_ORACLE_REQUEST_DELAY: u32 = 2; // 0.1s = 2 rounds
/// The maximum allowed delay for oracle requests, in consensus rounds.
pub const MAX_ORACLE_REQUEST_DELAY: u32 = 4800; // 240s = 4800 rounds
/// Default maximum number of ASAP duties to process in a single consensus round
pub const DEFAULT_MAX_ASAP_DUTIES_PER_COMMIT: usize = 5;
/// Default timeout for ASAP duties in rounds
pub const DEFAULT_ASAP_TIMEOUT_COMMITS: u32 = 50;
/// Sets the oracle request delay (in consensus rounds).
///
/// # Arguments
///
/// * `delay` - The number of rounds to wait before issuing an oracle request.
pub fn set_oracle_request_delay(&mut self, delay: u32) {
self.oracle_request_delay = delay;
}
/// Sets the maximum oracle output size (in bytes).
///
/// # Arguments
///
/// * `max_oracle_output_size` - The maximum size allowed for oracle output data.
pub fn set_max_output_size(&mut self, max_oracle_output_size: usize) {
self.max_oracle_output_size = max_oracle_output_size as _;
}
}
/// Builder for `OracleDutyConfig`.
///
/// Provides a convenient way to construct an `OracleDutyConfig` with custom parameters.
#[derive(Default)]
pub struct OracleDutyConfigBuilder {
config: OracleDutyConfig,
}
impl OracleDutyConfigBuilder {
/// Sets the oracle request delay (in consensus rounds) for the config being built.
pub fn set_oracle_request_delay(mut self, delay: u32) -> Self {
self.config.oracle_request_delay = delay;
self
}
/// Sets the number of validators to assign per duty.
pub fn set_validators_per_duty(mut self, validators_per_duty: u32) -> Self {
self.config.validators_per_duty = validators_per_duty;
self
}
/// Sets the commitment_buffer
pub fn set_commitment_buffer(mut self, commitment_buffer: u32) -> Self {
self.config.commitment_buffer = commitment_buffer;
self
}
/// Finalizes and returns the constructed `OracleDutyConfig`.
pub fn build(self) -> OracleDutyConfig {
self.config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_oracle_duty_config_builder() {
let default_config = OracleDutyConfig::default();
let config = OracleDutyConfigBuilder::default()
.set_oracle_request_delay(10)
.set_validators_per_duty(42)
.build();
assert_eq!(config.oracle_request_delay, 10);
assert_eq!(config.validators_per_duty, 42);
// Verify other fields use default values
assert_eq!(
config.collection_window_size,
default_config.collection_window_size
);
assert_eq!(config.commitment_buffer, default_config.commitment_buffer);
let config = OracleDutyConfigBuilder::default().build();
assert_eq!(
config.oracle_request_delay,
default_config.oracle_request_delay
);
assert_eq!(
config.validators_per_duty,
default_config.validators_per_duty
);
assert_eq!(
config.collection_window_size,
default_config.collection_window_size
);
assert_eq!(config.commitment_buffer, default_config.commitment_buffer);
}
}