Skip to content

Commit

Permalink
Add Last Block Time support for mock ledger and BlockFrost (#150)
Browse files Browse the repository at this point in the history
* Add latest block time endpoints to LC and trireme

* Cleanup some timing docs and stuff

* Use newly published blockfrost client
  • Loading branch information
MitchTurner authored Sep 3, 2023
1 parent b67cfcc commit 620f924
Show file tree
Hide file tree
Showing 14 changed files with 85 additions and 26 deletions.
7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,8 @@ scrolls-client = { version = "0.1.0", git = "https://github.com/free-honey/scrol
secrecy = "0.8.0"

[dependencies.blockfrost-http-client]
version = "0.0.12"
git = "https://github.com/MitchTurner/blockfrost-http-client.git"
rev = "bbb29df268464a055b17b5ebfae20d5f02165dc0"
version = "0.0.14"
#git = "https://github.com/MitchTurner/blockfrost-http-client.git"

[dependencies.cardano-multiplatform-lib]
version = "3.1.1"
Expand Down Expand Up @@ -86,7 +85,7 @@ pallas-crypto = { version = "0.19.0-alpha.0", git = "https://github.com/txpipe/p
#uplc = { version = "1.0.3-alpha", path = "../aiken-lang/aiken/crates/uplc" }

#[patch."https://github.com/MitchTurner/blockfrost-http-client.git"]
#blockfrost-http-client = { version = "0.0.12", path = "../blockfrost-http-client"}
#blockfrost-http-client = { version = "0.0.13", path = "../blockfrost-http-client"}
#
#[patch."https://github.com/dcSpark/cardano-multiplatform-lib.git"]
#cardano-multiplatform-lib = { version = "3.1.1", path = "../forks/cardano-multiplatform-lib/rust"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ pub async fn init_account<LC: LedgerClient<CheckingAccountDatums, ()>>(
1,
);

println!("address: {:?}", address.to_bech32());
let actions = TxActions::v2()
.with_script_init(datum, values, address)
.with_specific_input(my_input)
Expand Down
5 changes: 5 additions & 0 deletions src/ledger_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ pub trait LedgerClient<Datum, Redeemer>: Send + Sync {

async fn network(&self) -> LedgerClientResult<Network>;

/// Get the posix time of the most recent block
async fn last_block_time_secs(&self) -> LedgerClientResult<i64>;

/// Get the current time in seconds since the UNIX epoch.
async fn current_time_secs(&self) -> LedgerClientResult<i64>;
}
Expand Down Expand Up @@ -82,6 +85,8 @@ pub enum LedgerClientError {
CurrentTime(Box<dyn error::Error + Send + Sync>),
#[error("While setting validity range: {0:?}")]
ValidityRange(String),
#[error("While getting last block time: {0:?}")]
FailedToGetBlockTime(Box<dyn error::Error + Send + Sync>),
}

pub type LedgerClientResult<T> = Result<T, LedgerClientError>;
16 changes: 10 additions & 6 deletions src/ledger_client/test_ledger_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ where
pub fn build_in_memory(
&self,
) -> Backend<Datum, Redeemer, TestLedgerClient<Datum, Redeemer, InMemoryStorage<Datum>>> {
let block_length = 1000;
let block_length = 20;
let ledger_client = TestLedgerClient::new_in_memory(
self.signer.clone(),
self.outputs.clone(),
Expand Down Expand Up @@ -213,7 +213,7 @@ where
{
pub fn new_local_persisted(dir: T, signer: &Address, starting_amount: u64) -> Self {
let signer_name = "Alice";
let block_length = 1000;
let block_length = 20;
let starting_time = 0;
let storage = LocalPersistedStorage::init(
dir,
Expand Down Expand Up @@ -247,11 +247,11 @@ where
Datum: Clone + Send + Sync + PartialEq,
Storage: TestLedgerStorage<Datum> + Send + Sync,
{
pub async fn current_time_millis(&self) -> LedgerClientResult<i64> {
pub async fn current_time_secs(&self) -> LedgerClientResult<i64> {
self.storage.current_time().await
}

pub async fn set_current_time_millis(&self, posix_time: i64) -> LedgerClientResult<()> {
pub async fn set_current_time_secs(&self, posix_time: i64) -> LedgerClientResult<()> {
self.storage.set_current_time(posix_time).await
}

Expand Down Expand Up @@ -298,7 +298,7 @@ where
async fn issue(&self, tx: UnbuiltTransaction<Datum, Redeemer>) -> LedgerClientResult<TxId> {
// Setup
let valid_range = tx.valid_range;
let current_time = self.current_time_millis().await?;
let current_time = self.current_time_secs().await?;
check_time_valid(valid_range, current_time)
.map_err(|e| LedgerClientError::FailedToIssueTx(Box::new(e)))?;

Expand Down Expand Up @@ -400,8 +400,12 @@ where
self.storage.network().await
}

async fn last_block_time_secs(&self) -> LedgerClientResult<i64> {
self.current_time_secs().await
}

async fn current_time_secs(&self) -> LedgerClientResult<i64> {
self.current_time_millis().await
self.current_time_secs().await
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ mod tests {
use super::*;
use tempfile::TempDir;

const BLOCK_LENGTH: i64 = 1000;
const BLOCK_LENGTH: i64 = 20;

#[tokio::test]
async fn outputs_at_address() {
Expand Down Expand Up @@ -366,7 +366,7 @@ mod tests {
);
let current_time = storage.current_time().await.unwrap();
assert_eq!(current_time, 0);
let new_time = 1000;
let new_time = 20;
storage.set_current_time(new_time).await.unwrap();
let current_time = storage.current_time().await.unwrap();
assert_eq!(current_time, new_time);
Expand Down
10 changes: 5 additions & 5 deletions src/ledger_client/test_ledger_client/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
const ALICE: &str = "addr_test1qrmezjhpelwzvz83wjl0e6mx766de7j3nksu2338s00yzx870xyxfa97xyz2zn5rknyntu5g0c66s7ktjnx0p6f0an6s3dyxwr";
const BOB: &str = "addr_test1qzvrhz9v6lwcr26a52y8mmk2nzq37lky68359keq3dgth4lkzpnnjv8vf98m20lhqdzl60mcftq7r2lc4xtcsv0w6xjstag0ua";

const BLOCK_LENGTH: i64 = 1000;
const BLOCK_LENGTH: i64 = 20;

#[tokio::test]
async fn outputs_at_address() {
Expand Down Expand Up @@ -102,7 +102,7 @@ async fn issuing_tx_advances_time_by_block_length() {
let outputs = vec![];
let record: TestLedgerClient<(), (), _> =
TestLedgerClient::new_in_memory(signer.clone(), outputs, BLOCK_LENGTH, 0);
let starting_time = record.current_time_millis().await.unwrap();
let starting_time = record.current_time_secs().await.unwrap();
let tx = UnbuiltTransaction {
script_version: TransactionVersion::V2,
script_inputs: vec![],
Expand All @@ -113,7 +113,7 @@ async fn issuing_tx_advances_time_by_block_length() {
};
record.issue(tx).await.unwrap();
let expected = starting_time + BLOCK_LENGTH;
let actual = record.current_time_millis().await.unwrap();
let actual = record.current_time_secs().await.unwrap();
assert_eq!(expected, actual);
}

Expand Down Expand Up @@ -155,7 +155,7 @@ async fn cannot_transfer_before_valid_range() {

let current_time = 5;
let valid_time = 10;
record.set_current_time_millis(current_time).await.unwrap();
record.set_current_time_secs(current_time).await.unwrap();

let mut values = Values::default();
values.add_one_value(&PolicyId::Lovelace, transfer_amount);
Expand Down Expand Up @@ -187,7 +187,7 @@ async fn cannot_transfer_after_valid_range() {

let current_time = 10_000;
let valid_time = 5;
record.set_current_time_millis(current_time).await.unwrap();
record.set_current_time_secs(current_time).await.unwrap();

let mut values = Values::default();
values.add_one_value(&PolicyId::Lovelace, transfer_amount);
Expand Down
2 changes: 1 addition & 1 deletion src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ pub enum TransactionVersion {
V2,
}

/// Range of times in milliseconds since the Unix epoch
/// Range of times in seconds since the Unix epoch
type Range = (Option<i64>, Option<i64>);

pub struct UnbuiltTransaction<Datum, Redeemer> {
Expand Down
19 changes: 17 additions & 2 deletions src/trireme_ledger_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ where
InnerClient::BlockFrost(_cml_client) => Err(LedgerClientError::CurrentTime(Box::new(
Error::Trireme("Not implemented for Blockfrost client".to_string()),
))),
InnerClient::Mocked(test_client) => test_client.current_time_millis().await,
InnerClient::Mocked(test_client) => test_client.current_time_secs().await,
InnerClient::OgmiosScrolls(_) => Err(LedgerClientError::CurrentTime(Box::new(
Error::Trireme("Not implemented for Ogmios/Scrolls client".to_string()),
))),
Expand Down Expand Up @@ -543,10 +543,25 @@ where
.await
}

async fn last_block_time_secs(&self) -> LedgerClientResult<i64> {
match &self.inner_client {
InnerClient::BlockFrost(cml_client) => cml_client.last_block_time_secs(),
InnerClient::Mocked(test_client) => test_client.last_block_time_secs(),
InnerClient::OgmiosScrolls(cml_client) => cml_client.last_block_time_secs(),
}
.await
}

async fn current_time_secs(&self) -> LedgerClientResult<i64> {
match &self.inner_client {
InnerClient::BlockFrost(cml_client) => cml_client.current_time_secs(),
InnerClient::Mocked(test_client) => test_client.current_time_secs(),
InnerClient::Mocked(test_client) => <TestLedgerClient<
Datum,
Redeemer,
LocalPersistedStorage<PathBuf, Datum>,
> as LedgerClient<Datum, Redeemer>>::current_time_secs(
test_client
),
InnerClient::OgmiosScrolls(cml_client) => cml_client.current_time_secs(),
}
.await
Expand Down
8 changes: 8 additions & 0 deletions src/trireme_ledger_client/cml_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ impl ExecutionCost {

#[async_trait]
pub trait Ledger {
async fn last_block_time_secs(&self) -> Result<i64>;
async fn get_utxos_for_addr(&self, addr: &CMLAddress, count: usize) -> Result<Vec<UTxO>>;
async fn get_all_utxos_for_addr(&self, addr: &CMLAddress) -> Result<Vec<UTxO>>;
async fn calculate_ex_units(&self, tx: &CMLTransaction) -> Result<HashMap<u64, ExecutionCost>>;
Expand Down Expand Up @@ -687,6 +688,13 @@ where
Ok(network)
}

async fn last_block_time_secs(&self) -> LedgerClientResult<i64> {
self.ledger
.last_block_time_secs()
.await
.map_err(as_failed_to_get_block_time)
}

async fn current_time_secs(&self) -> LedgerClientResult<i64> {
let now = std::time::SystemTime::now()
.duration_since(UNIX_EPOCH)
Expand Down
9 changes: 9 additions & 0 deletions src/trireme_ledger_client/cml_client/blockfrost_ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ pub fn cmlvalue_from_bfvalues(values: &[BFValue]) -> Result<CMLValue> {

#[async_trait]
impl Ledger for BlockFrostLedger {
async fn last_block_time_secs(&self) -> Result<i64> {
let res = self
.client
.latest_block_info()
.await
.map_err(|e| CMLLCError::LedgerError(Box::new(e)))?;
Ok(res.time() as i64)
}

async fn get_utxos_for_addr(&self, addr: &CMLAddress, count: usize) -> Result<Vec<UTxO>> {
let addr_string = addr
.to_bech32(None)
Expand Down
6 changes: 6 additions & 0 deletions src/trireme_ledger_client/cml_client/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,10 @@ pub fn as_failed_to_issue_tx<E: std::error::Error + Send + Sync + 'static>(
LedgerClientError::FailedToIssueTx(Box::new(error))
}

pub fn as_failed_to_get_block_time<E: std::error::Error + Send + Sync + 'static>(
error: E,
) -> LedgerClientError {
LedgerClientError::FailedToGetBlockTime(Box::new(error))
}

pub type Result<E, T = CMLLCError> = std::result::Result<E, T>;
4 changes: 4 additions & 0 deletions src/trireme_ledger_client/cml_client/ogmios_scrolls_ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ impl OgmiosScrollsLedger {

#[async_trait]
impl Ledger for OgmiosScrollsLedger {
async fn last_block_time_secs(&self) -> Result<i64> {
todo!()
}

async fn get_utxos_for_addr(&self, addr: &CMLAddress, count: usize) -> Result<Vec<UTxO>> {
let outputs = self
.get_utxos(addr)
Expand Down
11 changes: 9 additions & 2 deletions trireme/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@ fn get_password_with_prompt(prompt: &str) -> Result<String> {

async fn setup_local_mocked_env(name: &str) -> Result<()> {
let block_length: i64 = Input::new()
.with_prompt("What is the block length in ms?")
.default(1000)
.with_prompt("What is the block length in secs?")
.default(20)
.interact_text()?;

let alice_name = "Alice";
Expand Down Expand Up @@ -407,6 +407,13 @@ pub async fn current_time_impl() -> Result<()> {
Ok(())
}

pub async fn last_block_time_impl() -> Result<()> {
let ledger_client: TriremeLedgerClient<(), ()> = get_trireme_ledger_client_from_file().await?;
let last_block_time = ledger_client.last_block_time_secs().await?;
println!("Last block time: {}", last_block_time);
Ok(())
}

pub async fn advance_blocks(count: i64) -> Result<()> {
let ledger_client: TriremeLedgerClient<(), ()> = get_trireme_ledger_client_from_file().await?;
ledger_client.advance_blocks(count).await?;
Expand Down
9 changes: 6 additions & 3 deletions trireme/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::environment::{
active_signer_impl, advance_blocks, current_time_impl, get_address_impl, get_pubkey_hash_impl,
switch_signer_impl,
last_block_time_impl, switch_signer_impl,
};
use crate::{
balance::{ada_balance_impl, balance_impl},
Expand Down Expand Up @@ -45,7 +45,9 @@ enum ActionParams {
/// Switch to different signer 👽 (Mock Network Only)
SwitchSigner,
/// Get get time relative to your local environment 🕰
CurrentTime,
Time,
/// Get the time of the last block in seconds
LastBlockTime,
/// Advance time and block height by count 🧱
AdvanceBlocks { count: u16 },
}
Expand All @@ -72,7 +74,8 @@ async fn main() -> Result<()> {
ActionParams::PubKeyHash => get_pubkey_hash_impl().await?,
ActionParams::Signer => active_signer_impl().await?,
ActionParams::SwitchSigner => switch_signer_impl().await?,
ActionParams::CurrentTime => current_time_impl().await?,
ActionParams::Time => current_time_impl().await?,
ActionParams::LastBlockTime => last_block_time_impl().await?,
ActionParams::AdvanceBlocks { count } => advance_blocks(count as i64).await?,
}
Ok(())
Expand Down

0 comments on commit 620f924

Please sign in to comment.