4 Commits
rocket ... main

Author SHA1 Message Date
12c2769d2b Some cleanup on the index page 2024-07-15 22:13:09 +01:00
9fd9873bc1 Added "From Blockchain Time" / "To Obsolete Time"
I hardly believe it myself, but this "just werkded" (TM) the first time
2024-07-15 22:07:33 +01:00
a4b673d644 Implemented the wrong way around 2024-07-15 21:39:52 +01:00
d544e598e4 Caught error where you don't put Date or Time in 2024-07-15 21:22:58 +01:00
5 changed files with 101 additions and 16 deletions

View File

@@ -1,9 +1,10 @@
use chrono::prelude::*; use chrono::{prelude::*, TimeDelta};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rocket::serde::Serialize; use rocket::serde::Serialize;
use std::convert::Into; use std::convert::Into;
use std::sync::RwLock; use std::sync::RwLock;
use serde_with::{serde_as, DisplayFromStr}; use serde_with::{serde_as, DisplayFromStr};
use std::str::FromStr;
pub enum BlockchainSupported { pub enum BlockchainSupported {
BTC, BTC,
@@ -12,6 +13,19 @@ pub enum BlockchainSupported {
ETH, ETH,
} }
impl FromStr for BlockchainSupported {
type Err = String;
fn from_str(val: &str) -> Result<Self, Self::Err> {
match val {
"BTC" => Ok(BlockchainSupported::BTC),
"BSV" => Ok(BlockchainSupported::BSV),
"XMR" => Ok(BlockchainSupported::XMR),
"ETH" => Ok(BlockchainSupported::ETH),
_ => Err("You picked an unsupported blockchain type! Create a patch and I'll probably accept it!".to_string())
}
}
}
type BlockHeight = i64; type BlockHeight = i64;
#[serde_as] #[serde_as]
@@ -71,6 +85,18 @@ pub fn time_to_blockheight(time: DateTime<Utc>, bi: BlockchainInfo) -> BlockHeig
num_blocks + bi.latest_block_height num_blocks + bi.latest_block_height
} }
pub fn blockheight_specific_chain_to_time(height: BlockHeight, blockchain: BlockchainSupported) -> DateTime<Utc> {
let bi: BlockchainInfo = blockchain.into();
blockheight_to_time(height, bi)
}
#[deprecated = "The output of this function (Date & Time) will eventually be redundant, please look to change your own time keeping system to the superior blocktime as set out in this repository"]
pub fn blockheight_to_time(height: BlockHeight, bi: BlockchainInfo) -> DateTime<Utc> {
// TODO check the + and - are the right way around
let diff_seconds = (height - bi.latest_block_height) * bi.block_period as i64;
bi.latest_block_time + TimeDelta::seconds(diff_seconds)
}
// I know there's code duplication... I _could_ abstract it out. // I know there's code duplication... I _could_ abstract it out.
// I think it's probably very YAGNI // I think it's probably very YAGNI
@@ -170,8 +196,9 @@ pub fn update_all_blockheights() {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use chrono::TimeDelta;
use super::*; use super::*;
use chrono::Duration;
#[test] #[test]
#[ignore] #[ignore]
@@ -230,6 +257,22 @@ mod tests {
assert_eq!(result, 1001); assert_eq!(result, 1001);
} }
#[test]
fn back_and_forth() {
let latest_block_time = Utc.with_ymd_and_hms(2024, 10, 10, 10, 10, 0).unwrap();
let wanted_future_block_time = Utc.with_ymd_and_hms(2024, 10, 10, 10, 20, 1).unwrap();
let blockchain_info = BlockchainInfo {
block_period: 60 * 10, // 10 minutes
latest_block_height: 1000,
latest_block_time,
};
let result = time_to_blockheight(wanted_future_block_time, blockchain_info);
assert_eq!(result, 1001);
let future_time = blockheight_to_time(1001, blockchain_info);
assert_eq!(future_time, Utc.with_ymd_and_hms(2024, 10, 10, 10, 20, 0).unwrap());
// ignore the missing second... that second will not be needed in the future
}
#[test] #[test]
fn one_block_time_previous() { fn one_block_time_previous() {
let latest_block_time = Utc.with_ymd_and_hms(2024, 10, 10, 10, 20, 1).unwrap(); let latest_block_time = Utc.with_ymd_and_hms(2024, 10, 10, 10, 20, 1).unwrap();
@@ -261,23 +304,23 @@ mod tests {
// Doesn't feel like an overly good test - but I can't think of anyother way that's "dynamic" // Doesn't feel like an overly good test - but I can't think of anyother way that's "dynamic"
// to me manually updating the times above // to me manually updating the times above
let bi: BlockchainInfo = BlockchainSupported::BTC.into(); let bi: BlockchainInfo = BlockchainSupported::BTC.into();
let wanted_time = bi.latest_block_time + Duration::seconds(bi.block_period as i64 + 1); let wanted_time = bi.latest_block_time + TimeDelta::seconds(bi.block_period as i64 + 1);
let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::BTC); let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::BTC);
assert_eq!(bh, bi.latest_block_height + 1); assert_eq!(bh, bi.latest_block_height + 1);
let bi: BlockchainInfo = BlockchainSupported::BSV.into(); let bi: BlockchainInfo = BlockchainSupported::BSV.into();
let wanted_time = bi.latest_block_time + Duration::seconds(bi.block_period as i64 + 2); let wanted_time = bi.latest_block_time + TimeDelta::seconds(bi.block_period as i64 + 2);
let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::BSV); let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::BSV);
assert_eq!(bh, bi.latest_block_height + 1); assert_eq!(bh, bi.latest_block_height + 1);
let bi: BlockchainInfo = BlockchainSupported::XMR.into(); let bi: BlockchainInfo = BlockchainSupported::XMR.into();
let wanted_time = bi.latest_block_time + Duration::seconds(bi.block_period as i64 + 3); let wanted_time = bi.latest_block_time + TimeDelta::seconds(bi.block_period as i64 + 3);
let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::XMR); let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::XMR);
assert_eq!(bh, bi.latest_block_height + 1); assert_eq!(bh, bi.latest_block_height + 1);
let bi: BlockchainInfo = BlockchainSupported::ETH.into(); let bi: BlockchainInfo = BlockchainSupported::ETH.into();
let wanted_time = bi.latest_block_time + Duration::seconds(bi.block_period as i64 + 4); let wanted_time = bi.latest_block_time + TimeDelta::seconds(bi.block_period as i64 + 4);
let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::ETH); let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::ETH);
assert_eq!(bh, bi.latest_block_height + 1); assert_eq!(bh, bi.latest_block_height + 1);
let bi: BlockchainInfo = BlockchainSupported::ETH.into(); let bi: BlockchainInfo = BlockchainSupported::ETH.into();
let wanted_time = bi.latest_block_time + Duration::seconds(bi.block_period as i64 + 5); let wanted_time = bi.latest_block_time + TimeDelta::seconds(bi.block_period as i64 + 5);
let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::XMR); let bh = time_to_blockheight_specific_chain(wanted_time, BlockchainSupported::XMR);
assert_ne!(bh, bi.latest_block_height + 1); assert_ne!(bh, bi.latest_block_height + 1);
} }

