Skip to content

Commit

Permalink
Merge pull request #84 from zama-ai/updates2
Browse files Browse the repository at this point in the history
refactor: immutable euint64 and skipped test
  • Loading branch information
PacificYield authored Dec 20, 2024
2 parents 0198603 + 6030338 commit a91c46e
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 43 deletions.
32 changes: 12 additions & 20 deletions contracts/governance/ConfidentialERC20Votes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia

/// @notice Constant for zero using TFHE.
/// @dev Since it is expensive to compute 0, it is stored instead.
/// However, is not possible to define it as constant due to TFHE constraints.
/* solhint-disable var-name-mixedcase*/
euint64 private _EUINT64_ZERO;
euint64 private immutable _EUINT64_ZERO;

/**
* @param owner_ Owner address.
Expand Down Expand Up @@ -168,11 +166,7 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia
revert GovernorInvalid();
}

if (blockNumber >= block.number) {
revert BlockNumberEqualOrHigherThanCurrentBlock();
}

votes = _getPriorVote(account, blockNumber);
votes = getPriorVotes(account, blockNumber);
TFHE.allow(votes, msg.sender);
}

Expand Down Expand Up @@ -223,26 +217,24 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia
_moveDelegates(currentDelegate, delegatee, delegatorBalance);
}

function _getPriorVote(address account, uint256 blockNumber) internal view returns (euint64 votes) {
function _getPriorVote(address account, uint256 blockNumber) internal view virtual returns (euint64 votes) {
uint32 nCheckpoints = numCheckpoints[account];

if (nCheckpoints == 0) {
/// If there is no checkpoint for the `account`, return encrypted zero.
/// @dev It will not be possible to reencrypt it by the `account`.
votes = _EUINT64_ZERO;
/// @dev If there is no checkpoint for the `account`, return empty handle.
return votes;
} else if (_checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
/// First, check the most recent balance.
votes = _checkpoints[account][nCheckpoints - 1].votes;
/// @dev First, check the most recent balance.
return _checkpoints[account][nCheckpoints - 1].votes;
} else if (_checkpoints[account][0].fromBlock > blockNumber) {
/// Then, check if there is zero balance.
/// @dev It will not be possible to reencrypt it by the `account`.
votes = _EUINT64_ZERO;
/// @dev Then, check if there is zero balance. If so, return empty handle.
return votes;
} else {
/// Else, search for the voting power at the `blockNumber`.
/// @dev Else, search for the voting power at the `blockNumber`.
uint32 lower = 0;
uint32 upper = nCheckpoints - 1;
while (upper > lower) {
/// Ceil to avoid overflow.
/// @dev Ceil to avoid overflow.
uint32 center = upper - (upper - lower) / 2;
Checkpoint memory cp = _checkpoints[account][center];

Expand All @@ -254,7 +246,7 @@ abstract contract ConfidentialERC20Votes is IConfidentialERC20Votes, Confidentia
upper = center - 1;
}
}
votes = _checkpoints[account][lower].votes;
return _checkpoints[account][lower].votes;
}
}

Expand Down
18 changes: 6 additions & 12 deletions contracts/governance/ConfidentialGovernorAlpha.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,12 @@ abstract contract ConfidentialGovernorAlpha is Ownable2Step, GatewayCaller {
ICompoundTimelock public immutable TIMELOCK;

/// @notice Constant for zero using TFHE.
/// @dev Since it is expensive to compute 0, it is stored instead.
/// However, is not possible to define it as constant due to TFHE constraints.
/* solhint-disable var-name-mixedcase*/
euint64 private _EUINT64_ZERO;
/// @dev Since it is expensive to compute 0, it is stored once instead.
euint64 private immutable _EUINT64_ZERO;

/// @notice Constant for PROPOSAL_THRESHOLD using TFHE.
/// @dev Since it is expensive to compute 0, it is stored instead.
/// However, is not possible to define it as constant due to TFHE constraints.
/* solhint-disable var-name-mixedcase*/
euint64 private _EUINT64_PROPOSAL_THRESHOLD;
/// @dev Since it is expensive to compute the PROPOSAL_THRESHOLD, it is stored once instead.
euint64 private immutable _EUINT64_PROPOSAL_THRESHOLD;

