Skip to content

Commit

Permalink
Adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
0xfornax committed Aug 27, 2024
1 parent ea4f086 commit 74ffd04
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ pragma abicoder v2;
// SPDX-License-Identifier: GPL-3.0-only

import "../RocketBase.sol";
import "../../interface/util/AddressLinkedQueueStorageInterface.sol";
import "../../interface/util/LinkedListStorageInterface.sol";

/// @notice Address linked queue storage helper for RocketStorage data (linked list implementation)
contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInterface {
/// @notice A linked list storage helper for the deposit requests queue data
contract LinkedListStorage is RocketBase, LinkedListStorageInterface {

// Constants for packing queue metadata into a single uint256
uint256 constant internal startOffset = 256 - 64;
uint256 constant internal endOffset = 256 - 128;
uint256 constant internal lengthOffset = 256 - 192;

// Constants for packing a deposit queue struct into a single uint256
// Constants for packing a deposit item (struct) into a single uint256
uint256 constant internal receiverOffset = 256 - 160;
uint256 constant internal indexOffset = 256 - 160 - 32;
uint256 constant internal suppliedOffset = 256 - 160 - 32 - 32;
Expand All @@ -29,27 +29,22 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
/// @notice The number of items in the queue
/// @param _namespace defines the queue to be used
function getLength(bytes32 _namespace) override public view returns (uint256) {
return uint256(uint64(getUint(keccak256(abi.encodePacked(_namespace, ".data"))) >> lengthOffset));
return uint64(getUint(keccak256(abi.encodePacked(_namespace, ".data"))) >> lengthOffset);
}

/// @notice The item in a queue by index
/// @param _namespace defines the queue to be used
/// @param _index the item index
function getItem(bytes32 _namespace, uint256 _index) override external view returns (DepositQueueValue memory) {
uint256 index = getUint(keccak256(abi.encodePacked(_namespace, ".data"))) >> startOffset + _index;
uint256 packedValue = getUint(keccak256(abi.encodePacked(_namespace, ".item", index)));
return unpackDepositQueueValue(packedValue);
uint256 packedValue = getUint(keccak256(abi.encodePacked(_namespace, ".item", _index)));
return _unpackItem(packedValue);
}

/// @notice The index of an item in a queue. Returns -1 if the value is not found
/// @notice The index of an item in a queue. Returns 0 if the value is not found
/// @param _namespace defines the queue to be used
/// @param _value the deposit queue value
function getIndexOf(bytes32 _namespace, DepositQueueValue memory _value) override external view returns (int) {
uint256 index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId)));
if (index > 0) {
return int256(index);
}
return -1;
function getIndexOf(bytes32 _namespace, DepositQueueValue memory _value) override external view returns (uint256) {
return getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId)));
}

/// @notice Finds an item index in a queue and returns the previous item
Expand All @@ -59,7 +54,7 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
uint256 index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId)));
if (index > 0) {
uint256 previousIndex = getUint(keccak256(abi.encodePacked(_namespace, ".prev", index)));
previousItem = unpackDepositQueueValue(getUint(keccak256(abi.encodePacked(_namespace, ".item", previousIndex))));
previousItem = _unpackItem(getUint(keccak256(abi.encodePacked(_namespace, ".item", previousIndex))));
}
}

Expand All @@ -70,16 +65,22 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
uint256 index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId)));
if (index > 0) {
uint256 nextIndex = getUint(keccak256(abi.encodePacked(_namespace, ".next", index)));
nextItem = unpackDepositQueueValue(getUint(keccak256(abi.encodePacked(_namespace, ".item", nextIndex))));
nextItem = _unpackItem(getUint(keccak256(abi.encodePacked(_namespace, ".item", nextIndex))));
}
}

/// @notice Add an item to the end of the list. Requires that the item does not exist in the list
/// @param _namespace defines the queue to be used
/// @param _value the deposit queue value
function enqueueItem(bytes32 _namespace, DepositQueueValue memory _value) virtual override external {
// onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract {
require(getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId))) == 0, "Item already exists in queue");
/// @param _item the deposit queue item to be added
function enqueueItem(bytes32 _namespace, DepositQueueValue memory _item) virtual override external onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract {
_enqueueItem(_namespace, _item);
}