View File

@@ -1,6 +1,6 @@
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
use rocket_dyn_templates::{context, Template}; use rocket_dyn_templates::{context, Template};
use blockchain_time::{BlockchainInfo, BlockchainSupported, update_all_blockheights, time_to_blockheight_specific_chain}; use blockchain_time::{BlockchainInfo, BlockchainSupported, update_all_blockheights, time_to_blockheight_specific_chain, blockheight_specific_chain_to_time};
use chrono::prelude::*; use chrono::prelude::*;
#[get("/")] #[get("/")]
@@ -32,8 +32,8 @@ fn to_blockchain_time(input_datetime: &str) -> Template {
dt.and_utc() dt.and_utc()
}, },
Err(e) => { Err(e) => {
println!("error: {}", e); let err_string = format!{"{}", e};
panic!(); return Template::render("error", context!{ error: err_string });
} }
}; };
let blocktimes = vec!{ let blocktimes = vec!{
@@ -45,12 +45,26 @@ fn to_blockchain_time(input_datetime: &str) -> Template {
let context = context!{ let context = context!{
blocktimes blocktimes
}; };
println!("{:?}", context);
Template::render("blockchain_time_results", context) Template::render("blockchain_time_results", context)
} }
#[get("/to_obsolete_time?<blockheight>&<blockchain>")]
fn to_obsolete_time(blockheight: i64, blockchain: &str) -> Template {
let blockchain: Result<BlockchainSupported, String> = blockchain.parse();
let blockchain = match blockchain {
Ok(bl) => bl,
Err(err) => {
return Template::render("error", context!{ error: err });
}
};
let context = context! {
time: blockheight_specific_chain_to_time(blockheight, blockchain)
};
Template::render("obsolete_time", context)
}
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
rocket::build().mount("/", routes![index, update_blockchains, to_blockchain_time]) rocket::build().mount("/", routes![index, update_blockchains, to_blockchain_time, to_obsolete_time])
.attach(Template::fairing()) .attach(Template::fairing())
} }

