Skip to content

NeuroWASM 개요 ​

NeuroWASM은 NeuroChain의 컨트랙트 런타임입니다. wasmi 인터프리터가 실행하는 WebAssembly로, fuel로 계량되며, host 함수는 env 모듈에서 import합니다. 의미론은 CosmWasm과 NEAR를 따르며, 여기에 네이티브 AI host 함수가 더해집니다.

wasmd나 nearcore와 바이너리 호환되지는 않습니다 — 같은 아이디어, 다른 인터페이스입니다.

실행 모델 ​

  • 동기식 호출. 다른 컨트랙트를 호출한 컨트랙트는 그 컨트랙트가 끝날 때까지 실행한 뒤에 계속 진행합니다(EVM과 같음).
  • 트랜잭션당 하나의 저널. 전체 호출 트리의 모든 스토리지 쓰기, 잔액 변경, 송금은 함께 커밋되며, 어느 하나라도 trap되면 아무것도 커밋되지 않습니다.
  • 자신의 쓰기 읽기(read-your-writes). 중첩 호출은 호출자의 커밋되지 않은 쓰기를 봅니다.
  • 중첩 호출 깊이 제한은 8입니다(MAX_CALL_DEPTH).
  • 결정론적. 모든 검증자가 같은 상태에서 같은 바이트코드를 실행해 같은 결과를 얻습니다. 시계, 난수, 네트워크 접근은 없습니다.

이후 계획: reply 진입점을 갖는 비동기 하위 메시지, 그다음 NEAR 방식의 promise와 IBC v2 패킷.

Host 함수 ​

모든 import는 env에서 옵니다. 포인터와 길이는 컨트랙트가 export한 memory에 대한 i32 오프셋입니다.

영역작동 중계획됨
메모리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, 신뢰 목록, 계정 추상화 상태 읽기

컨트랙트가 export하는 진입점은 게스트 export에, 제한과 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"}로 호출하면 1이 더해지고, 그 밖의 내용으로 호출하면 값을 읽습니다. 빌드와 배포는 컨트랙트 배포와 같습니다. neurochain/contracts/nrc20의 NRC-20 토큰이 더 크고 완전한 예제입니다.

이 인터페이스의 설계 문서는 저장소의 docs/neuro-wasm-spec.md입니다.