컨트랙트 배포
배포는 neuro:system.deploy로 보내는 평범한 서명 트랜잭션입니다. 모든 검증자가 합의 과정에서 VMGuardian으로 바이트코드를 감사하며, 감사를 통과하지 못한 컨트랙트는 어디에도 생성되지 않습니다.
1. 빌드
컨트랙트는 wasm32-unknown-unknown용 cdylib로 컴파일된 no_std Rust이며, env 모듈에서 host 함수를 import합니다. 최신 Rust에서 링크되도록 #[link(wasm_import_module = "env")]로 선언하세요. 인터페이스와 전체 예제는 NeuroWASM을 참고하세요.
[lib]
crate-type = ["cdylib"]
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1cargo build --release --target wasm32-unknown-unknown
od -An -tx1 -v target/wasm32-unknown-unknown/release/my_contract.wasm | tr -d ' \n' > my_contract.hexhex는 0061736d(WASM 매직 넘버)로 시작해야 합니다. 바이트코드 최대 크기: 512 KiB(MAX_BYTECODE_SIZE).
저장소의 동작 예제: neurochain/contracts/nrc20(대체 가능 토큰), ncert(NRC-721 방식의 보안 인증서), dao, gov_dao.
2. 보내기 전에 확인 선택 사항
| 엔드포인트 | 얻는 것 |
|---|---|
POST /api/v1/contracts/analyze { "bytecode_hex": "…" } | risk_score, security_score, ml_score, model, violations — 게이트가 실행하는 것과 같은 분석 |
POST /api/v1/contracts/attest { "bytecode_hex": "…" } | 노드가 ML-DSA-65로 서명한 같은 결과로, 브라우저에서 검증 가능 |
웹 앱의 배포 페이지는 먼저 브라우저에서 분석을 실행한 다음, 노드에 서명된 증명을 요청합니다.
3. 배포 보내기
SDK 사용(권장):
await nc.deployContract({
wallet,
bytecodeHex,
name: 'MyToken', // 고유한 컨트랙트 이름, 선택 사항
description: '…',
template: 'nrc20', // 등록된 템플릿 id, 선택 사항
initArgs: { … }, // initialize에 전달됨, 선택 사항; decimals는 숫자로
gasPrice,
})직접 보내기 — to: "neuro:system.deploy", value: 0, 그리고 data를 다음 JSON 문자열로 설정해 POST /api/v1/transactions를 호출합니다.
{ "bytecode_hex": "0061736d…", "name": "MyToken", "description": "", "template": "", "init_args": { } }서명은 다른 트랜잭션과 같습니다(nc-tx-v2|from|neuro:system.deploy|0|nonce).
노드는 POST /api/v1/contracts/deploy도 제공합니다(owner, bytecode_hex 또는 base64_wasm, 그리고 neuro:system.deploy에 대한 서명된 작업). 이 엔드포인트가 같은 트랜잭션을 대신 만들어 줍니다.
4. 모든 검증자가 하는 일
- 게이트. 바이트코드를 디코딩하고 SHA3-256 해시를 조회합니다.
- 화이트리스트에 있음(NRC-20 같은 공식 템플릿) → 보안 점수 100, 분석 없음;
- 거버넌스로 게이트가 꺼짐(
deploy_security_enabled = 0) → 중립 점수 70; - 그 외에는 VMGuardian
analyze_v2를 실행합니다.risk_score ≥ deploy_risk_threshold(기본값 0.80)이면 트랜잭션은 수수료 없이 실패하고, 거부 내역이 규칙 위반과 함께 로그에 기록되며,nc_deploy_rejected_total메트릭에 집계됩니다.
- 과금 10 000 가스 단위 ×
gas_price. - 생성
neuro:<10 hex>.app에 컨트랙트를 생성합니다 —SHA3-256(owner ‖ nonce)의 처음 5바이트. 다른 컨트랙트가 이미 사용 중인 컨트랙트 이름이면 배포가 실패합니다. - 생성자. 모듈이
init을 export하면 배포의 스토리지로 한 번 실행됩니다. - 초기화.
init_args가 있으면 컨트랙트가{"function": "initialize", …init_args}로 호출됩니다 — 인자는 JSON의 최상위 수준에 평탄화됩니다 — 이때 호출자는 여러분입니다. - 템플릿 수수료.
template이 수수료가 있는 등록된 템플릿을 가리키면, 그 수수료가 여러분에게서 템플릿 작성자에게 지급됩니다.
결과로 나온 보안 점수는 100 − risk_score × 100이며, 컨트랙트와 함께 저장됩니다.
수수료
| 항목 | 비용 |
|---|---|
| 배포 | 10 000 가스 단위 × gas_price(1 uNRO일 때: 0.01 NRO) |
| 게이트에서 거부됨 | 없음 |
| 템플릿 | 템플릿 자체 수수료(있는 경우) |
배포 후: 지속적 모니터링
각 노드는 배포된 컨트랙트를 20초마다 다시 감사합니다(MONITOR_INTERVAL_SECS). 컨트랙트 점수가 10점 이상 변하면(MONITOR_SCORE_THRESHOLD) — 예를 들어 모델이 업데이트된 후 — 합의를 통해 인증서 업데이트 트랜잭션이 발행됩니다. 인증서는 GET /api/v1/certificates/contract/:address에서 읽을 수 있습니다. VMGuardian을 참고하세요.
문제 해결
| 오류 | 원인 |
|---|---|
Deploy rejected by VMGuardian: risk_score … >= threshold … | 감사에서 위험한 패턴이 발견되었습니다. analyze가 목록을 보여 줍니다. |
gas_price … below block base_fee … | gasPrice를 현재 기본 수수료보다 높이세요. |
Contract name '…' is already taken | 다른 name을 선택하거나 비워 두세요. |
| 크기 오류 | 바이트코드가 512 KiB를 넘습니다 — opt-level = "z"와 LTO로 빌드하세요. |