chore: initial commit for v0.0.1
DChain single-node blockchain + React Native messenger client. Core: - PBFT consensus with multi-sig validator admission + equivocation slashing - BadgerDB + schema migration scaffold (CurrentSchemaVersion=0) - libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1) - Native Go contracts (username_registry) alongside WASM (wazero) - WebSocket gateway with topic-based fanout + Ed25519-nonce auth - Relay mailbox with NaCl envelope encryption (X25519 + Ed25519) - Prometheus /metrics, per-IP rate limit, body-size cap Deployment: - Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus - 3-node dev compose (docker-compose.yml) with mocked internet topology - 3-validator prod compose (deploy/prod/) for federation - Auto-update from Gitea via /api/update-check + systemd timer - Build-time version injection (ldflags → node --version) - UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER) Client (client-app/): - Expo / React Native / NativeWind - E2E NaCl encryption, typing indicator, contact requests - Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch Documentation: - README.md, CHANGELOG.md, CONTEXT.md - deploy/single/README.md with 6 operator scenarios - deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design - docs/contracts/*.md per contract
This commit is contained in:
458
contracts/name_registry/gen/main.go
Normal file
458
contracts/name_registry/gen/main.go
Normal file
@@ -0,0 +1,458 @@
|
||||
// gen generates contracts/name_registry/name_registry.wasm
|
||||
// Run from the repo root: go run ./contracts/name_registry/gen/
|
||||
//
|
||||
// Contract methods: register, resolve, transfer, release
|
||||
// Host imports from "env": get_arg_str, get_caller, get_state, set_state, log
|
||||
//
|
||||
// Every contract action emits a human-readable log entry visible in the
|
||||
// block explorer, e.g.:
|
||||
// "registered: alice"
|
||||
// "name taken: alice"
|
||||
// "not found: alice"
|
||||
// "owner: <pubkey>"
|
||||
// "transferred: alice"
|
||||
// "unauthorized: alice"
|
||||
// "released: alice"
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ── LEB128 ───────────────────────────────────────────────────────────────────
|
||||
|
||||
func u(v uint64) []byte {
|
||||
var b []byte
|
||||
for {
|
||||
bt := byte(v & 0x7f)
|
||||
v >>= 7
|
||||
if v != 0 {
|
||||
bt |= 0x80
|
||||
}
|
||||
b = append(b, bt)
|
||||
if v == 0 {
|
||||
return b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func s(v int64) []byte {
|
||||
var b []byte
|
||||
for {
|
||||
bt := byte(v & 0x7f)
|
||||
v >>= 7
|
||||
sign := (bt & 0x40) != 0
|
||||
if (v == 0 && !sign) || (v == -1 && sign) {
|
||||
return append(b, bt)
|
||||
}
|
||||
b = append(b, bt|0x80)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Builders ──────────────────────────────────────────────────────────────────
|
||||
|
||||
func cat(slices ...[]byte) []byte {
|
||||
var out []byte
|
||||
for _, sl := range slices {
|
||||
out = append(out, sl...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func wstr(str string) []byte { return cat(u(uint64(len(str))), []byte(str)) }
|
||||
|
||||
func section(id byte, content []byte) []byte {
|
||||
return cat([]byte{id}, u(uint64(len(content))), content)
|
||||
}
|
||||
|
||||
func vec(items ...[]byte) []byte {
|
||||
out := u(uint64(len(items)))
|
||||
for _, it := range items {
|
||||
out = append(out, it...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func functype(params, results []byte) []byte {
|
||||
return cat([]byte{0x60}, u(uint64(len(params))), params, u(uint64(len(results))), results)
|
||||
}
|
||||
|
||||
func importFunc(mod, name string, typeIdx uint32) []byte {
|
||||
return cat(wstr(mod), wstr(name), []byte{0x00}, u(uint64(typeIdx)))
|
||||
}
|
||||
|
||||
func exportEntry(name string, kind byte, idx uint32) []byte {
|
||||
return cat(wstr(name), []byte{kind}, u(uint64(idx)))
|
||||
}
|
||||
|
||||
func dataSegment(offset int32, data []byte) []byte {
|
||||
return cat(
|
||||
[]byte{0x00},
|
||||
[]byte{0x41}, s(int64(offset)), []byte{0x0B},
|
||||
u(uint64(len(data))), data,
|
||||
)
|
||||
}
|
||||
|
||||
func funcBody(localDecls []byte, instrs ...[]byte) []byte {
|
||||
inner := cat(localDecls)
|
||||
for _, ins := range instrs {
|
||||
inner = append(inner, ins...)
|
||||
}
|
||||
inner = append(inner, 0x0B) // end
|
||||
return cat(u(uint64(len(inner))), inner)
|
||||
}
|
||||
|
||||
var noLocals = u(0)
|
||||
|
||||
func localDecl(n uint32, typ byte) []byte { return cat(u(uint64(n)), []byte{typ}) }
|
||||
func withLocals(decls ...[]byte) []byte {
|
||||
return cat(u(uint64(len(decls))), cat(decls...))
|
||||
}
|
||||
|
||||
// ── Instructions ──────────────────────────────────────────────────────────────
|
||||
|
||||
const (
|
||||
tI32 byte = 0x7F
|
||||
tI64 byte = 0x7E
|
||||
)
|
||||
|
||||
func call(fn uint32) []byte { return cat([]byte{0x10}, u(uint64(fn))) }
|
||||
func lget(i uint32) []byte { return cat([]byte{0x20}, u(uint64(i))) }
|
||||
func lset(i uint32) []byte { return cat([]byte{0x21}, u(uint64(i))) }
|
||||
func ic32(v int32) []byte { return cat([]byte{0x41}, s(int64(v))) }
|
||||
func block_() []byte { return []byte{0x02, 0x40} }
|
||||
func loop_() []byte { return []byte{0x03, 0x40} }
|
||||
func if_() []byte { return []byte{0x04, 0x40} }
|
||||
func ifI32() []byte { return []byte{0x04, tI32} } // if that returns i32
|
||||
func else_() []byte { return []byte{0x05} }
|
||||
func end_() []byte { return []byte{0x0B} }
|
||||
func br_(lbl uint32) []byte { return cat([]byte{0x0C}, u(uint64(lbl))) }
|
||||
func brIf_(lbl uint32) []byte { return cat([]byte{0x0D}, u(uint64(lbl))) }
|
||||
func return_() []byte { return []byte{0x0F} }
|
||||
func i32Eqz() []byte { return []byte{0x45} }
|
||||
func i32Ne() []byte { return []byte{0x47} }
|
||||
func i32GtU() []byte { return []byte{0x4B} }
|
||||
func i32GeU() []byte { return []byte{0x4F} }
|
||||
func i32Add() []byte { return []byte{0x6A} }
|
||||
func i32Load8U() []byte { return []byte{0x2D, 0x00, 0x00} }
|
||||
func i32Store8() []byte { return []byte{0x3A, 0x00, 0x00} }
|
||||
|
||||
// ── Memory layout ─────────────────────────────────────────────────────────────
|
||||
|
||||
const (
|
||||
offArg0 = 0x000 // arg[0] name buffer (64 bytes)
|
||||
offArg1 = 0x040 // arg[1] new_owner buffer (128 bytes)
|
||||
offCaller = 0x0C0 // caller pubkey buffer (128 bytes)
|
||||
offStateRead = 0x140 // existing owner buffer (128 bytes)
|
||||
|
||||
// Verbose prefix strings — each ends with ": " for readable log messages.
|
||||
offRegisteredPfx = 0x200 // "registered: " 12 bytes
|
||||
offNameTakenPfx = 0x20C // "name taken: " 12 bytes
|
||||
offNotFoundPfx = 0x218 // "not found: " 11 bytes
|
||||
offOwnerPfx = 0x224 // "owner: " 7 bytes
|
||||
offTransferredPfx = 0x22C // "transferred: " 13 bytes
|
||||
offUnauthPfx = 0x23A // "unauthorized: " 14 bytes
|
||||
offReleasedPfx = 0x249 // "released: " 10 bytes
|
||||
|
||||
// Scratch buffer for building concatenated log messages.
|
||||
offScratch = 0x300 // 256 bytes
|
||||
)
|
||||
|
||||
// Import function indices (order must match importSection below)
|
||||
const (
|
||||
fnGetArgStr = 0 // get_arg_str(idx, dstPtr, dstLen i32) → i32
|
||||
fnGetCaller = 1 // get_caller(bufPtr, bufLen i32) → i32
|
||||
fnGetState = 2 // get_state(kP,kL,dP,dL i32) → i32
|
||||
fnSetState = 3 // set_state(kP,kL,vP,vL i32)
|
||||
fnLog = 4 // log(msgPtr, msgLen i32)
|
||||
)
|
||||
|
||||
// Local function indices (imports first, then locals in declaration order)
|
||||
const (
|
||||
fnBytesEqual = 5 // $bytes_equal(aPtr,bPtr,len i32) → i32
|
||||
fnMemcpy = 6 // $memcpy(dst,src,len i32)
|
||||
fnLogPrefixName = 7 // $log_prefix_name(pfxPtr,pfxLen,sfxPtr,sfxLen i32)
|
||||
fnRegister = 8
|
||||
fnResolve = 9
|
||||
fnTransfer = 10
|
||||
fnRelease = 11
|
||||
)
|
||||
|
||||
// ── $bytes_equal helper ───────────────────────────────────────────────────────
|
||||
// (aPtr i32, bPtr i32, len i32) → i32
|
||||
// locals: i(3), same(4)
|
||||
func bytesEqualBody() []byte {
|
||||
return funcBody(
|
||||
withLocals(localDecl(2, tI32)), // locals 3=i, 4=same
|
||||
// same = 1; i = 0
|
||||
ic32(1), lset(4),
|
||||
ic32(0), lset(3),
|
||||
block_(),
|
||||
loop_(),
|
||||
lget(3), lget(2), i32GeU(), brIf_(1), // i >= len → exit block
|
||||
// load mem[aPtr+i]
|
||||
lget(0), lget(3), i32Add(), i32Load8U(),
|
||||
// load mem[bPtr+i]
|
||||
lget(1), lget(3), i32Add(), i32Load8U(),
|
||||
i32Ne(), if_(),
|
||||
ic32(0), lset(4),
|
||||
br_(2), // exit block
|
||||
end_(),
|
||||
lget(3), ic32(1), i32Add(), lset(3),
|
||||
br_(0), // next iteration
|
||||
end_(),
|
||||
end_(),
|
||||
lget(4), // return same
|
||||
)
|
||||
}
|
||||
|
||||
// ── $memcpy helper ────────────────────────────────────────────────────────────
|
||||
// (dst i32, src i32, len i32) — copies len bytes from src to dst.
|
||||
// locals: i(3)
|
||||
func memcpyBody() []byte {
|
||||
return funcBody(
|
||||
withLocals(localDecl(1, tI32)), // local 3 = i
|
||||
ic32(0), lset(3), // i = 0
|
||||
block_(),
|
||||
loop_(),
|
||||
lget(3), lget(2), i32GeU(), brIf_(1), // if i >= len: exit
|
||||
// mem[dst+i] = mem[src+i]
|
||||
lget(0), lget(3), i32Add(), // dst+i (store address)
|
||||
lget(1), lget(3), i32Add(), i32Load8U(), // load mem[src+i]
|
||||
i32Store8(),
|
||||
lget(3), ic32(1), i32Add(), lset(3), // i++
|
||||
br_(0),
|
||||
end_(),
|
||||
end_(),
|
||||
)
|
||||
}
|
||||
|
||||
// ── $log_prefix_name helper ───────────────────────────────────────────────────
|
||||
// (prefixPtr i32, prefixLen i32, suffixPtr i32, suffixLen i32)
|
||||
// Builds "prefix<suffix>" in scratch buffer and logs it.
|
||||
func logPrefixNameBody() []byte {
|
||||
return funcBody(
|
||||
noLocals,
|
||||
// memcpy(offScratch, prefixPtr, prefixLen)
|
||||
ic32(offScratch), lget(0), lget(1), call(fnMemcpy),
|
||||
// memcpy(offScratch + prefixLen, suffixPtr, suffixLen)
|
||||
ic32(offScratch), lget(1), i32Add(), lget(2), lget(3), call(fnMemcpy),
|
||||
// log(offScratch, prefixLen + suffixLen)
|
||||
ic32(offScratch), lget(1), lget(3), i32Add(), call(fnLog),
|
||||
)
|
||||
}
|
||||
|
||||
// ── isOwner: shared caller-vs-existing check ──────────────────────────────────
|
||||
// Assumes: caller is at offCaller with len callerLenLocal,
|
||||
// existing is at offStateRead with len existingLenLocal.
|
||||
// Returns instructions that leave i32 (1=same, 0=not) on stack.
|
||||
func isOwnerCheck(callerLenLocal, existingLenLocal uint32) []byte {
|
||||
return cat(
|
||||
// if callerLen != existingLen → push 0
|
||||
ifI32(),
|
||||
ic32(0),
|
||||
else_(),
|
||||
// else call bytes_equal(offCaller, offStateRead, callerLen)
|
||||
ic32(offCaller), ic32(offStateRead), lget(callerLenLocal),
|
||||
call(fnBytesEqual),
|
||||
end_(),
|
||||
)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// ── Type section ──────────────────────────────────────────────────────────
|
||||
// Type 0: (i32,i32,i32)→(i32) get_arg_str, bytes_equal
|
||||
// Type 1: (i32,i32)→(i32) get_caller
|
||||
// Type 2: (i32,i32,i32,i32)→(i32) get_state
|
||||
// Type 3: (i32,i32,i32,i32)→() set_state, log_prefix_name
|
||||
// Type 4: (i32,i32)→() log
|
||||
// Type 5: ()→() register, resolve, transfer, release
|
||||
// Type 6: (i32,i32,i32)→() memcpy
|
||||
typeSection := section(0x01, vec(
|
||||
functype([]byte{tI32, tI32, tI32}, []byte{tI32}), // 0
|
||||
functype([]byte{tI32, tI32}, []byte{tI32}), // 1
|
||||
functype([]byte{tI32, tI32, tI32, tI32}, []byte{tI32}), // 2
|
||||
functype([]byte{tI32, tI32, tI32, tI32}, []byte{}), // 3
|
||||
functype([]byte{tI32, tI32}, []byte{}), // 4
|
||||
functype([]byte{}, []byte{}), // 5
|
||||
functype([]byte{tI32, tI32, tI32}, []byte{}), // 6
|
||||
))
|
||||
|
||||
// ── Import section ────────────────────────────────────────────────────────
|
||||
importSection := section(0x02, vec(
|
||||
importFunc("env", "get_arg_str", 0), // fnGetArgStr=0 type 0
|
||||
importFunc("env", "get_caller", 1), // fnGetCaller=1 type 1
|
||||
importFunc("env", "get_state", 2), // fnGetState=2 type 2
|
||||
importFunc("env", "set_state", 3), // fnSetState=3 type 3
|
||||
importFunc("env", "log", 4), // fnLog=4 type 4
|
||||
))
|
||||
|
||||
// ── Function section: 7 local functions ──────────────────────────────────
|
||||
functionSection := section(0x03, vec(
|
||||
u(0), // bytes_equal → type 0
|
||||
u(6), // memcpy → type 6
|
||||
u(3), // log_prefix_name → type 3
|
||||
u(5), // register → type 5
|
||||
u(5), // resolve → type 5
|
||||
u(5), // transfer → type 5
|
||||
u(5), // release → type 5
|
||||
))
|
||||
|
||||
// ── Memory section ────────────────────────────────────────────────────────
|
||||
memorySection := section(0x05, vec(cat([]byte{0x00}, u(1))))
|
||||
|
||||
// ── Export section ────────────────────────────────────────────────────────
|
||||
exportSection := section(0x07, vec(
|
||||
exportEntry("memory", 0x02, 0),
|
||||
exportEntry("register", 0x00, fnRegister),
|
||||
exportEntry("resolve", 0x00, fnResolve),
|
||||
exportEntry("transfer", 0x00, fnTransfer),
|
||||
exportEntry("release", 0x00, fnRelease),
|
||||
))
|
||||
|
||||
// ── Data section ──────────────────────────────────────────────────────────
|
||||
dataSection := section(0x0B, cat(
|
||||
u(7),
|
||||
dataSegment(offRegisteredPfx, []byte("registered: ")),
|
||||
dataSegment(offNameTakenPfx, []byte("name taken: ")),
|
||||
dataSegment(offNotFoundPfx, []byte("not found: ")),
|
||||
dataSegment(offOwnerPfx, []byte("owner: ")),
|
||||
dataSegment(offTransferredPfx, []byte("transferred: ")),
|
||||
dataSegment(offUnauthPfx, []byte("unauthorized: ")),
|
||||
dataSegment(offReleasedPfx, []byte("released: ")),
|
||||
))
|
||||
|
||||
// ── Code section ─────────────────────────────────────────────────────────
|
||||
|
||||
// register(): locals nameLen(0), callerLen(1), existingLen(2)
|
||||
registerBody := funcBody(
|
||||
withLocals(localDecl(3, tI32)),
|
||||
// nameLen = get_arg_str(0, offArg0, 64)
|
||||
ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0),
|
||||
// if nameLen == 0: return
|
||||
lget(0), i32Eqz(), if_(), return_(), end_(),
|
||||
// existingLen = get_state(offArg0, nameLen, offStateRead, 128)
|
||||
ic32(offArg0), lget(0), ic32(offStateRead), ic32(128), call(fnGetState), lset(2),
|
||||
// if existingLen > 0: log("name taken: <name>"); return
|
||||
lget(2), ic32(0), i32GtU(), if_(),
|
||||
ic32(offNameTakenPfx), ic32(12), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
return_(),
|
||||
end_(),
|
||||
// callerLen = get_caller(offCaller, 128)
|
||||
ic32(offCaller), ic32(128), call(fnGetCaller), lset(1),
|
||||
// set_state(offArg0, nameLen, offCaller, callerLen)
|
||||
ic32(offArg0), lget(0), ic32(offCaller), lget(1), call(fnSetState),
|
||||
// log("registered: <name>")
|
||||
ic32(offRegisteredPfx), ic32(12), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
)
|
||||
|
||||
// resolve(): locals nameLen(0), ownerLen(1)
|
||||
resolveBody := funcBody(
|
||||
withLocals(localDecl(2, tI32)),
|
||||
// nameLen = get_arg_str(0, offArg0, 64)
|
||||
ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0),
|
||||
lget(0), i32Eqz(), if_(), return_(), end_(),
|
||||
// ownerLen = get_state(offArg0, nameLen, offStateRead, 128)
|
||||
ic32(offArg0), lget(0), ic32(offStateRead), ic32(128), call(fnGetState), lset(1),
|
||||
// if ownerLen == 0: log("not found: <name>"); return
|
||||
lget(1), i32Eqz(), if_(),
|
||||
ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
return_(),
|
||||
end_(),
|
||||
// log("owner: <pubkey>")
|
||||
// The pubkey stored in state is the raw caller string (hex-encoded),
|
||||
// so the log will display the human-readable address.
|
||||
ic32(offOwnerPfx), ic32(7), ic32(offStateRead), lget(1), call(fnLogPrefixName),
|
||||
)
|
||||
|
||||
// transfer(): locals nameLen(0), newOwnerLen(1), callerLen(2), existingLen(3)
|
||||
transferBody := funcBody(
|
||||
withLocals(localDecl(4, tI32)),
|
||||
// nameLen = get_arg_str(0, offArg0, 64)
|
||||
ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0),
|
||||
lget(0), i32Eqz(), if_(), return_(), end_(),
|
||||
// newOwnerLen = get_arg_str(1, offArg1, 128)
|
||||
ic32(1), ic32(offArg1), ic32(128), call(fnGetArgStr), lset(1),
|
||||
lget(1), i32Eqz(), if_(), return_(), end_(),
|
||||
// existingLen = get_state(offArg0, nameLen, offStateRead, 128)
|
||||
ic32(offArg0), lget(0), ic32(offStateRead), ic32(128), call(fnGetState), lset(3),
|
||||
// if existingLen == 0: not registered → anyone can claim
|
||||
lget(3), i32Eqz(), if_(),
|
||||
ic32(offArg0), lget(0), ic32(offArg1), lget(1), call(fnSetState),
|
||||
ic32(offTransferredPfx), ic32(13), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
return_(),
|
||||
end_(),
|
||||
// callerLen = get_caller(offCaller, 128)
|
||||
ic32(offCaller), ic32(128), call(fnGetCaller), lset(2),
|
||||
// isOwner = (callerLen == existingLen) ? bytes_equal(...) : 0
|
||||
lget(2), lget(3), i32Ne(),
|
||||
isOwnerCheck(2, 3),
|
||||
// if !isOwner: log("unauthorized: <name>"); return
|
||||
i32Eqz(), if_(),
|
||||
ic32(offUnauthPfx), ic32(14), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
return_(),
|
||||
end_(),
|
||||
// Authorized
|
||||
ic32(offArg0), lget(0), ic32(offArg1), lget(1), call(fnSetState),
|
||||
ic32(offTransferredPfx), ic32(13), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
)
|
||||
|
||||
// release(): locals nameLen(0), callerLen(1), existingLen(2)
|
||||
releaseBody := funcBody(
|
||||
withLocals(localDecl(3, tI32)),
|
||||
// nameLen = get_arg_str(0, offArg0, 64)
|
||||
ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0),
|
||||
lget(0), i32Eqz(), if_(), return_(), end_(),
|
||||
// existingLen = get_state(offArg0, nameLen, offStateRead, 128)
|
||||
ic32(offArg0), lget(0), ic32(offStateRead), ic32(128), call(fnGetState), lset(2),
|
||||
// if existingLen == 0: log("not found: <name>"); return
|
||||
lget(2), i32Eqz(), if_(),
|
||||
ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
return_(),
|
||||
end_(),
|
||||
// callerLen = get_caller(offCaller, 128)
|
||||
ic32(offCaller), ic32(128), call(fnGetCaller), lset(1),
|
||||
// isOwner check
|
||||
lget(1), lget(2), i32Ne(),
|
||||
isOwnerCheck(1, 2),
|
||||
i32Eqz(), if_(),
|
||||
ic32(offUnauthPfx), ic32(14), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
return_(),
|
||||
end_(),
|
||||
// Store empty value → effectively releases the name
|
||||
ic32(offArg0), lget(0), ic32(offArg0), ic32(0), call(fnSetState),
|
||||
ic32(offReleasedPfx), ic32(10), ic32(offArg0), lget(0), call(fnLogPrefixName),
|
||||
)
|
||||
|
||||
codeSection := section(0x0A, cat(
|
||||
u(7),
|
||||
bytesEqualBody(),
|
||||
memcpyBody(),
|
||||
logPrefixNameBody(),
|
||||
registerBody,
|
||||
resolveBody,
|
||||
transferBody,
|
||||
releaseBody,
|
||||
))
|
||||
|
||||
// ── Assemble module ───────────────────────────────────────────────────────
|
||||
module := cat(
|
||||
[]byte{0x00, 0x61, 0x73, 0x6d}, // \0asm
|
||||
[]byte{0x01, 0x00, 0x00, 0x00}, // version 1
|
||||
typeSection,
|
||||
importSection,
|
||||
functionSection,
|
||||
memorySection,
|
||||
exportSection,
|
||||
dataSection,
|
||||
codeSection,
|
||||
)
|
||||
|
||||
out := "contracts/name_registry/name_registry.wasm"
|
||||
if err := os.WriteFile(out, module, 0644); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "write:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Written %s (%d bytes)\n", out, len(module))
|
||||
}
|
||||
Reference in New Issue
Block a user