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
use solana_sdk::compute_budget::ComputeBudgetInstruction;
use solana_sdk::instruction::Instruction;
use anchor_lang::prelude::{AccountMeta, Pubkey};
use anyhow::Context;
pub trait AnyhowWrap {
type Value;
fn map_err_anyhow(self) -> anyhow::Result<Self::Value>;
}
impl<T, E: std::fmt::Debug> AnyhowWrap for Result<T, E> {
type Value = T;
fn map_err_anyhow(self) -> anyhow::Result<Self::Value> {
self.map_err(|err| anyhow::anyhow!("{:?}", err))
}
}
pub trait AsyncChannelSendUnlessFull<T> {
fn send_unless_full(&self, msg: T) -> anyhow::Result<()>;
}
impl<T> AsyncChannelSendUnlessFull<T> for async_channel::Sender<T> {
fn send_unless_full(&self, msg: T) -> anyhow::Result<()> {
use async_channel::*;
match self.try_send(msg) {
Ok(()) => Ok(()),
Err(TrySendError::Closed(_)) => Err(anyhow::format_err!("channel is closed")),
Err(TrySendError::Full(_)) => Ok(()),
}
}
}
impl<T> AsyncChannelSendUnlessFull<T> for tokio::sync::mpsc::Sender<T> {
fn send_unless_full(&self, msg: T) -> anyhow::Result<()> {
use tokio::sync::mpsc::*;
match self.try_send(msg) {
Ok(()) => Ok(()),
Err(error::TrySendError::Closed(_)) => Err(anyhow::format_err!("channel is closed")),
Err(error::TrySendError::Full(_)) => Ok(()),
}
}
}
pub fn delay_interval(period: std::time::Duration) -> tokio::time::Interval {
let mut interval = tokio::time::interval(period);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
interval
}
pub fn tracing_subscriber_init() {
let format = tracing_subscriber::fmt::format().with_ansi(atty::is(atty::Stream::Stdout));
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.event_format(format)
.init();
}
pub async fn http_error_handling<T: serde::de::DeserializeOwned>(
response: reqwest::Response,
) -> anyhow::Result<T> {
let status = response.status();
let response_text = response
.text()
.await
.context("awaiting body of http request")?;
if !status.is_success() {
anyhow::bail!("http request failed, status: {status}, body: {response_text}");
}
serde_json::from_str::<T>(&response_text)
.with_context(|| format!("response has unexpected format, body: {response_text}"))
}
pub fn to_readonly_account_meta(pubkey: Pubkey) -> AccountMeta {
AccountMeta {
pubkey,
is_writable: false,
is_signer: false,
}
}
pub fn to_writable_account_meta(pubkey: Pubkey) -> AccountMeta {
AccountMeta {
pubkey,
is_writable: true,
is_signer: false,
}
}
#[derive(Default, Clone)]
pub struct PreparedInstructions {
pub instructions: Vec<Instruction>,
pub cu: u32,
}
impl PreparedInstructions {
pub fn new() -> Self {
Self {
instructions: vec![],
cu: 0,
}
}
pub fn from_vec(instructions: Vec<Instruction>, cu: u32) -> Self {
Self { instructions, cu }
}
pub fn from_single(instruction: Instruction, cu: u32) -> Self {
Self {
instructions: vec![instruction],
cu,
}
}
pub fn push(&mut self, ix: Instruction, cu: u32) {
self.instructions.push(ix);
self.cu += cu;
}
pub fn append(&mut self, mut other: Self) {
self.instructions.append(&mut other.instructions);
self.cu += other.cu;
}
pub fn to_instructions(self) -> Vec<Instruction> {
let mut ixs = self.instructions;
ixs.insert(0, ComputeBudgetInstruction::set_compute_unit_limit(self.cu));
ixs
}
pub fn is_empty(&self) -> bool {
self.instructions.is_empty()
}
pub fn clear(&mut self) {
self.instructions.clear();
self.cu = 0;
}
pub fn len(&self) -> usize {
self.instructions.len()
}
}