Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(protocol): Introduce oracle and system prover concept #13729

Merged
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))
Brechtpd marked this conversation as resolved.
Show resolved Hide resolved
revert L1_ALREADY_PROVEN();
davidtaikocha marked this conversation as resolved.
Show resolved Hide resolved

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)
davidtaikocha marked this conversation as resolved.
Show resolved Hide resolved
? 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