use anyhow::{anyhow as err, Error, Result};
use async_trait::async_trait;
#[allow(unused_imports)]
use chrono::{DateTime, Utc};
use super::Address;
use dydx_proto::cosmos_sdk_proto::{
cosmos::auth::v1beta1::{
query_client::QueryClient as QueryGrpcClient, BaseAccount, QueryAccountRequest,
},
traits::Message,
};
use std::collections::HashMap;
use tonic::{transport::Channel, Request};
use tower::timeout::Timeout;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Nonce {
Sequence(u64),
Timestamp(u64),
}
impl Nonce {
pub fn now() -> Self {
Self::Timestamp(Utc::now().timestamp_millis() as u64)
}
}
#[async_trait]
pub trait Sequencer: Send + 'static {
async fn next_nonce(&mut self, address: &Address) -> Result<Nonce, Error>;
}
#[derive(Clone, Debug)]
pub struct IncrementalSequencer {
counters: HashMap<Address, u64>,
}
impl IncrementalSequencer {
pub fn new(addresses: &[(Address, u64)]) -> Self {
Self {
counters: addresses.iter().cloned().collect(),
}
}
pub fn add_address(&mut self, address: Address, start_at: u64) -> Option<u64> {
self.counters.insert(address, start_at)
}
}
#[async_trait]
impl Sequencer for IncrementalSequencer {
async fn next_nonce(&mut self, address: &Address) -> Result<Nonce, Error> {
let counter = self
.counters
.get_mut(address)
.ok_or_else(|| err!("Address {address} not found in sequencer"))?;
*counter += 1;
Ok(Nonce::Sequence(*counter - 1))
}
}
#[derive(Clone, Debug)]
pub struct QueryingSequencer {
querier: QueryGrpcClient<Timeout<Channel>>,
}
impl QueryingSequencer {
pub fn new(channel: Timeout<Channel>) -> Self {
Self {
querier: QueryGrpcClient::new(channel),
}
}
}
#[async_trait]
impl Sequencer for QueryingSequencer {
async fn next_nonce(&mut self, address: &Address) -> Result<Nonce, Error> {
let response = self
.querier
.account(Request::new(QueryAccountRequest {
address: address.to_string(),
}))
.await?
.into_inner();
let sequence = BaseAccount::decode(
&response
.account
.ok_or_else(|| err!("Query account request failure, account should exist."))?
.value[..],
)
.map(|res| res.sequence)
.map_err(|e| err!("Query account request decode failure: {e}"))?;
Ok(Nonce::Sequence(sequence))
}
}
#[derive(Clone, Debug)]
pub struct TimestamperSequencer;
#[async_trait]
impl Sequencer for TimestamperSequencer {
async fn next_nonce(&mut self, _: &Address) -> Result<Nonce, Error> {
Ok(Nonce::now())
}
}