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

Abstract block info #105

Merged
merged 8 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 19 additions & 52 deletions contracts/EthStorageContractL2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,62 +28,29 @@ contract EthStorageContractL2 is EthStorageContract2 {
IL1Block internal constant L1_BLOCK = IL1Block(0x4200000000000000000000000000000000000015);

/// @notice Constructs the EthStorageContractL2 contract.
constructor(
Config memory _config,
uint256 _startTime,
uint256 _storageCost,
uint256 _dcfFactor
) EthStorageContract2(_config, _startTime, _storageCost, _dcfFactor) {}
constructor(Config memory _config, uint256 _startTime, uint256 _storageCost, uint256 _dcfFactor)
EthStorageContract2(_config, _startTime, _storageCost, _dcfFactor)
{}

/// @notice Get the current block number
function _blockNumber() internal view override returns (uint256) {
return L1_BLOCK.number();
}

/// @notice Get the current block timestamp
function _blockTs() internal view override returns (uint256) {
return L1_BLOCK.timestamp();
}

/// @notice Get the randao value from the L1 blockhash.
function _getRandao(uint256 _l1BlockNumber, bytes calldata _headerRlpBytes) internal view returns (bytes32) {
function _getRandao(uint256 _l1BlockNumber, bytes calldata _headerRlpBytes)
internal
view
override
returns (bytes32)
{
bytes32 bh = L1_BLOCK.blockHash(_l1BlockNumber);
require(bh != bytes32(0), "EthStorageContractL2: failed to obtain blockhash");

return RandaoLib.verifyHeaderAndGetRandao(bh, _headerRlpBytes);
}

/// @notice We are still using L1 block number, timestamp, and blockhash to mine eventhough we are on L2.
/// @param _blockNumber L1 blocknumber.
/// @param _shardId Shard ID.
/// @param _miner Miner address.
/// @param _nonce Nonce.
/// @param _encodedSamples Encoded samples.
/// @param _masks Sample masks.
/// @param _randaoProof L1 block header RLP bytes.
/// @param _inclusiveProofs Sample inclusive proofs.
/// @param _decodeProof Mask decode proof.
function _mine(
uint256 _blockNumber,
uint256 _shardId,
address _miner,
uint256 _nonce,
bytes32[] memory _encodedSamples,
uint256[] memory _masks,
bytes calldata _randaoProof,
bytes[] calldata _inclusiveProofs,
bytes[] calldata _decodeProof
) internal override {
// Obtain the blockhash of the block number of recent blocks
require(L1_BLOCK.number() - _blockNumber <= MAX_L1_MINING_DRIFT, "EthStorageContractL2: block number too old");
// To avoid stack too deep, we resue the hash0 instead of using randao

bytes32 hash0 = _getRandao(_blockNumber, _randaoProof);
// Estimate block timestamp
uint256 mineTs = L1_BLOCK.timestamp() - (L1_BLOCK.number() - _blockNumber) * 12;

// Given a blockhash and a miner, we only allow sampling up to nonce limit times.
require(_nonce < nonceLimit, "EthStorageContractL2: nonce too big");

// Check if the data matches the hash in metadata and obtain the solution hash.
hash0 = keccak256(abi.encode(_miner, hash0, _nonce));
hash0 = verifySamples(_shardId, hash0, _miner, _encodedSamples, _masks, _inclusiveProofs, _decodeProof);

// Check difficulty
uint256 diff = _calculateDiffAndInitHashSingleShard(_shardId, mineTs);
uint256 required = uint256(2 ** 256 - 1) / diff;
require(uint256(hash0) <= required, "EthStorageContractL2: diff not match");

_rewardMiner(_shardId, _miner, mineTs, diff);
}
}
57 changes: 35 additions & 22 deletions contracts/StorageContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ abstract contract StorageContract is DecentralizedKV {
uint256 totalPayment = 0;
if ((totalEntries >> SHARD_ENTRY_BITS) > shardId) {
uint256 kvCountNew = totalEntries % (1 << SHARD_ENTRY_BITS);
totalPayment += _upfrontPayment(block.timestamp) * kvCountNew;
totalPayment += _upfrontPayment(_blockTs()) * kvCountNew;
totalPayment += _upfrontPayment(infos[shardId].lastMineTime) * (_batchSize - kvCountNew);
} else {
totalPayment += _upfrontPayment(infos[shardId].lastMineTime) * _batchSize;
Expand All @@ -182,7 +182,7 @@ abstract contract StorageContract is DecentralizedKV {
if (shardId > (kvEntryCountPrev >> SHARD_ENTRY_BITS)) {
// Open a new shard and mark the shard is ready to mine.
// (TODO): Setup shard difficulty as current difficulty / factor?
infos[shardId].lastMineTime = block.timestamp;
infos[shardId].lastMineTime = _blockTs();
}
}

Expand Down Expand Up @@ -279,16 +279,16 @@ abstract contract StorageContract is DecentralizedKV {

/// @notice Get the mining reward.
/// @param _shardId The shard id.
/// @param _blockNumber The block number.
/// @param _blockNum The block number.
/// @return The mining reward.
function miningReward(uint256 _shardId, uint256 _blockNumber) public view returns (uint256) {
uint256 minedTs = block.timestamp - (block.number - _blockNumber) * 12;
function miningReward(uint256 _shardId, uint256 _blockNum) public view returns (uint256) {
uint256 minedTs = _getMinedTs(_blockNum);
(,, uint256 minerReward) = _miningReward(_shardId, minedTs);
return minerReward;
}

/// @notice Mine a block.
/// @param _blockNumber The block number.
/// @param _blockNum The block number.
/// @param _shardId The shard id.
/// @param _miner The miner address.
/// @param _nonce The nonce.
Expand All @@ -298,7 +298,7 @@ abstract contract StorageContract is DecentralizedKV {
/// @param _inclusiveProofs The inclusive proofs.
/// @param _decodeProof The decode proof.
function mine(
uint256 _blockNumber,
uint256 _blockNum,
uint256 _shardId,
address _miner,
uint256 _nonce,
Expand All @@ -309,15 +309,7 @@ abstract contract StorageContract is DecentralizedKV {
bytes[] calldata _decodeProof
) public virtual {
_mine(
_blockNumber,
_shardId,
_miner,
_nonce,
_encodedSamples,
_masks,
_randaoProof,
_inclusiveProofs,
_decodeProof
_blockNum, _shardId, _miner, _nonce, _encodedSamples, _masks, _randaoProof, _inclusiveProofs, _decodeProof
);
}

Expand All @@ -341,7 +333,7 @@ abstract contract StorageContract is DecentralizedKV {
/// to decoded one. The decoded samples will be used to perform inclusive check with on-chain datahashes.
/// The encoded samples will be used to calculate the solution hash, and if the hash passes the difficulty check,
/// the miner, or say the storage provider, shall be rewarded by the token number from out economic models
/// @param _blockNumber The block number.
/// @param _blockNum The block number.
/// @param _shardId The shard id.
/// @param _miner The miner address.
/// @param _nonce The nonce.
Expand All @@ -351,7 +343,7 @@ abstract contract StorageContract is DecentralizedKV {
/// @param _inclusiveProofs The inclusive proofs.
/// @param _decodeProof The decode proof.
function _mine(
uint256 _blockNumber,
uint256 _blockNum,
uint256 _shardId,
address _miner,
uint256 _nonce,
Expand All @@ -361,12 +353,11 @@ abstract contract StorageContract is DecentralizedKV {
bytes[] calldata _inclusiveProofs,
bytes[] calldata _decodeProof
) internal virtual {
// Obtain the blockhash of the block number of recent blocks
require(block.number - _blockNumber <= MAX_L1_MINING_DRIFT, "StorageContract: block number too old");
require(_blockNumber() - _blockNum <= MAX_L1_MINING_DRIFT, "StorageContract: block number too old");
// To avoid stack too deep, we resue the hash0 instead of using randao
bytes32 hash0 = RandaoLib.verifyHistoricalRandao(_blockNumber, _randaoProof);
bytes32 hash0 = _getRandao(_blockNum, _randaoProof);
// Estimate block timestamp
uint256 mineTs = block.timestamp - (block.number - _blockNumber) * 12;
uint256 mineTs = _getMinedTs(_blockNum);

// Given a blockhash and a miner, we only allow sampling up to nonce limit times.
require(_nonce < nonceLimit, "StorageContract: nonce too big");
Expand All @@ -383,6 +374,28 @@ abstract contract StorageContract is DecentralizedKV {
_rewardMiner(_shardId, _miner, mineTs, diff);
}

/// @notice Get the current block number
function _blockNumber() internal view virtual returns (uint256) {
return block.number;
}

/// @notice Get the current block timestamp
function _blockTs() internal view virtual returns (uint256) {
return block.timestamp;
}

/// @notice Get the randao value by block number.
function _getRandao(uint256 _blockNum, bytes calldata _headerRlpBytes) internal view virtual returns (bytes32) {
bytes32 bh = blockhash(_blockNum);
require(bh != bytes32(0), "StorageContract: failed to obtain blockhash");
return RandaoLib.verifyHeaderAndGetRandao(bh, _headerRlpBytes);
}

/// @notice Get the mined timestamp
function _getMinedTs(uint256 _blockNum) internal view returns (uint256) {
return _blockTs() - (_blockNumber() - _blockNum) * 12;
}

/// @notice Return the sample size bits.
function sampleSizeBits() public pure returns (uint256) {
return SAMPLE_SIZE_BITS;
Expand Down
13 changes: 0 additions & 13 deletions contracts/libraries/RandaoLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,4 @@ library RandaoLib {
require(_headerHash == item.rlpBytesKeccak256(), "RandaoLib: header hash mismatch");
return getRandaoFromHeader(item);
}

/// @notice Get the historical Randao mixDigest by block number
/// @param _blockNumber The block number
/// @param _headerRlpBytes The RLP data of the header
/// @return The Randao mixDigest
function verifyHistoricalRandao(
uint256 _blockNumber,
bytes memory _headerRlpBytes
) internal view returns (bytes32) {
bytes32 bh = blockhash(_blockNumber);
require(bh != bytes32(0), "RandaoLib: failed to obtain blockhash");
return verifyHeaderAndGetRandao(bh, _headerRlpBytes);
}
}
9 changes: 3 additions & 6 deletions contracts/test/TestEthStorageContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,9 @@ contract TestEthStorageContract is EthStorageContract {
bytes[] calldata inclusiveProofs,
bytes[] calldata decodeProof
) internal {
// Obtain the blockhash of the block number of recent blocks
require(block.number - blockNumber <= 64, "block number too old");
// To avoid stack too deep, we resue the hash0 instead of using randao
bytes32 hash0 = RandaoLib.verifyHistoricalRandao(blockNumber, randaoProof);
// Estimate block timestamp
uint256 mineTs = block.timestamp - (block.number - blockNumber) * 12;
require(_blockNumber() - blockNumber <= MAX_L1_MINING_DRIFT, "block number too old");
bytes32 hash0 = _getRandao(blockNumber, randaoProof);
uint256 mineTs = _getMinedTs(blockNumber);

// Given a blockhash and a miner, we only allow sampling up to nonce limit times.
require(nonce < nonceLimit, "nonce too big");
Expand Down
4 changes: 0 additions & 4 deletions contracts/test/TestRandao.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,4 @@ contract TestRandao {
function verifyHeaderAndGetRandao(bytes32 headerHash, bytes memory headerRlpBytes) public pure returns (bytes32) {
return RandaoLib.verifyHeaderAndGetRandao(headerHash, headerRlpBytes);
}

function verifyHistoricalRandao(uint256 blockNumber, bytes memory proof) public view returns (bytes32) {
return RandaoLib.verifyHistoricalRandao(blockNumber, proof);
}
}
4 changes: 2 additions & 2 deletions test/randao-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ describe("Randao Test", function () {
const Randao = await ethers.getContractFactory("TestRandao");
const rd = await Randao.deploy();
await rd.deployed();

let randao = await rd.verifyHistoricalRandao(bn, encodedHeader);
let randao = await rd.verifyHeaderAndGetRandao(hash, encodedHeader);
expect(randao).to.equal(block.mixHash);
});
});
Expand Down