Skip to content

Commit 954ff8a

Browse files
committed
add state object / outline of how the keeper will work
1 parent 74ca371 commit 954ff8a

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

apps/argus/src/keeper/state.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
2+
3+
4+
5+
6+
pub struct Block {
7+
pub hash: [u8; 32],
8+
pub parent: Option<[u8; 32]>,
9+
pub block_number: u64,
10+
11+
pub events: Vec<PulseEvent>,
12+
pub state_after: PulseRequests,
13+
}
14+
15+
16+
pub struct BlockchainState {
17+
pub block_number: u64,
18+
19+
// block[i]'s parent must equal block[i-1].hash
20+
// prune this at a certain length?
21+
pub blocks: Vec<Block>,
22+
}
23+
24+
// TODO: implement this so we can mock out the provider and the blockchain requests so we can test
25+
// TODO: whatever interface we choose for mocking out the provider, we should implement with multiple redundant RPCs
26+
impl BlockchainState {
27+
pub fn on_new_block_number(&mut self, block_number: u64) {
28+
let header = provider.get_block_header(block_number);
29+
30+
let my_current_block = self.blocks[self.blocks.len() - 1];
31+
32+
let mut headers = Vec::new();
33+
headers.push(header);
34+
35+
// get all headers for block numbers that are ahead of the current block we have
36+
let current_block_number = my_current_block.block_number;
37+
while (current_block_number + 1 < block_number) {
38+
let header = provider.get_block_header(current_block_number);
39+
headers.push(header);
40+
}
41+
42+
// check if there is a reorg (meaning the latest header's parent doesn't match our current block).
43+
// If there is a reorg, walk backward in our history and the header history until we find the common ancestor.
44+
// Also need to handle the case where the reorg spans the whole block history
45+
let mut current_block_index = self.blocks.len() - 1;
46+
if headers[headers.len() - 1].parent_hash != self.blocks[current_block_index].hash {
47+
current_block_index -= 1;
48+
let header = provider.get_block_header(current_block_number);
49+
headers.push(header);
50+
}
51+
52+
// Fetch the events for each header
53+
// make some blocks and put them in the array
54+
55+
// play forward the events to get the state.
56+
}
57+
}
58+
59+
// full set of currently pending on-chain requests
60+
pub struct PulseRequests {
61+
62+
}
63+
64+
impl PulseRequests {
65+
pub fn apply_events(events: &Vec<PulseEvent>) -> PulseRequests {
66+
67+
}
68+
}
69+
70+
pub struct PulseRequest {
71+
// whatever parameters you need for the callback
72+
}
73+
74+
75+
pub struct CallbackState {
76+
pub pending_requests: HashMap<PulseRequest, CallbackStatus>,
77+
}
78+
79+
impl CallbackState {
80+
pub fn update(requests: PulseRequests) {
81+
// add in new requests to pending_requests
82+
// remove any fulfilled requests or disappeared requests
83+
}
84+
85+
// this probably gets called in a loop forever
86+
pub fn spawn_tasks() {
87+
// loop over pending_requests and spawn a thread to fulfill the request
88+
// only spawn threads for requests that we think we can fulfill at the current time.
89+
// check status.task
90+
// - None - spawnable task
91+
// - Some(fut) -- see if fut is done, if so, increment num_retries. Potentially keep around the Result ?
92+
// - you could spawn a new task to retry here
93+
//
94+
95+
// keep pulse requests around for a long time and keep retrying them over that time
96+
// if any request has been around longer than XX minutes, then fire an alert.
97+
// (we have failed_requests counter that goes into grafana and then we trigger an alert from there)
98+
// log the request and the block where it was created.
99+
100+
// can potentially keep pending requests around if we think the blockchain is offline until it comes back.
101+
}
102+
103+
fn spawn_task(request: &PulseRequest) {
104+
// implement escalation policy to determine multipliers
105+
// call fulfill_request
106+
}
107+
}
108+
109+
// core logic of fulfilling pulse requests
110+
pub async fn fulfill_request(request: &PulseRequest, hermes: &str, gas_estimate_multiplier_pct: u64,
111+
fee_estimate_multiplier_pct: u64,) -> Result<()> {
112+
// get price update by calling hermes
113+
// create contract call and submit it
114+
}
115+
116+
117+
pub struct CallbackStatus {
118+
// task needs the ability to update these values.
119+
num_retries: u64,
120+
last_retry_time: Instant,
121+
task: Option<JoinHandle<Result<()>>>,
122+
}

0 commit comments

Comments
 (0)