/// @notice Internal function created to allow testing enqueueItem
/// @param _namespace defines the queue to be used
/// @param _item the deposit queue value
function _enqueueItem(bytes32 _namespace, DepositQueueValue memory _item) internal {
require(getUint(keccak256(abi.encodePacked(_namespace, ".index", _item.receiver, _item.validatorId))) == 0, "Item already exists in queue");
uint256 data = getUint(keccak256(abi.encodePacked(_namespace, ".data")));
uint256 endIndex = uint64(data >> endOffset);
uint256 newIndex = endIndex + 1;
Expand All @@ -93,8 +94,8 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
data |= newIndex << startOffset;
}

setUint(keccak256(abi.encodePacked(_namespace, ".item", newIndex)), packDepositQueueValue(_value));
setUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId)), newIndex);
setUint(keccak256(abi.encodePacked(_namespace, ".item", newIndex)), _packItem(_item));
setUint(keccak256(abi.encodePacked(_namespace, ".index", _item.receiver, _item.validatorId)), newIndex);
// clear the 64 bits used to stored the 'end' pointer
data &= ~(uint256(ones64Bits) << endOffset);
data |= newIndex << endOffset;
Expand All @@ -110,11 +111,18 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
/// @notice Remove an item from the start of a queue and return it. Requires that the queue is not empty
/// @param _namespace defines the queue to be used
function dequeueItem(bytes32 _namespace) public virtual override onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract returns (DepositQueueValue memory item) {
require(getLength(_namespace) > 0, "Queue is empty");
return _dequeueItem(_namespace);
}

/// @notice Remove an item from the start of a queue and return it. Requires that the queue is not empty
/// @param _namespace defines the queue to be used
function _dequeueItem(bytes32 _namespace) internal returns (DepositQueueValue memory item) {
uint256 data = getUint(keccak256(abi.encodePacked(_namespace, ".data")));
uint256 length = uint64(data >> lengthOffset);
require(length > 0, "Queue can't be empty");
uint256 start = uint64(data >> startOffset);
uint256 packedItem = getUint(keccak256(abi.encodePacked(_namespace, ".item", start)));
item = unpackDepositQueueValue(packedItem);
item = _unpackItem(packedItem);

uint256 nextItem = getUint(keccak256(abi.encodePacked(_namespace, ".next", start)));
// clear the 64 bits used to stored the 'start' pointer
Expand All @@ -130,19 +138,26 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
}

// Update the length of the queue
uint256 currentLength = uint64(data >> lengthOffset);
// clear the 64 bits used to stored the 'length' information
data &= ~(uint256(ones64Bits) << lengthOffset);
data |= (currentLength -1) << lengthOffset;
data |= (length - 1) << lengthOffset;
setUint(keccak256(abi.encodePacked(_namespace, ".data")), data);

return item;
}

/// @notice Removes an item from a queue. Requires that the item exists in the queue
/// @param _namespace defines the queue to be used
function removeItem(bytes32 _namespace, DepositQueueValue memory _value) public virtual override onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract {
uint256 index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId)));
/// @param _item to be removed from the queue
function removeItem(bytes32 _namespace, DepositQueueValue memory _item) public virtual override onlyLatestContract("addressLinkedListStorage", address(this)) onlyLatestNetworkContract {
_removeItem(_namespace, _item);
}

/// @notice Internal funciton to remove an item from a queue. Requires that the item exists in the queue
/// @param _namespace defines the queue to be used
/// @param _item to be removed from the queue
function _removeItem(bytes32 _namespace, DepositQueueValue memory _item) internal {
uint256 index = getUint(keccak256(abi.encodePacked(_namespace, ".index", _item.receiver, _item.validatorId)));
uint256 data = getUint(keccak256(abi.encodePacked(_namespace, ".data")));
require(index > 0, "Item does not exist in queue");

Expand All @@ -169,7 +184,7 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
data |= prevIndex << endOffset;
}

