1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::client::tendermint_types::{BlockResult, ValidatorSetResult};
use crate::errors::TerraRustAPIError::TendermintValidatorSet;
use crate::{LCDResult, Terra};

pub struct Tendermint<'a> {
    terra: &'a Terra,
}
impl Tendermint<'_> {
    pub fn create(terra: &'_ Terra) -> Tendermint<'_> {
        Tendermint { terra }
    }
    /// get the latest block
    pub async fn blocks(&self) -> anyhow::Result<BlockResult> {
        let response = self
            .terra
            .send_cmd::<BlockResult>("/blocks/latest", None)
            .await?;
        Ok(response)
    }
    /// get a block at a specific height
    pub async fn blocks_at_height(&self, height: u64) -> anyhow::Result<BlockResult> {
        let response = self
            .terra
            .send_cmd::<BlockResult>(&format!("/blocks/{}", height), None)
            .await?;
        Ok(response)
    }

    /// get the latest validatorset
    /// @warn the maximum limit (at time of development is 100)
    pub async fn validatorsets(
        &self,
        page: usize,
        limit: usize,
    ) -> anyhow::Result<LCDResult<ValidatorSetResult>> {
        let args = if page == 0 {
            format!("?limit={}", limit)
        } else {
            format!("?page={}&limit={}", page, limit)
        };
        let response = self
            .terra
            .send_cmd::<LCDResult<ValidatorSetResult>>("/validatorsets/latest", Some(&args))
            .await?;
        Ok(response)
    }
    /// get the latest full validatorset
    ///
    pub async fn validatorsets_full(&self) -> anyhow::Result<LCDResult<ValidatorSetResult>> {
        // the interesting thing here is that the height returned is not available for the 2nd one.. so need to fire them off at the same time.
        let part_1_f = self.validatorsets(1, 100);
        let part_2 = self.validatorsets(2, 100).await?;
        let part_1 = part_1_f.await?;
        if part_1.result.block_height != part_2.result.block_height {
            return Err(TendermintValidatorSet(
                part_1.result.block_height,
                part_2.result.block_height,
            )
            .into());
        }
        let mut combined = part_1.result.validators;
        combined.extend(part_2.result.validators);
        let vs_combined = ValidatorSetResult {
            block_height: part_1.result.block_height,
            validators: combined,
        };
        Ok(LCDResult {
            height: part_1.height,
            result: vs_combined,
        })
    }
    /// get the full validatorset at a certain height
    ///
    pub async fn validatorsets_full_at_height(
        &self,
        height: u64,
    ) -> anyhow::Result<LCDResult<ValidatorSetResult>> {
        let part_1 = self.validatorsets_at_height(height, 1, 100).await?;
        let part_2 = self.validatorsets_at_height(height, 2, 100).await?;
        if part_1.result.block_height != part_2.result.block_height {
            return Err(TendermintValidatorSet(
                part_1.result.block_height,
                part_2.result.block_height,
            )
            .into());
        }
        let mut combined = part_1.result.validators;
        combined.extend(part_2.result.validators);
        let vs_combined = ValidatorSetResult {
            block_height: part_1.result.block_height,
            validators: combined,
        };
        Ok(LCDResult {
            height: part_1.height,
            result: vs_combined,
        })
    }

    /// get a validatorset at a specific height
    /// @warn the maximum limit (at time of development is 100)
    pub async fn validatorsets_at_height(
        &self,
        height: u64,
        page: usize,
        limit: usize,
    ) -> anyhow::Result<LCDResult<ValidatorSetResult>> {
        let args = if page == 0 {
            format!("?limit={}", limit)
        } else {
            format!("?page={}&limit={}", page, limit)
        };
        let response = self
            .terra
            .send_cmd::<LCDResult<ValidatorSetResult>>(
                &format!("/validatorsets/{}", height),
                Some(&args),
            )
            .await?;
        Ok(response)
    }
}