Skip to content

Arbitrary Data#

Trident allows you to customize Instruction Data to provide structure.

For example your Initialize Instruction expects two arguments start_at and end_at you know that in order for the Instruction to make sense, it is required that the start_at < end_at. Moreover, there should be significant difference between these two. This can be utilized with the Arbitrary crate.

#[derive(Arbitrary, Debug)]
pub struct InitVestingData {
    pub recipient: AccountId,
    #[arbitrary(
        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1_000_000)
    )]
    pub amount: u64,
    // we want start_at smaller than end_at
    // and for testing purposes we can run tests with times from the past
    #[arbitrary(
        with = |u: &mut arbitrary::Unstructured| u.int_in_range(0..=1_000_000)
    )]
    pub start_at: u64,
    #[arbitrary(
        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1_001_001..=1_050_000)
    )]
    pub end_at: u64,
    #[arbitrary(
        with = |u: &mut arbitrary::Unstructured| u.int_in_range(1..=1000)
    )]
    pub interval: u64,
}

Implement Arbitrary#

There are macros available to use with Arbitrary, however, it is possible to Implement the arbitrary function by yourself.

// -------------------------------------------------------------------
// -------------------------------------------------------------------
// Implement Arbitrary
impl<'a> Arbitrary<'a> for InitVestingData {
    fn arbitrary(
        u: &mut arbitrary::Unstructured<'a>
    ) -> arbitrary::Result<Self> {
        // obtain AccountId
        let recipient = AccountId::arbitrary(u)?;

        // limit the generated amount to the 1_000_000
        let amount = u.int_in_range(1..=1_000_000)?;

        // now we want to obtain
        // - start_at
        // - end_at
        // - interval
        // however we want to limit the data such that:
        // - start_at < end_at
        // - end_at - start_at > interval
        // - interval has lower limit of 500 and upper limit of 1000.

        let start_at: u64 = u.int_in_range(1_000_000..=5_000_000)?;
        let end_at: u64 = u.int_in_range(1_000_000..=5_000_000)?;
        let interval: u64 = u.int_in_range(500..=1000)?;

        // ensure that start_at < end_at
        if start_at >= end_at {
            return Err(arbitrary::Error::IncorrectFormat);
        }

        // ensure that end_at - start_at > interval
        match end_at.checked_sub(start_at) {
            Some(diff) => {
                if diff <= interval {
                    return Err(arbitrary::Error::IncorrectFormat);
                }
            }
            None => return Err(arbitrary::Error::IncorrectFormat),
        }

        Ok(InitVestingData {
            recipient,
            amount,
            start_at,
            end_at,
            interval,
        })
    }
    // -------------------------------------------------------------------
    // -------------------------------------------------------------------
}

Tip

Consider checking the Examples section for more tips.