forked from neonevm/neon-tests
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ndev 3187 block timestamp number (#414)
- Loading branch information
1 parent
f7fd01d
commit fa4bcef
Showing
8 changed files
with
467 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.10; | ||
|
||
|
||
contract BlockTimestamp { | ||
event Result(uint256 block_timestamp); | ||
uint256 public a; | ||
uint256 public initial_block_timestamp; | ||
|
||
struct Data { | ||
uint256 value1; | ||
uint256 value2; | ||
} | ||
mapping(uint256 => Data) public dataByTimestamp; | ||
event DataAdded(uint256 timestamp, uint256 value1, uint256 value2); | ||
|
||
constructor() { | ||
initial_block_timestamp = block.timestamp; | ||
} | ||
|
||
function getBlockTimestamp() public view returns (uint256) { | ||
return block.timestamp; | ||
} | ||
|
||
function logTimestamp() public { | ||
emit Result(block.timestamp); | ||
} | ||
|
||
function callIterativeTrx() public payable { | ||
uint256 timestamp_before = block.timestamp; | ||
for (uint256 i = 0; i < 800; i++) { | ||
a = a + block.timestamp; | ||
} | ||
emit Result(block.timestamp); | ||
uint256 timestamp_after = block.timestamp; | ||
|
||
require(timestamp_after == timestamp_before, "Timestamp changed during transaction execution"); | ||
|
||
} | ||
|
||
function addDataToMapping(uint256 _value1, uint256 _value2) public { | ||
uint256 currentTimestamp = block.timestamp % 1000000; | ||
for (uint256 i = 0; i < 5; i++) { | ||
Data memory newData = Data({ | ||
value1: _value1, | ||
value2: _value2 | ||
}); | ||
dataByTimestamp[currentTimestamp] = newData; | ||
emit DataAdded(currentTimestamp, _value1, _value2); | ||
currentTimestamp = currentTimestamp + 1500; | ||
} | ||
} | ||
|
||
function getDataFromMapping(uint256 _timestamp) public view returns (uint256, uint256) { | ||
Data memory retrievedData = dataByTimestamp[_timestamp]; | ||
return (retrievedData.value1, retrievedData.value2); | ||
} | ||
|
||
} | ||
|
||
contract BlockTimestampDeployer { | ||
BlockTimestamp public blockTimestamp; | ||
event Log(address indexed addr); | ||
|
||
constructor() { | ||
blockTimestamp = new BlockTimestamp(); | ||
emit Log(address(blockTimestamp)); | ||
} | ||
} | ||
|
||
|
||
contract BlockNumber { | ||
event Log(address indexed sender, string message); | ||
event Result(uint256 block_number); | ||
|
||
|
||
uint256 public initial_block_number; | ||
|
||
struct Data { | ||
uint256 value1; | ||
uint256 value2; | ||
} | ||
mapping(uint256 => Data) public dataByNumber; | ||
uint256 public a; | ||
|
||
event DataAdded(uint256 number, uint256 value1, uint256 value2); | ||
|
||
constructor() payable { | ||
initial_block_number = block.number; | ||
} | ||
|
||
|
||
function getBlockNumber() public view returns (uint256) { | ||
return block.number; | ||
} | ||
|
||
function logBlockNumber() public { | ||
emit Result(block.number); | ||
} | ||
|
||
function callIterativeTrx() public payable { | ||
uint256 b = 1223; | ||
for (uint256 i = 0; i < 1000; i++) { | ||
a = a + block.number; | ||
} | ||
emit Result(block.number); | ||
} | ||
|
||
function addDataToMapping(uint256 _value1, uint256 _value2) public { | ||
uint256 currentNumber = block.number; | ||
for (uint256 i = 0; i < 5; i++) { | ||
Data memory newData = Data({ | ||
value1: _value1, | ||
value2: _value2 | ||
}); | ||
|
||
dataByNumber[currentNumber] = newData; | ||
emit DataAdded(currentNumber, _value1, _value2); | ||
currentNumber = currentNumber + 1; | ||
} | ||
} | ||
|
||
function getDataFromMapping(uint256 _number) public view returns (uint256, uint256) { | ||
Data memory retrievedData = dataByNumber[_number]; | ||
return (retrievedData.value1, retrievedData.value2); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
docs/tests/audit/evm/opcodes/test_block_timestamp_block_number.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Overview | ||
|
||
Check timestamp and block number opcodes. | ||
|
||
# Tests list | ||
|
||
| Test case | Description | XFailed | | ||
|----------------------------------------------------------------------------|------------------------------------------------|---------| | ||
| TestBlockTimestampAndNumber::test_block_timestamp_call | Check contract return timestamp | | | ||
| TestBlockTimestampAndNumber::test_block_timestamp_simple_trx | Check simple transaction with timestamp | | | ||
| TestBlockTimestampAndNumber::test_block_timestamp_iterative | Check iterative transaction with timestamp | | | ||
| TestBlockTimestampAndNumber::test_block_timestamp_constructor | Check timestamp in constructor | | | ||
| TestBlockTimestampAndNumber::test_block_timestamp_in_mapping | Check timestamp as a key in mapping | | | ||
| TestBlockTimestampAndNumber::test_contract_deploys_contract_with_timestamp | Check contract deploys contract with timestamp | | | ||
| TestBlockTimestampAndNumber::test_block_number_call | Check contract return block number | | | ||
| TestBlockTimestampAndNumber::test_block_number_simple_trx | Check simple transaction with block number | | | ||
| TestBlockTimestampAndNumber::test_block_number_iterative | Check iterative transaction with block number | | | ||
| TestBlockTimestampAndNumber::test_block_number_constructor | Check block number in constructor | | | ||
| TestBlockTimestampAndNumber::test_block_number_in_mapping | Check block number as a key in mapping | | |
165 changes: 165 additions & 0 deletions
165
integration/tests/basic/evm/opcodes/test_block_timestamp_block_number.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import random | ||
|
||
import pytest | ||
|
||
import allure | ||
|
||
from utils.accounts import EthAccounts | ||
from utils.models.result import EthGetBlockByHashResult | ||
from utils.web3client import NeonChainWeb3Client | ||
|
||
|
||
@pytest.fixture(scope="class") | ||
def block_timestamp_contract(web3_client, accounts): | ||
block_timestamp_contract, receipt = web3_client.deploy_and_get_contract( | ||
"common/Block.sol", "0.8.10", accounts[0], contract_name="BlockTimestamp" | ||
) | ||
return block_timestamp_contract, receipt | ||
|
||
|
||
@pytest.fixture(scope="class") | ||
def block_number_contract(web3_client, accounts): | ||
block_number_contract, receipt = web3_client.deploy_and_get_contract( | ||
"common/Block.sol", "0.8.10", accounts[0], contract_name="BlockNumber" | ||
) | ||
return block_number_contract, receipt | ||
|
||
|
||
@allure.feature("Opcodes verifications") | ||
@allure.story("Verify block timestamp and block number") | ||
@pytest.mark.usefixtures("accounts", "web3_client") | ||
class TestBlockTimestampAndNumber: | ||
web3_client: NeonChainWeb3Client | ||
accounts: EthAccounts | ||
|
||
def test_block_timestamp_call(self, block_timestamp_contract, json_rpc_client): | ||
contract, _ = block_timestamp_contract | ||
last_block = json_rpc_client.send_rpc("eth_blockNumber", [])["result"] | ||
current_timestamp = json_rpc_client.send_rpc("eth_getBlockByNumber", [last_block, False])["result"][ | ||
"timestamp" | ||
] | ||
assert hex(contract.functions.getBlockTimestamp().call()) >= current_timestamp | ||
|
||
def test_block_timestamp_simple_trx(self, block_timestamp_contract, json_rpc_client): | ||
contract, _ = block_timestamp_contract | ||
sender_account = self.accounts[0] | ||
|
||
tx = self.web3_client.make_raw_tx(sender_account) | ||
instruction_tx = contract.functions.logTimestamp().build_transaction(tx) | ||
receipt = self.web3_client.send_transaction(sender_account, instruction_tx) | ||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_timestamp = EthGetBlockByHashResult(**response).result.timestamp | ||
|
||
event_logs = contract.events.Result().process_receipt(receipt) | ||
assert hex(event_logs[0]["args"]["block_timestamp"]) <= tx_block_timestamp | ||
|
||
def test_block_timestamp_iterative(self, block_timestamp_contract, json_rpc_client): | ||
contract, _ = block_timestamp_contract | ||
sender_account = self.accounts[0] | ||
|
||
tx = self.web3_client.make_raw_tx(sender_account) | ||
instruction_tx = contract.functions.callIterativeTrx().build_transaction(tx) | ||
receipt = self.web3_client.send_transaction(sender_account, instruction_tx) | ||
assert receipt["status"] == 1 | ||
assert self.web3_client.is_trx_iterative(receipt["transactionHash"].hex()) | ||
|
||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_timestamp = EthGetBlockByHashResult(**response).result.timestamp | ||
|
||
event_logs = contract.events.Result().process_receipt(receipt) | ||
assert len(event_logs) == 1, "Event logs are not found" | ||
assert hex(event_logs[0]["args"]["block_timestamp"]) <= tx_block_timestamp | ||
|
||
def test_block_timestamp_constructor(self, block_timestamp_contract, json_rpc_client): | ||
contract, receipt = block_timestamp_contract | ||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_timestamp = EthGetBlockByHashResult(**response).result.timestamp | ||
|
||
assert hex(contract.functions.initial_block_timestamp().call()) <= tx_block_timestamp | ||
|
||
def test_block_timestamp_in_mapping(self, block_timestamp_contract, json_rpc_client): | ||
contract, _ = block_timestamp_contract | ||
sender_account = self.accounts[0] | ||
|
||
v1 = random.randint(1, 100) | ||
v2 = random.randint(1, 100) | ||
tx = self.web3_client.make_raw_tx(sender_account) | ||
instruction_tx = contract.functions.addDataToMapping(v1, v2).build_transaction(tx) | ||
receipt = self.web3_client.send_transaction(sender_account, instruction_tx) | ||
assert self.web3_client.is_trx_iterative(receipt["transactionHash"].hex()) | ||
assert receipt["status"] == 1 | ||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_timestamp = EthGetBlockByHashResult(**response).result.timestamp | ||
|
||
event_logs = contract.events.DataAdded().process_receipt(receipt) | ||
added_timestamp = event_logs[0]["args"]["timestamp"] | ||
|
||
assert added_timestamp <= int(tx_block_timestamp, 16) | ||
assert contract.functions.getDataFromMapping(added_timestamp).call() == [v1, v2] | ||
|
||
def test_block_number_call(self, block_number_contract, json_rpc_client): | ||
contract, _ = block_number_contract | ||
current_block_number = json_rpc_client.send_rpc(method="eth_blockNumber", params=[])["result"] | ||
assert hex(contract.functions.getBlockNumber().call()) >= current_block_number | ||
|
||
def test_block_number_simple_trx(self, block_number_contract, json_rpc_client): | ||
contract, _ = block_number_contract | ||
sender_account = self.accounts[0] | ||
|
||
tx = self.web3_client.make_raw_tx(sender_account) | ||
instruction_tx = contract.functions.logBlockNumber().build_transaction(tx) | ||
receipt = self.web3_client.send_transaction(sender_account, instruction_tx) | ||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_number = EthGetBlockByHashResult(**response).result.number | ||
|
||
event_logs = contract.events.Result().process_receipt(receipt) | ||
assert hex(event_logs[0]["args"]["block_number"]) <= tx_block_number | ||
|
||
def test_block_number_iterative(self, block_number_contract, json_rpc_client): | ||
contract, _ = block_number_contract | ||
sender_account = self.accounts[0] | ||
|
||
tx = self.web3_client.make_raw_tx(sender_account) | ||
instruction_tx = contract.functions.callIterativeTrx().build_transaction(tx) | ||
receipt = self.web3_client.send_transaction(sender_account, instruction_tx) | ||
assert self.web3_client.is_trx_iterative(receipt["transactionHash"].hex()) | ||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_number = EthGetBlockByHashResult(**response).result.number | ||
event_logs = contract.events.Result().process_receipt(receipt) | ||
|
||
assert hex(event_logs[0]["args"]["block_number"]) <= tx_block_number | ||
|
||
def test_block_number_constructor(self, block_number_contract, json_rpc_client): | ||
contract, receipt = block_number_contract | ||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_number = EthGetBlockByHashResult(**response).result.number | ||
|
||
assert hex(contract.functions.initial_block_number().call()) <= tx_block_number | ||
|
||
def test_contract_deploys_contract_with_timestamp(self, json_rpc_client): | ||
deployer, receipt = self.web3_client.deploy_and_get_contract( | ||
"common/Block.sol", "0.8.10", self.accounts[0], contract_name="BlockTimestampDeployer" | ||
) | ||
response = json_rpc_client.send_rpc(method="eth_getBlockByHash", params=[receipt["blockHash"].hex(), False]) | ||
tx_block_timestamp = EthGetBlockByHashResult(**response).result.timestamp | ||
|
||
addr = deployer.events.Log().process_receipt(receipt)[0]["args"]["addr"] | ||
contract = self.web3_client.get_deployed_contract(addr, "common/Block.sol", "BlockTimestamp") | ||
assert hex(contract.functions.initial_block_timestamp().call()) <= tx_block_timestamp | ||
|
||
def test_block_number_in_mapping(self, block_number_contract): | ||
contract, _ = block_number_contract | ||
sender_account = self.accounts[0] | ||
|
||
tx = self.web3_client.make_raw_tx(sender_account) | ||
v1 = random.randint(1, 100) | ||
v2 = random.randint(1, 100) | ||
instruction_tx = contract.functions.addDataToMapping(v1, v2).build_transaction(tx) | ||
receipt = self.web3_client.send_transaction(sender_account, instruction_tx) | ||
assert self.web3_client.is_trx_iterative(receipt["transactionHash"].hex()) | ||
assert receipt["status"] == 1 | ||
event_logs = contract.events.DataAdded().process_receipt(receipt) | ||
assert len(event_logs) == 5, "Event logs are not found" | ||
block_number_added = event_logs[0]["args"]["number"] | ||
assert block_number_added <= receipt["blockNumber"] | ||
assert contract.functions.getDataFromMapping(block_number_added).call() == [v1, v2] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.