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: finalizeUpgrade_v4 for legacy oracle #705

Merged
merged 2 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 9 additions & 0 deletions contracts/0.4.24/oracle/LegacyOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ contract LegacyOracle is Versioned, AragonApp {
) external onlyInit {
// Initializations for v0 --> v3
_checkContractVersion(0);
// deprecated version slot must be empty
require(CONTRACT_VERSION_POSITION_DEPRECATED.getStorageUint256() == 0, "WRONG_BASE_VERSION");
require(_lidoLocator != address(0), "ZERO_LOCATOR_ADDRESS");
ILidoLocator locator = ILidoLocator(_lidoLocator);

Expand All @@ -294,7 +296,11 @@ contract LegacyOracle is Versioned, AragonApp {
* Can be called only once.
*/
function finalizeUpgrade_v4(address _accountingOracle) external {
// deprecated version slot must be set to v3
require(CONTRACT_VERSION_POSITION_DEPRECATED.getStorageUint256() == 3, "WRONG_BASE_VERSION");
// current version slot must not be initialized yet
_checkContractVersion(0);

IHashConsensus consensus = IHashConsensus(IAccountingOracle(_accountingOracle).getConsensusContract());

_initialize_v4(_accountingOracle);
Expand All @@ -313,7 +319,10 @@ contract LegacyOracle is Versioned, AragonApp {
function _initialize_v4(address _accountingOracle) internal {
require(_accountingOracle != address(0), "ZERO_ACCOUNTING_ORACLE_ADDRESS");
ACCOUNTING_ORACLE_POSITION.setStorageAddress(_accountingOracle);
// write current version slot
_setContractVersion(4);
// reset deprecated version slot
CONTRACT_VERSION_POSITION_DEPRECATED.setStorageUint256(0);
}

function _getTime() internal view returns (uint256) {
Expand Down
15 changes: 9 additions & 6 deletions contracts/0.4.24/test_helpers/MockLegacyOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ contract MockLegacyOracle is ILegacyOracle, LegacyOracle {
_setChainSpec(ChainSpec(epochsPerFrame,slotsPerEpoch,secondsPerSlot,genesisTime));
}


function _getTime() internal view returns (uint256) {
address accountingOracle = ACCOUNTING_ORACLE_POSITION.getStorageAddress();
return ITimeProvider(accountingOracle).getTime();
Expand All @@ -63,8 +63,6 @@ contract MockLegacyOracle is ILegacyOracle, LegacyOracle {
return _getTime();
}



function handleConsensusLayerReport(uint256 refSlot, uint256 clBalance, uint256 clValidators)
external
{
Expand All @@ -85,13 +83,18 @@ contract MockLegacyOracle is ILegacyOracle, LegacyOracle {
_setChainSpec(ChainSpec(epochsPerFrame,slotsPerEpoch,secondsPerSlot,genesisTime));
LAST_COMPLETED_EPOCH_ID_POSITION.setStorageUint256(lastCompletedEpochId);
}

function setLastCompletedEpochId(uint256 lastCompletedEpochId) external {
LAST_COMPLETED_EPOCH_ID_POSITION.setStorageUint256(lastCompletedEpochId);
}

function initializeAsV3() external {
CONTRACT_VERSION_POSITION_DEPRECATED.setStorageUint256(3);
function initializeAsVersion(uint256 _version) external {
CONTRACT_VERSION_POSITION_DEPRECATED.setStorageUint256(_version);
}

// NB: overrides `getVersion()` to mimic the real legacy oracle
function getVersion() external view returns (uint256) {
return CONTRACT_VERSION_POSITION_DEPRECATED.getStorageUint256();
}

function setLido(address lido) external {
Expand Down
67 changes: 65 additions & 2 deletions test/0.4.24/legacy-oracle.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ contract('LegacyOracle', ([admin, stranger]) => {
newImplementation = await LegacyOracle.new({ from: admin })
proxy = await OssifiableProxy.new(oldImplementation.address, admin, '0x')
proxyAsOldImplementation = await MockLegacyOracle.at(proxy.address)
proxyAsNewImplementation = await LegacyOracle.at(proxy.address)
})

it('implementations are petrified', async () => {
Expand All @@ -185,7 +186,7 @@ contract('LegacyOracle', ([admin, stranger]) => {
})

it('set state to mimic legacy oracle', async () => {
await proxyAsOldImplementation.initializeAsV3()
await proxyAsOldImplementation.initializeAsVersion(3)
await proxyAsOldImplementation.setParams(
EPOCHS_PER_FRAME,
SLOTS_PER_EPOCH,
Expand All @@ -209,10 +210,72 @@ contract('LegacyOracle', ([admin, stranger]) => {
await proxyAsOldImplementation.setLido(deployedInfra.lido.address)
})

it('upgrade implementation', async () => {
it('cant upgrade from zero version', async () => {
// can't upgrade if old version is zero
await proxyAsOldImplementation.initializeAsVersion(0)
await proxy.proxy__upgradeTo(newImplementation.address)

await assert.reverts(
proxyAsNewImplementation.finalizeUpgrade_v4(deployedInfra.oracle.address),
'WRONG_BASE_VERSION'
)

await proxy.proxy__upgradeTo(oldImplementation.address)
})

it('cant upgrade from incorrect version', async () => {
// can't upgrade if old version is 4
await proxyAsOldImplementation.initializeAsVersion(4)
await proxy.proxy__upgradeTo(newImplementation.address)

await assert.reverts(
proxyAsNewImplementation.finalizeUpgrade_v4(deployedInfra.oracle.address),
'WRONG_BASE_VERSION'
)

await proxy.proxy__upgradeTo(oldImplementation.address)
})

it('cant initialize instead of upgrade from v3', async () => {
// can't initialize if old version is 3
await proxyAsOldImplementation.initializeAsVersion(3)
await proxy.proxy__upgradeTo(newImplementation.address)

await assert.reverts(
proxyAsNewImplementation.initialize(deployedInfra.locatorAddr, deployedInfra.consensus.address),
'WRONG_BASE_VERSION'
)

await proxy.proxy__upgradeTo(oldImplementation.address)
})

it('upgrade implementation from v3 to v4', async () => {
assert.equals(await proxyAsOldImplementation.getVersion(), 3)
await proxy.proxy__upgradeTo(newImplementation.address)
proxyAsNewImplementation = await LegacyOracle.at(proxy.address)
assert.equals(await proxyAsNewImplementation.getContractVersion(), 0)
await proxyAsNewImplementation.finalizeUpgrade_v4(deployedInfra.oracle.address)
assert.equals(await proxyAsNewImplementation.getContractVersion(), 4)
assert.equals(await proxyAsNewImplementation.getVersion(), 4)
})

it('cant upgrade v4 twice', async () => {
assert.equals(await proxyAsNewImplementation.getContractVersion(), 4)
assert.equals(await proxyAsNewImplementation.getVersion(), 4)

// can't upgrade twice
await assert.reverts(
proxyAsNewImplementation.finalizeUpgrade_v4(deployedInfra.oracle.address),
'WRONG_BASE_VERSION'
)
})

it('cant initialize v4 again', async () => {
// can't initialize
await assert.reverts(
proxyAsNewImplementation.initialize(deployedInfra.locatorAddr, deployedInfra.consensus.address),
'UNEXPECTED_CONTRACT_VERSION'
)
})

it('first report since migration', async () => {
Expand Down