generated from pooltogether/pooltogether-contracts-template
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add(PrizeTierHistoryV2):optimized binary search
- Loading branch information
Showing
7 changed files
with
558 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity 0.8.6; | ||
import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol"; | ||
import "./abstract/IdBinarySearchLib.sol"; | ||
|
||
contract PrizeTierHistoryV2 is IdBinarySearchLib, Manageable { | ||
|
||
struct PrizeTier { | ||
uint8 bitRangeSize; | ||
uint32 drawId; | ||
uint32 maxPicksPerUser; | ||
uint32 expiryDuration; | ||
uint32 endTimestampOffset; | ||
uint256 prize; | ||
uint32[16] tiers; | ||
} | ||
|
||
uint32[] internal history; | ||
mapping(uint32 => PrizeTier) internal prizeTiers; | ||
|
||
/** | ||
* @notice Emit when new PrizeTier is added to history | ||
* @param drawId Draw ID | ||
* @param prizeTier PrizeTier parameters | ||
*/ | ||
event PrizeTierPushed(uint32 indexed drawId, PrizeTier prizeTier); | ||
|
||
/** | ||
* @notice Emit when existing PrizeTier is updated in history | ||
* @param drawId Draw ID | ||
* @param prizeTier PrizeTier parameters | ||
*/ | ||
event PrizeTierSet(uint32 indexed drawId, PrizeTier prizeTier); | ||
|
||
constructor(address owner, PrizeTier[] memory _history) Ownable(owner) { | ||
if (_history.length > 0) { | ||
inject(_history); | ||
} | ||
} | ||
|
||
// @inheritdoc DrawIDBinarySearch | ||
function getNewestIndex() internal view override returns (uint32) { | ||
return uint32(history.length - 1); | ||
} | ||
|
||
// @inheritdoc DrawIDBinarySearch | ||
function getIdForIndex(uint256 index) internal view override returns (uint32) { | ||
return history[index]; | ||
} | ||
|
||
function getPrizeTier(uint32 drawId) external view returns (PrizeTier memory) { | ||
require(drawId > 0, "PrizeTierHistoryV2/draw-id-not-zero"); | ||
return prizeTiers[history[_binarySearch(drawId)]]; | ||
} | ||
|
||
function getPrizeTierList(uint32[] calldata _drawIds) external view returns (PrizeTier[] memory) { | ||
PrizeTier[] memory _data = new PrizeTier[](_drawIds.length); | ||
for (uint256 index = 0; index < _drawIds.length; index++) { | ||
_data[index] = prizeTiers[history[_binarySearch(_drawIds[index])]]; | ||
} | ||
return _data; | ||
} | ||
|
||
function push(PrizeTier calldata nextPrizeTier) external onlyManagerOrOwner { | ||
_push(nextPrizeTier); | ||
} | ||
|
||
function popAndPush(PrizeTier calldata newPrizeTier) external onlyManagerOrOwner { | ||
uint length = history.length; | ||
require(length > 0, "PrizeTierHistoryV2/history-empty"); | ||
require(history[length - 1] == newPrizeTier.drawId, "PrizeTierHistoryV2/invalid-draw-id"); | ||
_replace(newPrizeTier); | ||
} | ||
|
||
function replace(PrizeTier calldata newPrizeTier) external onlyOwner { | ||
_replace(newPrizeTier); | ||
} | ||
|
||
function inject(PrizeTier[] memory timeline) public onlyOwner { | ||
require(history.length == 0, "PrizeTierHistoryV2/history-not-empty"); | ||
require(timeline.length > 0, "PrizeTierHistoryV2/timeline-empty"); | ||
for (uint256 i = 0; i < timeline.length; i++) { | ||
_push(timeline[i]); | ||
} | ||
} | ||
|
||
function _push(PrizeTier memory _prizeTier) internal { | ||
if (history.length > 0) { | ||
uint32 _id = history[history.length - 1]; | ||
require( | ||
_prizeTier.drawId > _id, | ||
"PrizeTierHistoryV2/non-sequential-dpr" | ||
); | ||
} | ||
history.push(_prizeTier.drawId); | ||
prizeTiers[_prizeTier.drawId] = _prizeTier; | ||
emit PrizeTierPushed(_prizeTier.drawId, _prizeTier); | ||
} | ||
|
||
function _replace(PrizeTier calldata _prizeTier) internal { | ||
uint256 cardinality = history.length; | ||
require(cardinality > 0, "PrizeTierHistoryV2/no-prize-tiers"); | ||
uint32 oldestDrawId = history[0]; | ||
require(_prizeTier.drawId >= oldestDrawId, "PrizeTierHistoryV2/draw-id-out-of-range"); | ||
uint32 index = _binarySearch(_prizeTier.drawId); | ||
require(history[index] == _prizeTier.drawId, "PrizeTierHistoryV2/draw-id-must-match"); | ||
prizeTiers[_prizeTier.drawId] = _prizeTier; | ||
emit PrizeTierSet(_prizeTier.drawId, _prizeTier); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity 0.8.6; | ||
|
||
/** | ||
* @title PoolTogether V4 DrawIDBinarySearch | ||
* @author PoolTogether Inc Team | ||
* @notice DrawIDBinarySearch uses binary search to find a parent contract struct with the drawId parameter | ||
* @dev The implementing contract must provider access to a struct (i.e. PrizeTier) list with is both | ||
* sorted and indexed by the drawId field for binary search to work. | ||
*/ | ||
abstract contract DrawIDBinarySearch { | ||
/** | ||
* @notice Get newest index in array | ||
*/ | ||
function getNewestIndex() internal view virtual returns (uint32); | ||
|
||
/** | ||
* @notice Get Draw ID for using an index position | ||
* @param index uint256 - Index of element in array | ||
*/ | ||
function getDrawIdForIndex(uint256 index) internal view virtual returns (uint32); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity 0.8.6; | ||
|
||
/** | ||
* @title PoolTogether V4 IdBinarySearchLib | ||
* @author PoolTogether Inc Team | ||
* @notice IdBinarySearchLib uses binary search to find a parent contract struct with the drawId parameter | ||
* @dev The implementing contract must provider access to a struct (i.e. PrizeTier) list with is both | ||
* sorted and indexed by the drawId field for binary search to work. | ||
*/ | ||
abstract contract IdBinarySearchLib { | ||
/** | ||
* @notice Get newest index in array | ||
*/ | ||
function getNewestIndex() internal view virtual returns (uint32); | ||
|
||
/** | ||
* @notice Get Draw ID for using an index position | ||
* @param index uint256 - Index of element in array | ||
*/ | ||
function getIdForIndex(uint256 index) internal view virtual returns (uint32); | ||
|
||
function _binarySearch(uint32 _drawId) internal view returns (uint32) { | ||
uint32 index; | ||
uint32 leftSide = 0; | ||
uint32 rightSide = getNewestIndex(); | ||
|
||
uint32 oldestDrawId = getIdForIndex(leftSide); | ||
uint32 newestDrawId = getIdForIndex(rightSide); | ||
|
||
require(_drawId >= oldestDrawId, "IdBinarySearchLib/draw-id-out-of-range"); | ||
if (_drawId >= newestDrawId) return rightSide; | ||
if (_drawId == oldestDrawId) return leftSide; | ||
|
||
while (true) { | ||
uint32 length = rightSide - leftSide; | ||
uint32 center = leftSide + (length) / 2; | ||
uint32 centerID = getIdForIndex(center); | ||
|
||
if (centerID == _drawId || length == 1) { | ||
index = center; | ||
break; | ||
} | ||
|
||
if (centerID < _drawId) { | ||
leftSide = center; | ||
} else if (centerID > _drawId) { | ||
rightSide = center - 1; | ||
} | ||
|
||
if (leftSide == rightSide) { | ||
if (centerID >= _drawId) { | ||
index = center - 1; | ||
break; | ||
} else { | ||
index = center; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return index; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity 0.8.6; | ||
import "../abstract/IdBinarySearchLib.sol"; | ||
|
||
contract DrawIDAndStructMappingBinarySearch is IdBinarySearchLib { | ||
struct Draw { | ||
uint32 drawId; | ||
uint256 randomNumber; | ||
} | ||
|
||
uint32[] internal history; | ||
mapping(uint32 => Draw) internal draws; | ||
|
||
constructor(Draw[] memory _history) { | ||
if (_history.length > 0) { | ||
inject(_history); | ||
} | ||
} | ||
|
||
// @inheritdoc DrawIDBinarySearch | ||
function getNewestIndex() internal view override returns (uint32) { | ||
return uint32(history.length - 1); | ||
} | ||
|
||
// @inheritdoc DrawIDBinarySearch | ||
function getIdForIndex(uint256 index) internal view override returns (uint32) { | ||
return history[index]; | ||
} | ||
|
||
function get(uint32 _drawId) external view returns (Draw memory) { | ||
return draws[history[_binarySearch(_drawId)]]; | ||
} | ||
|
||
function list(uint32[] calldata _drawIds) external view returns (Draw[] memory) { | ||
Draw[] memory _data = new Draw[](_drawIds.length); | ||
for (uint256 index = 0; index < _drawIds.length; index++) { | ||
_data[index] = draws[history[_binarySearch(_drawIds[index])]]; | ||
} | ||
return _data; | ||
} | ||
|
||
function inject(Draw[] memory _timeline) public { | ||
require(history.length == 0, "DrawIDAndStructMappingBinarySearch/history-not-empty"); | ||
require(_timeline.length > 0, "DrawIDAndStructMappingBinarySearch/timeline-empty"); | ||
for (uint256 i = 0; i < _timeline.length; i++) { | ||
_push(_timeline[i]); | ||
} | ||
} | ||
|
||
function _push(Draw memory _draw) internal { | ||
if (history.length > 0) { | ||
uint32 _id = history[history.length - 1]; | ||
require( | ||
_draw.drawId > _id, | ||
"DrawIDAndStructMappingBinarySearch/non-sequential-dpr" | ||
); | ||
} | ||
history.push(_draw.drawId); | ||
draws[_draw.drawId] = _draw; | ||
} | ||
} |
Binary file not shown.
Oops, something went wrong.