Skip to main content

urma_runtime/
config.rs

1use urma_core::format::Urma;
2pub struct Limits;
3impl Limits {
4    pub const INPUT_BYTES: usize = 16 * 1024 * 1024;
5    pub const RECORDS: usize = Self::INPUT_BYTES / Urma::CHUNK_BYTES;
6    pub const CONTAINER_BYTES: usize = 12 + Self::RECORDS * (4 + Urma::PRIVATE_RECORD_BYTES);
7    pub const OBJECTS: usize = 64;
8}
9
10use crate::error::{Context, Error};
11use serde_json::Value;
12
13pub fn confirmations(value: &Value) -> Result<i64, Error> {
14    match value.get("confirmations") {
15        Some(number) => number.as_i64().context("invalid confirmations"),
16        None => Ok(0),
17    }
18}
19
20#[derive(Clone, Copy)]
21pub enum RpcScope<'a> {
22    Node,
23    Wallet(&'a str),
24}
25impl<'a> From<Option<&'a str>> for RpcScope<'a> {
26    fn from(wallet: Option<&'a str>) -> Self {
27        match wallet {
28            Some(name) => Self::Wallet(name),
29            None => Self::Node,
30        }
31    }
32}
33#[derive(Clone, Copy)]
34pub enum ScanEnd {
35    Tip,
36    Height(u64),
37}
38#[derive(Clone, Copy)]
39pub enum RevealSelection {
40    All,
41    First(usize),
42}
43impl RevealSelection {
44    pub fn count(self, total: usize) -> usize {
45        match self {
46            Self::All => total,
47            Self::First(count) => count.min(total),
48        }
49    }
50}
51#[derive(Clone, Copy)]
52pub enum TxPresence {
53    Missing,
54    Observed(i64),
55}
56impl TxPresence {
57    pub fn confirmed(self) -> bool {
58        match self {
59            Self::Missing => false,
60            Self::Observed(count) => count > 0,
61        }
62    }
63}
64
65#[derive(Clone, Copy)]
66pub enum MempoolPresence {
67    Absent,
68    Present,
69}
70impl From<Option<usize>> for RevealSelection {
71    fn from(count: Option<usize>) -> Self {
72        match count {
73            Some(n) => Self::First(n),
74            None => Self::All,
75        }
76    }
77}
78pub const MAX_OBJECTS: usize = Limits::OBJECTS;
79pub const MAX_DIRECTORY_RECORDS: usize = MAX_OBJECTS * Limits::RECORDS;
80pub const LITECOIN_NETWORK: &str = "litecoin-testnet";
81pub const LITECOIN_GENESIS: &str = urma_chain::observation::Chain::LITECOIN_TESTNET_GENESIS;
82pub const LITECOIN_RPC_PORT: u16 = 19332;
83pub const LITECOIN_RETURN_LITOSHIS: u64 = 1_000;
84pub const LITECOIN_MAX_FEE_LITOSHIS: u64 = 500_000;
85pub const LITECOIN_MAX_SCAN_BLOCKS: u64 = 10_000;
86pub const LITECOIN_MAX_SCAN_BYTES: usize = 256 * 1024 * 1024;
87pub const LITECOIN_MAX_JOURNAL_BYTES: usize = 4_000_000;
88pub const RELAY_MAX_BUDGET_SATS: u64 = 500_000;
89pub const SOURCE_MAX_BLOCK_BYTES: usize = 4_000_000;
90pub const SOURCE_MAX_JSON_BYTES: usize = 1_000_000;
91pub const SOURCE_MAX_SCAN_BLOCKS: u64 = 10_000;
92pub const SOURCE_MAX_SCAN_BYTES: usize = 256 * 1024 * 1024;
93pub const BITCOIN_RETURN_SATS: u64 = 1_000;
94pub const BITCOIN_MAX_FEE_SATS: u64 = 500_000;
95pub const BITCOIN_MAX_FEE_RATE: u64 = 100;
96
97pub const PUBLIC_METHODS: [&str; 10] = [
98    "getblockhash",
99    "getblockchaininfo",
100    "getrawtransaction",
101    "getblockheader",
102    "getblock",
103    "getrawmempool",
104    "gettxout",
105    "addressutxos",
106    "testmempoolaccept",
107    "sendrawtransaction",
108];
109pub const ABSENT_TRANSACTION: &str = "transaction not found on selected network";
110pub const ABSENT_RECORD: &str = "transaction or block not found on selected network";
111pub const MAX_PROVIDERS: usize = 8;
112pub const TIP_RACE_WIDTH: usize = 2;
113pub const PROVIDER_BREAKER_FAILURES: u32 = 3;
114pub const PROVIDER_BREAKER_WINDOW: std::time::Duration = std::time::Duration::from_secs(30);
115pub const PROVIDER_RETRY_DEFAULT: std::time::Duration = std::time::Duration::from_secs(60);
116pub const PROVIDER_RETRY_MAX: std::time::Duration = std::time::Duration::from_secs(300);
117pub const PROVIDER_PACING: std::time::Duration = std::time::Duration::from_millis(300);
118pub const RPC_GATEWAY_WINDOW: std::time::Duration = std::time::Duration::from_secs(60);
119pub const RPC_GATEWAY_WINDOW_REQUESTS: u8 = 5;
120pub const LOCAL_PROVIDER_LABEL: &str = "local validating node";
121pub const ELECTRUM_PROTOCOL: &str = "1.4";
122pub const ELECTRUM_CONNECT_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
123pub const ELECTRUM_MAX_LINE_BYTES: usize = 4 * 1024 * 1024;
124pub const ELECTRUM_UNSPENT_CACHE: std::time::Duration = std::time::Duration::from_secs(30);
125pub const WALLET_VERIFY_OUTPUTS: usize = 64;
126pub const WALLET_CHECKS: usize = 2 * WALLET_VERIFY_OUTPUTS;
127#[deprecated(
128    since = "0.3.2",
129    note = "no longer caps anything: wallets keep their largest WALLET_CHECKS coins and skip the rest"
130)]
131pub const WALLET_MAX_COINS: usize = 1000;
132#[deprecated(
133    since = "0.3.2",
134    note = "no longer caps anything: provider UTXO listings are bounded by response bytes"
135)]
136pub const SOURCE_MAX_UTXOS: usize = 1_000;
137pub const WALLET_GAP: u32 = 20;
138pub const WALLET_RANGE: u32 = 1000;
139pub const WALLET_MAX_INPUTS: usize = 50;
140pub const SUBMISSION_ACK_WINDOW: std::time::Duration = std::time::Duration::from_secs(180);
141pub const AWAITING_PARENT: &str = "awaiting parent propagation across sources";
142pub const MISSING_INPUT_REJECTIONS: [&str; 2] =
143    ["missing-inputs", "bad-txns-inputs-missingorspent"];
144pub const SUBMISSION_PRESENCE_CHECKS: u32 = 3;
145pub const SUBMISSION_PRESENCE_DELAY: std::time::Duration = std::time::Duration::from_secs(4);
146pub const ELECTRUM_PROBE_METHODS: [&str; 5] = [
147    "server.features",
148    "blockchain.transaction.id_from_pos",
149    "blockchain.transaction.get",
150    "blockchain.scripthash.get_balance",
151    "blockchain.scripthash.listunspent",
152];
153
154pub fn method_timeout(method: &str) -> std::time::Duration {
155    match method {
156        "getblock" => std::time::Duration::from_secs(60),
157        "getrawmempool" | "addressutxos" => std::time::Duration::from_secs(30),
158        _ => std::time::Duration::from_secs(12),
159    }
160}
161
162pub const STANDARD_TX_WEIGHT: u64 = 400_000;
163pub const PUBLICATION_BUFFER_WEIGHT: u64 = 7_960_000;
164pub const PUBLICATION_PENDING_COMMITS: usize = 24;
165pub const PUBLICATION_COMMIT_VBYTES: u64 = 90_000;
166pub const LITECOIN_DUST_RELAY_FEE: u64 = 30_000;
167
168pub const P2P_PROTOCOL_VERSION: u32 = 70015;
169pub const P2P_USER_AGENT: &str = "/urma:0.2.2/";
170pub const P2P_MAX_PEERS: usize = 8;
171pub const P2P_DIAL_CONCURRENCY: usize = 24;
172pub const P2P_REDIAL_BACKOFF_SECS: u64 = 30;
173pub const P2P_GOOD_PEERS: usize = 64;
174pub const P2P_POLL_MESSAGES: usize = 64;
175pub const P2P_POLL_READ_TIMEOUT_MILLIS: u64 = 1000;
176pub const P2P_GOSSIP_FUTURE_SECS: u64 = 600;
177pub const P2P_GOSSIP_PENALTY_SECS: u64 = 5 * 24 * 60 * 60;
178pub const P2P_IPV6_ROUTE_PROBE: &str = "[2001:4860:4860::8888]:53";
179pub const P2P_CONNECT_TIMEOUT_SECS: u64 = 2;
180pub const P2P_TOP_UP_BUDGET_SECS: u64 = 6;
181pub const P2P_HANDSHAKE_TIMEOUT_SECS: u64 = 15;
182pub const P2P_READ_TIMEOUT_SECS: u64 = 20;
183pub const P2P_HEADERS_TIMEOUT_SECS: u64 = 8;
184pub const P2P_BLOCK_TIMEOUT_SECS: u64 = 60;
185pub const P2P_BLOCK_PEER_TIMEOUT_SECS: u64 = 8;
186pub const P2P_MAX_PAYLOAD_BYTES: usize = 8_000_000;
187pub const P2P_MAX_HEADERS_PER_MESSAGE: usize = 2000;
188pub const P2P_MAX_INVENTORY: usize = 50_000;
189pub const P2P_MAX_ADDRESSES: usize = 1000;
190pub const P2P_ADDRESS_POOL: usize = 1000;
191pub const P2P_HEADER_CACHE_MAX: usize = 1_000_000;
192pub const P2P_HEADER_CACHE_REVALIDATE: usize = 2016;
193pub const P2P_BLOCK_CACHE_BYTES: usize = 64 * 1024 * 1024;
194pub const P2P_TIP_REFRESH_SECS: u64 = 20;
195pub const P2P_MAX_FUTURE_SECS: u32 = 7200;
196pub const P2P_MEDIAN_TIME_SPAN: usize = 11;
197pub const P2P_LIMITED_PEER_DEPTH: u64 = 288;
198pub const P2P_HEIGHT_SLACK: u64 = 12;
199pub const P2P_IDLE_POLL_MILLIS: u64 = 250;
200pub const P2P_LOCATOR_LINEAR: usize = 10;
201pub const P2P_LITECOIN_NODE_MWEB: u64 = 1 << 24;
202pub const P2P_SEED_INTERVAL_SECS: u64 = 60;
203pub const P2P_SEED_TIMEOUT_SECS: u64 = 3;
204pub const P2P_FETCH_ATTEMPTS: usize = 4;
205pub const P2P_POW_WORKERS: usize = 4;
206pub const P2P_PREFETCH_BLOCKS: u64 = 16;
207pub const P2P_PIPELINE_PER_PEER: usize = 8;
208
209pub struct Checkpoint {
210    pub height: u64,
211    pub header: &'static str,
212    pub next_hash: &'static str,
213}
214
215pub const LITECOIN_MAINNET_CHECKPOINT: Checkpoint = Checkpoint {
216    height: 3_187_295,
217    header: "14000020931d31f868aaaad00ab3d07bfb30e1adf261e843ea1efe367ea85ed4d50b0beccbee28d90e5dc1495e97786a8dc63e6b741e1ca8ef6226323ed5039c5d74fa7e73d7bd6adda82e1930924a09",
218    next_hash: "17976eb8639d9274e2f0b96314aa4cd259c976eecd7100c1c3bbf7c2ad31ed7a",
219};
220
221pub const LITECOIN_TESTNET_CHECKPOINT: Checkpoint = Checkpoint {
222    height: 4_904_927,
223    header: "000000206a866190a6c8e920929c51bc5b3318eb8fb68bd411ae365a5d922f33059816bc6c23b147db3e44528fd06f87e19e876788df08f5323a1ad46f2c863910ef02762125c06affff0f1ec0003c2f",
224    next_hash: "ed607657d250aa0a76e6a6e6c451bfa313f93c727a0bb96ba371e9007200e843",
225};
226
227pub fn publication_return(chain: urma_chain::observation::Chain) -> u64 {
228    use urma_chain::observation::Chain;
229    match chain {
230        Chain::LitecoinTestnet | Chain::LitecoinMainnet => 110 * LITECOIN_DUST_RELAY_FEE / 1000,
231        Chain::BitcoinMainnet | Chain::BitcoinRegtest | Chain::BitcoinTestnet4 => 1000,
232    }
233}