Skip to content

Commit

Permalink
Merge pull request #94 from keep-network/full-weight-range
Browse files Browse the repository at this point in the history
Use WEIGHT_WIDTH to index full weight range in RNG 

The `RNG` was using the `POSITION_BITS` to determine how many total bits can be used in a pool index. This limited the RNG's range to the total number of positions in the pool, rather than the total weight the pool could manage. In previous usage, this was sufficient for total weight as well, but since the system has since moved to handling ETH fully backed pools and denominate KEEP stakes by individual tokens instead of minstakes, the ~2M position limit is no longer sufficient to represent the magnitude of total weights that need to be handled.
  • Loading branch information
nkuba authored Sep 14, 2020
2 parents 094c701 + 7759d13 commit f803a37
Show file tree
Hide file tree
Showing 5 changed files with 377 additions and 26 deletions.
10 changes: 3 additions & 7 deletions contracts/RNG.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ library RNG {
// How many bits a position uses per level of the tree;
// each branch of the tree contains 2**SLOT_BITS slots.
uint256 constant SLOT_BITS = 3;
uint256 constant LEVELS = 7;
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
// Derived constants, do not touch
uint256 constant POSITION_BITS = LEVELS * SLOT_BITS;
uint256 constant SLOT_COUNT = 2**SLOT_BITS;
uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;
////////////////////////////////////////////////////////////////////////////

struct State {
Expand Down Expand Up @@ -127,16 +127,12 @@ library RNG {
/// @notice Calculate how many bits are required
/// for an index in the range `[0 .. range-1]`.
///
/// @dev Our sortition pool can support up to 2^21 virtual stakers,
/// therefore we calculate how many bits we need from 1 to 21.
///
/// @param range The upper bound of the desired range, exclusive.
///
/// @return uint The smallest number of bits
/// that can contain the number `range-1`.
function bitsRequired(uint256 range) internal pure returns (uint256) {
// Start at 19 to be faster for large ranges
uint256 bits = POSITION_BITS - 1;
uint256 bits = WEIGHT_WIDTH - 1;

// Left shift by `bits`,
// so we have a 1 in the (bits + 1)th least significant bit
Expand Down
2 changes: 1 addition & 1 deletion test/contracts/BondingContractStub.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity 0.5.17;

contract BondingContractStub {
mapping(address => uint) unbondedValue;
mapping(address => uint) public unbondedValue;

function setBondableValue(address operator, uint256 value) public {
unbondedValue[operator] = value;
Expand Down
2 changes: 1 addition & 1 deletion test/contracts/StakingContractStub.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity 0.5.17;

contract StakingContractStub {
mapping(address => uint256) stakedTokens;
mapping(address => uint256) public stakedTokens;

function eligibleStake(
address operator,
Expand Down
33 changes: 16 additions & 17 deletions test/rngTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,33 @@ const DEPLOY = [
{name: "RNGStub", contract: RNGStub},
]

contract("RNG", (accounts) => {
contract("RNG", () => {
let rngInstance

before(async () => {
deployed = await utils.deploySystem(DEPLOY)
rngInstance = deployed.RNGStub

indices = [451, 2945, 3017, 3120]
weights = [1997, 72, 35, 1984]
weightSum = 4088
})

describe("bitsRequired()", async () => {
it("Returns the number of bits required", async () => {
a = 2 ** 19 - 1
b = 2 ** 16
c = 2 ** 10 + 1
d = 2
assert.equal(await rngInstance.bitsRequired.call(2 ** 32 + 1), 32)
assert.equal(await rngInstance.bitsRequired.call(2 ** 32), 32)
assert.equal(await rngInstance.bitsRequired.call(2 ** 32 - 1), 32)

assert.equal(await rngInstance.bitsRequired.call(2 ** 31 + 1), 32)
assert.equal(await rngInstance.bitsRequired.call(2 ** 31), 31)
assert.equal(await rngInstance.bitsRequired.call(2 ** 31 - 1), 31)

assert.equal(await rngInstance.bitsRequired.call(2 ** 16 + 1), 17)
assert.equal(await rngInstance.bitsRequired.call(2 ** 16), 16)
assert.equal(await rngInstance.bitsRequired.call(2 ** 16 - 1), 16)

ba = await rngInstance.bitsRequired.call(a)
bb = await rngInstance.bitsRequired.call(b)
bc = await rngInstance.bitsRequired.call(c)
bd = await rngInstance.bitsRequired.call(d)
assert.equal(await rngInstance.bitsRequired.call(2 ** 2 + 1), 3)
assert.equal(await rngInstance.bitsRequired.call(2 ** 2), 2)
assert.equal(await rngInstance.bitsRequired.call(2 ** 2 - 1), 2)

assert.equal(ba, 19)
assert.equal(bb, 16)
assert.equal(bc, 11)
assert.equal(bd, 1)
assert.equal(await rngInstance.bitsRequired.call(2), 1)
})
})

Expand Down
Loading

0 comments on commit f803a37

Please sign in to comment.