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
// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
use std::fmt;
use serde::{Deserialize, Serialize};
use validator::Validate;
use crate::validation::validate_transaction_data;
/// The configuration for sending a transaction.
/// This is a part of the SendTransaction request.
///
/// Note: Currently only `encoding` and `wait_for_execution` are implemented.
/// The following parameters are parsed but not yet used in the implementation:
/// - max_retries: Will be implemented with retry logic (SUB-47)
/// - min_context_slot: Will be used for slot-aware transaction submission (SUB-47)
/// - skip_preflight: Will be used to control preflight validation (SUB-47)
///
/// These are kept for compatibility with the Solana CLI and will be implemented
/// as part of the full sendTransaction feature rollout.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Validate)]
pub struct SendTransactionConfig {
/// Encoding used for the transaction data.
#[serde(default)]
pub encoding: TransactionEncoding,
/// This field exists for compatibility with Solana.
/// The Rialo implementation ignores it.
#[validate(range(min = 0, max = 100, message = "Max retries must be between 0 and 100"))]
#[serde(rename = "maxRetries")]
pub max_retries: Option<usize>,
/// This field exists for compatibility with Solana.
/// The Rialo implementation ignores it.
#[validate(range(min = 0, message = "Min context slot must be non-negative"))]
#[serde(rename = "minContextSlot")]
pub min_context_slot: Option<u64>,
/// This field exists for compatibility with Solana.
/// The Rialo implementation ignores it.
#[serde(rename = "skipPreflight", default)]
pub skip_preflight: bool,
/// Whether the RPC node should wait for the transaction execution before replying.
#[serde(rename = "waitForExecution", default)]
pub wait_for_execution: bool,
/// Allow legacy BPF program deployment during RISC-V migration.
/// This is an unstable escape hatch that will be removed in a future release.
/// When set to true, bypasses the BPF loader rejection at the RPC level.
#[serde(rename = "allowLegacyUnstableBpf", default)]
#[deprecated = "The support for BPF programs will be unconditionally removed in the next Rialo Development Kit (RDK) release"]
pub allow_legacy_unstable_bpf: bool,
}
impl SendTransactionConfig {
pub fn new(encoding: TransactionEncoding) -> Self {
Self {
encoding,
max_retries: None,
min_context_slot: None,
skip_preflight: false,
wait_for_execution: false,
#[allow(deprecated)]
allow_legacy_unstable_bpf: false,
}
}
}
impl Default for SendTransactionConfig {
fn default() -> Self {
Self::new(TransactionEncoding::Base64)
}
}
/// Request type for sendTransaction RPC handler
#[derive(Debug, Deserialize, Serialize, Clone, Validate)]
pub struct SendTransactionRequest {
#[validate(length(min = 1, message = "Transaction cannot be empty"))]
#[validate(custom(function = validate_transaction_data))]
pub transaction: String,
#[validate(nested)]
pub config: SendTransactionConfig,
}
impl SendTransactionRequest {
pub fn new(transaction: String, config: SendTransactionConfig) -> Self {
Self {
transaction,
config,
}
}
}
/// Supported transaction encodings.
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum TransactionEncoding {
#[default]
Base64,
Base58,
}
impl fmt::Display for TransactionEncoding {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Base64 => f.write_str("base64"),
Self::Base58 => f.write_str("base58"),
}
}
}