Skip to content

Commit

Permalink
Merge branch 'main' into sygma-message-relayer
Browse files Browse the repository at this point in the history
  • Loading branch information
viatrix committed Oct 18, 2023
2 parents 8fc33e6 + 9d2e117 commit cd1deb9
Show file tree
Hide file tree
Showing 16 changed files with 284 additions and 16 deletions.
35 changes: 34 additions & 1 deletion packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

import { ILightClient } from "./interfaces/IDendrETH.sol";
import { ILightClient, LightClientUpdate } from "./interfaces/IDendrETH.sol";
import { SSZ } from "../Telepathy/libraries/SimpleSerialize.sol";
import { BlockHashOracleAdapter } from "../BlockHashOracleAdapter.sol";

contract DendrETHAdapter is BlockHashOracleAdapter {
error InvalidUpdate();
error BlockHeaderNotAvailable(uint256 slot);
error InvalidBlockNumberProof();
error InvalidBlockHashProof();
Expand Down Expand Up @@ -59,4 +60,36 @@ contract DendrETHAdapter is BlockHashOracleAdapter {

_storeHash(uint256(_chainId), _blockNumber, _blockHash);
}

/// @notice Updates DendrETH Light client and stores the given block
// for the update
function storeBlockHeader(
uint32 _chainId,
uint64 _slot,
uint256 _blockNumber,
bytes32[] calldata _blockNumberProof,
bytes32 _blockHash,
bytes32[] calldata _blockHashProof,
LightClientUpdate calldata update
) external {
ILightClient lightClient = ILightClient(dendrETHAddress);

lightClient.light_client_update(update);

if (lightClient.optimisticHeaderSlot() != _slot) {
revert InvalidUpdate();
}

bytes32 blockHeaderRoot = lightClient.optimisticHeaderRoot();

if (!SSZ.verifyBlockNumber(_blockNumber, _blockNumberProof, blockHeaderRoot)) {
revert InvalidBlockNumberProof();
}

if (!SSZ.verifyBlockHash(_blockHash, _blockHashProof, blockHeaderRoot)) {
revert InvalidBlockHashProof();
}

_storeHash(uint256(_chainId), _blockNumber, _blockHash);
}
}
16 changes: 16 additions & 0 deletions packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.17;

struct LightClientUpdate {
bytes32 attestedHeaderRoot;
uint256 attestedHeaderSlot;
bytes32 finalizedHeaderRoot;
bytes32 finalizedExecutionStateRoot;
uint256[2] a;
uint256[2][2] b;
uint256[2] c;
}

