soroban_cli/commands/tx/
xdr.rs1use crate::xdr::{
2 Limits, Operation, ReadXdr, Transaction, TransactionEnvelope, TransactionV1Envelope,
3};
4use std::ffi::OsString;
5use std::fs::File;
6use std::io::{stdin, Read};
7use std::io::{Cursor, IsTerminal};
8use std::path::Path;
9use stellar_xdr::curr::Limited;
10
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13 #[error("failed to decode XDR: {0}")]
14 XDRDecode(#[from] stellar_xdr::curr::Error),
15 #[error(transparent)]
16 Io(#[from] std::io::Error),
17 #[error("only transaction v1 is supported")]
18 OnlyTransactionV1Supported,
19 #[error("too many operations, limited to 100 operations in a transaction")]
20 TooManyOperations,
21 #[error("no transaction provided")]
22 NoStdin,
23}
24
25pub fn tx_envelope_from_input(input: &Option<OsString>) -> Result<TransactionEnvelope, Error> {
26 let read: &mut dyn Read = if let Some(input) = input {
27 let exist = Path::new(input).try_exists();
28 if let Ok(true) = exist {
29 &mut File::open(input)?
30 } else {
31 &mut Cursor::new(input.clone().into_encoded_bytes())
32 }
33 } else {
34 if stdin().is_terminal() {
35 return Err(Error::NoStdin);
36 }
37 &mut stdin()
38 };
39
40 let mut lim = Limited::new(SkipWhitespace::new(read), Limits::none());
41 Ok(TransactionEnvelope::read_xdr_base64_to_end(&mut lim)?)
42}
43
44pub struct SkipWhitespace<R: Read> {
46 pub inner: R,
47}
48
49impl<R: Read> SkipWhitespace<R> {
50 pub fn new(inner: R) -> Self {
51 SkipWhitespace { inner }
52 }
53}
54
55impl<R: Read> Read for SkipWhitespace<R> {
56 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
57 let n = self.inner.read(buf)?;
58
59 let mut written = 0;
60 for read in 0..n {
61 if !buf[read].is_ascii_whitespace() {
62 buf[written] = buf[read];
63 written += 1;
64 }
65 }
66
67 Ok(written)
68 }
69}
70pub fn unwrap_envelope_v1(tx_env: TransactionEnvelope) -> Result<Transaction, Error> {
73 let TransactionEnvelope::Tx(TransactionV1Envelope { tx, .. }) = tx_env else {
74 return Err(Error::OnlyTransactionV1Supported);
75 };
76 Ok(tx)
77}
78
79pub fn add_op(tx_env: TransactionEnvelope, op: Operation) -> Result<TransactionEnvelope, Error> {
80 let mut tx = unwrap_envelope_v1(tx_env)?;
81 let mut ops = tx.operations.to_vec();
82 ops.push(op);
83 tx.operations = ops.try_into().map_err(|_| Error::TooManyOperations)?;
84 Ok(tx.into())
85}