scid_utils: add utils for retrieving txindex and vout
[rust-lightning] / lightning / src / util / scid_utils.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 /// Maximum block height that can be used in a `short_channel_id`. This
11 /// value is based on the 3-bytes available for block height.
12 pub const MAX_SCID_BLOCK: u64 = 0x00ffffff;
13
14 /// Maximum transaction index that can be used in a `short_channel_id`.
15 /// This value is based on the 3-bytes available for tx index.
16 pub const MAX_SCID_TX_INDEX: u64 = 0x00ffffff;
17
18 /// Maximum vout index that can be used in a `short_channel_id`. This
19 /// value is based on the 2-bytes available for the vout index.
20 pub const MAX_SCID_VOUT_INDEX: u64 = 0xffff;
21
22 /// A `short_channel_id` construction error
23 #[derive(Debug, PartialEq)]
24 pub enum ShortChannelIdError {
25         BlockOverflow,
26         TxIndexOverflow,
27         VoutIndexOverflow,
28 }
29
30 /// Extracts the block height (most significant 3-bytes) from the `short_channel_id`
31 pub fn block_from_scid(short_channel_id: &u64) -> u32 {
32         return (short_channel_id >> 40) as u32;
33 }
34
35 /// Extracts the tx index (bytes [2..4]) from the `short_channel_id`
36 pub fn tx_index_from_scid(short_channel_id: &u64) -> u32 {
37         return ((short_channel_id >> 16) & MAX_SCID_TX_INDEX) as u32;
38 }
39
40 /// Extracts the vout (bytes [0..2]) from the `short_channel_id`
41 pub fn vout_from_scid(short_channel_id: &u64) -> u16 {
42         return ((short_channel_id) & MAX_SCID_VOUT_INDEX) as u16;
43 }
44
45 /// Constructs a `short_channel_id` using the components pieces. Results in an error
46 /// if the block height, tx index, or vout index overflow the maximum sizes.
47 pub fn scid_from_parts(block: u64, tx_index: u64, vout_index: u64) -> Result<u64, ShortChannelIdError> {
48         if block > MAX_SCID_BLOCK {
49                 return Err(ShortChannelIdError::BlockOverflow);
50         }
51
52         if tx_index > MAX_SCID_TX_INDEX {
53                 return Err(ShortChannelIdError::TxIndexOverflow);
54         }
55
56         if vout_index > MAX_SCID_VOUT_INDEX {
57                 return Err(ShortChannelIdError::VoutIndexOverflow);
58         }
59
60         Ok((block << 40) | (tx_index << 16) | vout_index)
61 }
62
63 #[cfg(test)]
64 mod tests {
65         use super::*;
66
67         #[test]
68         fn test_block_from_scid() {
69                 assert_eq!(block_from_scid(&0x000000_000000_0000), 0);
70                 assert_eq!(block_from_scid(&0x000001_000000_0000), 1);
71                 assert_eq!(block_from_scid(&0x000001_ffffff_ffff), 1);
72                 assert_eq!(block_from_scid(&0x800000_ffffff_ffff), 0x800000);
73                 assert_eq!(block_from_scid(&0xffffff_ffffff_ffff), 0xffffff);
74         }
75
76         #[test]
77         fn test_tx_index_from_scid() {
78                 assert_eq!(tx_index_from_scid(&0x000000_000000_0000), 0);
79                 assert_eq!(tx_index_from_scid(&0x000000_000001_0000), 1);
80                 assert_eq!(tx_index_from_scid(&0xffffff_000001_ffff), 1);
81                 assert_eq!(tx_index_from_scid(&0xffffff_800000_ffff), 0x800000);
82                 assert_eq!(tx_index_from_scid(&0xffffff_ffffff_ffff), 0xffffff);
83         }
84
85         #[test]
86         fn test_vout_from_scid() {
87                 assert_eq!(vout_from_scid(&0x000000_000000_0000), 0);
88                 assert_eq!(vout_from_scid(&0x000000_000000_0001), 1);
89                 assert_eq!(vout_from_scid(&0xffffff_ffffff_0001), 1);
90                 assert_eq!(vout_from_scid(&0xffffff_ffffff_8000), 0x8000);
91                 assert_eq!(vout_from_scid(&0xffffff_ffffff_ffff), 0xffff);
92         }
93
94         #[test]
95         fn test_scid_from_parts() {
96                 assert_eq!(scid_from_parts(0x00000000, 0x00000000, 0x0000).unwrap(), 0x000000_000000_0000);
97                 assert_eq!(scid_from_parts(0x00000001, 0x00000002, 0x0003).unwrap(), 0x000001_000002_0003);
98                 assert_eq!(scid_from_parts(0x00111111, 0x00222222, 0x3333).unwrap(), 0x111111_222222_3333);
99                 assert_eq!(scid_from_parts(0x00ffffff, 0x00ffffff, 0xffff).unwrap(), 0xffffff_ffffff_ffff);
100                 assert_eq!(scid_from_parts(0x01ffffff, 0x00000000, 0x0000).err().unwrap(), ShortChannelIdError::BlockOverflow);
101                 assert_eq!(scid_from_parts(0x00000000, 0x01ffffff, 0x0000).err().unwrap(), ShortChannelIdError::TxIndexOverflow);
102                 assert_eq!(scid_from_parts(0x00000000, 0x00000000, 0x010000).err().unwrap(), ShortChannelIdError::VoutIndexOverflow);
103         }
104 }