interface ILightClient {
function currentIndex() external view returns (uint256);

function optimisticHeaders(uint256 index) external view returns (bytes32);

function optimisticHeaderRoot() external view returns (bytes32);

function optimisticSlots(uint256 index) external view returns (uint256);

function optimisticHeaderSlot() external view returns (uint256);

function light_client_update(LightClientUpdate calldata update) external;
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { IAxiomV0 } from "./IAxiomV0.sol";
import { IAxiomV0StoragePf } from "./IAxiomV0StoragePf.sol";
// import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
import { Ownable } from "./Ownable.sol";
import { IHashi } from "../interfaces/IHashi.sol";
import { IOracleAdapter } from "../interfaces/IOracleAdapter.sol";
import { IHashi } from "../../interfaces/IHashi.sol";
import { IOracleAdapter } from "../../interfaces/IOracleAdapter.sol";

uint8 constant SLOT_NUMBER = 10;

Expand Down
File renamed without changes.
File renamed without changes.
11 changes: 11 additions & 0 deletions packages/evm/contracts/ownable/GiriGiriBashi.sol
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,17 @@ contract GiriGiriBashi is ShuSo {
updateHead(domain, id);
}

/// @dev Returns the hash agreed upon by a threshold of the enabled oraclesAdapters.
/// @param domain Uint256 identifier for the domain to query.
/// @param id Uint256 identifier to query.
/// @return hash Bytes32 hash agreed upon by a threshold of the oracles for the given domain.
/// @notice Reverts if no threshold is not reached.
/// @notice Reverts if no oracles are set for the given domain.
function getThresholdHash(uint256 domain, uint256 id) public returns (bytes32 hash) {
hash = _getThresholdHash(domain, id);
updateHead(domain, id);
}

/// @dev Returns the hash unanimously agreed upon by all of the given oraclesAdapters..
/// @param domain Uint256 identifier for the domain to query.
/// @param _adapters Array of oracle adapter addresses to query.
Expand Down
10 changes: 10 additions & 0 deletions packages/evm/contracts/ownable/ShoyuBashi.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ contract ShoyuBashi is ShuSo {
hash = _getUnanimousHash(domain, id);
}

/// @dev Returns the hash agreed upon by a threshold of the enabled oraclesAdapters.
/// @param domain Uint256 identifier for the domain to query.
/// @param id Uint256 identifier to query.
/// @return hash Bytes32 hash agreed upon by a threshold of the oracles for the given domain.
/// @notice Reverts if no threshold is not reached.
/// @notice Reverts if no oracles are set for the given domain.
function getThresholdHash(uint256 domain, uint256 id) public view returns (bytes32 hash) {
hash = _getThresholdHash(domain, id);
}

/// @dev Returns the hash unanimously agreed upon by all of the given oraclesAdapters..
/// @param domain Uint256 identifier for the domain to query.
/// @param _adapters Array of oracle adapter addresses to query.
Expand Down
38 changes: 38 additions & 0 deletions packages/evm/contracts/ownable/ShuSo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,44 @@ abstract contract ShuSo is OwnableUpgradeable {
hash = hashi.getHash(domain, id, _adapters);
}

/// @dev Returns the hash agreed upon by a threshold of the enabled oraclesAdapters.
/// @param domain Uint256 identifier for the domain to query.
/// @param id Uint256 identifier to query.
/// @return hash Bytes32 hash agreed upon by a threshold of the oracles for the given domain.
/// @notice Reverts if no threshold is not reached.
/// @notice Reverts if no oracles are set for the given domain.
function _getThresholdHash(uint256 domain, uint256 id) internal view returns (bytes32 hash) {
IOracleAdapter[] memory _adapters = getOracleAdapters(domain);
(uint256 threshold, uint256 count) = getThresholdAndCount(domain);
if (count == 0) revert NoAdaptersEnabled(address(this), domain);
if (_adapters.length < threshold) revert ThresholdNotMet(address(this));

// get hashes
bytes32[] memory hashes = new bytes32[](_adapters.length);
for (uint i = 0; i < _adapters.length; i++) {
try _adapters[i].getHashFromOracle(domain, id) returns (bytes32 currentHash) {
hashes[i] = currentHash;
} catch {}
}

// find a hash agreed on by a threshold of oracles
for (uint i = 0; i < hashes.length; i++) {
bytes32 baseHash = hashes[i];
if (baseHash == bytes32(0)) continue;

// increment num for each instance of the curent hash
uint256 num = 1;
for (uint j = 0; j < hashes.length; j++) {
if (baseHash == hashes[j] && i != j) {
num++;
// return current hash if num equals threshold
if (num == threshold) return hashes[i];
}
}
}
revert ThresholdNotMet(address(this));
}

/// @dev Returns the hash unanimously agreed upon by all of the given oraclesAdapters..
/// @param domain Uint256 identifier for the domain to query.
/// @param _adapters Array of oracle adapter addresses to query.
Expand Down
1 change: 1 addition & 0 deletions packages/evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"@gnosis.pm/zodiac": "^3.3.2",
"@openzeppelin/contracts-upgradeable": "^4.8.1",
"hardhat-change-network": "^0.0.7",
"hardhat-deploy": "^0.11.31",
"solidity-rlp": "^2.0.7"
}
}
35 changes: 33 additions & 2 deletions packages/evm/test/02_ShoyuBashi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ const setup = async () => {
const mockOracleAdapter = await MockOracleAdapter.deploy()
const anotherOracleAdapter = await MockOracleAdapter.deploy()

await mockOracleAdapter.setHashes(DOMAIN_ID, [0, 1], [HASH_ZERO, HASH_GOOD])
await anotherOracleAdapter.setHashes(DOMAIN_ID, [0, 1], [HASH_ZERO, HASH_GOOD])
await mockOracleAdapter.setHashes(DOMAIN_ID, [0, 1, 2], [HASH_ZERO, HASH_GOOD, HASH_GOOD])
await anotherOracleAdapter.setHashes(DOMAIN_ID, [0, 1, 2], [HASH_ZERO, HASH_GOOD, HASH_BAD])
await shoyuBashi.setThreshold(DOMAIN_ID, 2)

return {
Expand Down Expand Up @@ -278,6 +278,37 @@ describe("ShoyuBashi", function () {
})
})

