Checkpoints.sol 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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 Pushes a value onto a History so that it is stored as the checkpoint for the current block.
  61. *
  62. * Returns previous value and new value.
  63. */
  64. function push(History storage self, uint256 value) internal returns (uint256, uint256) {
  65. return _insert(self._checkpoints, SafeCast.toUint32(block.number), SafeCast.toUint224(value));
  66. }
  67. /**
  68. * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will
  69. * be set to `op(latest, delta)`.
  70. *
  71. * Returns previous value and new value.
  72. */
  73. function push(
  74. History storage self,
  75. function(uint256, uint256) view returns (uint256) op,
  76. uint256 delta
  77. ) internal returns (uint256, uint256) {
  78. return push(self, op(latest(self), delta));
  79. }
  80. /**
  81. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  82. */
  83. function latest(History storage self) internal view returns (uint224) {
  84. uint256 pos = self._checkpoints.length;
  85. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  86. }
  87. /**
  88. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  89. * in the most recent checkpoint.
  90. */
  91. function latestCheckpoint(History storage self)
  92. internal
  93. view
  94. returns (
  95. bool exists,
  96. uint32 _blockNumber,
  97. uint224 _value
  98. )
  99. {
  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(
  119. Checkpoint[] storage self,
  120. uint32 key,
  121. uint224 value
  122. ) private returns (uint224, uint224) {
  123. uint256 pos = self.length;
  124. if (pos > 0) {
  125. // Copying to memory is important here.
  126. Checkpoint memory last = _unsafeAccess(self, pos - 1);
  127. // Checkpoint keys must be non-decreasing.
  128. require(last._blockNumber <= key, "Checkpoint: decreasing keys");
  129. // Update or push new checkpoint
  130. if (last._blockNumber == key) {
  131. _unsafeAccess(self, pos - 1)._value = value;
  132. } else {
  133. self.push(Checkpoint({_blockNumber: key, _value: value}));
  134. }
  135. return (last._value, value);
  136. } else {
  137. self.push(Checkpoint({_blockNumber: key, _value: value}));
  138. return (0, value);
  139. }
  140. }
  141. /**
  142. * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
  143. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  144. *
  145. * WARNING: `high` should not be greater than the array's length.
  146. */
  147. function _upperBinaryLookup(
  148. Checkpoint[] storage self,
  149. uint32 key,
  150. uint256 low,
  151. uint256 high
  152. ) private view returns (uint256) {
  153. while (low < high) {
  154. uint256 mid = Math.average(low, high);
  155. if (_unsafeAccess(self, mid)._blockNumber > key) {
  156. high = mid;
  157. } else {
  158. low = mid + 1;
  159. }
  160. }
  161. return high;
  162. }
  163. /**
  164. * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
  165. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  166. *
  167. * WARNING: `high` should not be greater than the array's length.
  168. */
  169. function _lowerBinaryLookup(
  170. Checkpoint[] storage self,
  171. uint32 key,
  172. uint256 low,
  173. uint256 high
  174. ) private view returns (uint256) {
  175. while (low < high) {
  176. uint256 mid = Math.average(low, high);
  177. if (_unsafeAccess(self, mid)._blockNumber < key) {
  178. low = mid + 1;
  179. } else {
  180. high = mid;
  181. }
  182. }
  183. return high;
  184. }
  185. /**
  186. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  187. */
  188. function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) {
  189. assembly {
  190. mstore(0, self.slot)
  191. result.slot := add(keccak256(0, 0x20), pos)
  192. }
  193. }
  194. struct Trace224 {
  195. Checkpoint224[] _checkpoints;
  196. }
  197. struct Checkpoint224 {
  198. uint32 _key;
  199. uint224 _value;
  200. }
  201. /**
  202. * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
  203. *
  204. * Returns previous value and new value.
  205. */
  206. function push(
  207. Trace224 storage self,
  208. uint32 key,
  209. uint224 value
  210. ) internal returns (uint224, uint224) {
  211. return _insert(self._checkpoints, key, value);
  212. }
  213. /**
  214. * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
  215. */
  216. function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
  217. uint256 len = self._checkpoints.length;
  218. uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
  219. return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
  220. }
  221. /**
  222. * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key.
  223. */
  224. function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
  225. uint256 len = self._checkpoints.length;
  226. uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
  227. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  228. }
  229. /**
  230. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  231. */
  232. function latest(Trace224 storage self) internal view returns (uint224) {
  233. uint256 pos = self._checkpoints.length;
  234. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  235. }
  236. /**
  237. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  238. * in the most recent checkpoint.
  239. */
  240. function latestCheckpoint(Trace224 storage self)
  241. internal
  242. view
  243. returns (
  244. bool exists,
  245. uint32 _key,
  246. uint224 _value
  247. )
  248. {
  249. uint256 pos = self._checkpoints.length;
  250. if (pos == 0) {
  251. return (false, 0, 0);
  252. } else {
  253. Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  254. return (true, ckpt._key, ckpt._value);
  255. }
  256. }
  257. /**
  258. * @dev Returns the number of checkpoint.
  259. */
  260. function length(Trace224 storage self) internal view returns (uint256) {
  261. return self._checkpoints.length;
  262. }
  263. /**
  264. * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
  265. * or by updating the last one.
  266. */
  267. function _insert(
  268. Checkpoint224[] storage self,
  269. uint32 key,
  270. uint224 value
  271. ) private returns (uint224, uint224) {
  272. uint256 pos = self.length;
  273. if (pos > 0) {
  274. // Copying to memory is important here.
  275. Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
  276. // Checkpoint keys must be non-decreasing.
  277. require(last._key <= key, "Checkpoint: decreasing keys");
  278. // Update or push new checkpoint
  279. if (last._key == key) {
  280. _unsafeAccess(self, pos - 1)._value = value;
  281. } else {
  282. self.push(Checkpoint224({_key: key, _value: value}));
  283. }
  284. return (last._value, value);
  285. } else {
  286. self.push(Checkpoint224({_key: key, _value: value}));
  287. return (0, value);
  288. }
  289. }
  290. /**
  291. * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
  292. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  293. *
  294. * WARNING: `high` should not be greater than the array's length.
  295. */
  296. function _upperBinaryLookup(
  297. Checkpoint224[] storage self,
  298. uint32 key,
  299. uint256 low,
  300. uint256 high
  301. ) private view returns (uint256) {
  302. while (low < high) {
  303. uint256 mid = Math.average(low, high);
  304. if (_unsafeAccess(self, mid)._key > key) {
  305. high = mid;
  306. } else {
  307. low = mid + 1;
  308. }
  309. }
  310. return high;
  311. }
  312. /**
  313. * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
  314. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  315. *
  316. * WARNING: `high` should not be greater than the array's length.
  317. */
  318. function _lowerBinaryLookup(
  319. Checkpoint224[] storage self,
  320. uint32 key,
  321. uint256 low,
  322. uint256 high
  323. ) private view returns (uint256) {
  324. while (low < high) {
  325. uint256 mid = Math.average(low, high);
  326. if (_unsafeAccess(self, mid)._key < key) {
  327. low = mid + 1;
  328. } else {
  329. high = mid;
  330. }
  331. }
  332. return high;
  333. }
  334. /**
  335. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  336. */
  337. function _unsafeAccess(Checkpoint224[] storage self, uint256 pos)
  338. private
  339. pure
  340. returns (Checkpoint224 storage result)
  341. {
  342. assembly {
  343. mstore(0, self.slot)
  344. result.slot := add(keccak256(0, 0x20), pos)
  345. }
  346. }
  347. struct Trace160 {
  348. Checkpoint160[] _checkpoints;
  349. }
  350. struct Checkpoint160 {
  351. uint96 _key;
  352. uint160 _value;
  353. }
  354. /**
  355. * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
  356. *
  357. * Returns previous value and new value.
  358. */
  359. function push(
  360. Trace160 storage self,
  361. uint96 key,
  362. uint160 value
  363. ) internal returns (uint160, uint160) {
  364. return _insert(self._checkpoints, key, value);
  365. }
  366. /**
  367. * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none.
  368. */
  369. function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
  370. uint256 len = self._checkpoints.length;
  371. uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
  372. return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
  373. }
  374. /**
  375. * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key.
  376. */
  377. function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
  378. uint256 len = self._checkpoints.length;
  379. uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
  380. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  381. }
  382. /**
  383. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  384. */
  385. function latest(Trace160 storage self) internal view returns (uint160) {
  386. uint256 pos = self._checkpoints.length;
  387. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  388. }
  389. /**
  390. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  391. * in the most recent checkpoint.
  392. */
  393. function latestCheckpoint(Trace160 storage self)
  394. internal
  395. view
  396. returns (
  397. bool exists,
  398. uint96 _key,
  399. uint160 _value
  400. )
  401. {
  402. uint256 pos = self._checkpoints.length;
  403. if (pos == 0) {
  404. return (false, 0, 0);
  405. } else {
  406. Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  407. return (true, ckpt._key, ckpt._value);
  408. }
  409. }
  410. /**
  411. * @dev Returns the number of checkpoint.
  412. */
  413. function length(Trace160 storage self) internal view returns (uint256) {
  414. return self._checkpoints.length;
  415. }
  416. /**
  417. * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
  418. * or by updating the last one.
  419. */
  420. function _insert(
  421. Checkpoint160[] storage self,
  422. uint96 key,
  423. uint160 value
  424. ) private returns (uint160, uint160) {
  425. uint256 pos = self.length;
  426. if (pos > 0) {
  427. // Copying to memory is important here.
  428. Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
  429. // Checkpoint keys must be non-decreasing.
  430. require(last._key <= key, "Checkpoint: decreasing keys");
  431. // Update or push new checkpoint
  432. if (last._key == key) {
  433. _unsafeAccess(self, pos - 1)._value = value;
  434. } else {
  435. self.push(Checkpoint160({_key: key, _value: value}));
  436. }
  437. return (last._value, value);
  438. } else {
  439. self.push(Checkpoint160({_key: key, _value: value}));
  440. return (0, value);
  441. }
  442. }
  443. /**
  444. * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none.
  445. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  446. *
  447. * WARNING: `high` should not be greater than the array's length.
  448. */
  449. function _upperBinaryLookup(
  450. Checkpoint160[] storage self,
  451. uint96 key,
  452. uint256 low,
  453. uint256 high
  454. ) private view returns (uint256) {
  455. while (low < high) {
  456. uint256 mid = Math.average(low, high);
  457. if (_unsafeAccess(self, mid)._key > key) {
  458. high = mid;
  459. } else {
  460. low = mid + 1;
  461. }
  462. }
  463. return high;
  464. }
  465. /**
  466. * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none.
  467. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  468. *
  469. * WARNING: `high` should not be greater than the array's length.
  470. */
  471. function _lowerBinaryLookup(
  472. Checkpoint160[] storage self,
  473. uint96 key,
  474. uint256 low,
  475. uint256 high
  476. ) private view returns (uint256) {
  477. while (low < high) {
  478. uint256 mid = Math.average(low, high);
  479. if (_unsafeAccess(self, mid)._key < key) {
  480. low = mid + 1;
  481. } else {
  482. high = mid;
  483. }
  484. }
  485. return high;
  486. }
  487. /**
  488. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  489. */
  490. function _unsafeAccess(Checkpoint160[] storage self, uint256 pos)
  491. private
  492. pure
  493. returns (Checkpoint160 storage result)
  494. {
  495. assembly {
  496. mstore(0, self.slot)
  497. result.slot := add(keccak256(0, 0x20), pos)
  498. }
  499. }
  500. }