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
use anchor_client::ClientError;
use solana_account_decoder::UiAccountEncoding;
use solana_client::{pubsub_client::PubsubClient, rpc_config::RpcAccountInfoConfig};
use solana_client_helpers::Client;
use solana_sdk::{
    account::Account,
    clock::{Clock, Epoch, Slot, UnixTimestamp},
    commitment_config::CommitmentConfig,
    pubkey::Pubkey,
};
use std::{
    str::FromStr,
    sync::{
        mpsc::{self, Receiver},
        Arc,
    },
    thread,
};

pub fn get_time(client: &Arc<Client>) -> Result<i64, ClientError> {
    let clock = fetch(client).unwrap();
    Ok(clock.unix_timestamp)
}

pub fn monitor_time(url: String) -> Receiver<i64> {
    let (blocktime_sender, blocktime_receiver) = mpsc::channel::<i64>();
    thread::spawn(move || {
        let mut latest_blocktime: i64 = 0;
        let (_ws_client, clock_receiver) = PubsubClient::account_subscribe(
            url.as_str(),
            &address(),
            Some(RpcAccountInfoConfig {
                encoding: Some(UiAccountEncoding::Base64),
                commitment: Some(CommitmentConfig::processed()),
                data_slice: None,
            }),
        )
        .unwrap();

        for ui_account_response in clock_receiver {
            let ui_account = ui_account_response.value;
            let account = ui_account.decode::<Account>().unwrap();
            let clock = deserialize(account.data);
            let blocktime = clock.unix_timestamp;
            if blocktime > latest_blocktime {
                latest_blocktime = blocktime;
                blocktime_sender.send(blocktime).unwrap()
            }
        }
    });
    return blocktime_receiver;
}

/**
 * Helpers
 */

fn address() -> Pubkey {
    Pubkey::from_str("SysvarC1ock11111111111111111111111111111111").unwrap()
}

fn fetch(client: &Arc<Client>) -> Result<Clock, ClientError> {
    let data = client.get_account_data(&address())?;
    Ok(deserialize(data))
}

fn deserialize(data: Vec<u8>) -> Clock {
    Clock {
        slot: Slot::from_le_bytes(data.as_slice()[0..8].try_into().unwrap()),
        epoch_start_timestamp: UnixTimestamp::from_le_bytes(
            data.as_slice()[8..16].try_into().unwrap(),
        ),
        epoch: Epoch::from_le_bytes(data.as_slice()[16..24].try_into().unwrap()),
        leader_schedule_epoch: Epoch::from_le_bytes(data.as_slice()[24..32].try_into().unwrap()),
        unix_timestamp: UnixTimestamp::from_le_bytes(data.as_slice()[32..40].try_into().unwrap()),
    }
}