11
templates/error.html.tera Normal file
View File

@@ -0,0 +1,11 @@
{% extends "base" %}
{% block content %}
<h1>Error!</h1>
<p>Error: <span class="result">{{ error }}</span></p>
<p>I don't know what you did</p>
<p>Maybe that error above will make sense to you, maybe not</p>
<p>It's probably because you up a wrong DateTime in</p>
<p>Don't forget to put a time in - I don't know how to enforce this with HTML</p>
<p><a href="/">Please try again</a></p>
{% endblock content %}

View File

@@ -3,16 +3,26 @@
<h1>Welcome to Blockchain Time</h1><p>A.K.A. Big Tim</p> <h1>Welcome to Blockchain Time</h1><p>A.K.A. Big Tim</p>
<div> <div>
<h2>Convert to Blockchain Time</h2> <h2>Convert to Blockchain Time</h2>
<form id="form" method="GET" action="to_blockchain_time"> <form id="to_blocktmie" method="GET" action="to_blockchain_time">
<label for="input_datetime">Input DateTime (in UTC only currently)</label> <label for="input_datetime">Input DateTime (in UTC only currently)</label>
<input type="datetime-local" id="input_datetime" name="input_datetime"> <input type="datetime-local" id="input_datetime" name="input_datetime">
<input type="submit" value="Submit"> <input type="submit" value="Submit">
</form> </form>
</div> </div>
<div> <div>
<h2>Convert from Blockchain Time</h2> <h2 title="Boooooooo">Convert from Blockchain Time</h2>
<p><b>Booo</b> why are you going this way??? Don't you know your blocktimes??</p> <form id="to_obsolete_time" method="GET" action="to_obsolete_time">
<p><b><i><a href="#">UNIMPLEMENTED</a></i></b></p> <label for="blockheight">Input Block Height</label>
<input type="int" id="blockheight" name="blockheight" value="{{blockchain_infos[0][1].latest_block_height}}">
<label for="blockchain">Blockchain</label>
<select if="blockchain" name="blockchain">
<option value="BSV">BSV</option>
<option value="BTC">BTC</option>
<option value="XMR">XMR</option>
<option value="ETH">ETH</option>
</select>
<input type="submit" value="I'm a weenie that doesn't know my blocktimes">
</form>
</div> </div>
<div class="cur_blocks"> <div class="cur_blocks">
<h2>Latest Block Heights and Times Cached</h2> <h2>Latest Block Heights and Times Cached</h2>

View File

@@ -0,0 +1,7 @@
{% extends "base" %}
{% block content %}
<h1>BOOOOOOOOOOOOOOOOOOO</h1>
<h6>here's your obsolete time, in UTC, because timezones are boring to get correct, and no longer needed in the new blocktime order</h6>
<p class="result">{{time}}</p>
<p>Why don't you go back <a href="/">home</a> and try another thing</p>
{% endblock content %}