/// @notice The total number of proposals made.
/// It includes all proposals, including the ones that
Expand Down Expand Up @@ -465,10 +461,8 @@ abstract contract ConfidentialGovernorAlpha is Ownable2Step, GatewayCaller {
description
);

ebool canPropose = TFHE.lt(
_EUINT64_PROPOSAL_THRESHOLD,
CONFIDENTIAL_ERC20_VOTES.getPriorVotesForGovernor(msg.sender, block.number - 1)
);
euint64 priorVotes = CONFIDENTIAL_ERC20_VOTES.getPriorVotesForGovernor(msg.sender, block.number - 1);
ebool canPropose = TFHE.lt(_EUINT64_PROPOSAL_THRESHOLD, priorVotes);

uint256[] memory cts = new uint256[](1);
cts[0] = Gateway.toUint256(canPropose);
Expand Down
1 change: 1 addition & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const config: HardhatUserConfig = {
},
networks: {
hardhat: {
gas: "auto",
accounts: {
count: 10,
mnemonic,
Expand Down
20 changes: 9 additions & 11 deletions test/governance/ConfidentialERC20Votes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,12 @@ describe("ConfidentialERC20Votes", function () {
.connect(this.signers.bob)
.getPriorVotes(this.signers.bob.address, latestBlockNumber);

// It is an encrypted constant that is not reencryptable by Bob.
expect(currentVoteHandle).not.to.be.eq(0n);
// The handle is not set.
expect(currentVoteHandle).to.be.eq(0n);

await expect(
reencryptEuint64(this.signers.bob, this.instance, currentVoteHandle, this.confidentialERC20Votes),
).to.be.rejectedWith("Invalid contract address.");
).to.be.rejectedWith("Handle is not initialized");

// 3. If a checkpoint exists using getPriorVotes but block.number < block of first checkpoint
latestBlockNumber = await ethers.provider.getBlockNumber();
Expand All @@ -408,11 +408,11 @@ describe("ConfidentialERC20Votes", function () {
.getPriorVotes(this.signers.bob.address, latestBlockNumber);

// It is an encrypted constant that is not reencryptable by Bob.
expect(currentVoteHandle).not.to.be.eq(0n);
expect(currentVoteHandle).to.eq(0n);

await expect(
reencryptEuint64(this.signers.bob, this.instance, currentVoteHandle, this.confidentialERC20Votes),
).to.be.rejectedWith("Invalid contract address.");
).to.be.rejectedWith("Handle is not initialized");
});

it("can do multiple checkpoints and access the values when needed", async function () {
Expand Down Expand Up @@ -541,18 +541,16 @@ describe("ConfidentialERC20Votes", function () {
);
});

// TODO: fix issue with mining
it.skip("number of checkpoints is incremented once per block, even when written multiple times in same block", async function () {
it("number of checkpoints is incremented once per block, even when written multiple times in same block", async function () {
await network.provider.send("evm_setAutomine", [false]);
await network.provider.send("evm_setIntervalMining", [0]);

// do two checkpoints in same block
const tx1 = this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.bob);
const tx2 = this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.carol);
// @dev There are two checkpoints in the same block.
await this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.bob);
await this.confidentialERC20Votes.connect(this.signers.alice).delegate(this.signers.carol);

await network.provider.send("evm_mine");
await network.provider.send("evm_setAutomine", [true]);
await Promise.all([tx1, tx2]);

expect(await this.confidentialERC20Votes.numCheckpoints(this.signers.alice.address)).to.be.equal(0n);
expect(await this.confidentialERC20Votes.numCheckpoints(this.signers.bob.address)).to.be.equal(1n);
Expand Down
2 changes: 2 additions & 0 deletions test/governance/ConfidentialGovernorAlpha.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,8 @@ describe("ConfidentialGovernorAlpha", function () {
"TransactionTooLateForExecution",
);

await mineNBlocks(1);

proposalInfo = await this.governor.getProposalInfo(proposalId);
// 9 ==> Expired
expect(proposalInfo.state).to.equal(9);
Expand Down

0 comments on commit a91c46e

Please sign in to comment.