forked from FuelLabs/sway
-
Notifications
You must be signed in to change notification settings - Fork 0
/
block.sw
155 lines (142 loc) · 4.06 KB
/
block.sw
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Functionality for accessing block-related data.
library;
use ::assert::assert;
use ::constants::ZERO_B256;
use ::result::Result::{self, *};
use ::logging::log;
/// Error type for when the block hash cannot be found.
enum BlockHashError {
/// Error returned when the block hash cannot be found.
BlockHeightTooHigh: (),
}
/// Get the current block height.
///
/// # Returns
///
/// * [u32] - The current block height.
///
/// # Examples
///
/// ```sway
/// use std::block::height;
///
/// fn foo() {
/// let current_height = height();
/// log(current_height);
/// }
/// ```
pub fn height() -> u32 {
asm(height) {
bhei height;
height: u32
}
}
/// Get the TAI64 timestamp of the current block.
///
/// # Additional Information
///
/// The TAI64 timestamp begins at 2^62 seconds before 1970, and ends at 2^62 seconds after 1970,
/// with a TAI second defined as the duration of 9192631770 periods of the radiation corresponding
/// to the transition between the two hyperfine levels of the ground state of the cesium atom.
///
/// # Returns
///
/// * [u64] - The TAI64 timestamp of the current block.
///
/// # Examples
///
/// ```sway
/// use std::block::timestamp;
///
/// fn foo() {
/// let current_timestamp = timestamp();
/// log(current_timestamp);
/// }
/// ```
pub fn timestamp() -> u64 {
timestamp_of_block(height())
}
/// Get the TAI64 timestamp of a block at a given `block_height`.
///
/// # Additional Information
///
/// The TAI64 timestamp begins at 2^62 seconds before 1970, and ends at 2^62 seconds after 1970,
/// with a TAI second defined as the duration of 9192631770 periods of the radiation corresponding
/// to the transition between the two hyperfine levels of the ground state of the cesium atom.
///
/// # Arguments
///
/// * `block_height`: [u32] - The height of the block to get the timestamp of.
///
/// # Returns
///
/// * [u64] - The TAI64 timestamp of the block at `block_height`.
///
/// # Examples
///
/// ```sway
/// use std::block::timestamp_of_block;
///
/// fn foo() {
/// let timestamp_of_block_100 = timestamp_of_block(100u32);
/// log(timestamp_of_block_100);
/// }
/// ```
pub fn timestamp_of_block(block_height: u32) -> u64 {
asm(timestamp, height: block_height) {
time timestamp height;
timestamp: u64
}
}
/// Get the header hash of the block at height `block_height`
///
/// # Returns
///
/// * [Result<b256, BlockHashError>] - The header hash of the block at `block_height`, or a [BlockHashError] if the block is not found.
///
/// # Examples
///
/// ```sway
/// use std::block::block_header_hash;
///
/// fn foo() {
/// let header_hash_of_block_100 = block_header_hash(100u32);
/// log(header_hash_of_block_100);
/// }
/// ```
pub fn block_header_hash(block_height: u32) -> Result<b256, BlockHashError> {
let mut header_hash = ZERO_B256;
asm(r1: __addr_of(header_hash), r2: block_height) {
bhsh r1 r2;
};
// `bhsh` returns b256(0) if the block is not found, so catch this and return an error
if header_hash == ZERO_B256 {
Err(BlockHashError::BlockHeightTooHigh)
} else {
Ok(header_hash)
}
}
////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////
#[test(should_revert)]
fn test_block_header_hash_err_current_height() {
// Get the header hash of the current block. Each time this test runs, the block height will be 1. calling BHSH with a height >= current height will fail.
let mut hash = block_header_hash(height());
let correct_error = match hash {
Ok(_) => false,
Err(BlockHashError::BlockHeightTooHigh) => true,
};
assert(correct_error);
}
#[test(should_revert)]
fn test_block_header_hash_err_future_height() {
// Try to get header hash of a block in the future
// The function should return a BlockHashError
let hash = block_header_hash(height() + 1u32);
let correct_error = match hash {
Ok(_) => false,
Err(BlockHashError::BlockHeightTooHigh) => true,
};
assert(correct_error);
}