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
122
123
124
125
126
127
128
129
130
131
132
pub struct Offset {
    pub start: usize,
    pub length: usize,
}

pub struct Field {
    pub trit_offset: Offset,
    pub tryte_offset: Offset,
}

impl Field {
    pub fn byte_start(&self) -> usize {
        self.trit_offset.start / 5
    }

    pub fn byte_length(&self) -> usize {
        if self.trit_offset.length % 5 == 0 {
            self.trit_offset.length / 5
        } else {
            self.trit_offset.length / 5 + 1
        }
    }
}

macro_rules! offsets_from_trits {
    ($start:expr, $length:expr) => {
        Field {
            trit_offset: Offset {
                start: $start,
                length: $length,
            },
            tryte_offset: Offset {
                start: $start / 3,
                length: $length / 3,
            },
        }
    };
}

macro_rules! offsets_from_previous_field {
    ($prev:expr, $length:expr) => {
        Field {
            trit_offset: Offset {
                start: ($prev).trit_offset.start + ($prev).trit_offset.length,
                length: $length,
            },
            tryte_offset: Offset {
                start: (($prev).trit_offset.start + ($prev).trit_offset.length) / 3,
                length: $length / 3,
            },
        }
    };
}

pub const IOTA_SUPPLY: i64 = 2779530283277761;

pub const TRANSACTION_TRIT_LEN: usize = 8019;
pub const TRANSACTION_TRYT_LEN: usize = TRANSACTION_TRIT_LEN / 3; //2673
pub const TRANSACTION_BYTE_LEN: usize = TRANSACTION_TRIT_LEN / 5 + 1; //1604

pub const PAYLOAD_TRIT_LEN: usize = 6561;
pub const ADDRESS_TRIT_LEN: usize = 243;
pub const VALUE_TRIT_LEN: usize = 81;
pub const TAG_TRIT_LEN: usize = 81;
pub const TIMESTAMP_TRIT_LEN: usize = 27;
pub const INDEX_TRIT_LEN: usize = 27;
pub const HASH_TRIT_LEN: usize = 243;
pub const NONCE_TRIT_LEN: usize = 81;

pub(crate) const PAYLOAD: Field = offsets_from_trits!(0, PAYLOAD_TRIT_LEN);
pub(crate) const ADDRESS: Field = offsets_from_previous_field!(PAYLOAD, ADDRESS_TRIT_LEN);
pub(crate) const VALUE: Field = offsets_from_previous_field!(ADDRESS, VALUE_TRIT_LEN);
pub(crate) const OBSOLETE_TAG: Field = offsets_from_previous_field!(VALUE, TAG_TRIT_LEN);
pub(crate) const TIMESTAMP: Field = offsets_from_previous_field!(OBSOLETE_TAG, TIMESTAMP_TRIT_LEN);
pub(crate) const INDEX: Field = offsets_from_previous_field!(TIMESTAMP, INDEX_TRIT_LEN);
pub(crate) const LAST_INDEX: Field = offsets_from_previous_field!(INDEX, INDEX_TRIT_LEN);
pub(crate) const BUNDLE: Field = offsets_from_previous_field!(LAST_INDEX, HASH_TRIT_LEN);
pub(crate) const TRUNK: Field = offsets_from_previous_field!(BUNDLE, HASH_TRIT_LEN);
pub(crate) const BRANCH: Field = offsets_from_previous_field!(TRUNK, HASH_TRIT_LEN);
pub(crate) const TAG: Field = offsets_from_previous_field!(BRANCH, TAG_TRIT_LEN);
pub(crate) const ATTACHMENT_TS: Field = offsets_from_previous_field!(TAG, TIMESTAMP_TRIT_LEN);
pub(crate) const ATTACHMENT_LBTS: Field = offsets_from_previous_field!(ATTACHMENT_TS, TIMESTAMP_TRIT_LEN);
pub(crate) const ATTACHMENT_UBTS: Field = offsets_from_previous_field!(ATTACHMENT_LBTS, TIMESTAMP_TRIT_LEN);
pub(crate) const NONCE: Field = offsets_from_previous_field!(ATTACHMENT_UBTS, NONCE_TRIT_LEN);

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn add_up_to_transaction_trit_length() {
        let total_trit_length = PAYLOAD.trit_offset.length
            + ADDRESS.trit_offset.length
            + VALUE.trit_offset.length
            + OBSOLETE_TAG.trit_offset.length
            + TIMESTAMP.trit_offset.length
            + INDEX.trit_offset.length
            + LAST_INDEX.trit_offset.length
            + BUNDLE.trit_offset.length
            + TRUNK.trit_offset.length
            + BRANCH.trit_offset.length
            + TAG.trit_offset.length
            + ATTACHMENT_TS.trit_offset.length
            + ATTACHMENT_LBTS.trit_offset.length
            + ATTACHMENT_UBTS.trit_offset.length
            + NONCE.trit_offset.length;

        assert_eq!(total_trit_length, TRANSACTION_TRIT_LEN);
    }

    #[test]
    fn add_up_to_transaction_tryte_length() {
        let total_tryte_length = PAYLOAD.tryte_offset.length
            + ADDRESS.tryte_offset.length
            + VALUE.tryte_offset.length
            + OBSOLETE_TAG.tryte_offset.length
            + TIMESTAMP.tryte_offset.length
            + INDEX.tryte_offset.length
            + LAST_INDEX.tryte_offset.length
            + BUNDLE.tryte_offset.length
            + TRUNK.tryte_offset.length
            + BRANCH.tryte_offset.length
            + TAG.tryte_offset.length
            + ATTACHMENT_TS.tryte_offset.length
            + ATTACHMENT_LBTS.tryte_offset.length
            + ATTACHMENT_UBTS.tryte_offset.length
            + NONCE.tryte_offset.length;

        assert_eq!(total_tryte_length, TRANSACTION_TRYT_LEN);
    }
}