Checkpoints.sol 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.8.1) (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(
  92. History storage self
  93. ) internal view returns (bool exists, uint32 _blockNumber, uint224 _value) {
  94. uint256 pos = self._checkpoints.length;
  95. if (pos == 0) {
  96. return (false, 0, 0);
  97. } else {
  98. Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  99. return (true, ckpt._blockNumber, ckpt._value);
  100. }
  101. }
  102. /**
  103. * @dev Returns the number of checkpoint.
  104. */
  105. function length(History storage self) internal view returns (uint256) {
  106. return self._checkpoints.length;
  107. }
  108. /**
  109. * @dev Returns checkpoint at given position.
  110. */
  111. function at(History storage self, uint32 pos) internal view returns (Checkpoint memory) {
  112. return self._checkpoints[pos];
  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 last (most recent) checkpoint with key lower or equal 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 first (oldest) checkpoint with 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 first (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 last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none.
  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 last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none.
  223. *
  224. * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys).
  225. */
  226. function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) {
  227. uint256 len = self._checkpoints.length;
  228. uint256 low = 0;
  229. uint256 high = len;
  230. if (len > 5) {
  231. uint256 mid = len - Math.sqrt(len);
  232. if (key < _unsafeAccess(self._checkpoints, mid)._key) {
  233. high = mid;
  234. } else {
  235. low = mid + 1;
  236. }
  237. }
  238. uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
  239. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  240. }
  241. /**
  242. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  243. */
  244. function latest(Trace224 storage self) internal view returns (uint224) {
  245. uint256 pos = self._checkpoints.length;
  246. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  247. }
  248. /**
  249. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  250. * in the most recent checkpoint.
  251. */
  252. function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
  253. uint256 pos = self._checkpoints.length;
  254. if (pos == 0) {
  255. return (false, 0, 0);
  256. } else {
  257. Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  258. return (true, ckpt._key, ckpt._value);
  259. }
  260. }
  261. /**
  262. * @dev Returns the number of checkpoint.
  263. */
  264. function length(Trace224 storage self) internal view returns (uint256) {
  265. return self._checkpoints.length;
  266. }
  267. /**
  268. * @dev Returns checkpoint at given position.
  269. */
  270. function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) {
  271. return self._checkpoints[pos];
  272. }
  273. /**
  274. * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
  275. * or by updating the last one.
  276. */
  277. function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
  278. uint256 pos = self.length;
  279. if (pos > 0) {
  280. // Copying to memory is important here.
  281. Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
  282. // Checkpoint keys must be non-decreasing.
  283. require(last._key <= key, "Checkpoint: decreasing keys");
  284. // Update or push new checkpoint
  285. if (last._key == key) {
  286. _unsafeAccess(self, pos - 1)._value = value;
  287. } else {
  288. self.push(Checkpoint224({_key: key, _value: value}));
  289. }
  290. return (last._value, value);
  291. } else {
  292. self.push(Checkpoint224({_key: key, _value: value}));
  293. return (0, value);
  294. }
  295. }
  296. /**
  297. * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none.
  298. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  299. *
  300. * WARNING: `high` should not be greater than the array's length.
  301. */
  302. function _upperBinaryLookup(
  303. Checkpoint224[] storage self,
  304. uint32 key,
  305. uint256 low,
  306. uint256 high
  307. ) private view returns (uint256) {
  308. while (low < high) {
  309. uint256 mid = Math.average(low, high);
  310. if (_unsafeAccess(self, mid)._key > key) {
  311. high = mid;
  312. } else {
  313. low = mid + 1;
  314. }
  315. }
  316. return high;
  317. }
  318. /**
  319. * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none.
  320. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  321. *
  322. * WARNING: `high` should not be greater than the array's length.
  323. */
  324. function _lowerBinaryLookup(
  325. Checkpoint224[] storage self,
  326. uint32 key,
  327. uint256 low,
  328. uint256 high
  329. ) private view returns (uint256) {
  330. while (low < high) {
  331. uint256 mid = Math.average(low, high);
  332. if (_unsafeAccess(self, mid)._key < key) {
  333. low = mid + 1;
  334. } else {
  335. high = mid;
  336. }
  337. }
  338. return high;
  339. }
  340. /**
  341. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  342. */
  343. function _unsafeAccess(
  344. Checkpoint224[] storage self,
  345. uint256 pos
  346. ) private pure returns (Checkpoint224 storage result) {
  347. assembly {
  348. mstore(0, self.slot)
  349. result.slot := add(keccak256(0, 0x20), pos)
  350. }
  351. }
  352. struct Trace160 {
  353. Checkpoint160[] _checkpoints;
  354. }
  355. struct Checkpoint160 {
  356. uint96 _key;
  357. uint160 _value;
  358. }
  359. /**
  360. * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
  361. *
  362. * Returns previous value and new value.
  363. */
  364. function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
  365. return _insert(self._checkpoints, key, value);
  366. }
  367. /**
  368. * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if there is none.
  369. */
  370. function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
  371. uint256 len = self._checkpoints.length;
  372. uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
  373. return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
  374. }
  375. /**
  376. * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none.
  377. */
  378. function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
  379. uint256 len = self._checkpoints.length;
  380. uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
  381. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  382. }
  383. /**
  384. * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none.
  385. *
  386. * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys).
  387. */
  388. function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) {
  389. uint256 len = self._checkpoints.length;
  390. uint256 low = 0;
  391. uint256 high = len;
  392. if (len > 5) {
  393. uint256 mid = len - Math.sqrt(len);
  394. if (key < _unsafeAccess(self._checkpoints, mid)._key) {
  395. high = mid;
  396. } else {
  397. low = mid + 1;
  398. }
  399. }
  400. uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
  401. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  402. }
  403. /**
  404. * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
  405. */
  406. function latest(Trace160 storage self) internal view returns (uint160) {
  407. uint256 pos = self._checkpoints.length;
  408. return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
  409. }
  410. /**
  411. * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
  412. * in the most recent checkpoint.
  413. */
  414. function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
  415. uint256 pos = self._checkpoints.length;
  416. if (pos == 0) {
  417. return (false, 0, 0);
  418. } else {
  419. Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
  420. return (true, ckpt._key, ckpt._value);
  421. }
  422. }
  423. /**
  424. * @dev Returns the number of checkpoint.
  425. */
  426. function length(Trace160 storage self) internal view returns (uint256) {
  427. return self._checkpoints.length;
  428. }
  429. /**
  430. * @dev Returns checkpoint at given position.
  431. */
  432. function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) {
  433. return self._checkpoints[pos];
  434. }
  435. /**
  436. * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
  437. * or by updating the last one.
  438. */
  439. function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) {
  440. uint256 pos = self.length;
  441. if (pos > 0) {
  442. // Copying to memory is important here.
  443. Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
  444. // Checkpoint keys must be non-decreasing.
  445. require(last._key <= key, "Checkpoint: decreasing keys");
  446. // Update or push new checkpoint
  447. if (last._key == key) {
  448. _unsafeAccess(self, pos - 1)._value = value;
  449. } else {
  450. self.push(Checkpoint160({_key: key, _value: value}));
  451. }
  452. return (last._value, value);
  453. } else {
  454. self.push(Checkpoint160({_key: key, _value: value}));
  455. return (0, value);
  456. }
  457. }
  458. /**
  459. * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none.
  460. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  461. *
  462. * WARNING: `high` should not be greater than the array's length.
  463. */
  464. function _upperBinaryLookup(
  465. Checkpoint160[] storage self,
  466. uint96 key,
  467. uint256 low,
  468. uint256 high
  469. ) private view returns (uint256) {
  470. while (low < high) {
  471. uint256 mid = Math.average(low, high);
  472. if (_unsafeAccess(self, mid)._key > key) {
  473. high = mid;
  474. } else {
  475. low = mid + 1;
  476. }
  477. }
  478. return high;
  479. }
  480. /**
  481. * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none.
  482. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
  483. *
  484. * WARNING: `high` should not be greater than the array's length.
  485. */
  486. function _lowerBinaryLookup(
  487. Checkpoint160[] storage self,
  488. uint96 key,
  489. uint256 low,
  490. uint256 high
  491. ) private view returns (uint256) {
  492. while (low < high) {
  493. uint256 mid = Math.average(low, high);
  494. if (_unsafeAccess(self, mid)._key < key) {
  495. low = mid + 1;
  496. } else {
  497. high = mid;
  498. }
  499. }
  500. return high;
  501. }
  502. /**
  503. * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
  504. */
  505. function _unsafeAccess(
  506. Checkpoint160[] storage self,
  507. uint256 pos
  508. ) private pure returns (Checkpoint160 storage result) {
  509. assembly {
  510. mstore(0, self.slot)
  511. result.slot := add(keccak256(0, 0x20), pos)
  512. }
  513. }
  514. }