mirror of
https://github.com/status-im/dagger-contracts.git
synced 2025-02-21 02:48:16 +00:00
feat: Add validator slot id groups
Related to nim-codex/457, nim-codex/458. To cover the entire SlotId (uint256) address space, each validator must validate a portion of the SlotId space. When a slot is filled, the SlotId will be put in to a bucket, based on the value of the SlotId and the number of buckets (validators) configured. Similar to `myRequests` and `mySlots`, a function called `validationSlots` can be used to retrieve the `SlotIds` being validated for a particular bucket (validator index). This facilitates loading actively filled slots in need of validation when a validator starts.
This commit is contained in:
parent
7ad26688a3
commit
2b840dcc80
@ -6,6 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|||||||
struct MarketplaceConfig {
|
struct MarketplaceConfig {
|
||||||
CollateralConfig collateral;
|
CollateralConfig collateral;
|
||||||
ProofConfig proofs;
|
ProofConfig proofs;
|
||||||
|
ValidationConfig validation;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CollateralConfig {
|
struct CollateralConfig {
|
||||||
@ -25,3 +26,12 @@ struct ProofConfig {
|
|||||||
uint8 downtime; // ignore this much recent blocks for proof requirements
|
uint8 downtime; // ignore this much recent blocks for proof requirements
|
||||||
string zkeyHash; // hash of the zkey file which is linked to the verifier
|
string zkeyHash; // hash of the zkey file which is linked to the verifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ValidationConfig {
|
||||||
|
// Number of validators to cover the entire SlotId space, max 65,535 (2^16-1).
|
||||||
|
// IMPORTANT: This value should be a power of 2 for even distribution,
|
||||||
|
// otherwise, the last validator will have a significantly less number of
|
||||||
|
// SlotIds to validate. The closest power of 2 without overflow is 2^15 =
|
||||||
|
// 32,768, giving each validator a maximum of 3.534e72 slots to validate.
|
||||||
|
uint16 validators;
|
||||||
|
}
|
||||||
|
@ -10,7 +10,8 @@ contract FuzzMarketplace is Marketplace {
|
|||||||
Marketplace(
|
Marketplace(
|
||||||
MarketplaceConfig(
|
MarketplaceConfig(
|
||||||
CollateralConfig(10, 5, 3, 10),
|
CollateralConfig(10, 5, 3, 10),
|
||||||
ProofConfig(10, 5, 64, "")
|
ProofConfig(10, 5, 64, ""),
|
||||||
|
ValidationConfig(5)
|
||||||
),
|
),
|
||||||
new TestToken(),
|
new TestToken(),
|
||||||
new TestVerifier()
|
new TestVerifier()
|
||||||
|
@ -7,11 +7,12 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|||||||
import "./Configuration.sol";
|
import "./Configuration.sol";
|
||||||
import "./Requests.sol";
|
import "./Requests.sol";
|
||||||
import "./Proofs.sol";
|
import "./Proofs.sol";
|
||||||
|
import "./Validation.sol";
|
||||||
import "./StateRetrieval.sol";
|
import "./StateRetrieval.sol";
|
||||||
import "./Endian.sol";
|
import "./Endian.sol";
|
||||||
import "./Groth16.sol";
|
import "./Groth16.sol";
|
||||||
|
|
||||||
contract Marketplace is Proofs, StateRetrieval, Endian {
|
contract Marketplace is Proofs, Validation, StateRetrieval, Endian {
|
||||||
using EnumerableSet for EnumerableSet.Bytes32Set;
|
using EnumerableSet for EnumerableSet.Bytes32Set;
|
||||||
using Requests for Request;
|
using Requests for Request;
|
||||||
|
|
||||||
@ -58,7 +59,8 @@ contract Marketplace is Proofs, StateRetrieval, Endian {
|
|||||||
MarketplaceConfig memory configuration,
|
MarketplaceConfig memory configuration,
|
||||||
IERC20 token_,
|
IERC20 token_,
|
||||||
IGroth16Verifier verifier
|
IGroth16Verifier verifier
|
||||||
) Proofs(configuration.proofs, verifier) {
|
) Proofs(configuration.proofs, verifier)
|
||||||
|
Validation(configuration.validation) {
|
||||||
_token = token_;
|
_token = token_;
|
||||||
|
|
||||||
require(
|
require(
|
||||||
@ -145,6 +147,8 @@ contract Marketplace is Proofs, StateRetrieval, Endian {
|
|||||||
slot.currentCollateral = collateralAmount;
|
slot.currentCollateral = collateralAmount;
|
||||||
|
|
||||||
_addToMySlots(slot.host, slotId);
|
_addToMySlots(slot.host, slotId);
|
||||||
|
uint16 groupIdx = _getValidatorIndex(slotId);
|
||||||
|
_addToValidationSlots(groupIdx, slotId);
|
||||||
|
|
||||||
emit SlotFilled(requestId, slotIndex);
|
emit SlotFilled(requestId, slotIndex);
|
||||||
if (context.slotsFilled == request.ask.slots) {
|
if (context.slotsFilled == request.ask.slots) {
|
||||||
@ -166,6 +170,8 @@ contract Marketplace is Proofs, StateRetrieval, Endian {
|
|||||||
_payoutCancelledSlot(slot.requestId, slotId);
|
_payoutCancelledSlot(slot.requestId, slotId);
|
||||||
} else if (state == SlotState.Failed) {
|
} else if (state == SlotState.Failed) {
|
||||||
_removeFromMySlots(msg.sender, slotId);
|
_removeFromMySlots(msg.sender, slotId);
|
||||||
|
uint16 groupIdx = _getValidatorIndex(slotId);
|
||||||
|
_removeFromValidationSlots(groupIdx, slotId);
|
||||||
} else if (state == SlotState.Filled) {
|
} else if (state == SlotState.Filled) {
|
||||||
_forciblyFreeSlot(slotId);
|
_forciblyFreeSlot(slotId);
|
||||||
}
|
}
|
||||||
@ -233,6 +239,8 @@ contract Marketplace is Proofs, StateRetrieval, Endian {
|
|||||||
RequestContext storage context = _requestContexts[requestId];
|
RequestContext storage context = _requestContexts[requestId];
|
||||||
|
|
||||||
_removeFromMySlots(slot.host, slotId);
|
_removeFromMySlots(slot.host, slotId);
|
||||||
|
uint16 groupIdx = _getValidatorIndex(slotId);
|
||||||
|
_removeFromValidationSlots(groupIdx, slotId);
|
||||||
|
|
||||||
uint256 slotIndex = slot.slotIndex;
|
uint256 slotIndex = slot.slotIndex;
|
||||||
delete _slots[slotId];
|
delete _slots[slotId];
|
||||||
@ -265,6 +273,8 @@ contract Marketplace is Proofs, StateRetrieval, Endian {
|
|||||||
Slot storage slot = _slots[slotId];
|
Slot storage slot = _slots[slotId];
|
||||||
|
|
||||||
_removeFromMySlots(slot.host, slotId);
|
_removeFromMySlots(slot.host, slotId);
|
||||||
|
uint16 groupIdx = _getValidatorIndex(slotId);
|
||||||
|
_removeFromValidationSlots(groupIdx, slotId);
|
||||||
|
|
||||||
uint256 amount = _requests[requestId].pricePerSlot() +
|
uint256 amount = _requests[requestId].pricePerSlot() +
|
||||||
slot.currentCollateral;
|
slot.currentCollateral;
|
||||||
@ -279,6 +289,8 @@ contract Marketplace is Proofs, StateRetrieval, Endian {
|
|||||||
) private requestIsKnown(requestId) {
|
) private requestIsKnown(requestId) {
|
||||||
Slot storage slot = _slots[slotId];
|
Slot storage slot = _slots[slotId];
|
||||||
_removeFromMySlots(slot.host, slotId);
|
_removeFromMySlots(slot.host, slotId);
|
||||||
|
uint16 groupIdx = _getValidatorIndex(slotId);
|
||||||
|
_removeFromValidationSlots(groupIdx, slotId);
|
||||||
|
|
||||||
uint256 amount = _expiryPayoutAmount(requestId, slot.filledAt) +
|
uint256 amount = _expiryPayoutAmount(requestId, slot.filledAt) +
|
||||||
slot.currentCollateral;
|
slot.currentCollateral;
|
||||||
|
@ -10,6 +10,7 @@ contract StateRetrieval {
|
|||||||
|
|
||||||
mapping(address => EnumerableSet.Bytes32Set) private _requestsPerClient;
|
mapping(address => EnumerableSet.Bytes32Set) private _requestsPerClient;
|
||||||
mapping(address => EnumerableSet.Bytes32Set) private _slotsPerHost;
|
mapping(address => EnumerableSet.Bytes32Set) private _slotsPerHost;
|
||||||
|
mapping(uint16 => EnumerableSet.Bytes32Set) private _slotsPerValidator;
|
||||||
|
|
||||||
function myRequests() public view returns (RequestId[] memory) {
|
function myRequests() public view returns (RequestId[] memory) {
|
||||||
return _requestsPerClient[msg.sender].values().toRequestIds();
|
return _requestsPerClient[msg.sender].values().toRequestIds();
|
||||||
@ -19,6 +20,10 @@ contract StateRetrieval {
|
|||||||
return _slotsPerHost[msg.sender].values().toSlotIds();
|
return _slotsPerHost[msg.sender].values().toSlotIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validationSlots(uint16 groupIdx) public view returns (SlotId[] memory) {
|
||||||
|
return _slotsPerValidator[groupIdx].values().toSlotIds();
|
||||||
|
}
|
||||||
|
|
||||||
function _hasSlots(address host) internal view returns (bool) {
|
function _hasSlots(address host) internal view returns (bool) {
|
||||||
return _slotsPerHost[host].length() > 0;
|
return _slotsPerHost[host].length() > 0;
|
||||||
}
|
}
|
||||||
@ -31,6 +36,10 @@ contract StateRetrieval {
|
|||||||
_slotsPerHost[host].add(SlotId.unwrap(slotId));
|
_slotsPerHost[host].add(SlotId.unwrap(slotId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _addToValidationSlots(uint16 groupIdx, SlotId slotId) internal {
|
||||||
|
_slotsPerValidator[groupIdx].add(SlotId.unwrap(slotId));
|
||||||
|
}
|
||||||
|
|
||||||
function _removeFromMyRequests(address client, RequestId requestId) internal {
|
function _removeFromMyRequests(address client, RequestId requestId) internal {
|
||||||
_requestsPerClient[client].remove(RequestId.unwrap(requestId));
|
_requestsPerClient[client].remove(RequestId.unwrap(requestId));
|
||||||
}
|
}
|
||||||
@ -38,4 +47,8 @@ contract StateRetrieval {
|
|||||||
function _removeFromMySlots(address host, SlotId slotId) internal {
|
function _removeFromMySlots(address host, SlotId slotId) internal {
|
||||||
_slotsPerHost[host].remove(SlotId.unwrap(slotId));
|
_slotsPerHost[host].remove(SlotId.unwrap(slotId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _removeFromValidationSlots(uint16 groupIdx, SlotId slotId) internal {
|
||||||
|
_slotsPerValidator[groupIdx].remove(SlotId.unwrap(slotId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
16
contracts/TestValidation.sol
Normal file
16
contracts/TestValidation.sol
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./Validation.sol";
|
||||||
|
import "./Requests.sol";
|
||||||
|
|
||||||
|
contract TestValidation is Validation {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
ValidationConfig memory config
|
||||||
|
) Validation(config) {} // solhint-disable-line no-empty-blocks
|
||||||
|
|
||||||
|
function getValidatorIndex(SlotId slotId) public view returns (uint16) {
|
||||||
|
return _getValidatorIndex(slotId);
|
||||||
|
}
|
||||||
|
}
|
54
contracts/Validation.sol
Normal file
54
contracts/Validation.sol
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.23;
|
||||||
|
|
||||||
|
import "./Configuration.sol";
|
||||||
|
import "./Requests.sol";
|
||||||
|
import "hardhat/console.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title Validation
|
||||||
|
* @notice Abstract contract that handles distribution of SlotIds to validators
|
||||||
|
based on the number of validators specified in the config.
|
||||||
|
*/
|
||||||
|
abstract contract Validation {
|
||||||
|
ValidationConfig private _config;
|
||||||
|
uint256 private _idsPerValidator; // number of uint256's in each group of the 2^256 bit space
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Validation contract.
|
||||||
|
* @param config network-level validator configuration used to determine
|
||||||
|
number of SlotIds per validator.
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
ValidationConfig memory config
|
||||||
|
) {
|
||||||
|
require(config.validators > 0, "validators must be > 0");
|
||||||
|
|
||||||
|
uint256 high = type(uint256).max;
|
||||||
|
|
||||||
|
// To find the number of SlotIds per validator, we could do
|
||||||
|
// 2^256/validators, except that would overflow. Instead, we use
|
||||||
|
// floor(2^256-1 / validators) + 1. For example, if we used a 4-bit space
|
||||||
|
// (2^4=16) with 2 validators, we'd expect 8 per group: floor(2^4-1 / 2) + 1
|
||||||
|
// = 8
|
||||||
|
if (config.validators == 1) {
|
||||||
|
// max(uint256) + 1 would overflow, so assign 0 and handle as special case
|
||||||
|
// later
|
||||||
|
_idsPerValidator = 0;
|
||||||
|
} else {
|
||||||
|
_idsPerValidator = (high / config.validators) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines which validator group (0-based index) a SlotId belongs to, based
|
||||||
|
on the number of total validators in the config.
|
||||||
|
* @param slotId SlotID for which to determine the validator group index.
|
||||||
|
*/
|
||||||
|
function _getValidatorIndex(SlotId slotId) internal view returns(uint16) {
|
||||||
|
uint256 slotIdInt = uint256(SlotId.unwrap(slotId));
|
||||||
|
return uint16(slotIdInt / _idsPerValidator);
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,9 @@ const CONFIGURATION = {
|
|||||||
// in automine mode, because it can produce a block every second
|
// in automine mode, because it can produce a block every second
|
||||||
downtime: 64,
|
downtime: 64,
|
||||||
},
|
},
|
||||||
|
validation: {
|
||||||
|
validators: 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mine256blocks({ network, ethers }) {
|
async function mine256blocks({ network, ethers }) {
|
||||||
|
@ -1114,4 +1114,101 @@ describe("Marketplace", function () {
|
|||||||
expect(await marketplace.mySlots()).to.not.contain(slotId(slot))
|
expect(await marketplace.mySlots()).to.not.contain(slotId(slot))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("list of validation slots", function () {
|
||||||
|
beforeEach(async function () {
|
||||||
|
switchAccount(client)
|
||||||
|
await token.approve(marketplace.address, price(request))
|
||||||
|
await marketplace.requestStorage(request)
|
||||||
|
switchAccount(host)
|
||||||
|
await token.approve(marketplace.address, request.ask.collateral)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("adds slot to list when filling slot", async function () {
|
||||||
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
||||||
|
let slot1 = { ...slot, index: slot.index + 1 }
|
||||||
|
await token.approve(marketplace.address, request.ask.collateral)
|
||||||
|
await marketplace.fillSlot(slot.request, slot1.index, proof)
|
||||||
|
const allSlots = (
|
||||||
|
await marketplace.validationSlots(0)).concat(
|
||||||
|
await marketplace.validationSlots(1)).concat(
|
||||||
|
await marketplace.validationSlots(2)
|
||||||
|
)
|
||||||
|
expect(allSlots).to.have.members([
|
||||||
|
slotId(slot),
|
||||||
|
slotId(slot1),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("removes slot from list when slot is freed", async function () {
|
||||||
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
||||||
|
let slot1 = { ...slot, index: slot.index + 1 }
|
||||||
|
await token.approve(marketplace.address, request.ask.collateral)
|
||||||
|
await marketplace.fillSlot(slot.request, slot1.index, proof)
|
||||||
|
await token.approve(marketplace.address, request.ask.collateral)
|
||||||
|
await marketplace.freeSlot(slotId(slot))
|
||||||
|
const allSlots = (
|
||||||
|
await marketplace.validationSlots(0)).concat(
|
||||||
|
await marketplace.validationSlots(1)).concat(
|
||||||
|
await marketplace.validationSlots(2)
|
||||||
|
)
|
||||||
|
expect(allSlots).to.not.have.members([slotId(slot)])
|
||||||
|
expect(allSlots).to.have.members([slotId(slot1)])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("keeps slots when cancelled", async function () {
|
||||||
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
||||||
|
let slot1 = { ...slot, index: slot.index + 1 }
|
||||||
|
|
||||||
|
await token.approve(marketplace.address, request.ask.collateral)
|
||||||
|
await marketplace.fillSlot(slot.request, slot1.index, proof)
|
||||||
|
await waitUntilCancelled(request)
|
||||||
|
await mine()
|
||||||
|
const allSlots = (
|
||||||
|
await marketplace.validationSlots(0)).concat(
|
||||||
|
await marketplace.validationSlots(1)).concat(
|
||||||
|
await marketplace.validationSlots(2)
|
||||||
|
)
|
||||||
|
expect(allSlots).to.have.members([
|
||||||
|
slotId(slot),
|
||||||
|
slotId(slot1),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("removes slot when finished slot is freed", async function () {
|
||||||
|
await waitUntilStarted(marketplace, request, proof, token)
|
||||||
|
await waitUntilFinished(marketplace, requestId(request))
|
||||||
|
await marketplace.freeSlot(slotId(slot))
|
||||||
|
const allSlots = (
|
||||||
|
await marketplace.validationSlots(0)).concat(
|
||||||
|
await marketplace.validationSlots(1)).concat(
|
||||||
|
await marketplace.validationSlots(2)
|
||||||
|
)
|
||||||
|
expect(allSlots).to.not.contain(slotId(slot))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("removes slot when cancelled slot is freed", async function () {
|
||||||
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
||||||
|
await waitUntilCancelled(request)
|
||||||
|
await marketplace.freeSlot(slotId(slot))
|
||||||
|
const allSlots = (
|
||||||
|
await marketplace.validationSlots(0)).concat(
|
||||||
|
await marketplace.validationSlots(1)).concat(
|
||||||
|
await marketplace.validationSlots(2)
|
||||||
|
)
|
||||||
|
expect(allSlots).to.not.contain(slotId(slot))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("removes slot when failed slot is freed", async function () {
|
||||||
|
await waitUntilStarted(marketplace, request, proof, token)
|
||||||
|
await waitUntilSlotFailed(marketplace, request, slot)
|
||||||
|
await marketplace.freeSlot(slotId(slot))
|
||||||
|
const allSlots = (
|
||||||
|
await marketplace.validationSlots(0)).concat(
|
||||||
|
await marketplace.validationSlots(1)).concat(
|
||||||
|
await marketplace.validationSlots(2)
|
||||||
|
)
|
||||||
|
expect(allSlots).to.not.contain(slotId(slot))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
107
test/Validation.test.js
Normal file
107
test/Validation.test.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
const { expect } = require("chai")
|
||||||
|
const { ethers } = require("hardhat")
|
||||||
|
const {BigNumber, utils} = require("ethers")
|
||||||
|
|
||||||
|
describe("Validation", function () {
|
||||||
|
const zero =
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
const low =
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000001"
|
||||||
|
const mid =
|
||||||
|
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||||
|
|
||||||
|
describe("constructor", function() {
|
||||||
|
// let validation
|
||||||
|
let Validation
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
Validation = await ethers.getContractFactory("TestValidation")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails to deploy with > uint16.max validators", async function() {
|
||||||
|
await expect(
|
||||||
|
Validation.deploy({validators: 2**16}) // uint16.max is 2^16-1
|
||||||
|
).to.be.reverted
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails to deploy with 0 number of validators", async function() {
|
||||||
|
await expect(
|
||||||
|
Validation.deploy({validators: 0})
|
||||||
|
).to.be.revertedWith("validators must be > 0")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("successfully deploys with a valid number of validators", async function() {
|
||||||
|
await expect(
|
||||||
|
Validation.deploy({validators: 1})
|
||||||
|
).to.be.ok
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("groups of SlotIds per validator", function() {
|
||||||
|
|
||||||
|
let Validation
|
||||||
|
|
||||||
|
const high = ethers.constants.MaxUint256
|
||||||
|
|
||||||
|
function toUInt256Hex(bn) {
|
||||||
|
return utils.hexZeroPad(bn.toHexString(), 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
function random(max) {
|
||||||
|
return Math.floor(Math.random() * max)
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
Validation = await ethers.getContractFactory("TestValidation")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("tests that the min and max boundary SlotIds into the correct group", async function () {
|
||||||
|
let validators = 2**16-1 // max value of uint16
|
||||||
|
let idsPerGroup = high.div( validators ).add(1) // as in the contract
|
||||||
|
let validation = await Validation.deploy({validators})
|
||||||
|
|
||||||
|
// Returns the minimum SlotId of all allowed SlotIds of the validator
|
||||||
|
// (given its index)
|
||||||
|
function minIdFor(validatorIdx) {
|
||||||
|
return BigNumber.from(validatorIdx).mul(idsPerGroup)
|
||||||
|
}
|
||||||
|
// Returns the maximum SlotId of all allowed SlotIds of the validator
|
||||||
|
// (given its index)
|
||||||
|
function maxIdFor(validatorIdx) {
|
||||||
|
const max = BigNumber.from(validatorIdx + 1).mul(idsPerGroup).sub(1)
|
||||||
|
// Never return more than max value of uint256 because it would
|
||||||
|
// overflow. BigNumber.js lets us do MaxUint256+1 without overflows.
|
||||||
|
if (max.gt(high)) {
|
||||||
|
return high
|
||||||
|
}
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate randomised number of validators. If we fuzzed all possible
|
||||||
|
// number of validators, the test would take far too long to execute. This
|
||||||
|
// should absolutely never fail.
|
||||||
|
let validatorsRandomised = Array.from({ length: 128 }, (_) => random(validators))
|
||||||
|
|
||||||
|
for(let i=0; i<validatorsRandomised.length; i++) {
|
||||||
|
let validatorIdx = validatorsRandomised[i]
|
||||||
|
|
||||||
|
// test the boundary of the SlotIds that are allowed in this particular
|
||||||
|
// validator validatorIdx
|
||||||
|
let min = toUInt256Hex( minIdFor(validatorIdx) )
|
||||||
|
let max = toUInt256Hex( maxIdFor(validatorIdx) )
|
||||||
|
|
||||||
|
try{
|
||||||
|
expect(await validation.getValidatorIndex(min)).to.equal(validatorIdx)
|
||||||
|
expect(await validation.getValidatorIndex(max)).to.equal(validatorIdx)
|
||||||
|
} catch(e) {
|
||||||
|
console.log('FAILING TEST PARAMETERS')
|
||||||
|
console.log('-----------------------------------------------------------------------------------')
|
||||||
|
console.log('validator index:', validatorIdx)
|
||||||
|
console.log('slotId min: ', min)
|
||||||
|
console.log('slotId max: ', max)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -15,6 +15,9 @@ const exampleConfiguration = () => ({
|
|||||||
downtime: 64,
|
downtime: 64,
|
||||||
zkeyHash: "",
|
zkeyHash: "",
|
||||||
},
|
},
|
||||||
|
validation: {
|
||||||
|
validators: 3
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const exampleRequest = async () => {
|
const exampleRequest = async () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user