Checkpoints.sol 18 KB

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