setUint(keccak256(abi.encodePacked(_namespace, ".index", _value.receiver, _value.validatorId)), 0);
setUint(keccak256(abi.encodePacked(_namespace, ".index", _item.receiver, _item.validatorId)), 0);
setUint(keccak256(abi.encodePacked(_namespace, ".next", index)), 0);
setUint(keccak256(abi.encodePacked(_namespace, ".prev", index)), 0);

Expand All @@ -182,21 +197,21 @@ contract AddressLinkedQueueStorage is RocketBase, AddressLinkedQueueStorageInter
}

/// @notice packs a deposit queue value into a single uint256
/// @param _struct the deposit queue value to be packed
function packDepositQueueValue(DepositQueueValue memory _struct) internal pure returns (uint256 packed) {
packed |= uint256(uint160(_struct.receiver)) << receiverOffset;
packed |= uint256(_struct.validatorId) << indexOffset;
packed |= uint256(_struct.suppliedValue) << suppliedOffset;
packed |= uint256(_struct.requestedValue);
/// @param _item the deposit queue item to be packed
function _packItem(DepositQueueValue memory _item) internal pure returns (uint256 packed) {
packed |= uint256(uint160(_item.receiver)) << receiverOffset;
packed |= uint256(_item.validatorId) << indexOffset;
packed |= uint256(_item.suppliedValue) << suppliedOffset;
packed |= uint256(_item.requestedValue);
}

/// @notice unpacks an uint256 value into a deposit queue struct
/// @param _packedValue the packed deposit queue value
function unpackDepositQueueValue(uint256 _packedValue) internal pure returns (DepositQueueValue memory value) {
value.receiver = address(uint160(_packedValue >> receiverOffset));
value.validatorId = uint32(_packedValue >> indexOffset);
value.suppliedValue = uint32(_packedValue >> suppliedOffset);
value.requestedValue = uint32(_packedValue);
function _unpackItem(uint256 _packedValue) internal pure returns (DepositQueueValue memory item) {
item.receiver = address(uint160(_packedValue >> receiverOffset));
item.validatorId = uint32(_packedValue >> indexOffset);
item.suppliedValue = uint32(_packedValue >> suppliedOffset);
item.requestedValue = uint32(_packedValue);
}

}
43 changes: 43 additions & 0 deletions contracts/contract/util/LinkedListStorageHelper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pragma solidity 0.8.18;
pragma abicoder v2;

// SPDX-License-Identifier: GPL-3.0-only

import "./LinkedListStorage.sol";

/// @notice A linked list storage helper to test internal functions
contract LinkedListStorageHelper is LinkedListStorage {

// Construct
constructor(RocketStorageInterface _rocketStorageAddress) LinkedListStorage(_rocketStorageAddress) {
version = 1;
}

/// @notice Add an item to the end of the list. Requires that the item does not exist in the list
/// @param _namespace defines the queue to be used
/// @param _item the deposit queue item
function enqueueItem(bytes32 _namespace, DepositQueueValue memory _item) public override {
_enqueueItem(_namespace, _item);
}

/// @notice Remove an item from the start of a queue and return it. Requires that the queue is not empty
/// @param _namespace defines the queue to be used
function dequeueItem(bytes32 _namespace) public virtual override returns (DepositQueueValue memory item) {
return _dequeueItem(_namespace);
}

/// @notice Removes an item from a queue. Requires that the item exists in the queue
/// @param _namespace to be used
/// @param _item to be removed from the queue
function removeItem(bytes32 _namespace, DepositQueueValue memory _item) public virtual override {
return _removeItem(_namespace, _item);
}

function packItem(DepositQueueValue memory _item) public pure returns (uint256 packed) {
return _packItem(_item);
}

function unpackItem(uint256 _item) public pure returns (DepositQueueValue memory item) {
return _unpackItem(_item);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ pragma abicoder v2;
// SPDX-License-Identifier: GPL-3.0-only

struct DepositQueueValue {
address receiver; // the megapool address
address receiver; // the address that will receive the requested value
uint32 validatorId; // internal validator id
uint32 suppliedValue; // in milliether
uint32 requestedValue; // in milliether
}

interface AddressLinkedQueueStorageInterface {
function getLength(bytes32 _namespace) external view returns (uint);
interface LinkedListStorageInterface {
function getLength(bytes32 _namespace) external view returns (uint256);
function getItem(bytes32 _namespace, uint _index) external view returns (DepositQueueValue memory);
function getIndexOf(bytes32 _namespace, DepositQueueValue memory _value) external view returns (int);
function getIndexOf(bytes32 _namespace, DepositQueueValue memory _value) external view returns (uint256);
function enqueueItem(bytes32 _namespace, DepositQueueValue memory _value) external;
function dequeueItem(bytes32 _namespace) external returns (DepositQueueValue memory);
function removeItem(bytes32 _namespace, DepositQueueValue memory _value) external;
Expand Down
4 changes: 2 additions & 2 deletions test/_helpers/deployment.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/*** Dependencies ********************/
import { RocketDAOProtocolSettingsNode, RocketStorage } from '../_utils/artifacts';
import { setDAOProtocolBootstrapSetting } from '../dao/scenario-dao-protocol-bootstrap';
import { LinkedListStorage, RocketStorage } from '../_utils/artifacts';

const hre = require('hardhat');
const pako = require('pako');
Expand Down Expand Up @@ -101,6 +100,7 @@ const contracts = {
rocketDAOProtocolProposal: artifacts.require('RocketDAOProtocolProposal.sol'),
// Utils
addressQueueStorage: artifacts.require('AddressQueueStorage.sol'),
LinkedListStorage: artifacts.require('LinkedListStorageHelper.sol'),
addressSetStorage: artifacts.require('AddressSetStorage.sol'),
};

Expand Down
3 changes: 3 additions & 0 deletions test/_utils/artifacts.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { artifacts } from "hardhat";

export const RocketAuctionManager = artifacts.require('RocketAuctionManager.sol');
export const RocketClaimDAO = artifacts.require('RocketClaimDAO.sol');
export const RocketDAONodeTrusted = artifacts.require('RocketDAONodeTrusted.sol');
Expand Down Expand Up @@ -50,6 +52,7 @@ export const RocketMinipoolQueue = artifacts.require('RocketMinipoolQueue.sol');
export const RocketNodeDeposit = artifacts.require('RocketNodeDeposit.sol');
export const RocketMinipoolDelegate = artifacts.require('RocketMinipoolDelegate.sol');
export const RocketDAOProtocolSettingsMinipool = artifacts.require('RocketDAOProtocolSettingsMinipool.sol');
export const LinkedListStorage = artifacts.require('LinkedListStorageHelper.sol');
export const RocketDepositPool = artifacts.require('RocketDepositPool.sol');
export const RocketMinipoolBondReducer = artifacts.require('RocketMinipoolBondReducer.sol');
export const RocketNetworkSnapshots = artifacts.require('RocketNetworkSnapshots.sol');
Expand Down
2 changes: 1 addition & 1 deletion test/deposit/deposit-pool-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getDepositSetting } from '../_helpers/settings';
import { deposit } from './scenario-deposit';
import {
RocketDAONodeTrustedSettingsMembers,
RocketDAOProtocolSettingsDeposit, RocketDepositPool,
RocketDAOProtocolSettingsDeposit, RocketDepositPool, AddressLinkedQueueStorage
} from '../_utils/artifacts';
import { setDAOProtocolBootstrapSetting } from '../dao/scenario-dao-protocol-bootstrap';
import { setDAONodeTrustedBootstrapSetting } from '../dao/scenario-dao-node-trusted-bootstrap'
Expand Down
2 changes: 2 additions & 0 deletions test/rocket-pool-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { injectBNHelpers } from './_helpers/bn';
import { checkInvariants } from './_helpers/invariants';
import networkSnapshotsTests from './network/network-snapshots-tests';
import networkVotingTests from './network/network-voting-tests';
import utilTests from './util/util-tests';

// Header
console.log('\n');
Expand Down Expand Up @@ -85,3 +86,4 @@ nodeDistributorTests();
rethTests();
rplTests();
rewardsPoolTests();
utilTests();
Loading

0 comments on commit 74ffd04

Please sign in to comment.