Checkpoints.sol 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.8.0) (utils/Checkpoints.sol)
  3. // This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
  4. pragma solidity ^0.8.0;
  5. import "./math/Math.sol";
  6. import "./math/SafeCast.sol";
  7. /**
  8. * @dev This library defines the `History` struct, for checkpointing values as they change at different points in
  9. * time, and later looking up past values by block number. See {Votes} as an example.
  10. *
  11. * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new
  12. * checkpoint for the current transaction block using the {push} function.
  13. *
  14. * _Available since v4.5._
  15. */
  16. library Checkpoints {
  17. struct History {
  18. Checkpoint[] _checkpoints;
  19. }
  20. struct Checkpoint {
  21. uint32 _blockNumber;
  22. uint224 _value;
  23. }
  24. /**
  25. * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
  26. * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the
  27. * block, the requested block number must be in the past, excluding the current block.
  28. */
  29. function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
  30. require(blockNumber < block.number, "Checkpoints: block not yet mined");
  31. uint32 key = SafeCast.toUint32(blockNumber);
  32. uint256 len = self._checkpoints.length;
  33. uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
  34. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  35. }
  36. /**
  37. * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
  38. * before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched
  39. * checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of
  40. * checkpoints.
  41. */
  42. function getAtProbablyRecentBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
  43. require(blockNumber < block.number, "Checkpoints: block not yet mined");
  44. uint32 key = SafeCast.toUint32(blockNumber);
  45. uint256 len = self._checkpoints.length;
  46. uint256 low = 0;
  47. uint256 high = len;
  48. if (len > 5) {
  49. uint256 mid = len - Math.sqrt(len);
  50. if (key < _unsafeAccess(self._checkpoints, mid)._blockNumber) {
  51. high = mid;
  52. } else {
  53. low = mid + 1;
  54. }
  55. }
  56. uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
  57. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  58. }
  59. /**
  60. * @dev Returns checkpoint at given position.
  61. */
  62. function getAtPosition(History storage self, uint32 pos) internal view returns (Checkpoint memory) {
  63. return self._checkpoints[pos];
  64. }
  65. /**
  66. * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.
  67. *
  68. * Returns previous value and new value.
  69. */
  70. function push(History storage self, uint256 value) internal returns (uint256, uint256) {
  71. return _insert(self._checkpoints, SafeCast.toUint32(block.number), SafeCast.toUint224(value));
  72. }
  73. /**
  74. * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will
  75. * be set to `op(latest, delta)`.
  76. *
  77. * Returns previous value and new value.
  78. */
  79. function push(
  80. History storage self,
  81. function(uint256, uint256) view returns (uint256) op,
  82. uint256 delta
  83. ) internal returns (uint256, uint256) {
  84. return push(self, op(latest(self), delta));
  85. }
  86. /**
  87. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  88. */
  89. function latest(History storage self) internal view returns (uint224) {
  90. uint256 pos = self._checkpoints.length;
  91. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  92. }
  93. /**
  94. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  95. * in the most recent checkpoint.
  96. */
  97. function latestCheckpoint(
  98. History storage self
  99. ) internal view returns (bool exists, uint32 _blockNumber, uint224 _value) {
  100. uint256 pos = self._checkpoints.length;
  101. if (pos == 0) {
  102. return (false, 0, 0);
  103. } else {
  104. Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  105. return (true, ckpt._blockNumber, ckpt._value);
  106. }
  107. }
  108. /**
  109. * @dev Returns the number of checkpoint.
  110. */
  111. function length(History storage self) internal view returns (uint256) {
  112. return self._checkpoints.length;
  113. }
  114. /**
  115. * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
  116. * or by updating the last one.
  117. */
  118. function _insert(Checkpoint[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
  119. uint256 pos = self.length;
  120. if (pos > 0) {
  121. // Copying to memory is important here.
  122. Checkpoint memory last = _unsafeAccess(self, pos - 1);
  123. // Checkpoint keys must be non-decreasing.
  124. require(last._blockNumber <= key, "Checkpoint: decreasing keys");
  125. // Update or push new checkpoint
  126. if (last._blockNumber == key) {
  127. _unsafeAccess(self, pos - 1)._value = value;
  128. } else {
  129. self.push(Checkpoint({_blockNumber: key, _value: value}));
  130. }
  131. return (last._value, value);
  132. } else {
  133. self.push(Checkpoint({_blockNumber: key, _value: value}));
  134. return (0, value);
  135. }
  136. }
  137. /**
  138. * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
  139. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  140. *
  141. * WARNING: `high` should not be greater than the array's length.
  142. */
  143. function _upperBinaryLookup(
  144. Checkpoint[] storage self,
  145. uint32 key,
  146. uint256 low,
  147. uint256 high
  148. ) private view returns (uint256) {
  149. while (low < high) {
  150. uint256 mid = Math.average(low, high);
  151. if (_unsafeAccess(self, mid)._blockNumber > key) {
  152. high = mid;
  153. } else {
  154. low = mid + 1;
  155. }
  156. }
  157. return high;
  158. }
  159. /**
  160. * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
  161. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  162. *
  163. * WARNING: `high` should not be greater than the array's length.
  164. */
  165. function _lowerBinaryLookup(
  166. Checkpoint[] storage self,
  167. uint32 key,
  168. uint256 low,
  169. uint256 high
  170. ) private view returns (uint256) {
  171. while (low < high) {
  172. uint256 mid = Math.average(low, high);
  173. if (_unsafeAccess(self, mid)._blockNumber < key) {
  174. low = mid + 1;
  175. } else {
  176. high = mid;
  177. }
  178. }
  179. return high;
  180. }
  181. /**
  182. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  183. */
  184. function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) {
  185. assembly {
  186. mstore(0, self.slot)
  187. result.slot := add(keccak256(0, 0x20), pos)
  188. }
  189. }
  190. struct Trace224 {
  191. Checkpoint224[] _checkpoints;
  192. }
  193. struct Checkpoint224 {
  194. uint32 _key;
  195. uint224 _value;
  196. }
  197. /**
  198. * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
  199. *
  200. * Returns previous value and new value.
  201. */
  202. function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) {
  203. return _insert(self._checkpoints, key, value);
  204. }
  205. /**
  206. * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
  207. */
  208. function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
  209. uint256 len = self._checkpoints.length;
  210. uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
  211. return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
  212. }
  213. /**
  214. * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key.
  215. */
  216. function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
  217. uint256 len = self._checkpoints.length;
  218. uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
  219. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  220. }
  221. /**
  222. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  223. */
  224. function latest(Trace224 storage self) internal view returns (uint224) {
  225. uint256 pos = self._checkpoints.length;
  226. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  227. }
  228. /**
  229. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  230. * in the most recent checkpoint.
  231. */
  232. function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
  233. uint256 pos = self._checkpoints.length;
  234. if (pos == 0) {
  235. return (false, 0, 0);
  236. } else {
  237. Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  238. return (true, ckpt._key, ckpt._value);
  239. }
  240. }
  241. /**
  242. * @dev Returns the number of checkpoint.
  243. */
  244. function length(Trace224 storage self) internal view returns (uint256) {
  245. return self._checkpoints.length;
  246. }
  247. /**
  248. * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
  249. * or by updating the last one.
  250. */
  251. function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
  252. uint256 pos = self.length;
  253. if (pos > 0) {
  254. // Copying to memory is important here.
  255. Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
  256. // Checkpoint keys must be non-decreasing.
  257. require(last._key <= key, "Checkpoint: decreasing keys");
  258. // Update or push new checkpoint
  259. if (last._key == key) {
  260. _unsafeAccess(self, pos - 1)._value = value;
  261. } else {
  262. self.push(Checkpoint224({_key: key, _value: value}));
  263. }
  264. return (last._value, value);
  265. } else {
  266. self.push(Checkpoint224({_key: key, _value: value}));
  267. return (0, value);
  268. }
  269. }
  270. /**
  271. * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
  272. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  273. *
  274. * WARNING: `high` should not be greater than the array's length.
  275. */
  276. function _upperBinaryLookup(
  277. Checkpoint224[] storage self,
  278. uint32 key,
  279. uint256 low,
  280. uint256 high
  281. ) private view returns (uint256) {
  282. while (low < high) {
  283. uint256 mid = Math.average(low, high);
  284. if (_unsafeAccess(self, mid)._key > key) {
  285. high = mid;
  286. } else {
  287. low = mid + 1;
  288. }
  289. }
  290. return high;
  291. }
  292. /**
  293. * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
  294. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  295. *
  296. * WARNING: `high` should not be greater than the array's length.
  297. */
  298. function _lowerBinaryLookup(
  299. Checkpoint224[] storage self,
  300. uint32 key,
  301. uint256 low,
  302. uint256 high
  303. ) private view returns (uint256) {
  304. while (low < high) {
  305. uint256 mid = Math.average(low, high);
  306. if (_unsafeAccess(self, mid)._key < key) {
  307. low = mid + 1;
  308. } else {
  309. high = mid;
  310. }
  311. }
  312. return high;
  313. }
  314. /**
  315. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  316. */
  317. function _unsafeAccess(
  318. Checkpoint224[] storage self,
  319. uint256 pos
  320. ) private pure returns (Checkpoint224 storage result) {
  321. assembly {
  322. mstore(0, self.slot)
  323. result.slot := add(keccak256(0, 0x20), pos)
  324. }
  325. }
  326. struct Trace160 {
  327. Checkpoint160[] _checkpoints;
  328. }
  329. struct Checkpoint160 {
  330. uint96 _key;
  331. uint160 _value;
  332. }
  333. /**
  334. * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
  335. *
  336. * Returns previous value and new value.
  337. */
  338. function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
  339. return _insert(self._checkpoints, key, value);
  340. }
  341. /**
  342. * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
  343. */
  344. function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
  345. uint256 len = self._checkpoints.length;
  346. uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
  347. return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
  348. }
  349. /**
  350. * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key.
  351. */
  352. function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
  353. uint256 len = self._checkpoints.length;
  354. uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
  355. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  356. }
  357. /**
  358. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  359. */
  360. function latest(Trace160 storage self) internal view returns (uint160) {
  361. uint256 pos = self._checkpoints.length;
  362. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  363. }
  364. /**
  365. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  366. * in the most recent checkpoint.
  367. */
  368. function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
  369. uint256 pos = self._checkpoints.length;
  370. if (pos == 0) {
  371. return (false, 0, 0);
  372. } else {
  373. Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  374. return (true, ckpt._key, ckpt._value);
  375. }
  376. }
  377. /**
  378. * @dev Returns the number of checkpoint.
  379. */
  380. function length(Trace160 storage self) internal view returns (uint256) {
  381. return self._checkpoints.length;
  382. }
  383. /**
  384. * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
  385. * or by updating the last one.
  386. */
  387. function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) {
  388. uint256 pos = self.length;
  389. if (pos > 0) {
  390. // Copying to memory is important here.
  391. Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
  392. // Checkpoint keys must be non-decreasing.
  393. require(last._key <= key, "Checkpoint: decreasing keys");
  394. // Update or push new checkpoint
  395. if (last._key == key) {
  396. _unsafeAccess(self, pos - 1)._value = value;
  397. } else {
  398. self.push(Checkpoint160({_key: key, _value: value}));
  399. }
  400. return (last._value, value);
  401. } else {
  402. self.push(Checkpoint160({_key: key, _value: value}));
  403. return (0, value);
  404. }
  405. }
  406. /**
  407. * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
  408. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  409. *
  410. * WARNING: `high` should not be greater than the array's length.
  411. */
  412. function _upperBinaryLookup(
  413. Checkpoint160[] storage self,
  414. uint96 key,
  415. uint256 low,
  416. uint256 high
  417. ) private view returns (uint256) {
  418. while (low < high) {
  419. uint256 mid = Math.average(low, high);
  420. if (_unsafeAccess(self, mid)._key > key) {
  421. high = mid;
  422. } else {
  423. low = mid + 1;
  424. }
  425. }
  426. return high;
  427. }
  428. /**
  429. * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
  430. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  431. *
  432. * WARNING: `high` should not be greater than the array's length.
  433. */
  434. function _lowerBinaryLookup(
  435. Checkpoint160[] storage self,
  436. uint96 key,
  437. uint256 low,
  438. uint256 high
  439. ) private view returns (uint256) {
  440. while (low < high) {
  441. uint256 mid = Math.average(low, high);
  442. if (_unsafeAccess(self, mid)._key < key) {
  443. low = mid + 1;
  444. } else {
  445. high = mid;
  446. }
  447. }
  448. return high;
  449. }
  450. /**
  451. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  452. */
  453. function _unsafeAccess(
  454. Checkpoint160[] storage self,
  455. uint256 pos
  456. ) private pure returns (Checkpoint160 storage result) {
  457. assembly {
  458. mstore(0, self.slot)
  459. result.slot := add(keccak256(0, 0x20), pos)
  460. }
  461. }
  462. }