Skip to content

Огляд NeuroWASM ​

NeuroWASM — середовище виконання контрактів NeuroChain: WebAssembly, який виконує інтерпретатор wasmi, з обліком у fuel і host-функціями, що імпортуються з модуля env. Його семантика слідує CosmWasm і NEAR, плюс нативні функції AI host.

Він не сумісний на рівні бінарників з wasmd чи nearcore — ті самі ідеї, інший інтерфейс.

Модель виконання ​

  • Синхронні виклики. Контракт, що викликає інший, виконує його до кінця, перш ніж продовжити (як в EVM).
  • Один журнал на транзакцію. Усі записи сховища, зміни балансів і перекази всього дерева викликів фіксуються разом — або, якщо щось перервалося, жоден з них.
  • Читання власних записів. Вкладений виклик бачить незафіксовані записи того, хто викликає.
  • Ліміт глибини — 8 вкладених викликів (MAX_CALL_DEPTH).
  • Детермінованість. Кожен валідатор виконує той самий байткод на тому самому стані й отримує той самий результат; немає годинника, випадковості чи доступу до мережі.

Заплановано пізніше: асинхронні підповідомлення з точкою входу reply, потім обіцянки в стилі NEAR і пакети IBC v2.

Host-функції ​

Усі імпорти — з env. Вказівники й довжини — зміщення i32 в експортовану контрактом memory.

ОбластьПрацюєЗаплановано
Пам'ятьallocate, deallocate, abort—
Сховищеget_storage, set_storageremove_storage, storage_has, storage_usage
Контекстget_caller, get_block_height, get_balance, get_stake, get_stake_atget_self_addr, get_signer, get_block_time, get_shard_id, get_attached_deposit, gas_remaining
Банк і подіїtransfer, emit_event, set_returnlog
Міжконтрактні викликиcall_contractcall_contract_with_value
Криптографія—sha3_256, verify_mldsa65, addr_validate
AI host—Читання моделей, сертифікатів, Sentinel, списку довіри й абстракції акаунтів

Точки входу, які експортує контракт, описано в Експортах контракту; ліміти й ціни fuel — у Газ і ліміти.

Мінімальний контракт ​

Лічильник на no_std Rust. Він читає виклик, зберігає число в сховищі й повертає його.

rust
#![no_std]

#[link(wasm_import_module = "env")]
extern "C" {
    fn get_storage(key_ptr: i32, key_len: i32, val_ptr: i32, val_max: i32) -> i32;
    fn set_storage(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32);
    fn set_return(ptr: i32, len: i32);
}

#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! { core::arch::wasm32::unreachable() }

const KEY: &[u8] = b"count";

fn read_count() -> u64 {
    let mut buf = [0u8; 20];
    let n = unsafe { get_storage(KEY.as_ptr() as i32, KEY.len() as i32, buf.as_mut_ptr() as i32, 20) };
    if n <= 0 { return 0; }
    core::str::from_utf8(&buf[..n as usize]).ok().and_then(|s| s.parse().ok()).unwrap_or(0)
}

#[no_mangle]
pub extern "C" fn call(input_ptr: i32, input_len: i32) {
    let input = unsafe { core::slice::from_raw_parts(input_ptr as *const u8, input_len as usize) };
    let mut n = read_count();
    if input.windows(11).any(|w| w == b"\"increment\"") {
        n += 1;
        let mut out = [0u8; 20];
        let s = fmt_u64(n, &mut out);
        unsafe { set_storage(KEY.as_ptr() as i32, KEY.len() as i32, s.as_ptr() as i32, s.len() as i32) };
    }
    let mut out = [0u8; 20];
    let s = fmt_u64(n, &mut out);
    unsafe { set_return(s.as_ptr() as i32, s.len() as i32) };
}

fn fmt_u64(mut v: u64, buf: &mut [u8; 20]) -> &[u8] {
    let mut i = 20;
    loop { i -= 1; buf[i] = b'0' + (v % 10) as u8; v /= 10; if v == 0 { break; } }
    &buf[i..]
}

Викличте його з {"function":"increment"}, щоб додати одиницю, або з будь-чим іншим, щоб прочитати. Збирайте й розгортайте, як описано в Розгортанні контрактів. Токен NRC-20 у neurochain/contracts/nrc20 — повний, більший приклад.

Проєктний документ цього інтерфейсу — docs/neuro-wasm-spec.md у репозиторії.