Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: only propose revealed assets of epoch #726

Merged
merged 16 commits into from
Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 61 additions & 85 deletions contracts/Core/BlockManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,6 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager
// note that only one staker or no stakers selected in each iteration.
// stakers elected in higher iterations can also propose hoping that
// stakers with lower iteration do not propose for some reason

/// @dev The IDs being passed here, are only used for disputeForNonAssignedCollection
/// for delegator, we have seprate registry
/// If user passes invalid ids, disputeForProposedCollectionIds can happen

function propose(
uint32 epoch,
uint16[] memory ids,
Expand All @@ -67,7 +62,6 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager
//following line is to prevent that
require(voteManager.getEpochLastRevealed(proposerId) == epoch, "Cannot propose without revealing");
require(epochLastProposed[proposerId] != epoch, "Already proposed");
require(medians.length == collectionManager.getNumActiveCollections(), "invalid block proposed");

uint256 biggestStake = voteManager.getStakeSnapshot(epoch, biggestStakerId);
if (sortedProposedBlockIds[epoch].length == 0) numProposedBlocks = 0;
Expand All @@ -83,18 +77,18 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager
//anyone can give sorted votes in batches in dispute state
function giveSorted(
uint32 epoch,
uint16 medianIndex,
uint16 activeCollectionIndex,
uint32[] memory sortedValues
) external initialized checkEpochAndState(State.Dispute, epoch) {
require(medianIndex <= (collectionManager.getNumActiveCollections() - 1), "Invalid MedianIndex value");
uint256 medianWeight = voteManager.getTotalInfluenceRevealed(epoch, medianIndex) / 2;
require(activeCollectionIndex <= (collectionManager.getNumActiveCollections() - 1), "Invalid activeCollectionIndex");
uint256 medianWeight = voteManager.getTotalInfluenceRevealed(epoch, activeCollectionIndex) / 2;
uint256 accWeight = disputes[epoch][msg.sender].accWeight;
uint32 lastVisitedValue = disputes[epoch][msg.sender].lastVisitedValue;

if (disputes[epoch][msg.sender].accWeight == 0) {
disputes[epoch][msg.sender].medianIndex = medianIndex;
disputes[epoch][msg.sender].activeCollectionIndex = activeCollectionIndex;
} else {
require(disputes[epoch][msg.sender].medianIndex == medianIndex, "MedianIndex not matching");
require(disputes[epoch][msg.sender].activeCollectionIndex == activeCollectionIndex, "activeCollectionIndex mismatch");
// require(disputes[epoch][msg.sender].median == 0, "median already found");
}
for (uint32 i = 0; i < sortedValues.length; i++) {
Expand All @@ -103,7 +97,7 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager

// reason to ignore : has to be done, as each vote will have diff weight
// slither-disable-next-line calls-loop
uint256 weight = voteManager.getVoteWeight(epoch, medianIndex, sortedValues[i]);
uint256 weight = voteManager.getVoteWeight(epoch, activeCollectionIndex, sortedValues[i]);
accWeight = accWeight + weight; // total influence revealed for this collection
if (disputes[epoch][msg.sender].median == 0 && accWeight > medianWeight) {
disputes[epoch][msg.sender].median = sortedValues[i];
Expand All @@ -130,11 +124,6 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager
require(proposerId == stakerId, "Block Proposer mismatches");
_confirmBlock(epoch, proposerId);
}
uint32 updateRegistryEpoch = collectionManager.getUpdateRegistryEpoch();
// slither-disable-next-line incorrect-equality
if (updateRegistryEpoch <= epoch) {
collectionManager.updateRegistry();
}
}

function confirmPreviousEpochBlock(uint32 stakerId) external override initialized onlyRole(BLOCK_CONFIRMER_ROLE) {
Expand All @@ -143,12 +132,6 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager
if (sortedProposedBlockIds[epoch - 1].length != 0 && blockIndexToBeConfirmed != -1) {
_confirmBlock(epoch - 1, stakerId);
}

uint32 updateRegistryEpoch = collectionManager.getUpdateRegistryEpoch();
// slither-disable-next-line incorrect-equality
if (updateRegistryEpoch <= epoch - 1) {
collectionManager.updateRegistry();
}
}

function disputeBiggestStakeProposed(
Expand All @@ -163,92 +146,76 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager
_executeDispute(epoch, blockIndex, blockId);
}

// Epoch X
// 0,1,2,3
// 1,2,3,4
// Deactivate 3

// Epoch X+1
// 0,1,2
// 1,2,4

// Only 1,2 revealed by stakers, in this epoch,
// so for 4 value should be used from previous
// Follwoing function allows dispute for so
function disputeForNonAssignedCollection(
// @dev : dispute to check if ids passed are correct or not,
// ids should be active ones, which were revealed this epoch
// id as input
// if totalInfluncedRevealed == 0, then id shouldnt be present
// !=0, id should be present
function disputeForProposedCollectionIds(
uint32 epoch,
uint8 blockIndex,
uint16 medianIndex
uint16 id
) external initialized checkEpochAndState(State.Dispute, epoch) {
require(medianIndex <= (collectionManager.getNumActiveCollections() - 1), "Invalid MedianIndex value");
require(voteManager.getTotalInfluenceRevealed(epoch, medianIndex) == 0, "Collec is revealed this epoch");

uint32 blockId = sortedProposedBlockIds[epoch][blockIndex];

require(proposedBlocks[epoch][blockId].valid, "Block already has been disputed");

uint16 currentId = proposedBlocks[epoch][blockId].ids[medianIndex];
uint16 oldIndex = collectionManager.getIdToIndexRegistryValue(currentId);
require(
proposedBlocks[epoch][blockId].medians[medianIndex] != blocks[epoch - 1].medians[oldIndex],
"Block proposed with corr medians"
);
_executeDispute(epoch, blockIndex, blockId);
}
uint16 activeCollectionIndex = collectionManager.getIdToIndexRegistryValue(id);
uint256 totalInfluenceRevealed = voteManager.getTotalInfluenceRevealed(epoch, activeCollectionIndex);

// Epoch X
// 0,1,2,3
// 1,2,3,4
// Deactivate 3

// Epoch X+1
// 0,1,2
// 1,2,4

// Propose
// [1,2,4]
// [100,200,400]
// In Dispute I pass 2nd Index

// Here thing is there is nothing stopping me from passing any deactivated asset also in place of 4
// 1,2,3
// 100,200,300
// This will pass in disputeForNonAssignedCollection(), as indeed value is 300 for id 3 in last epoch
// Or even repeating same thing
// For ex. consider case when there are lot of assets
// 1,2,4,4,4,4,4
// 100,200,400,400,400.....
// so as its dependant on user input, it can exploited
// to solve so, will need to have follwoing dispute

function disputeForProposedCollectionIds(uint32 epoch, uint8 blockIndex) external initialized checkEpochAndState(State.Dispute, epoch) {
uint32 blockId = sortedProposedBlockIds[epoch][blockIndex];
Structs.Block memory _block = proposedBlocks[epoch][blockId];

require(proposedBlocks[epoch][blockId].valid, "Block already has been disputed");
// shouldnt be present
if (totalInfluenceRevealed == 0) {
bool toDispute = false;
for (uint256 i = 0; i < _block.ids.length; i++)
0xcuriousapple marked this conversation as resolved.
Show resolved Hide resolved
if (_block.ids[i] == id) {
toDispute = true;
break;
}

bytes32 proposedHash = keccak256(abi.encodePacked(proposedBlocks[epoch][blockId].ids));
bytes32 actualHash = collectionManager.getActiveCollectionsHash();
require(toDispute, "Dispute: ID not present only");
}
// should be present
else {
bool toDispute = true;
for (uint256 i = 0; i < _block.ids.length; i++)
if (_block.ids[i] == id) {
toDispute = false;
break;
}
require(toDispute, "Dispute: ID present only");
}

require(proposedHash != actualHash, "Block proposed with corr ids");
_executeDispute(epoch, blockIndex, blockId);
}

// Complexity O(1)
function finalizeDispute(uint32 epoch, uint8 blockIndex) external initialized checkEpochAndState(State.Dispute, epoch) {
require(
disputes[epoch][msg.sender].accWeight == voteManager.getTotalInfluenceRevealed(epoch, disputes[epoch][msg.sender].medianIndex),
disputes[epoch][msg.sender].accWeight ==
voteManager.getTotalInfluenceRevealed(epoch, disputes[epoch][msg.sender].activeCollectionIndex),
"TIR is wrong"
); // TIR : total influence revealed
require(disputes[epoch][msg.sender].accWeight != 0, "Invalid dispute");
// Would revert if no block is proposed, or the asset specifed was not revealed
require(disputes[epoch][msg.sender].median > 0, "median can not be zero");
uint32 blockId = sortedProposedBlockIds[epoch][blockIndex];
require(proposedBlocks[epoch][blockId].valid, "Block already has been disputed");
uint16 medianIndex = disputes[epoch][msg.sender].medianIndex;
require(
proposedBlocks[epoch][blockId].medians[medianIndex] != disputes[epoch][msg.sender].median,
"Block proposed with same medians"
);
uint16 activeCollectionIndex = disputes[epoch][msg.sender].activeCollectionIndex;
// get position in block for that activeCollectionIndex
uint16 id = collectionManager.getIndexToIdRegistryValue(activeCollectionIndex);

Structs.Block memory _block = proposedBlocks[epoch][blockId];

uint32 proposedValue = 0;
for (uint256 i = 0; i < _block.ids.length; i++)
if (_block.ids[i] == id) {
0xcuriousapple marked this conversation as resolved.
Show resolved Hide resolved
proposedValue = proposedBlocks[epoch][blockId].medians[i];
break;
}

require(proposedValue != disputes[epoch][msg.sender].median, "Block proposed with same medians");
_executeDispute(epoch, blockIndex, blockId);
}

Expand All @@ -269,11 +236,20 @@ contract BlockManager is Initializable, BlockStorage, StateManager, BlockManager
return (blocks[epoch].proposerId != 0);
}

function getLatestResults(uint16 id) external view override returns (uint32) {
return latestResults[id];
}

function _confirmBlock(uint32 epoch, uint32 stakerId) internal {
uint32 blockId = sortedProposedBlockIds[epoch][uint8(blockIndexToBeConfirmed)];
blocks[epoch] = proposedBlocks[epoch][blockId];
bytes32 salt = keccak256(abi.encodePacked(epoch, blocks[epoch].medians)); // not iteration as it can be manipulated

Structs.Block memory _block = blocks[epoch];
for (uint256 i = 0; i < _block.ids.length; i++) {
latestResults[_block.ids[i]] = _block.medians[i];
}

emit BlockConfirmed(epoch, proposedBlocks[epoch][blockId].proposerId, proposedBlocks[epoch][blockId].medians, block.timestamp);

voteManager.storeSalt(salt);
Expand Down
34 changes: 7 additions & 27 deletions contracts/Core/CollectionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,14 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co
require(assetStatus != collections[id].active, "status not being changed");

uint32 epoch = _getEpoch();
// slither-disable-next-line incorrect-equality
if (updateRegistryEpoch <= epoch) {
_updateRegistry();
}

if (!collections[id].active) {
numActiveCollections = numActiveCollections + 1;
} else {
numActiveCollections = numActiveCollections - 1;
}

collections[id].active = assetStatus;
updateRegistryEpoch = epoch + 1;
_updateRegistry();
emit CollectionActivityStatus(collections[id].active, id, epoch, block.timestamp);
voteManager.storeDepth(_getDepth()); // update depth now only, as from next epoch's commit it starts
}
Expand All @@ -189,19 +184,12 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co
require(jobIDs.length > 0, "no jobs added");
require(tolerance <= maxTolerance, "Invalid tolerance value");

uint32 epoch = _getEpoch();

// slither-disable-next-line incorrect-equality
if (updateRegistryEpoch <= epoch) {
_updateRegistry();
}

numCollections = numCollections + 1;

collections[numCollections] = Structs.Collection(true, numCollections, power, tolerance, aggregationMethod, jobIDs, name);

numActiveCollections = numActiveCollections + 1;
updateRegistryEpoch = epoch + 1;
_updateRegistry();
emit CollectionCreated(numCollections, block.timestamp);

_setIDName(name, numCollections);
Expand Down Expand Up @@ -308,25 +296,21 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co
return numActiveCollections;
}

/// @inheritdoc ICollectionManager
function getUpdateRegistryEpoch() external view override returns (uint32) {
return updateRegistryEpoch;
}

/// @inheritdoc ICollectionManager
function getIdToIndexRegistryValue(uint16 id) external view override returns (uint16) {
require(collections[id].active, "Query for Inactive Collection");
return idToIndexRegistry[id];
}

/// @inheritdoc ICollectionManager
function getActiveCollectionsHash() external view override returns (bytes32 hash) {
hash = keccak256(abi.encodePacked(getActiveCollections()));
function getIndexToIdRegistryValue(uint16 index) external view override returns (uint16) {
0xcuriousapple marked this conversation as resolved.
Show resolved Hide resolved
return indexToIdRegistry[index];
}

/**
* @return array of active collections
*/
function getActiveCollections() public view returns (uint16[] memory) {
function getActiveCollections() external view returns (uint16[] memory) {
uint16[] memory result = new uint16[](numActiveCollections);
uint16 j = 0;
for (uint16 i = 1; i <= numCollections; i++) {
Expand All @@ -340,11 +324,7 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co

/// @inheritdoc ICollectionManager
function getResultFromID(uint16 _id) public view override returns (uint32, int8) {
uint16 index = idToIndexRegistry[_id];
uint32 epoch = _getEpoch();
uint32[] memory medians = blockManager.getBlock(epoch - 1).medians;
int8 power = collections[_id].power;
return (medians[index], power);
return (blockManager.getLatestResults(_id), collections[_id].power);
}

/**
Expand Down
Loading