describe("getThresholdHash()", function () {
it("Reverts if no adapters are enabled", async function () {
const { shoyuBashi } = await setup()
await expect(shoyuBashi.getThresholdHash(DOMAIN_ID, 1)).to.be.revertedWithCustomError(
shoyuBashi,
"NoAdaptersEnabled",
)
})
it("Reverts if threshold is not met", async function () {
const { shoyuBashi, mockOracleAdapter, anotherOracleAdapter } = await setup()
await shoyuBashi.enableOracleAdapters(DOMAIN_ID, [mockOracleAdapter.address, anotherOracleAdapter.address])
await expect(shoyuBashi.getThresholdHash(DOMAIN_ID, 2)).to.be.revertedWithCustomError(
shoyuBashi,
"ThresholdNotMet",
)
})
it("Reverts if threshold returns bytes(0)", async function () {
const { shoyuBashi, mockOracleAdapter, anotherOracleAdapter } = await setup()
await shoyuBashi.enableOracleAdapters(DOMAIN_ID, [mockOracleAdapter.address, anotherOracleAdapter.address])
await expect(shoyuBashi.getThresholdHash(DOMAIN_ID, 0)).to.be.revertedWithCustomError(
shoyuBashi,
"ThresholdNotMet",
)
})
it("Returns unanimous agreed on hash", async function () {
const { shoyuBashi, mockOracleAdapter, anotherOracleAdapter } = await setup()
await shoyuBashi.enableOracleAdapters(DOMAIN_ID, [mockOracleAdapter.address, anotherOracleAdapter.address])
expect(await shoyuBashi.getThresholdHash(DOMAIN_ID, 1)).to.equal(HASH_GOOD)
})
})

describe("getHash()", function () {
it("Reverts if threshold is not met", async function () {
const { shoyuBashi, mockOracleAdapter } = await setup()
Expand Down
16 changes: 16 additions & 0 deletions packages/evm/test/03_GiriGiriBashi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,22 @@ describe("GiriGiriBashi", function () {
})
})

describe("getThresholdHash()", function () {
it("Updates head for given domain", async function () {
const { giriGiriBashi, mockOracleAdapter, secondMockOracleAdapter, settings } = await setup()
await giriGiriBashi.enableOracleAdapters(
DOMAIN_ID,
[mockOracleAdapter.address, secondMockOracleAdapter.address],
[settings, settings],
)
const oldHead = await giriGiriBashi.heads(DOMAIN_ID)
expect(await giriGiriBashi.callStatic.getThresholdHash(DOMAIN_ID, 1)).to.equal(HASH_GOOD)
await giriGiriBashi.getThresholdHash(DOMAIN_ID, 1)
const newHead = await giriGiriBashi.heads(DOMAIN_ID)
expect(newHead).not.to.equal(oldHead)
})
})

describe("getHash()", function () {
it("Updates head for given domain", async function () {
const { giriGiriBashi, mockOracleAdapter, secondMockOracleAdapter, settings } = await setup()
Expand Down
2 changes: 1 addition & 1 deletion packages/evm/test/adapters/axiom/00_Play.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const setup = async () => {
}
}

describe("End-to-end tests", function () {
describe("Axiom E2E test", function () {
describe("Execution layer", function () {
it("Attest slots for the claimed block head with the block hash agreed on by N adapters", async function () {
const { amb, hashi, storageProof } = await setup()
Expand Down
Loading

0 comments on commit cd1deb9

Please sign in to comment.