Skip to content

Commit

Permalink
feat(protocol): Introduce oracle and system prover concept (#13729)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com>
Co-authored-by: jeff <113397187+cyberhorsey@users.noreply.github.com>
Co-authored-by: Daniel Wang <dan@taiko.xyz>
  • Loading branch information
4 people committed May 10, 2023
1 parent aac14ef commit e8ba716
Show file tree
Hide file tree
Showing 17 changed files with 611 additions and 213 deletions.
1 change: 1 addition & 0 deletions packages/protocol/contracts/L1/TaikoConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ library TaikoConfig {
maxBytesPerTxList: 120000,
minTxGasLimit: 21000,
proofCooldownPeriod: 30 minutes,
systemProofCooldownPeriod: 15 minutes,
// Only need 1 real zkp per 10 blocks.
// If block number is N, then only when N % 10 == 0, the real ZKP
// is needed. For mainnet, this must be 0 or 1.
Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ library TaikoData {
uint256 minTxGasLimit;
uint256 txListCacheExpiry;
uint256 proofCooldownPeriod;
uint256 systemProofCooldownPeriod;
uint256 realProofSkipSize;
uint256 ethDepositGas;
uint256 ethDepositMaxFee;
Expand Down Expand Up @@ -93,7 +94,7 @@ library TaikoData {
bytes32 blockHash;
bytes32 signalRoot;
uint64 provenAt;
address prover; // 0x0 to mark as 'oracle proof'
address prover;
uint32 gasUsed;
}

Expand Down
7 changes: 5 additions & 2 deletions packages/protocol/contracts/L1/TaikoErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ abstract contract TaikoErrors {
error L1_INVALID_METADATA();
error L1_INVALID_PARAM();
error L1_INVALID_PROOF();
error L1_NOT_ORACLE_PROVER();
error L1_ORACLE_DISABLED();
error L1_INVALID_PROOF_OVERWRITE();
error L1_NOT_SPECIAL_PROVER();
error L1_ORACLE_PROVER_DISABLED();
error L1_SAME_PROOF();
error L1_SYSTEM_PROVER_DISABLED();
error L1_SYSTEM_PROVER_PROHIBITED();
error L1_TOO_MANY_BLOCKS();
error L1_TX_LIST_NOT_EXIST();
error L1_TX_LIST_HASH();
Expand Down
93 changes: 55 additions & 38 deletions packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ library LibProving {
error L1_BLOCK_ID();
error L1_EVIDENCE_MISMATCH(bytes32 expected, bytes32 actual);
error L1_FORK_CHOICE_NOT_FOUND();
error L1_INVALID_PROOF();
error L1_INVALID_EVIDENCE();
error L1_ORACLE_DISABLED();
error L1_NOT_ORACLE_PROVER();
error L1_INVALID_PROOF();
error L1_INVALID_PROOF_OVERWRITE();
error L1_NOT_SPECIAL_PROVER();
error L1_ORACLE_PROVER_DISABLED();
error L1_SAME_PROOF();
error L1_SYSTEM_PROVER_DISABLED();
error L1_SYSTEM_PROVER_PROHIBITED();

function proveBlock(
TaikoData.State storage state,
Expand Down Expand Up @@ -60,42 +63,47 @@ library LibProving {
if (blk.metaHash != evidence.metaHash)
revert L1_EVIDENCE_MISMATCH(blk.metaHash, evidence.metaHash);

// Separate between oracle proof (which needs to be overwritten)
// and non-oracle but system proofs
address specialProver;
if (evidence.prover == address(0)) {
address oracleProver = resolver.resolve("oracle_prover", true);
if (oracleProver == address(0)) revert L1_ORACLE_DISABLED();

if (msg.sender != oracleProver) {
if (evidence.proof.length != 64) {
revert L1_NOT_ORACLE_PROVER();
} else {
uint8 v = uint8(evidence.verifierId);
bytes32 r;
bytes32 s;
bytes memory data = evidence.proof;
assembly {
r := mload(add(data, 32))
s := mload(add(data, 64))
}

// clear the proof before hashing evidence
evidence.verifierId = 0;
evidence.proof = new bytes(0);

if (
oracleProver !=
ecrecover(keccak256(abi.encode(evidence)), v, r, s)
) revert L1_NOT_ORACLE_PROVER();
}
specialProver = resolver.resolve("oracle_prover", true);
if (specialProver == address(0)) {
revert L1_ORACLE_PROVER_DISABLED();
}
} else if (evidence.prover == address(1)) {
specialProver = resolver.resolve("system_prover", true);
if (specialProver == address(0)) {
revert L1_SYSTEM_PROVER_DISABLED();
}

if (
config.realProofSkipSize > 1 &&
blockId % config.realProofSkipSize != 0
) {
// For this block, real ZKP is not necessary, so the oracle
// proof will be treated as a real proof (by setting the prover
// to a non-zero value)
evidence.prover = oracleProver;
config.realProofSkipSize <= 1 ||
blockId % config.realProofSkipSize == 0
) revert L1_SYSTEM_PROVER_PROHIBITED();
}

if (specialProver != address(0) && msg.sender != specialProver) {
if (evidence.proof.length != 64) {
revert L1_NOT_SPECIAL_PROVER();
} else {
uint8 v = uint8(evidence.verifierId);
bytes32 r;
bytes32 s;
bytes memory data = evidence.proof;
assembly {
r := mload(add(data, 32))
s := mload(add(data, 64))
}

// clear the proof before hashing evidence
evidence.verifierId = 0;
evidence.proof = new bytes(0);

if (
specialProver !=
ecrecover(keccak256(abi.encode(evidence)), v, r, s)
) revert L1_NOT_SPECIAL_PROVER();
}
}

Expand Down Expand Up @@ -129,15 +137,24 @@ library LibProving {
] = fcId;
}
} else if (evidence.prover == address(0)) {
// This is the branch the oracle prover is trying to overwrite
fc = blk.forkChoices[fcId];

if (
fc.blockHash == evidence.blockHash &&
fc.signalRoot == evidence.signalRoot &&
fc.gasUsed == evidence.gasUsed
) revert L1_SAME_PROOF();
} else {
revert L1_ALREADY_PROVEN();
// This is the branch provers trying to overwrite
fc = blk.forkChoices[fcId];
if (fc.prover != address(0) && fc.prover != address(1))
revert L1_ALREADY_PROVEN();

if (
fc.blockHash != evidence.blockHash ||
fc.signalRoot != evidence.signalRoot ||
fc.gasUsed != evidence.gasUsed
) revert L1_INVALID_PROOF_OVERWRITE();
}

fc.blockHash = evidence.blockHash;
Expand All @@ -146,7 +163,7 @@ library LibProving {
fc.provenAt = uint64(block.timestamp);
fc.prover = evidence.prover;

if (evidence.prover != address(0)) {
if (evidence.prover != address(0) && evidence.prover != address(1)) {
uint256[9] memory inputs;

inputs[0] = uint256(
Expand Down
32 changes: 18 additions & 14 deletions packages/protocol/contracts/L1/libs/LibVerifying.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ library LibVerifying {
config.proofTimeTarget == 0 ||
config.adjustmentQuotient == 0
) revert L1_INVALID_CONFIG();

uint64 timeNow = uint64(block.timestamp);
state.genesisHeight = uint64(block.number);
state.genesisTimestamp = timeNow;
Expand Down Expand Up @@ -97,8 +96,7 @@ library LibVerifying {
++i;
}

address oracleProver = resolver.resolve("oracle_prover", true);

address systemProver = resolver.resolve("system_prover", true);
while (i < state.numBlocks && processed < maxBlocks) {
blk = state.blocks[i % config.ringBufferSize];
assert(blk.blockId == i);
Expand All @@ -111,9 +109,8 @@ library LibVerifying {

if (fc.prover == address(0)) break;

uint256 proofCooldownPeriod = oracleProver == address(0) ||
fc.prover == oracleProver
? 0
uint256 proofCooldownPeriod = fc.prover == address(1)
? config.systemProofCooldownPeriod
: config.proofCooldownPeriod;

if (block.timestamp < fc.provenAt + proofCooldownPeriod) break;
Expand All @@ -127,7 +124,8 @@ library LibVerifying {
config: config,
blk: blk,
fcId: uint24(fcId),
fc: fc
fc: fc,
systemProver: systemProver
});

unchecked {
Expand Down Expand Up @@ -161,7 +159,8 @@ library LibVerifying {
TaikoData.Config memory config,
TaikoData.Block storage blk,
TaikoData.ForkChoice storage fc,
uint24 fcId
uint24 fcId,
address systemProver
) private {
uint64 proofTime;
unchecked {
Expand All @@ -180,12 +179,17 @@ library LibVerifying {

// reward the prover
if (reward != 0) {
if (state.taikoTokenBalances[fc.prover] == 0) {
// Reduce refund to 1 wei as a penalty if the proposer
// has 0 TKO outstanding balance.
state.taikoTokenBalances[fc.prover] = 1;
} else {
state.taikoTokenBalances[fc.prover] += reward;
address prover = fc.prover != address(1) ? fc.prover : systemProver;

// systemProver may become address(0) after a block is proven
if (prover != address(0)) {
if (state.taikoTokenBalances[prover] == 0) {
// Reduce refund to 1 wei as a penalty if the proposer
// has 0 TKO outstanding balance.
state.taikoTokenBalances[prover] = 1;
} else {
state.taikoTokenBalances[prover] += reward;
}
}
}

Expand Down
11 changes: 3 additions & 8 deletions packages/protocol/contracts/common/AddressResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ abstract contract AddressResolver {

error RESOLVER_DENIED();
error RESOLVER_INVALID_ADDR();
error RESOLVER_ZERO_ADDR(uint256 chainId, bytes32 name);

modifier onlyFromNamed(bytes32 name) {
if (msg.sender != resolve(name, false)) revert RESOLVER_DENIED();
Expand Down Expand Up @@ -81,13 +82,7 @@ abstract contract AddressResolver {
) private view returns (address payable addr) {
addr = payable(_addressManager.getAddress(chainId, name));

if (!allowZeroAddress) {
// We do not use custom error so this string-based
// error message is more helpful for diagnosis.
require(
addr != address(0),
string(abi.encode("AR:zeroAddr:", chainId, ".", name))
);
}
if (!allowZeroAddress && addr == address(0))
revert RESOLVER_ZERO_ADDR(chainId, name);
}
}
2 changes: 2 additions & 0 deletions packages/protocol/script/DeployOnL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ contract DeployOnL1 is Script {
address public owner = vm.envAddress("OWNER");

address public oracleProver = vm.envAddress("ORACLE_PROVER");
address public systemProver = vm.envAddress("SYSTEM_PROVER");

address public sharedSignalService = vm.envAddress("SHARED_SIGNAL_SERVICE");

Expand Down Expand Up @@ -86,6 +87,7 @@ contract DeployOnL1 is Script {
setAddress(l2ChainId, "taiko", taikoL2Address);
setAddress(l2ChainId, "signal_service", l2SignalService);
setAddress("oracle_prover", oracleProver);
setAddress("system_prover", systemProver);
setAddress(l2ChainId, "treasure", treasure);

// TaikoToken
Expand Down
1 change: 1 addition & 0 deletions packages/protocol/script/test_deploy_on_l1.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set -e
PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
SHARED_SIGNAL_SERVICE=0x0000000000000000000000000000000000000000 \
ORACLE_PROVER=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 \
SYSTEM_PROVER=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 \
OWNER=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 \
TAIKO_L2_ADDRESS=0x0000777700000000000000000000000000000001 \
L2_SIGNAL_SERVICE=0x0000777700000000000000000000000000000007 \
Expand Down
12 changes: 6 additions & 6 deletions packages/protocol/test/TaikoL1.sim.sol
Original file line number Diff line number Diff line change
Expand Up @@ -308,14 +308,14 @@ contract TaikoL1Simulation is TaikoL1TestBase {
];

proveBlock(
Bob,
Bob,
metas[blockId],
parentHashes[blockId],
parentGasUsed[blockId],
gasUsed[blockId],
blockHashes[blockId],
signalRoots[blockId],
false
signalRoots[blockId]
);
}
}
Expand Down Expand Up @@ -552,14 +552,14 @@ contract TaikoL1Simulation is TaikoL1TestBase {
];

proveBlock(
Bob,
Bob,
metas[blockId],
parentHashes[blockId],
parentGasUsed[blockId],
gasUsed[blockId],
blockHashes[blockId],
signalRoots[blockId],
false
signalRoots[blockId]
);
}
}
Expand Down Expand Up @@ -801,14 +801,14 @@ contract TaikoL1Simulation is TaikoL1TestBase {
];

proveBlock(
Bob,
Bob,
metas[blockId],
parentHashes[blockId],
parentGasUsed[blockId],
gasUsed[blockId],
blockHashes[blockId],
signalRoots[blockId],
false
signalRoots[blockId]
);
}
}
Expand Down
Loading

0 comments on commit e8ba716

Please sign in to comment.