#![warn(dead_code)]
#![warn(unused_imports)]
#![warn(non_snake_case)]
#![warn(unused_variables)]
#![warn(clippy::style)]
#![allow(clippy::let_and_return)]
use std::collections::{HashMap, HashSet};
use std::fmt::{self, Display};
use primitive_types::U256;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
use thiserror::Error;
use tokio::sync::oneshot;
use crate::bits::ProtoSerialize;
use crate::runtime;
use crate::net::ProtoComm;
use crate::node::{self, PoolError, TransactionError};
use crate::util;
pub use kindelia_common::Name;
use kindelia_lang::ast;
pub fn u256_to_hex(value: &U256) -> String {
let mut be_bytes = [0u8; 32];
value.to_big_endian(&mut be_bytes);
format!("0x{}", hex::encode(be_bytes))
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(into = "String", try_from = "&str")]
pub struct Hash {
value: U256,
}
impl From<U256> for Hash {
fn from(value: U256) -> Self {
Hash { value }
}
}
impl From<Hash> for U256 {
fn from(hash: Hash) -> Self {
hash.value
}
}
impl Display for Hash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut be_bytes = [0u8; 32];
self.value.to_big_endian(&mut be_bytes);
f.write_fmt(format_args!("0x{}", hex::encode(be_bytes)))
}
}
impl TryFrom<&str> for Hash {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let rest = value.strip_prefix("0x");
let hex_str = rest.ok_or("Missing `0x` prefix from hash hex string.")?;
let bytes = hex::decode(hex_str).map_err(|e| e.to_string())?;
if bytes.len() != 32 {
return Err("Hash hex string must be 64 hex digits long.".to_string());
}
let bytes = &bytes[0..32];
let value = U256::from_big_endian(bytes);
Ok(Hash { value })
}
}
impl From<Hash> for String {
fn from(hash: Hash) -> Self {
u256_to_hex(&hash.value)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HexStatement(ast::Statement);
impl std::ops::Deref for HexStatement {
type Target = ast::Statement;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<HexStatement> for ast::Statement {
fn from(hex_statement: HexStatement) -> Self {
hex_statement.0
}
}
impl From<ast::Statement> for HexStatement {
fn from(statement: ast::Statement) -> Self {
HexStatement(statement)
}
}
impl Display for HexStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes = util::bitvec_to_bytes(&self.proto_serialized());
let hex = hex::encode(bytes);
write!(f, "{}", hex)
}
}
impl TryFrom<&str> for HexStatement {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let bytes = hex::decode(value).map_err(|e| e.to_string())?;
let bits = util::bytes_to_bitvec(&bytes);
let stmt =
ast::Statement::proto_deserialize(&bits, &mut 0, &mut HashMap::new())
.ok_or_else(|| format!("invalid Statement serialization: {}", value))?;
Ok(HexStatement(stmt))
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LimitStats {
pub limit: u64,
pub used: u64,
pub available: u64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Stats {
pub tick: u64,
pub mana: LimitStats,
pub space: LimitStats,
pub fun_count: u64,
pub ctr_count: u64,
pub reg_count: u64,
}
impl From<&node::Transaction> for String {
fn from(transaction: &node::Transaction) -> Self {
hex::encode(&**transaction)
}
}
#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
pub struct BlockRepr {
#[serde(with = "u128_time_ser")]
pub time: u128, #[serde_as(as = "DisplayFromStr")]
pub meta: u128, pub prev: Hash, pub body: Vec<String>, }
mod u128_time_ser {
use chrono::prelude::{DateTime, Utc};
use serde::{de, ser};
use serde::{Deserializer, Serializer};
use std::{fmt, time};
type T = u128;
struct TimeVisitor;
impl<'de> de::Visitor<'de> for TimeVisitor {
type Value = T;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a valid ISO 8601 timestamp string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let dt = DateTime::parse_from_rfc3339(v);
let dt = dt.map_err(|e| {
de::Error::custom(format!("invalid timestamp '{}': {}", v, e))
})?;
let st: time::SystemTime = dt.into();
let epoc = st.duration_since(time::UNIX_EPOCH);
let epoc = epoc.map_err(|e| {
de::Error::custom(format!("invalid epoch '{}': {}", dt, e))
})?;
Ok(epoc.as_millis())
}
}
pub fn serialize<S>(v: &T, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let epoc = *v as u64;
let st = time::SystemTime::UNIX_EPOCH
.checked_add(time::Duration::from_micros(epoc));
let st = st.ok_or_else(|| {
ser::Error::custom(format!("invalid time value '{}': ", epoc,))
})?;
let dt: DateTime<Utc> = st.into();
s.serialize_str(&dt.format("%+").to_string())
}
pub fn deserialize<'de, D>(d: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
d.deserialize_str(TimeVisitor)
}
}
impl From<&node::Block> for BlockRepr {
fn from(block: &node::Block) -> Self {
let transactions = node::extract_transactions(&block.body);
let hexes = transactions.iter().map(|t| t.into());
BlockRepr {
time: block.time,
meta: block.meta,
prev: block.prev.into(),
body: hexes.collect(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlockInfo {
pub block: BlockRepr,
pub hash: Hash,
pub height: u64,
pub results: Option<Vec<runtime::StatementResult>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct FuncInfo {
pub func: ast::Func,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CtrInfo {
pub arit: u64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RegInfo {
pub ownr: Name,
pub stmt: Vec<Name>,
}
pub type ReqAnsSend<T> = oneshot::Sender<T>;
pub type ReqAnsRecv<T> = oneshot::Receiver<T>;
#[derive(Debug, Error, Serialize, Deserialize)]
#[error(transparent)]
pub enum PublishError {
PoolError(#[from] PoolError),
TransactionError(#[from] TransactionError),
}
type PublishResults = Vec<Result<(), PublishError>>;
pub enum NodeRequest<C: ProtoComm> {
GetStats {
tx: ReqAnsSend<Stats>,
},
GetBlockHash {
index: u64,
tx: ReqAnsSend<Option<U256>>,
},
GetBlock {
hash: U256,
tx: ReqAnsSend<Option<BlockInfo>>,
},
GetBlocks {
range: (i64, i64),
tx: ReqAnsSend<Vec<BlockInfo>>,
},
GetFunctions {
tx: ReqAnsSend<HashSet<u128>>,
},
GetFunction {
name: Name,
tx: ReqAnsSend<Option<FuncInfo>>,
},
GetState {
name: Name,
tx: ReqAnsSend<Option<ast::Term>>,
},
GetPeers {
all: bool,
tx: ReqAnsSend<Vec<node::Peer<C::Address>>>,
},
GetConstructor {
name: Name,
tx: ReqAnsSend<Option<CtrInfo>>,
},
GetReg {
name: Name,
tx: ReqAnsSend<Option<RegInfo>>,
},
RunCode {
code: String,
tx: ReqAnsSend<Vec<runtime::StatementResult>>,
},
PublishCode {
code: String,
tx: ReqAnsSend<Result<PublishResults, String>>,
},
Run {
code: Vec<ast::Statement>,
tx: ReqAnsSend<Vec<runtime::StatementResult>>,
},
Publish {
code: Vec<ast::Statement>,
tx: ReqAnsSend<PublishResults>,
},
}
impl<C: ProtoComm> NodeRequest<C> {
pub fn get_stats() -> (Self, ReqAnsRecv<Stats>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetStats { tx }, rx)
}
pub fn get_block_hash(index: u64) -> (Self, ReqAnsRecv<Option<U256>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetBlockHash { index, tx }, rx)
}
pub fn get_block(hash: U256) -> (Self, ReqAnsRecv<Option<BlockInfo>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetBlock { hash, tx }, rx)
}
pub fn get_blocks(range: (i64, i64)) -> (Self, ReqAnsRecv<Vec<BlockInfo>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetBlocks { range, tx }, rx)
}
pub fn get_functions() -> (Self, ReqAnsRecv<HashSet<u128>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetFunctions { tx }, rx)
}
pub fn get_function(name: Name) -> (Self, ReqAnsRecv<Option<FuncInfo>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetFunction { name, tx }, rx)
}
pub fn get_state(name: Name) -> (Self, ReqAnsRecv<Option<ast::Term>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetState { name, tx }, rx)
}
pub fn get_peers(
all: bool,
) -> (Self, ReqAnsRecv<Vec<node::Peer<C::Address>>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetPeers { all, tx }, rx)
}
pub fn get_constructor(name: Name) -> (Self, ReqAnsRecv<Option<CtrInfo>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetConstructor { name, tx }, rx)
}
pub fn get_reg(name: Name) -> (Self, ReqAnsRecv<Option<RegInfo>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::GetReg { name, tx }, rx)
}
pub fn test_code(
code: String,
) -> (Self, ReqAnsRecv<Vec<runtime::StatementResult>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::RunCode { code, tx }, rx)
}
pub fn post_code(
code: String,
) -> (Self, ReqAnsRecv<Result<PublishResults, String>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::PublishCode { code, tx }, rx)
}
pub fn run(
code: Vec<ast::Statement>,
) -> (Self, ReqAnsRecv<Vec<runtime::StatementResult>>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::Run { code, tx }, rx)
}
pub fn publish(
code: Vec<ast::Statement>,
) -> (Self, ReqAnsRecv<PublishResults>) {
let (tx, rx) = oneshot::channel();
(NodeRequest::Publish { code, tx }, rx)
}
}