Skip to content

Commit f9a8e92

Browse files
Merge pull request #170 from keep-network/constants-library
Add a `Constants.sol` Library to Aggregate the Constants
2 parents 0093d32 + dd5c0c5 commit f9a8e92

9 files changed

Lines changed: 55499 additions & 827 deletions

File tree

contracts/Branch.sol

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
11
pragma solidity 0.8.9;
22

3+
import "./Constants.sol";
4+
35
/// @notice The implicit 8-ary trees of the sortition pool
46
/// rely on packing 8 "slots" of 32-bit values into each uint256.
57
/// The Branch library permits efficient calculations on these slots.
68
library Branch {
7-
////////////////////////////////////////////////////////////////////////////
8-
// Parameters for configuration
9-
10-
// How many bits a position uses per level of the tree;
11-
// each branch of the tree contains 2**SLOT_BITS slots.
12-
uint256 private constant SLOT_BITS = 3;
13-
////////////////////////////////////////////////////////////////////////////
14-
15-
////////////////////////////////////////////////////////////////////////////
16-
// Derived constants, do not touch
17-
uint256 private constant SLOT_COUNT = 2**SLOT_BITS;
18-
uint256 private constant SLOT_WIDTH = 256 / SLOT_COUNT;
19-
uint256 private constant LAST_SLOT = SLOT_COUNT - 1;
20-
uint256 private constant SLOT_MAX = (2**SLOT_WIDTH) - 1;
21-
22-
////////////////////////////////////////////////////////////////////////////
23-
249
/// @notice Calculate the right shift required
2510
/// to make the 32 least significant bits of an uint256
2611
/// be the bits of the `position`th slot
@@ -31,7 +16,7 @@ library Branch {
3116
/// I wish solidity had macros, even C macros.
3217
function slotShift(uint256 position) internal pure returns (uint256) {
3318
unchecked {
34-
return position * SLOT_WIDTH;
19+
return position * Constants.SLOT_WIDTH;
3520
}
3621
}
3722

@@ -43,12 +28,12 @@ library Branch {
4328
returns (uint256)
4429
{
4530
unchecked {
46-
uint256 shiftBits = position * SLOT_WIDTH;
31+
uint256 shiftBits = position * Constants.SLOT_WIDTH;
4732
// Doing a bitwise AND with `SLOT_MAX`
4833
// clears all but the 32 least significant bits.
4934
// Because of the right shift by `slotShift(position)` bits,
5035
// those 32 bits contain the 32 bits in the `position`th slot of `node`.
51-
return (node >> shiftBits) & SLOT_MAX;
36+
return (node >> shiftBits) & Constants.SLOT_MAX;
5237
}
5338
}
5439

@@ -59,7 +44,7 @@ library Branch {
5944
returns (uint256)
6045
{
6146
unchecked {
62-
uint256 shiftBits = position * SLOT_WIDTH;
47+
uint256 shiftBits = position * Constants.SLOT_WIDTH;
6348
// Shifting `SLOT_MAX` left by `slotShift(position)` bits
6449
// gives us a number where all bits of the `position`th slot are set,
6550
// and all other bits are unset.
@@ -71,7 +56,7 @@ library Branch {
7156
// Bitwise ANDing the original `node` with this number
7257
// sets the bits of `position`th slot to zero,
7358
// leaving all other bits unchanged.
74-
return node & ~(SLOT_MAX << shiftBits);
59+
return node & ~(Constants.SLOT_MAX << shiftBits);
7560
}
7661
}
7762

@@ -86,17 +71,17 @@ library Branch {
8671
uint256 weight
8772
) internal pure returns (uint256) {
8873
unchecked {
89-
uint256 shiftBits = position * SLOT_WIDTH;
74+
uint256 shiftBits = position * Constants.SLOT_WIDTH;
9075
// Clear the `position`th slot like in `clearSlot()`.
91-
uint256 clearedNode = node & ~(SLOT_MAX << shiftBits);
76+
uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);
9277
// Bitwise AND `weight` with `SLOT_MAX`
9378
// to clear all but the 32 least significant bits.
9479
//
9580
// Shift this left by `slotShift(position)` bits
9681
// to obtain a uint256 with all bits unset
9782
// except in the `position`th slot
9883
// which contains the 32-bit value of `weight`.
99-
uint256 shiftedWeight = (weight & SLOT_MAX) << shiftBits;
84+
uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;
10085
// When we bitwise OR these together,
10186
// all other slots except the `position`th one come from the left argument,
10287
// and the `position`th gets filled with `weight` from the right argument.
@@ -107,14 +92,14 @@ library Branch {
10792
/// @notice Calculate the summed weight of all slots in the `node`.
10893
function sumWeight(uint256 node) internal pure returns (uint256 sum) {
10994
unchecked {
110-
sum = node & SLOT_MAX;
95+
sum = node & Constants.SLOT_MAX;
11196
// Iterate through each slot
11297
// by shifting `node` right in increments of 32 bits,
11398
// and adding the 32 least significant bits to the `sum`.
114-
uint256 newNode = node >> SLOT_WIDTH;
99+
uint256 newNode = node >> Constants.SLOT_WIDTH;
115100
while (newNode > 0) {
116-
sum += (newNode & SLOT_MAX);
117-
newNode = newNode >> SLOT_WIDTH;
101+
sum += (newNode & Constants.SLOT_MAX);
102+
newNode = newNode >> Constants.SLOT_WIDTH;
118103
}
119104
return sum;
120105
}
@@ -143,12 +128,12 @@ library Branch {
143128
unchecked {
144129
newIndex = index;
145130
uint256 newNode = node;
146-
uint256 currentSlotWeight = newNode & SLOT_MAX;
131+
uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;
147132
while (newIndex >= currentSlotWeight) {
148133
newIndex -= currentSlotWeight;
149134
slot++;
150-
newNode = newNode >> SLOT_WIDTH;
151-
currentSlotWeight = newNode & SLOT_MAX;
135+
newNode = newNode >> Constants.SLOT_WIDTH;
136+
currentSlotWeight = newNode & Constants.SLOT_MAX;
152137
}
153138
return (slot, newIndex);
154139
}

contracts/Constants.sol

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
pragma solidity 0.8.9;
2+
3+
library Constants {
4+
////////////////////////////////////////////////////////////////////////////
5+
// Parameters for configuration
6+
7+
// How many bits a position uses per level of the tree;
8+
// each branch of the tree contains 2**SLOT_BITS slots.
9+
uint256 constant SLOT_BITS = 3;
10+
uint256 constant LEVELS = 7;
11+
////////////////////////////////////////////////////////////////////////////
12+
13+
////////////////////////////////////////////////////////////////////////////
14+
// Derived constants, do not touch
15+
uint256 constant SLOT_COUNT = 2**SLOT_BITS;
16+
uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;
17+
uint256 constant LAST_SLOT = SLOT_COUNT - 1;
18+
uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;
19+
uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;
20+
21+
uint256 constant ID_WIDTH = SLOT_WIDTH;
22+
uint256 constant ID_MAX = SLOT_MAX;
23+
24+
uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;
25+
uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;
26+
27+
uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;
28+
uint256 constant LEAF_FLAG = 1 << 255;
29+
30+
uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;
31+
////////////////////////////////////////////////////////////////////////////
32+
}

contracts/Leaf.sol

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,8 @@
11
pragma solidity 0.8.9;
22

3-
library Leaf {
4-
////////////////////////////////////////////////////////////////////////////
5-
// Parameters for configuration
6-
7-
// How many bits a position uses per level of the tree;
8-
// each branch of the tree contains 2**SLOT_BITS slots.
9-
uint256 private constant SLOT_BITS = 3;
10-
////////////////////////////////////////////////////////////////////////////
11-
12-
////////////////////////////////////////////////////////////////////////////
13-
// Derived constants, do not touch
14-
uint256 private constant SLOT_COUNT = 2**SLOT_BITS;
15-
uint256 private constant SLOT_WIDTH = 256 / SLOT_COUNT;
16-
uint256 private constant SLOT_MAX = (2**SLOT_WIDTH) - 1;
17-
18-
uint256 private constant ID_WIDTH = SLOT_WIDTH;
19-
uint256 private constant ID_MAX = SLOT_MAX;
20-
21-
uint256 private constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;
22-
uint256 private constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;
23-
24-
////////////////////////////////////////////////////////////////////////////
3+
import "./Constants.sol";
254

5+
library Leaf {
266
function make(
277
address _operator,
288
uint256 _creationBlock,
@@ -35,10 +15,11 @@ library Leaf {
3515
uint256 op = uint256(bytes32(bytes20(_operator)));
3616
// Bitwise AND the id to erase
3717
// all but the 32 least significant bits
38-
uint256 uid = _id & ID_MAX;
18+
uint256 uid = _id & Constants.ID_MAX;
3919
// Erase all but the 64 least significant bits,
4020
// then shift left by 32 bits to make room for the id
41-
uint256 cb = (_creationBlock & BLOCKHEIGHT_MAX) << ID_WIDTH;
21+
uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<
22+
Constants.ID_WIDTH;
4223
// Bitwise OR them all together to get
4324
// [address operator || uint64 creationBlock || uint32 id]
4425
return (op | cb | uid);
@@ -52,12 +33,12 @@ library Leaf {
5233

5334
/// @notice Return the block number the leaf was created in.
5435
function creationBlock(uint256 leaf) internal pure returns (uint256) {
55-
return ((leaf >> ID_WIDTH) & BLOCKHEIGHT_MAX);
36+
return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);
5637
}
5738

5839
function id(uint256 leaf) internal pure returns (uint32) {
5940
// Id is stored in the 32 least significant bits.
6041
// Bitwise AND ensures that we only get the contents of those bits.
61-
return uint32(leaf & ID_MAX);
42+
return uint32(leaf & Constants.ID_MAX);
6243
}
6344
}

contracts/Position.sol

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,30 @@
11
pragma solidity 0.8.9;
22

3-
library Position {
4-
////////////////////////////////////////////////////////////////////////////
5-
// Parameters for configuration
6-
7-
// How many bits a position uses per level of the tree;
8-
// each branch of the tree contains 2**SLOT_BITS slots.
9-
uint256 private constant SLOT_BITS = 3;
10-
////////////////////////////////////////////////////////////////////////////
11-
12-
////////////////////////////////////////////////////////////////////////////
13-
// Derived constants, do not touch
14-
uint256 private constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;
15-
uint256 private constant LEAF_FLAG = 1 << 255;
16-
17-
////////////////////////////////////////////////////////////////////////////
3+
import "./Constants.sol";
184

5+
library Position {
196
// Return the last 3 bits of a position number,
207
// corresponding to its slot in its parent
218
function slot(uint256 a) internal pure returns (uint256) {
22-
return a & SLOT_POINTER_MAX;
9+
return a & Constants.SLOT_POINTER_MAX;
2310
}
2411

2512
// Return the parent of a position number
2613
function parent(uint256 a) internal pure returns (uint256) {
27-
return a >> SLOT_BITS;
14+
return a >> Constants.SLOT_BITS;
2815
}
2916

3017
// Return the location of the child of a at the given slot
3118
function child(uint256 a, uint256 s) internal pure returns (uint256) {
32-
return (a << SLOT_BITS) | (s & SLOT_POINTER_MAX); // slot(s)
19+
return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)
3320
}
3421

3522
// Return the uint p as a flagged position uint:
3623
// the least significant 21 bits contain the position
3724
// and the 22nd bit is set as a flag
3825
// to distinguish the position 0x000000 from an empty field.
3926
function setFlag(uint256 p) internal pure returns (uint256) {
40-
return p | LEAF_FLAG;
27+
return p | Constants.LEAF_FLAG;
4128
}
4229

4330
// Turn a flagged position into an unflagged position
@@ -47,6 +34,6 @@ library Position {
4734
// as all position-manipulating code should ignore non-position bits anyway
4835
// but it's cheap to call so might as well do it.
4936
function unsetFlag(uint256 p) internal pure returns (uint256) {
50-
return p & (~LEAF_FLAG);
37+
return p & (~Constants.LEAF_FLAG);
5138
}
5239
}

contracts/RNG.sol

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,9 @@
11
pragma solidity 0.8.9;
22

33
import "./Leaf.sol";
4+
import "./Constants.sol";
45

56
library RNG {
6-
////////////////////////////////////////////////////////////////////////////
7-
// Parameters for configuration
8-
9-
// How many bits a position uses per level of the tree;
10-
// each branch of the tree contains 2**SLOT_BITS slots.
11-
uint256 private constant SLOT_BITS = 3;
12-
////////////////////////////////////////////////////////////////////////////
13-
14-
////////////////////////////////////////////////////////////////////////////
15-
// Derived constants, do not touch
16-
uint256 private constant SLOT_COUNT = 2**SLOT_BITS;
17-
uint256 private constant WEIGHT_WIDTH = 256 / SLOT_COUNT;
18-
19-
////////////////////////////////////////////////////////////////////////////
20-
217
/// @notice Get an index in the range `[0 .. range-1]`
228
/// and the new state of the RNG,
239
/// using the provided `state` of the RNG.
@@ -76,7 +62,7 @@ library RNG {
7662
return 0;
7763
}
7864

79-
uint256 bits = WEIGHT_WIDTH - 1;
65+
uint256 bits = Constants.WEIGHT_WIDTH - 1;
8066

8167
// Left shift by `bits`,
8268
// so we have a 1 in the (bits + 1)th least significant bit

contracts/SortitionTree.sol

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,13 @@ pragma solidity 0.8.9;
33
import "./Branch.sol";
44
import "./Position.sol";
55
import "./Leaf.sol";
6+
import "./Constants.sol";
67

78
contract SortitionTree {
89
using Branch for uint256;
910
using Position for uint256;
1011
using Leaf for uint256;
1112

12-
////////////////////////////////////////////////////////////////////////////
13-
// Parameters for configuration
14-
15-
// How many bits a position uses per level of the tree;
16-
// each branch of the tree contains 2**SLOT_BITS slots.
17-
uint256 private constant SLOT_BITS = 3;
18-
uint256 private constant LEVELS = 7;
19-
////////////////////////////////////////////////////////////////////////////
20-
21-
////////////////////////////////////////////////////////////////////////////
22-
// Derived constants, do not touch
23-
uint256 private constant SLOT_COUNT = 2**SLOT_BITS;
24-
uint256 private constant SLOT_WIDTH = 256 / SLOT_COUNT;
25-
uint256 private constant SLOT_MAX = (2**SLOT_WIDTH) - 1;
26-
uint256 private constant POOL_CAPACITY = SLOT_COUNT**LEVELS;
27-
////////////////////////////////////////////////////////////////////////////
28-
2913
// implicit tree
3014
// root 8
3115
// level2 64
@@ -226,7 +210,7 @@ contract SortitionTree {
226210

227211
uint256 parent = position;
228212
// set levels 7 to 2
229-
for (uint256 level = LEVELS; level >= 2; level--) {
213+
for (uint256 level = Constants.LEVELS; level >= 2; level--) {
230214
childSlot = parent.slot();
231215
parent = parent.parent();
232216
treeNode = branches[level][parent];
@@ -242,7 +226,7 @@ contract SortitionTree {
242226

243227
function getEmptyLeafPosition() internal returns (uint256) {
244228
uint256 rLeaf = rightmostLeaf;
245-
bool spaceOnRight = (rLeaf + 1) < POOL_CAPACITY;
229+
bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;
246230
if (spaceOnRight) {
247231
rightmostLeaf = rLeaf + 1;
248232
return rLeaf;
@@ -266,7 +250,7 @@ contract SortitionTree {
266250
function getLeafWeight(uint256 position) internal view returns (uint256) {
267251
uint256 slot = position.slot();
268252
uint256 parent = position.parent();
269-
uint256 node = branches[LEVELS][parent];
253+
uint256 node = branches[Constants.LEVELS][parent];
270254
return node.getSlot(slot);
271255
}
272256

@@ -286,7 +270,7 @@ contract SortitionTree {
286270
(currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);
287271

288272
// get slots from levels 2 to 7
289-
for (uint256 level = 2; level <= LEVELS; level++) {
273+
for (uint256 level = 2; level <= Constants.LEVELS; level++) {
290274
currentPosition = currentPosition.child(currentSlot);
291275
currentNode = branches[level][currentPosition];
292276
(currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);

hardhat.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "@keep-network/hardhat-local-networks-config"
55
import "@nomiclabs/hardhat-waffle"
66
import "@nomiclabs/hardhat-ethers"
77
import "hardhat-deploy"
8+
import "hardhat-gas-reporter"
89

910
const config: HardhatUserConfig = {
1011
solidity: {

0 commit comments

Comments
 (0)