Skip to content

Commit

Permalink
add some tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Keszey Dániel authored and Keszey Dániel committed Jul 5, 2024
1 parent 2b2a36e commit ef000d9
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 68 deletions.
2 changes: 1 addition & 1 deletion packages/protocol/contracts/L1/BasedOperator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ contract BasedOperator is EssentialContract, TaikoErrors {
// invalid
// Get the currently stored transition
TaikoData.TransitionState memory storedTransition = taiko.getTransition(
proofBatch.blockMetadata.l2BlockNumber, proofBatch.transition.parentHash
proofBatch.blockMetadata.l2BlockNumber, proofBatch.transition.parentBlockHash
);

// Brecht: SO we set the blockHash in proposeBlock().
Expand Down
8 changes: 4 additions & 4 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ library TaikoData {
/// @dev Struct containing data only required for proving a block
struct BlockMetadata {
bytes32 blockHash;
bytes32 parentBlockHash;
bytes32 parentMetaHash;
bytes32 l1Hash;
uint256 difficulty;
Expand All @@ -40,13 +41,13 @@ library TaikoData {

/// @dev Struct representing transition to be proven.
struct Transition {
bytes32 parentHash;
bytes32 parentBlockHash;
bytes32 blockHash;
}

/// @dev Struct representing state transition data.
struct TransitionState {
bytes32 blockHash;
bytes32 blockHash; //Might be removed..
uint64 timestamp;
address prover;
uint64 verifiableAfter;
Expand All @@ -65,8 +66,7 @@ library TaikoData {
/// @dev Struct holding the state variables for the {TaikoL1} contract.
struct State {
mapping(uint256 blockId => Block) blocks;
// Todo (Brecht): please check which one to use here (?) metaHash or blockHash
mapping(uint256 blockId => mapping(bytes32 parentMetaHash => TransitionState)) transitions;
mapping(uint256 blockId => mapping(bytes32 parentBlockHash => TransitionState)) transitions;
uint64 genesisHeight;
uint64 genesisTimestamp;
uint64 numBlocks;
Expand Down
43 changes: 18 additions & 25 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pragma solidity ^0.8.20;
import "../common/EssentialContract.sol";
import "./TaikoErrors.sol";
import "./TaikoEvents.sol";
import "forge-std/console2.sol";

/// @title TaikoL1
contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
Expand Down Expand Up @@ -69,6 +68,7 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
// Verify L1 data
// TODO(Brecht): needs to be more configurable for preconfirmations
require(_block.l1Hash == blockhash(_block.l1StateBlockNumber), "INVALID_L1_BLOCKHASH");
require(_block.blockHash != 0x0, "INVALID_L2_BLOCKHASH");
require(_block.difficulty == block.prevrandao, "INVALID_DIFFICULTY");
// Verify misc data
require(_block.gasLimit == config.blockMaxGasLimit, "INVALID_GAS_LIMIT");
Expand All @@ -95,9 +95,6 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {

TaikoData.Block storage parentBlock = state.blocks[(state.numBlocks - 1)];

console2.log("Mi a faszom");
console2.logBytes32(_block.parentMetaHash);
console2.logBytes32(parentBlock.metaHash);
require(_block.parentMetaHash == parentBlock.metaHash, "invalid parentHash");

// Verify the passed in L1 state block number.
Expand Down Expand Up @@ -136,10 +133,9 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
state.blocks[state.numBlocks] = blk;

// Store the passed in block hash as is
state.transitions[blk.blockId][_block.parentMetaHash].blockHash = _block.blockHash;
// For now it does not matter - we are not going to prove anyways
state.transitions[blk.blockId][_block.parentMetaHash].verifiableAfter =
uint64(block.timestamp) + 365 days;
state.transitions[blk.blockId][_block.parentBlockHash].blockHash = _block.blockHash;
// Big enough number so that we are sure we don't hit that deadline in the future.
state.transitions[blk.blockId][_block.parentBlockHash].verifiableAfter = type(uint64).max;

// Increment the counter (cursor) by 1.
state.numBlocks++;
Expand All @@ -161,10 +157,6 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
whenNotPaused
onlyFromNamed("operator")
{
console2.log("Miafasz van mar");
console2.log(_block.l2BlockNumber);
console2.log(state.lastVerifiedBlockId);
console2.log(state.numBlocks);
// Check that the block has been proposed but has not yet been verified.
if (
_block.l2BlockNumber <= state.lastVerifiedBlockId
Expand All @@ -176,13 +168,13 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
TaikoData.Block storage blk = state.blocks[_block.l2BlockNumber];

// Make sure the correct block was proven
if(blk.metaHash != keccak256(abi.encode(_block))) {
if (blk.metaHash != keccak256(abi.encode(_block))) {
revert L1_INCORRECT_BLOCK();
}

// Store the transition
TaikoData.TransitionState storage storedTransition =
state.transitions[_block.l2BlockNumber][transition.parentHash];
state.transitions[_block.l2BlockNumber][transition.parentBlockHash];
storedTransition.blockHash = transition.blockHash;
storedTransition.prover = prover;
storedTransition.verifiableAfter = uint32(block.timestamp + SECURITY_DELAY_AFTER_PROVEN);
Expand All @@ -201,26 +193,23 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
{
// Get the last verified blockhash
TaikoData.Block storage blk = state.blocks[state.lastVerifiedBlockId];
// Brecht: i think this was a bug, or indeed TaikoData's Transition mapping was misleading.. Now i'm using metaHash as a path/key in the mapping, so i guess we shall use it here to query data, right ? But somehow it is not working :D
// Go to the first unverified block
bytes32 blockHash = blk.metaHash;
//blockHash = blk.blockHash;
bytes32 blockHash = blk.blockHash;
uint256 blockId = uint256(state.lastVerifiedBlockId) + 1;
uint256 numBlocksVerified;
console2.log("V1");

while (blockId < state.numBlocks && numBlocksVerified < maxBlocksToVerify) {
blk = state.blocks[blockId];
// Check if the parent block hash matches the actual block hash of the parent
// Check if the timestamp is older than required
if (
// Brecht: I think here is also not good, or a mismatch.. How we use/save transitions. Is it blockHash or metaHash??
state.transitions[blockId][blockHash].blockHash == bytes32(0)
|| block.timestamp < state.transitions[blockId][blockHash].verifiableAfter
block
// Genesis is already verified with initialization so if we do not allow to set
// blockHash = bytes32(0), then we can remove the bytes32(0) check.
/*state.transitions[blockId][blockHash].blockHash == bytes32(0)
|| */
.timestamp < state.transitions[blockId][blockHash].verifiableAfter
) {
break;
}

console2.log("V3");
// Copy the blockhash to the block
blk.blockHash = state.transitions[blockId][blockHash].blockHash;
// Update latest block hash
Expand Down Expand Up @@ -272,6 +261,10 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
return uint256(state.lastVerifiedBlockId);
}

function getNumOfBlocks() public view returns (uint256) {
return uint256(state.numBlocks);
}

/// @notice Gets the configuration of the TaikoL1 contract.
/// @return Config struct containing configuration parameters.
function getConfig() public view virtual returns (TaikoData.Config memory) {
Expand Down
10 changes: 8 additions & 2 deletions packages/protocol/contracts/L1/VerifierBattleRoyale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ contract VerifierBattleRoyale is EssentialContract {

TaikoData.Transition memory transitionA = proofBatch.proofs[0].transition;
TaikoData.Transition memory transitionB = proofBatch.proofs[1].transition;
require(transitionA.parentHash == transitionB.parentHash, "parentHash not the same");
require(
transitionA.parentBlockHash == transitionB.parentBlockHash,
"parentHash not the same"
);
require(transitionA.blockHash != transitionB.blockHash, "blockhash the same");
} else if (proofBatch.proofs.length == 3) {
/* Multiple verifiers in a consensus show that another verifier is faulty */
Expand All @@ -105,7 +108,10 @@ contract VerifierBattleRoyale is EssentialContract {
for (uint256 i = 0; i < proofBatch.proofs.length - 1; i++) {
TaikoData.Transition memory transitionA = proofBatch.proofs[i].transition;
TaikoData.Transition memory transitionB = proofBatch.proofs[i + 1].transition;
require(transitionA.parentHash == transitionB.parentHash, "parentHash not the same");
require(
transitionA.parentBlockHash == transitionB.parentBlockHash,
"parentHash not the same"
);
if (i < proofBatch.proofs.length - 2) {
require(transitionA.blockHash == transitionB.blockHash, "blockhash the same");
} else {
Expand Down
76 changes: 55 additions & 21 deletions packages/protocol/test/L1/TaikoL1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,20 @@ contract TaikoL1Test is TaikoL1TestBase {
TaikoL1(payable(deployProxy({ name: "taiko", impl: address(new TaikoL1()), data: "" })));
}

function test_L1_proposeBlock() external {
function test_L1_propose_prove_and_verify_blocks_sequentially() external {
giveEthAndTko(Alice, 100 ether, 100 ether);

TaikoData.BlockMetadata memory meta;

vm.roll(block.number + 1);
vm.warp(block.timestamp + 12);

// console2.log(block.number);
// meta.blockHash = randBytes32();
// meta.parentHash = GENESIS_BLOCK_HASH;
// meta.l1Hash = blockhash(block.number - 1);
// meta.difficulty = block.prevrandao;
// meta.blobHash = randBytes32();
// meta.coinbase = Alice;
// meta.l2BlockNumber = 1;
// meta.gasLimit = L1.getConfig().blockMaxGasLimit;
// meta.l1StateBlockNumber = uint32(block.number-1);
// meta.timestamp = uint64(block.timestamp - 12); // 1 block behind

// meta.txListByteOffset = 0;
// meta.txListByteSize = 0;
// meta.blobUsed = true;
bytes32 parentMetaHash;
for (uint64 blockId = 1; blockId <= 1; blockId++) {
printVariables("before propose");
for (uint64 blockId = 1; blockId <= 20; blockId++) {
printVariables("before propose & prove & verify");
// Create metadata and propose the block
meta = createBlockMetaData(parentMetaHash, Alice, blockId, 1, true);
proposeBlock(Alice, Alice, meta);
meta = createBlockMetaData(Alice, blockId, 1, true);
proposeBlock(Alice, Alice, meta, "");

// Create proofs and prove a block
BasedOperator.ProofBatch memory blockProofs = createProofs(meta, Alice, true);
Expand All @@ -47,9 +32,58 @@ contract TaikoL1Test is TaikoL1TestBase {
vm.warp(uint32(block.timestamp + L1.SECURITY_DELAY_AFTER_PROVEN() + 1));
vm.roll(block.number + 10);
verifyBlock(1);
parentMetaHash = keccak256(abi.encode(meta));
printVariables("after verify");
}
}

parentMetaHash = keccak256(abi.encode(meta));
function test_L1_propose_some_blocks_in_a_row_then_prove_and_verify() external {
giveEthAndTko(Alice, 100 ether, 100 ether);

TaikoData.BlockMetadata[] memory blockMetaDatas = new TaikoData.BlockMetadata[](20);

vm.roll(block.number + 1);
vm.warp(block.timestamp + 12);

bytes32 parentMetaHash;
for (uint64 blockId = 1; blockId <= 20; blockId++) {
printVariables("before propose & prove & verify");
// Create metadata and propose the block
blockMetaDatas[blockId - 1] = createBlockMetaData(Alice, blockId, 1, true);
proposeBlock(Alice, Alice, blockMetaDatas[blockId - 1], "");
vm.roll(block.number + 1);
vm.warp(block.timestamp + 12);
}

for (uint64 blockId = 1; blockId <= 20; blockId++) {
// Create proofs and prove a block
BasedOperator.ProofBatch memory blockProofs =
createProofs(blockMetaDatas[blockId - 1], Alice, true);
proveBlock(Alice, abi.encode(blockProofs));

//Wait enought time and verify block (currently we simply just "wait enough" from latest
// block and not time it perfectly)
vm.warp(uint32(block.timestamp + L1.SECURITY_DELAY_AFTER_PROVEN() + 1));
vm.roll(block.number + 10);
verifyBlock(1);
parentMetaHash = keccak256(abi.encode(blockMetaDatas[blockId - 1]));
printVariables("after verify 1");
}
}

function test_L1_propose_block_outside_the_4_epoch_window() external {
giveEthAndTko(Alice, 100 ether, 100 ether);

TaikoData.BlockMetadata memory meta;

vm.roll(block.number + 1);
vm.warp(block.timestamp + 12);

// Create metadata and propose the block 129 blocks later only
meta = createBlockMetaData(Alice, 1, 1, true);
vm.roll(block.number + 129);
vm.warp(block.timestamp + 129 * 12);

proposeBlock(Alice, Alice, meta, TaikoErrors.L1_INVALID_L1_STATE_BLOCK.selector);
}
}
35 changes: 20 additions & 15 deletions packages/protocol/test/L1/TaikoL1TestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ abstract contract TaikoL1TestBase is TaikoTest {
function proposeBlock(
address proposer,
address prover,
TaikoData.BlockMetadata memory meta
TaikoData.BlockMetadata memory meta,
bytes4 revertReason
)
internal
returns (TaikoData.BlockMetadata memory)
Expand Down Expand Up @@ -296,10 +297,18 @@ abstract contract TaikoL1TestBase is TaikoTest {
hex"0000000000000000000000000000000000000000000000000000000000000001";
bytes memory emptyTxList;

vm.prank(proposer, proposer);
meta = basedOperator.proposeBlock{ value: 1 ether / 10 }(
abi.encode(meta), meta.blobUsed == true ? emptyTxList : dummyTxList, prover
);
if (revertReason == "") {
vm.prank(proposer, proposer);
meta = basedOperator.proposeBlock{ value: 1 ether / 10 }(
abi.encode(meta), meta.blobUsed == true ? emptyTxList : dummyTxList, prover
);
} else {
vm.prank(proposer, proposer);
vm.expectRevert(revertReason);
meta = basedOperator.proposeBlock{ value: 1 ether / 10 }(
abi.encode(meta), meta.blobUsed == true ? emptyTxList : dummyTxList, prover
);
}

return meta;
}
Expand Down Expand Up @@ -400,13 +409,12 @@ abstract contract TaikoL1TestBase is TaikoTest {
}

function printVariables(string memory comment) internal {
(,,, uint64 numBlock,,) = L1.state();
string memory str = string.concat(
Strings.toString(logCount++),
":[",
Strings.toString(L1.getLastVerifiedBlockId()),
unicode"",
Strings.toString(numBlock),
Strings.toString(L1.getNumOfBlocks()),
"] // ",
comment
);
Expand All @@ -419,22 +427,19 @@ abstract contract TaikoL1TestBase is TaikoTest {
}

function createBlockMetaData(
bytes32 parentMetaHash,
address coinbase,
uint64 l2BlockNumber,
uint32 belowBlockTipHeight, // How many blocks (negatived direction) away from block.id
uint32 belowBlockTipHeight, // How many blocks below from current tip (block.id)
bool blobUsed
)
internal
returns (TaikoData.BlockMetadata memory meta)
{
meta.blockHash = randBytes32();

meta.parentMetaHash = parentMetaHash;
if (l2BlockNumber == 1) {
meta.parentMetaHash = hex"0000000000000000000000000000000000000000000000000000000000000000";
}

TaikoData.Block memory parentBlock = L1.getBlock(l2BlockNumber - 1);
meta.parentMetaHash = parentBlock.metaHash;
meta.parentBlockHash = parentBlock.blockHash;
meta.l1Hash = blockhash(block.number - belowBlockTipHeight);
meta.difficulty = block.prevrandao;
meta.blobHash = randBytes32();
Expand Down Expand Up @@ -471,7 +476,7 @@ abstract contract TaikoL1TestBase is TaikoTest {

// Set transition
TaikoData.Transition memory transition;
transition.parentHash = L1.getBlock(meta.l2BlockNumber).blockHash;
transition.parentBlockHash = L1.getBlock(meta.l2BlockNumber - 1).blockHash;
transition.blockHash = meta.blockHash;
proofBatch.transition = transition;

Expand Down

0 comments on commit ef000d9

Please sign in to comment.