feat(nu-proto): initial Faz 0 scaffold
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
37862083c4
7 changed files with 321 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
target/
|
||||
*.rs.bk
|
||||
39
CLAUDE.md
Normal file
39
CLAUDE.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# nu-proto — CLAUDE.md
|
||||
|
||||
Tüm ekosistemin canonical tip ve RPC API tanımları. **Değişince diğer repolar kırılır.**
|
||||
|
||||
## Kritik Kural
|
||||
|
||||
`v0.1` tag'i atıldıktan sonra field silemezsin, field tipi değiştiremezsin. Yeni field eklemek non-breaking — sıra numarası bir kez atandıktan sonra değişmez.
|
||||
|
||||
```protobuf
|
||||
// BREAKING: field silindi/tipi değişti — bunu yapma v0.1 sonrası
|
||||
// Yeni field ekle, eski field'ı deprecated bırak
|
||||
```
|
||||
|
||||
## Dosya Yapısı
|
||||
|
||||
```
|
||||
types/
|
||||
transaction.proto ← TxPayload enum; tüm sistemi kilitler
|
||||
block.proto ← BlockHeader, Block, BlockReceipt
|
||||
story_node.proto ← StoryNode, Story, NodeStatus
|
||||
nft.proto ← Nft, Collection
|
||||
rpc/
|
||||
api.proto ← Platform ↔ Node JSON-RPC sözleşmesi
|
||||
```
|
||||
|
||||
## Derleme
|
||||
|
||||
```bash
|
||||
# Rust crate üret
|
||||
protoc --rust_out=src/ types/*.proto rpc/*.proto
|
||||
|
||||
# TypeScript (platform için)
|
||||
protoc --ts_out=../nu-platform/src/proto/ types/*.proto rpc/*.proto
|
||||
```
|
||||
|
||||
## Versiyon
|
||||
|
||||
Şu an: **v0.1-dev** (henüz dondurulmadı)
|
||||
v0.1 lock sonrası paralel geliştirme başlar.
|
||||
89
rpc/api.proto
Normal file
89
rpc/api.proto
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package nu.rpc;
|
||||
|
||||
import "types/block.proto";
|
||||
import "types/transaction.proto";
|
||||
import "types/story_node.proto";
|
||||
import "types/nft.proto";
|
||||
|
||||
// JSON-RPC v2 method catalog — v0.1
|
||||
// All methods over HTTP POST /rpc and WS /ws
|
||||
|
||||
// ── Queries ──────────────────────────────────────────────────────────────────
|
||||
|
||||
message GetBlockRequest { uint64 height = 1; }
|
||||
message GetBlockResponse { nu.types.Block block = 1; }
|
||||
|
||||
message GetTxRequest { string tx_id = 1; }
|
||||
message GetTxResponse {
|
||||
nu.types.Transaction tx = 1;
|
||||
nu.types.BlockReceipt receipt = 2;
|
||||
}
|
||||
|
||||
message GetAccountRequest { string address = 1; }
|
||||
message GetAccountResponse {
|
||||
string address = 1;
|
||||
uint64 balance = 2; // NUT micro-units
|
||||
uint64 staked = 3;
|
||||
uint64 locked = 4;
|
||||
uint64 locked_until = 5; // Unix epoch ms
|
||||
string pon_score = 6; // decimal string
|
||||
repeated string nft_ids = 7;
|
||||
}
|
||||
|
||||
message GetStoryRequest { string story_id = 1; }
|
||||
message GetStoryResponse {
|
||||
nu.types.Story story = 1;
|
||||
repeated nu.types.StoryNode nodes = 2;
|
||||
}
|
||||
|
||||
message GetNodeRequest { string node_id = 1; } // canonical or temp_id
|
||||
message GetNodeResponse { nu.types.StoryNode node = 1; }
|
||||
|
||||
message GetNftRequest { string nft_id = 1; }
|
||||
message GetNftResponse { nu.types.Nft nft = 1; }
|
||||
|
||||
message ListStoriesRequest {
|
||||
uint32 page = 1;
|
||||
uint32 per_page = 2;
|
||||
}
|
||||
message ListStoriesResponse {
|
||||
repeated nu.types.Story stories = 1;
|
||||
uint32 total = 2;
|
||||
}
|
||||
|
||||
message ListPendingVotesRequest { string voter = 1; } // Address; empty = all
|
||||
message ListPendingVotesResponse { repeated nu.types.StoryNode nodes = 1; }
|
||||
|
||||
// ── Mutations ────────────────────────────────────────────────────────────────
|
||||
|
||||
message SendRawTxRequest { bytes raw_tx = 1; } // protobuf-encoded signed Transaction
|
||||
message SendRawTxResponse {
|
||||
string tx_id = 1;
|
||||
bool queued = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
// ── Chain Info ───────────────────────────────────────────────────────────────
|
||||
|
||||
message ChainInfoRequest {}
|
||||
message ChainInfoResponse {
|
||||
uint64 latest_height = 1;
|
||||
string latest_hash = 2;
|
||||
uint32 validator_count = 3;
|
||||
string chain_id = 4; // e.g. "nu-devnet-1"
|
||||
}
|
||||
|
||||
// ── WebSocket Subscriptions (event stream) ───────────────────────────────────
|
||||
|
||||
message SubscribeRequest {
|
||||
repeated string topics = 1;
|
||||
// topics: "blocks", "node:<story_id>", "vote:<node_id>", "nft:<address>"
|
||||
}
|
||||
|
||||
message Event {
|
||||
string topic = 1;
|
||||
string kind = 2; // "new_block" | "node_approved" | "vote_cast" | "nft_minted"
|
||||
bytes payload = 3; // protobuf-encoded type depending on kind
|
||||
}
|
||||
29
types/block.proto
Normal file
29
types/block.proto
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package nu.types;
|
||||
|
||||
import "types/transaction.proto";
|
||||
|
||||
message BlockHeader {
|
||||
uint64 height = 1;
|
||||
string prev_block_hash = 2; // Hash256
|
||||
int64 timestamp = 3; // Unix epoch milliseconds
|
||||
string validator_addr = 4; // Address
|
||||
bytes validator_sig = 5; // secp256k1
|
||||
string tx_root = 6; // Merkle root of transactions
|
||||
string state_root = 7; // Merkle Patricia Trie root
|
||||
string receipts_root = 8;
|
||||
uint32 slot = 9;
|
||||
}
|
||||
|
||||
message Block {
|
||||
BlockHeader header = 1;
|
||||
repeated Transaction transactions = 2;
|
||||
}
|
||||
|
||||
message BlockReceipt {
|
||||
string tx_id = 1;
|
||||
bool success = 2;
|
||||
string error = 3; // empty if success
|
||||
uint64 gas_used = 4;
|
||||
}
|
||||
20
types/nft.proto
Normal file
20
types/nft.proto
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package nu.types;
|
||||
|
||||
message Nft {
|
||||
string nft_id = 1; // same as canonical node_id
|
||||
string node_id = 2;
|
||||
string owner = 3; // Address
|
||||
string collection_id = 4; // empty until CollectionClaim
|
||||
uint32 depth = 5; // path length from root
|
||||
repeated string lineage = 6; // ancestor node_ids root → this
|
||||
int64 minted_at = 7;
|
||||
}
|
||||
|
||||
message Collection {
|
||||
string collection_id = 1; // leaf node_id of the path
|
||||
string owner = 2; // Address
|
||||
repeated string nft_ids = 3; // ordered root → leaf
|
||||
int64 claimed_at = 4;
|
||||
}
|
||||
39
types/story_node.proto
Normal file
39
types/story_node.proto
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package nu.types;
|
||||
|
||||
enum NodeStatus {
|
||||
PENDING = 0;
|
||||
VOTING_OPEN = 1;
|
||||
APPROVED = 2;
|
||||
REJECTED = 3;
|
||||
}
|
||||
|
||||
message WeightedVote {
|
||||
string voter = 1; // Address
|
||||
bool approve = 2;
|
||||
string weight = 3; // decimal string; computed at finalization
|
||||
}
|
||||
|
||||
message StoryNode {
|
||||
string node_id = 1; // canonical; empty until approved
|
||||
string temp_id = 2; // client UUID during pending/voting
|
||||
string story_id = 3;
|
||||
string parent_id = 4;
|
||||
string author = 5; // Address
|
||||
string content_hash = 6; // IpfsHash
|
||||
NodeStatus status = 7;
|
||||
int64 submitted_at = 8; // Unix epoch ms
|
||||
int64 vote_open_at = 9; // day 7
|
||||
int64 vote_end_at = 10; // day 10
|
||||
repeated WeightedVote votes = 11;
|
||||
string nft_id = 12; // set on approval
|
||||
}
|
||||
|
||||
message Story {
|
||||
string story_id = 1;
|
||||
string root_node_id = 2; // canonical
|
||||
string creator = 3; // Address
|
||||
int64 created_at = 4;
|
||||
bool is_genesis = 5; // genesis dev log — no voting, no entry fee
|
||||
}
|
||||
103
types/transaction.proto
Normal file
103
types/transaction.proto
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package nu.types;
|
||||
|
||||
option java_package = "tr.cw.narrativeunion.types";
|
||||
option java_outer_classname = "TransactionProto";
|
||||
|
||||
// Hash256: 32-byte SHA-256 digest, hex-encoded
|
||||
// Address: 20-byte account address, hex-encoded
|
||||
// IpfsHash: CIDv1 string
|
||||
|
||||
message Transaction {
|
||||
string tx_id = 1; // SHA-256(payload bytes)
|
||||
string sender = 2; // Address
|
||||
uint64 nonce = 3;
|
||||
uint64 fee = 4; // NUT micro-units (1 NUT = 1_000_000 units)
|
||||
bytes signature = 5; // secp256k1 compact (64 bytes)
|
||||
TxPayload payload = 6;
|
||||
}
|
||||
|
||||
message TxPayload {
|
||||
oneof kind {
|
||||
TokenTransfer token_transfer = 1;
|
||||
NodeSubmit node_submit = 2;
|
||||
VoteRegister vote_register = 3;
|
||||
VoteCast vote_cast = 4;
|
||||
NftTransfer nft_transfer = 5;
|
||||
CollectionClaim collection_claim = 6;
|
||||
StakeOp stake_op = 7;
|
||||
ValidatorRegister validator_register = 8;
|
||||
// Auto-generated by validator — never submitted by users directly:
|
||||
NodeApprove node_approve = 9;
|
||||
NftMint nft_mint = 10;
|
||||
NodeReject node_reject = 11;
|
||||
VotingOpen voting_open = 12;
|
||||
}
|
||||
}
|
||||
|
||||
message TokenTransfer {
|
||||
string to = 1; // Address
|
||||
uint64 amount = 2;
|
||||
}
|
||||
|
||||
message NodeSubmit {
|
||||
string story_id = 1;
|
||||
string parent_node_id = 2; // empty if root node
|
||||
string content_hash = 3; // IpfsHash
|
||||
uint64 entry_fee = 4; // must equal reward * 0.25
|
||||
string temp_id = 5; // client-generated UUID; replaced by canonical NodeId on approval
|
||||
}
|
||||
|
||||
message VoteRegister {
|
||||
string node_id = 1; // temp_id at this stage
|
||||
uint64 stake_lock = 2; // must equal node_reward * 0.10; locked 10 days
|
||||
}
|
||||
|
||||
message VoteCast {
|
||||
string node_id = 1;
|
||||
bool approve = 2; // true = approve, false = reject
|
||||
}
|
||||
|
||||
message NftTransfer {
|
||||
string nft_id = 1;
|
||||
string to = 2; // Address
|
||||
}
|
||||
|
||||
message CollectionClaim {
|
||||
repeated string nft_ids = 1; // must form a valid lineage path from root
|
||||
}
|
||||
|
||||
message StakeOp {
|
||||
enum Kind {
|
||||
STAKE = 0;
|
||||
UNSTAKE = 1;
|
||||
}
|
||||
Kind op = 1;
|
||||
uint64 amount = 2;
|
||||
}
|
||||
|
||||
message ValidatorRegister {
|
||||
uint64 stake = 1; // minimum 1_000_000_000 units (1000 NUT)
|
||||
}
|
||||
|
||||
// --- Auto-generated scheduler/validator transactions ---
|
||||
|
||||
message NodeApprove {
|
||||
string node_id = 1; // canonical NodeId assigned at approval
|
||||
string temp_id = 2; // maps back to NodeSubmit.temp_id
|
||||
string canonical_id = 3; // numeric path-encoded id e.g. "1159"
|
||||
}
|
||||
|
||||
message NftMint {
|
||||
string node_id = 1; // canonical
|
||||
string recipient = 2; // Address — node author
|
||||
}
|
||||
|
||||
message NodeReject {
|
||||
string temp_id = 1;
|
||||
}
|
||||
|
||||
message VotingOpen {
|
||||
string node_id = 1; // temp_id; triggered at day 7
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue