soroban_spec/
read.rs

1use std::io::Cursor;
2
3use base64::Engine;
4use stellar_xdr::curr as stellar_xdr;
5use stellar_xdr::{Limited, Limits, ReadXdr, ScSpecEntry};
6use wasmparser::{BinaryReaderError, Parser, Payload};
7
8// TODO: Move these functions into stellar_xdr.
9
10#[derive(thiserror::Error, Debug)]
11pub enum ParseSpecBase64Error {
12    #[error("parsing contract spec base64")]
13    ParseBase64(base64::DecodeError),
14    #[error("parsing contract spec xdr")]
15    ParseXdr(stellar_xdr::Error),
16}
17
18pub fn parse_base64(spec: &[u8]) -> Result<Vec<ScSpecEntry>, ParseSpecBase64Error> {
19    let decoded = base64::engine::general_purpose::STANDARD
20        .decode(spec)
21        .map_err(ParseSpecBase64Error::ParseBase64)?;
22    parse_raw(&decoded).map_err(ParseSpecBase64Error::ParseXdr)
23}
24
25pub fn parse_raw(spec: &[u8]) -> Result<Vec<ScSpecEntry>, stellar_xdr::Error> {
26    let cursor = Cursor::new(spec);
27    let entries = ScSpecEntry::read_xdr_iter(&mut Limited::new(
28        cursor,
29        Limits {
30            depth: 500,
31            len: 0x1000000,
32        },
33    ))
34    .collect::<Result<Vec<_>, _>>()?;
35    Ok(entries)
36}
37
38#[derive(thiserror::Error, Debug)]
39pub enum FromWasmError {
40    #[error("reading wasm")]
41    Read(BinaryReaderError),
42    #[error("parsing contract spec")]
43    Parse(stellar_xdr::Error),
44    #[error("contract spec not found")]
45    NotFound,
46}
47
48pub fn raw_from_wasm(wasm: &[u8]) -> Result<Vec<u8>, FromWasmError> {
49    for payload in Parser::new(0).parse_all(wasm) {
50        let payload = payload.map_err(FromWasmError::Read)?;
51        if let Payload::CustomSection(section) = payload {
52            if section.name() == "contractspecv0" {
53                return Ok(section.data().to_vec());
54            }
55        };
56    }
57    Err(FromWasmError::NotFound)
58}
59
60pub fn base64_from_wasm(wasm: &[u8]) -> Result<String, FromWasmError> {
61    let raw = raw_from_wasm(wasm)?;
62    let mut res = String::new();
63    base64::engine::general_purpose::STANDARD.encode_string(raw, &mut res);
64    Ok(res)
65}
66
67pub fn from_wasm(wasm: &[u8]) -> Result<Vec<ScSpecEntry>, FromWasmError> {
68    let spec = raw_from_wasm(wasm)?;
69    parse_raw(&spec).map_err(FromWasmError::Parse)
70}