Skip to content

Commit

Permalink
feat(ethexe): add timestamp to commitment (#4344)
Browse files Browse the repository at this point in the history
  • Loading branch information
breathx authored Nov 20, 2024
1 parent e511f97 commit 8c40587
Show file tree
Hide file tree
Showing 17 changed files with 146 additions and 21 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions ethexe/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,9 @@ impl Service {
db.set_block_header(block_data.hash, block_data.header);

let mut commitments = vec![];

let last_committed_chain = query.get_last_committed_chain(block_data.hash).await?;

for block_hash in last_committed_chain.into_iter().rev() {
let transitions = Self::process_one_block(db, query, processor, block_hash).await?;

Expand All @@ -366,8 +368,13 @@ impl Service {
continue;
}

let header = db
.block_header(block_hash)
.ok_or_else(|| anyhow!("header not found, but most exist"))?;

commitments.push(BlockCommitment {
block_hash,
block_timestamp: header.timestamp,
pred_block_hash: block_data.hash,
prev_commitment_hash: db
.block_prev_commitment(block_hash)
Expand Down
6 changes: 6 additions & 0 deletions ethexe/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,9 @@ impl From<wvara::RequestEvent> for BlockRequestEvent {
Self::WVara(value)
}
}

pub const fn u64_into_uint48_be_bytes_lossy(val: u64) -> [u8; 6] {
let [_, _, b1, b2, b3, b4, b5, b6] = val.to_be_bytes();

[b1, b2, b3, b4, b5, b6]
}
2 changes: 2 additions & 0 deletions ethexe/common/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub struct CodeCommitment {
#[derive(Clone, Debug, Default, Encode, Decode, PartialEq, Eq)]
pub struct BlockCommitment {
pub block_hash: H256,
/// represented as u48 in router contract
pub block_timestamp: u64,
pub prev_commitment_hash: H256,
pub pred_block_hash: H256,
pub transitions: Vec<StateTransition>,
Expand Down
4 changes: 4 additions & 0 deletions ethexe/contracts/src/IRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface IRouter {
address mirrorProxy;
address wrappedVara;
bytes32 lastBlockCommitmentHash;
uint48 lastBlockCommitmentTimestamp;
uint256 signingThresholdPercentage;
uint64 baseWeight;
uint128 valuePerWeight;
Expand All @@ -38,6 +39,7 @@ interface IRouter {

struct BlockCommitment {
bytes32 blockHash;
uint48 blockTimestamp;
bytes32 prevCommitmentHash;
bytes32 predBlockHash;
StateTransition[] transitions;
Expand Down Expand Up @@ -165,6 +167,8 @@ interface IRouter {

function lastBlockCommitmentHash() external view returns (bytes32);

function lastBlockCommitmentTimestamp() external view returns (uint48);

function wrappedVara() external view returns (address);

function mirrorProxy() external view returns (address);
Expand Down
12 changes: 11 additions & 1 deletion ethexe/contracts/src/Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient {
return router.lastBlockCommitmentHash;
}

function lastBlockCommitmentTimestamp() public view returns (uint48) {
Storage storage router = _getStorage();
return router.lastBlockCommitmentTimestamp;
}

function wrappedVara() public view returns (address) {
Storage storage router = _getStorage();
return router.wrappedVara;
Expand Down Expand Up @@ -355,6 +360,7 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient {
* @dev SECURITY: this settlement should be performed before any other calls to avoid reentrancy.
*/
router.lastBlockCommitmentHash = blockCommitment.blockHash;
router.lastBlockCommitmentTimestamp = blockCommitment.blockTimestamp;

bytes memory transitionsHashes;

Expand All @@ -370,6 +376,7 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient {

return _blockCommitmentHash(
blockCommitment.blockHash,
blockCommitment.blockTimestamp,
blockCommitment.prevCommitmentHash,
blockCommitment.predBlockHash,
keccak256(transitionsHashes)
Expand Down Expand Up @@ -450,11 +457,14 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient {

function _blockCommitmentHash(
bytes32 blockHash,
uint48 blockTimestamp,
bytes32 prevCommitmentHash,
bytes32 predBlockHash,
bytes32 transitionsHashesHash
) private pure returns (bytes32) {
return keccak256(abi.encodePacked(blockHash, prevCommitmentHash, predBlockHash, transitionsHashesHash));
return keccak256(
abi.encodePacked(blockHash, blockTimestamp, prevCommitmentHash, predBlockHash, transitionsHashesHash)
);
}

function _stateTransitionHash(
Expand Down
3 changes: 2 additions & 1 deletion ethexe/contracts/test/Router.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ contract RouterTest is Test {
transitionsArray[0] =
IRouter.StateTransition(actorId, bytes32(uint256(1)), address(0), 0, valueClaims, outgoingMessages);
blockCommitmentsArray[0] = IRouter.BlockCommitment(
bytes32(uint256(1)), bytes32(uint256(0)), blockhash(block.number - 1), transitionsArray
bytes32(uint256(1)), uint48(0), bytes32(uint256(0)), blockhash(block.number - 1), transitionsArray
);

commitBlocks(blockCommitmentsArray);
Expand Down Expand Up @@ -188,6 +188,7 @@ contract RouterTest is Test {
return keccak256(
abi.encodePacked(
commitment.blockHash,
commitment.blockTimestamp,
commitment.prevCommitmentHash,
commitment.predBlockHash,
keccak256(transitionsHashesBytes)
Expand Down
2 changes: 1 addition & 1 deletion ethexe/ethereum/Mirror.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/MirrorProxy.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/Router.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/WrappedVara.json

Large diffs are not rendered by default.

41 changes: 37 additions & 4 deletions ethexe/ethereum/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use alloy::{primitives::U256 as AlloyU256, sol};
use alloy::{primitives::Uint, sol};
use ethexe_common::{mirror, router, wvara};
use gear_core::message::ReplyDetails;
use gear_core_errors::ReplyCode;
use gprimitives::U256;

pub(crate) type Uint256 = Uint<256, 4>;
pub(crate) type Uint48 = Uint<48, 1>;

sol!(
#[sol(rpc)]
IMirror,
Expand Down Expand Up @@ -53,12 +56,16 @@ sol!(
"WrappedVara.json"
);

pub(crate) fn uint256_to_u128_lossy(value: AlloyU256) -> u128 {
pub(crate) fn uint256_to_u128_lossy(value: Uint256) -> u128 {
let [low, high, ..] = value.into_limbs();

((high as u128) << 64) | (low as u128)
}

pub(crate) fn u64_to_uint48_lossy(value: u64) -> Uint48 {
Uint48::try_from(value).unwrap_or(Uint48::MAX)
}

/* From common types to alloy */

impl From<router::CodeCommitment> for IRouter::CodeCommitment {
Expand All @@ -74,13 +81,15 @@ impl From<router::BlockCommitment> for IRouter::BlockCommitment {
fn from(
router::BlockCommitment {
block_hash,
block_timestamp,
prev_commitment_hash,
pred_block_hash,
transitions,
}: router::BlockCommitment,
) -> Self {
Self {
blockHash: block_hash.to_fixed_bytes().into(),
blockTimestamp: u64_to_uint48_lossy(block_timestamp),
prevCommitmentHash: prev_commitment_hash.to_fixed_bytes().into(),
predBlockHash: pred_block_hash.to_fixed_bytes().into(),
transitions: transitions.into_iter().map(Into::into).collect(),
Expand Down Expand Up @@ -326,8 +335,32 @@ impl From<IWrappedVara::Approval> for wvara::Event {

#[test]
fn cast_is_correct() {
use rand::Rng;

let mut rng = rand::thread_rng();

// uint256 -> u128
assert_eq!(uint256_to_u128_lossy(Uint256::MAX), u128::MAX);

for _ in 0..10 {
let res: u128 = rand::random();
assert_eq!(uint256_to_u128_lossy(AlloyU256::from(res)), res);
let val: u128 = rng.gen();
let uint256 = Uint256::from(val);

assert_eq!(uint256_to_u128_lossy(uint256), val);
}

// u64 -> uint48
assert_eq!(u64_to_uint48_lossy(u64::MAX), Uint48::MAX);

for _ in 0..10 {
let val = rng.gen_range(0..=Uint48::MAX.into_limbs()[0]);
let uint48 = Uint48::from(val);

assert_eq!(u64_to_uint48_lossy(val), uint48);

assert_eq!(
ethexe_common::u64_into_uint48_be_bytes_lossy(val),
uint48.to_be_bytes()
);
}
}
3 changes: 3 additions & 0 deletions ethexe/sequencer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ anyhow.workspace = true
futures.workspace = true
tokio.workspace = true
indexmap.workspace = true

[dev-dependencies]
rand.workspace = true
3 changes: 3 additions & 0 deletions ethexe/sequencer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,18 +683,21 @@ mod tests {

let commitment1 = BlockCommitment {
block_hash: H256::random(),
block_timestamp: rand::random(),
prev_commitment_hash: H256::random(),
pred_block_hash: H256::random(),
transitions: Default::default(),
};
let commitment2 = BlockCommitment {
block_hash: H256::random(),
block_timestamp: rand::random(),
prev_commitment_hash: commitment1.block_hash,
pred_block_hash: H256::random(),
transitions: Default::default(),
};
let commitment3 = BlockCommitment {
block_hash: H256::random(),
block_timestamp: rand::random(),
prev_commitment_hash: commitment1.block_hash,
pred_block_hash: H256::random(),
transitions: Default::default(),
Expand Down
3 changes: 3 additions & 0 deletions ethexe/signer/src/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,14 @@ impl ToDigest for BlockCommitment {
// To avoid missing incorrect hashing while developing.
let Self {
block_hash,
block_timestamp,
prev_commitment_hash,
pred_block_hash,
transitions,
} = self;

hasher.update(block_hash.as_bytes());
hasher.update(ethexe_common::u64_into_uint48_be_bytes_lossy(*block_timestamp).as_slice());
hasher.update(prev_commitment_hash.as_bytes());
hasher.update(pred_block_hash.as_bytes());
hasher.update(transitions.to_digest().as_ref());
Expand Down Expand Up @@ -225,6 +227,7 @@ mod tests {

let block_commitment = BlockCommitment {
block_hash: H256::from([0; 32]),
block_timestamp: 0,
pred_block_hash: H256::from([1; 32]),
prev_commitment_hash: H256::from([2; 32]),
transitions: transitions.clone(),
Expand Down
1 change: 1 addition & 0 deletions ethexe/validator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ static_init = "1.0.3"

[dev-dependencies]
ethexe-db.workspace = true
rand.workspace = true
Loading

0 comments on commit 8c40587

Please sign in to comment.