Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
AllFi committed Oct 27, 2023
1 parent 70947ba commit 71b35a6
Showing 1 changed file with 54 additions and 28 deletions.
82 changes: 54 additions & 28 deletions src/zkbob/sequencer/ZkBobSequencer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,6 @@ import {MemoUtils} from "./MemoUtils.sol";
contract ZkBobSequencer {
using PriorityQueue for PriorityQueue.Queue;

event Commited(); // TODO: Fill the data
event Proved();
event Rejected();
event Skipped();


PriorityQueue.Queue priorityQueue;
ZkBobPool pool;
mapping(address => uint256) accumulatedFees;
uint256 lastQueueUpdateTimestamp;

uint256 constant TRANSFER_DELTA_SIZE = 28;
bytes4 internal constant MESSAGE_PREFIX_COMMON_V1 = 0x00000000; // TODO: import it?
uint256 constant R = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // TODO: import it?

// TODO: make it configurable
uint256 constant EXPIRATION_TIME = 1 hours;
uint256 constant PROXY_GRACE_PERIOD = 10 minutes;

struct CommitData {
uint48 index;
uint256 out_commit;
Expand All @@ -42,15 +23,47 @@ contract ZkBobSequencer {
uint256[8] tree_proof;
}

event Commited(); // TODO: Fill the data
event Proved();
event Rejected();
event Skipped();

uint256 constant TRANSFER_DELTA_SIZE = 28;
bytes4 internal constant MESSAGE_PREFIX_COMMON_V1 = 0x00000000;
uint256 constant R = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
// TODO: make it configurable
uint256 constant EXPIRATION_TIME = 1 hours;
uint256 constant PROXY_GRACE_PERIOD = 10 minutes;

// Queue of operations
PriorityQueue.Queue priorityQueue;

// Pool contract, this contract is operator of the pool
ZkBobPool pool;

// Accumulated fees for each prover
mapping(address => uint256) accumulatedFees;

// Last time when queue was updated
uint256 lastQueueUpdateTimestamp;

mapping(uint256 => uint256) pendingNullifiers;

// 1. Verify that commit data is valid
// 1) msg.sender == proxy that is fixed in the memo
// 2) Nullifier is not spent
// 3) Index is not too high (this index is used to get used root from the pool)
// 4) Transfer proof is correct according to the current pool state
// 5) Memo version is ok
// 1) nullifier is not pending
// 2) msg.sender == proxy that is fixed in the memo
// 3) Nullifier is not spent
// 4) Index is not too high (this index is used to get used root from the pool)
// 5) Transfer proof is correct according to the current pool state
// 6) Memo version is ok
// 2. Save operation in the priority queue (only commit data hash and timestamp)
// 3. Emit event
// 3. Save pending nullifier
// 4. Emit event
// Possible problems here:
// 1. Malicious user can front run a prover and the prover spend some gas without any result
function commit(CommitData calldata commitData) external {
require(pendingNullifiers[commitData.nullifier] == 0, "ZkBobSequencer: nullifier is already pending");

(address proxy, , ) = MemoUtils.parseFees(commitData.memo);
require(msg.sender == proxy, "ZkBobSequencer: not authorized");

Expand All @@ -62,7 +75,7 @@ contract ZkBobSequencer {
PriorityOperation memory op = PriorityOperation(commitHash(commitData), block.timestamp);
priorityQueue.pushBack(op);

// We can also save pending nullifier
pendingNullifiers[commitData.nullifier] = 1;

emit Commited();
}
Expand All @@ -76,6 +89,12 @@ contract ZkBobSequencer {
// 3. Call pool.transact with the provided data
// 1) If call is successfull we store fees and emit event
// 2) If call is not successfull we only emit event. Important: we don't revert
// 4. Update lastQueueUpdateTimestamp and delete pending nullifier
// Possible problems here:
// 1. If the PROXY_GRACE_PERIOD is ended then anyone can prove the operation and race condition is possible
// We can prevent it by implementing some mechanism to pick a prover from the previous ones
// 2. Malicious user can commit a bad operation (low fees, problems with compliance, etc.) so there is no prover that will be ready to prove it
// In this case the prioirity queue will be locked until the expiration time
function prove(CommitData calldata commitData, ProveData calldata proveData) external {
PriorityOperation memory op = priorityQueue.popFront();
require(op.commitHash == commitHash(commitData), "ZkBobSequencer: invalid commit hash");
Expand All @@ -86,15 +105,16 @@ contract ZkBobSequencer {
if (block.timestamp <= timestamp + PROXY_GRACE_PERIOD) {
require(msg.sender == proxy, "ZkBobSequencer: not authorized");
}
// We can introduce some scheme to pick one of the previous prover to aboid race condition

// We check proofs twice with the current implementation.
// It should be possible to avoid it but we need to modify pool contract.
require(pool.tree_verifier().verifyProof(tree_pub(commitData, proveData), proveData.tree_proof), "ZkBobSequencer: invalid proof");

uint256 accumulatedFeeBefore = pool.accumulatedFee(address(this));
bool success = propogateToPool(commitData, proveData);

lastQueueUpdateTimestamp = block.timestamp;
delete pendingNullifiers[commitData.nullifier];

// We remove the commitment from the queue regardless of the result of the call to pool contract
// If we check that the prover is not malicious then the tx is not valid because of the limits or
Expand All @@ -116,10 +136,16 @@ contract ZkBobSequencer {
}

// If operation is expired then we can remove it from the queue
function skip() external {
// Possible problems here:
// 1. There is no one who interested in calling this method
function skip(CommitData calldata commitData) external {
PriorityOperation memory op = priorityQueue.popFront();
require(op.commitHash == commitHash(commitData), "ZkBobSequencer: invalid commit hash");
require(op.timestamp + EXPIRATION_TIME < block.timestamp, "ZkBobSequencer: not expired yet");

lastQueueUpdateTimestamp = block.timestamp;
delete pendingNullifiers[commitData.nullifier];

emit Skipped();
}

Expand Down

0 comments on commit 71b35a6

Please sign in to comment.