update kns-indexer wit api

This commit is contained in:
hosted-fornet 2024-12-16 17:23:14 -08:00
parent fefdb607d0
commit c2dfb25965
9 changed files with 146 additions and 52 deletions

2
Cargo.lock generated
View File

@ -4008,6 +4008,7 @@ dependencies = [
"anyhow",
"hex",
"kinode_process_lib 0.10.0",
"process_macros",
"rmp-serde",
"serde",
"serde_json",
@ -6069,6 +6070,7 @@ name = "state"
version = "0.1.0"
dependencies = [
"kinode_process_lib 0.10.0",
"process_macros",
"serde",
"serde_json",
"wit-bindgen 0.36.0",

View File

@ -1536,6 +1536,7 @@ dependencies = [
"anyhow",
"hex",
"kinode_process_lib",
"process_macros",
"rmp-serde",
"serde",
"serde_json",
@ -1958,6 +1959,15 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "process_macros"
version = "0.1.0"
source = "git+https://github.com/kinode-dao/process_macros?rev=626e501#626e501d351e3365480ec6f770d474ed4ae339bf"
dependencies = [
"quote",
"syn 2.0.90",
]
[[package]]
name = "proptest"
version = "1.5.0"
@ -2452,6 +2462,7 @@ name = "state"
version = "0.1.0"
dependencies = [
"kinode_process_lib",
"process_macros",
"serde",
"serde_json",
"wit-bindgen",

View File

@ -6,7 +6,7 @@ interface kns-indexer {
/// human readable name, you would send a NodeInfo request.
/// The block parameter specifies the recency of the data: the indexer will
/// not respond until it has processed events up to the specified block.
variant indexer-requests {
variant indexer-request {
/// return the human readable name for a namehash
/// returns an Option<String>
namehash-to-name(namehash-to-name-request),
@ -19,6 +19,12 @@ interface kns-indexer {
get-state(get-state-request),
}
variant indexer-response {
name(option<string>),
node-info(option<wit-kns-update>),
get-state(wit-state),
}
record namehash-to-name-request {
hash: string,
block: u64,
@ -32,6 +38,22 @@ interface kns-indexer {
record get-state-request {
block: u64,
}
record wit-kns-update {
name: string,
public-key: string,
ips: list<string>,
ports: list<tuple<string, u16>>, // map, but wit doesn't support maps
routers: list<string>,
}
record wit-state {
chain-id: u64,
contract-address: list<u8>, // 20-byte ETH address
names: list<tuple<string, string>>, // map, but wit doesn't support maps
nodes: list<tuple<string, wit-kns-update>>, // map, but wit doesn't support maps
last-block: u64,
}
}
world kns-indexer-sys-v0 {

View File

@ -12,6 +12,7 @@ alloy-primitives = "0.7.0"
alloy-sol-types = "0.7.0"
hex = "0.4.3"
kinode_process_lib = { git = "https://github.com/kinode-dao/process_lib", rev = "9c441fe" }
process_macros = { git = "https://github.com/kinode-dao/process_macros", rev = "626e501" }
rmp-serde = "1.1.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View File

@ -1,5 +1,5 @@
use crate::kinode::process::kns_indexer::{
GetStateRequest, IndexerRequests, NamehashToNameRequest, NodeInfoRequest,
GetStateRequest, IndexerRequest, IndexerResponse, NamehashToNameRequest, NodeInfoRequest, WitKnsUpdate, WitState,
};
use alloy_primitives::keccak256;
use alloy_sol_types::SolEvent;
@ -17,7 +17,7 @@ wit_bindgen::generate!({
path: "target/wit",
world: "kns-indexer-sys-v0",
generate_unused_types: true,
additional_derives: [serde::Deserialize, serde::Serialize],
additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto],
});
#[cfg(not(feature = "simulation-mode"))]
@ -52,14 +52,64 @@ struct State {
last_block: u64,
}
// note: not defined in wit api right now like IndexerRequests.
#[derive(Clone, Debug, Serialize, Deserialize)]
enum IndexerResponses {
Name(Option<String>),
NodeInfo(Option<net::KnsUpdate>),
GetState(State),
impl From<State> for WitState {
fn from(s: State) -> Self {
let contract_address: [u8; 20] = s.contract_address.into();
WitState {
chain_id: s.chain_id.clone(),
contract_address: contract_address.to_vec(),
names: s.names.iter().map(|(k, v)| (k.clone(), v.clone())).collect::<Vec<_>>(),
nodes: s.nodes.iter().map(|(k, v)| (k.clone(), v.clone().into())).collect::<Vec<_>>(),
last_block: s.last_block.clone(),
}
}
}
impl From<WitState> for State {
fn from(s: WitState) -> Self {
let contract_address: [u8; 20] = s.contract_address.try_into().expect("invalid contract addess: doesn't have 20 bytes");
State {
chain_id: s.chain_id.clone(),
contract_address: contract_address.into(),
names: HashMap::from_iter(s.names),
nodes: HashMap::from_iter(s.nodes.iter().map(|(k, v)| (k.clone(), v.clone().into()))),
last_block: s.last_block.clone(),
}
}
}
impl From<net::KnsUpdate> for WitKnsUpdate {
fn from(k: net::KnsUpdate) -> Self {
WitKnsUpdate {
name: k.name.clone(),
public_key: k.public_key.clone(),
ips: k.ips.clone(),
ports: k.ports.iter().map(|(k, v)| (k.clone(), v.clone())).collect::<Vec<_>>(),
routers: k.routers.clone(),
}
}
}
impl From<WitKnsUpdate> for net::KnsUpdate {
fn from(k: WitKnsUpdate) -> Self {
net::KnsUpdate {
name: k.name.clone(),
public_key: k.public_key.clone(),
ips: k.ips.clone(),
ports: BTreeMap::from_iter(k.ports),
routers: k.routers.clone(),
}
}
}
//// note: not defined in wit api right now like IndexerRequest.
//#[derive(Clone, Debug, Serialize, Deserialize)]
//enum IndexerResponse {
// Name(Option<String>),
// NodeInfo(Option<net::KnsUpdate>),
// GetState(State),
//}
#[derive(Debug, thiserror::Error)]
enum KnsError {
#[error("Parent node for note not found")]
@ -136,7 +186,7 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
// pending_requests temporarily on timeout.
// very naughty.
// let mut pending_requests: BTreeMap<u64, Vec<IndexerRequests>> = BTreeMap::new();
// let mut pending_requests: BTreeMap<u64, Vec<IndexerRequest>> = BTreeMap::new();
let mut pending_notes: BTreeMap<u64, Vec<(kimap::contract::Note, u8)>> = BTreeMap::new();
// if block in state is < current_block, get logs from that part.
@ -192,25 +242,26 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
let request = serde_json::from_slice(&body)?;
match request {
IndexerRequests::NamehashToName(NamehashToNameRequest { ref hash, .. }) => {
IndexerRequest::NamehashToName(NamehashToNameRequest { ref hash, .. }) => {
// TODO: make sure we've seen the whole block, while actually
// sending a response to the proper place.
Response::new()
.body(serde_json::to_vec(&IndexerResponses::Name(
.body(IndexerResponse::Name(
state.names.get(hash).cloned(),
))?)
))
.send()?;
}
IndexerRequests::NodeInfo(NodeInfoRequest { ref name, .. }) => {
IndexerRequest::NodeInfo(NodeInfoRequest { ref name, .. }) => {
Response::new()
.body(serde_json::to_vec(&IndexerResponses::NodeInfo(
state.nodes.get(name).cloned(),
))?)
.body(IndexerResponse::NodeInfo(
state.nodes.get(name).map(|n| n.clone().into()),
))
.send()?;
}
IndexerRequests::GetState(GetStateRequest { .. }) => {
Response::new().body(serde_json::to_vec(&state)?).send()?;
IndexerRequest::GetState(GetStateRequest { .. }) => {
//Response::new().body(serde_json::to_vec(&state)?).send()?;
Response::new().body(IndexerResponse::GetState(state.clone().into())).send()?;
}
}
}

View File

@ -1,5 +1,5 @@
{
"get_block.wasm": {
"get-block.wasm": {
"root": false,
"public": false,
"request_networking": false,
@ -23,4 +23,4 @@
],
"wit_version": 1
}
}
}

View File

@ -8,6 +8,7 @@ simulation-mode = []
[dependencies]
kinode_process_lib = { git = "https://github.com/kinode-dao/process_lib", rev = "9c441fe" }
process_macros = { git = "https://github.com/kinode-dao/process_macros", rev = "626e501" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
wit-bindgen = "0.36.0"

View File

@ -1,26 +1,29 @@
use kinode_process_lib::{eth, net, script, Address, Message, Request};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::kinode::process::kns_indexer::{
GetStateRequest, IndexerRequest, IndexerResponse,
};
use kinode_process_lib::{eth, script, Address, Message, Request};
wit_bindgen::generate!({
path: "target/wit",
world: "process-v1",
world: "kns-indexer-sys-v0",
generate_unused_types: true,
additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto],
});
/// From main kns-indexer process
#[derive(Clone, Debug, Serialize, Deserialize)]
struct State {
chain_id: u64,
// what contract this state pertains to
contract_address: eth::Address,
// namehash to human readable name
names: HashMap<String, String>,
// human readable name to most recent on-chain routing information as json
// TODO: optional params knsUpdate? also include tba.
nodes: HashMap<String, net::KnsUpdate>,
// last block we have an update from
last_block: u64,
}
///// From main kns-indexer process
//#[derive(Clone, Debug, Serialize, Deserialize)]
//struct State {
// chain_id: u64,
// // what contract this state pertains to
// contract_address: eth::Address,
// // namehash to human readable name
// names: HashMap<String, String>,
// // human readable name to most recent on-chain routing information as json
// // TODO: optional params knsUpdate? also include tba.
// nodes: HashMap<String, net::KnsUpdate>,
// // last block we have an update from
// last_block: u64,
//}
script!(init);
fn init(_our: Address, _args: String) -> String {
@ -28,31 +31,34 @@ fn init(_our: Address, _args: String) -> String {
let Ok(Message::Response { body, .. }) =
Request::to(("our", "kns-indexer", "kns-indexer", "sys"))
.body(
serde_json::json!({
"GetState": {
"block": 0
}
})
.to_string()
.as_bytes()
.to_vec(),
)
.body(IndexerRequest::GetState(GetStateRequest { block: 0 }))
// serde_json::json!({
// "GetState": {
// "block": 0
// }
// })
// .to_string()
// .as_bytes()
// .to_vec(),
//)
.send_and_await_response(10)
.unwrap()
else {
return "failed to get state from kns-indexer".to_string();
};
let Ok(state) = serde_json::from_slice::<State>(&body) else {
//let Ok(state) = serde_json::from_slice::<State>(&body) else {
let Ok(IndexerResponse::GetState(state)) = body.try_into() else {
return "failed to deserialize state".to_string();
};
// can change later, but for now, just print every known node name
let mut names = state.names.values().map(AsRef::as_ref).collect::<Vec<_>>();
let mut names = state.names.iter().map(|(_k, v)| v.clone()).collect::<Vec<_>>();
names.sort();
let contract_address: [u8; 20] = state.contract_address.try_into().expect("invalid contract addess: doesn't have 20 bytes");
let contract_address: eth::Address = contract_address.into();
format!(
"\nrunning on chain id {}\nCA: {}\n{} known nodes as of block {}\n {}",
state.chain_id,
state.contract_address,
contract_address,
names.len(),
state.last_block,
names.join("\n ")

Binary file not shown.