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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
use oasis_types::{Address, Balance, ExtStatusCode};

use super::Error;

/// @see the `blockchain-traits` crate for descriptions of these methods.
extern "C" {
    #[allow(improper_ctypes)] // u128 is just 2 u64s
    pub fn oasis_balance(addr: *const Address, balance: *mut u128) -> ExtStatusCode;

    pub fn oasis_code(addr: *const Address, buf: *mut u8) -> ExtStatusCode;
    pub fn oasis_code_len(addr: *const Address, len: *mut u32) -> ExtStatusCode;

    pub fn oasis_fetch_input(buf: *mut u8) -> ExtStatusCode;
    pub fn oasis_input_len(len: *mut u32) -> ExtStatusCode;

    pub fn oasis_ret(buf: *const u8, len: u32) -> ExtStatusCode;
    pub fn oasis_err(buf: *const u8, len: u32) -> ExtStatusCode;

    pub fn oasis_fetch_ret(buf: *mut u8) -> ExtStatusCode;
    pub fn oasis_ret_len(len: *mut u32) -> ExtStatusCode;

    pub fn oasis_fetch_err(buf: *mut u8) -> ExtStatusCode;
    pub fn oasis_err_len(len: *mut u32) -> ExtStatusCode;

    pub fn oasis_fetch_aad(buf: *mut u8) -> ExtStatusCode;
    pub fn oasis_aad_len(len: *mut u32) -> ExtStatusCode;

    #[allow(improper_ctypes)] // u128 is just 2 u64s
    pub fn oasis_transact(
        callee: *const Address,
        value: *const u128,
        input: *const u8,
        input_len: u32,
    ) -> ExtStatusCode;

    pub fn oasis_address(addr: *mut Address) -> ExtStatusCode;
    pub fn oasis_sender(addr: *mut Address) -> ExtStatusCode;
    pub fn oasis_payer(addr: *mut Address) -> ExtStatusCode;
    #[allow(improper_ctypes)] // u128 is just 2 u64s
    pub fn oasis_value(value: *mut u128) -> ExtStatusCode;

    pub fn oasis_read(key: *const u8, key_len: u32, value: *mut u8) -> ExtStatusCode;
    pub fn oasis_read_len(key: *const u8, key_len: u32, value_len: *mut u32) -> ExtStatusCode;
    pub fn oasis_write(
        key: *const u8,
        key_len: u32,
        value: *const u8,
        value_len: u32,
    ) -> ExtStatusCode;

    pub fn oasis_emit(
        topics: *const *const u8,
        topic_lens: *const u32,
        num_topics: u32,
        data: *const u8,
        data_len: u32,
    ) -> ExtStatusCode;
}

impl From<ExtStatusCode> for Error {
    fn from(code: ExtStatusCode) -> Self {
        match code {
            ExtStatusCode::Success => unreachable!(),
            ExtStatusCode::InsufficientFunds => Error::InsufficientFunds,
            ExtStatusCode::InvalidInput => Error::InvalidInput,
            ExtStatusCode::NoAccount => Error::InvalidCallee,
            _ => Error::Execution {
                payload: fetch_err(),
            },
        }
    }
}

macro_rules! ext {
    ($fn:ident $args:tt ) => {{
        let code = unsafe { $fn$args };
        if code != ExtStatusCode::Success {
            Err(Error::from(code))
        } else {
            Ok(())
        }
    }};
}

pub fn address() -> Address {
    let mut addr = Address::default();
    ext!(oasis_address(&mut addr as *mut _)).unwrap();
    addr
}

pub fn sender() -> Address {
    let mut addr = Address::default();
    ext!(oasis_sender(&mut addr as *mut _)).unwrap();
    addr
}

pub fn payer() -> Address {
    let mut addr = Address::default();
    ext!(oasis_payer(&mut addr as *mut _)).unwrap();
    addr
}

pub fn aad() -> Vec<u8> {
    let mut aad_len = 0u32;
    ext!(oasis_aad_len(&mut aad_len as *mut _)).unwrap();

    let mut aad = Vec::with_capacity(aad_len as usize);
    unsafe { aad.set_len(aad_len as usize) };

    ext!(oasis_fetch_aad(aad.as_mut_ptr())).unwrap();
    aad
}

pub fn value() -> Balance {
    let mut value = 0;
    ext!(oasis_value(&mut value as *mut _)).unwrap();
    Balance(value)
}

pub fn balance(addr: &Address) -> Option<Balance> {
    let mut balance = 0;
    ext!(oasis_balance(addr as *const _, &mut balance as *mut _))
        .ok()
        .map(|_| Balance(balance))
}

pub fn code(addr: &Address) -> Option<Vec<u8>> {
    let mut code_len = 0u32;
    let mut code = Vec::with_capacity(
        match ext!(oasis_code_len(
            addr as *const Address,
            &mut code_len as *mut _
        )) {
            Ok(_) => code_len as usize,
            Err(_) => return None,
        },
    );
    ext!(oasis_code(addr as *const Address, code.as_mut_ptr()))
        .ok()
        .map(|_| code)
}

pub fn transact(callee: &Address, value: Balance, input: &[u8]) -> Result<Vec<u8>, Error> {
    ext!(oasis_transact(
        callee as *const _,
        &value.0 as *const u128,
        input.as_ptr(),
        if input.len() > u32::max_value() as usize {
            return Err(Error::InvalidInput);
        } else {
            input.len() as u32
        },
    ))?;

    let mut ret_len = 0u32;
    ext!(oasis_ret_len(&mut ret_len as *mut _))?;

    let mut ret = Vec::with_capacity(ret_len as usize);
    unsafe { ret.set_len(ret_len as usize) };

    ext!(oasis_fetch_ret(ret.as_mut_ptr())).map(|_| ret)
}

pub fn input() -> Vec<u8> {
    let mut input_len = 0u32;
    ext!(oasis_input_len(&mut input_len as *mut _)).unwrap();

    let mut input = Vec::with_capacity(input_len as usize);
    unsafe { input.set_len(input_len as usize) };

    ext!(oasis_fetch_input(input.as_mut_ptr())).unwrap();
    input
}

pub fn ret(ret: &[u8]) -> ! {
    ext!(oasis_ret(ret.as_ptr(), ret.len() as u32)).unwrap();
    std::process::abort();
}

pub fn err(err: &[u8]) -> ! {
    ext!(oasis_err(err.as_ptr(), err.len() as u32)).unwrap();
    std::process::abort();
}

pub fn fetch_err() -> Vec<u8> {
    let mut err_len = 0u32;
    ext!(oasis_err_len(&mut err_len as *mut _)).unwrap();

    let mut err = Vec::with_capacity(err_len as usize);
    unsafe { err.set_len(err_len as usize) };

    ext!(oasis_fetch_err(err.as_mut_ptr())).unwrap();
    err
}

pub fn read(key: &[u8]) -> Vec<u8> {
    let mut val_len = 0u32;
    ext!(oasis_read_len(
        key.as_ptr(),
        key.len() as u32,
        &mut val_len as *mut _
    ))
    .unwrap();

    let mut val = Vec::with_capacity(val_len as usize);
    unsafe { val.set_len(val_len as usize) };

    ext!(oasis_read(key.as_ptr(), key.len() as u32, val.as_mut_ptr())).unwrap();
    val
}

pub fn write(key: &[u8], value: &[u8]) {
    ext!(oasis_write(
        key.as_ptr(),
        key.len() as u32,
        value.as_ptr(),
        value.len() as u32
    ))
    .unwrap();
}

pub fn emit(topics: &[&[u8]], data: &[u8]) {
    let topic_ptrs: Vec<*const u8> = topics.iter().map(|t| t.as_ptr()).collect();
    let topic_lens: Vec<u32> = topics.iter().map(|t| t.len() as u32).collect();
    ext!(oasis_emit(
        topic_ptrs.as_ptr(),
        topic_lens.as_ptr(),
        topics.len() as u32,
        data.as_ptr(),
        data.len() as u32
    ))
    .unwrap();
}