From fa2604b55c2567471da67465baba3fdaf4d3a425 Mon Sep 17 00:00:00 2001 From: Yosuke Otosu Date: Mon, 4 Apr 2022 19:40:24 +0900 Subject: [PATCH 1/4] feat: Log storage contract with frozen past logs --- contracts/utils/LogStorage.sol | 127 ++++++++++++++++ tests/utils/test_LogStorage.py | 258 +++++++++++++++++++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 contracts/utils/LogStorage.sol create mode 100644 tests/utils/test_LogStorage.py diff --git a/contracts/utils/LogStorage.sol b/contracts/utils/LogStorage.sol new file mode 100644 index 0000000..51e2885 --- /dev/null +++ b/contracts/utils/LogStorage.sol @@ -0,0 +1,127 @@ +/** +* Copyright BOOSTRY Co., Ltd. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +* See the License for the specific language governing permissions and +* limitations under the License. +* +* SPDX-License-Identifier: Apache-2.0 +*/ + +pragma solidity ^0.8.0; + +/// @title Log Storage +contract LogStorage { + // ログレコード + struct log { + address from; // ログ出力元アドレス + string message; // ログ本文 + uint256 createdBlockNumber; // ログ出力時のブロックカウント数 + uint256 freezingGraceBlockCount; // 凍結までのブロックカウント数 + } + + uint256 public nextIndex = 0; + mapping(uint256 => log) public logs; + + // イベント:ログ書込み + event Wrote( + uint256 logIndex, + address indexed logAuthorAddress, + string message, + uint256 createdBlockNumber, + uint256 freezingGraceBlockCount + ); + + // イベント:ログ編集 + event Edited( + uint256 logIndex, + address indexed logAuthorAddress, + string message + ); + + /// @dev ログが凍結されていないことをチェック + /// @param _index チェック対象のログインデックス + modifier onlyUnfrozen(uint256 _index) { + require( + logs[_index].createdBlockNumber + logs[_index].freezingGraceBlockCount >= block.number, + "frozen" + ); + _; + } + + /// @dev 対象のログがmsg.senderによって作成されたことをチェック + /// @param _index チェック対象のログインデックス + modifier onlyAuthor(uint256 _index) { + require( + logs[_index].from == msg.sender, + "Can be edited by the author." + ); + _; + } + + // [CONSTRUCTOR] + constructor() {} + + /// @notice ログ書込み + /// @param _message ログ本文 + /// @param _freezingGraceBlockCount 凍結までのブロックカウント数 + function writeLog(string memory _message, uint256 _freezingGraceBlockCount) public returns (uint256 logIndex) { + // ログレコードをストレージに追加 + logs[nextIndex] = log(msg.sender, _message, block.number, _freezingGraceBlockCount); + + // イベント登録 + emit Wrote( + nextIndex, + msg.sender, + _message, + block.number, + _freezingGraceBlockCount + ); + nextIndex += 1; + return nextIndex - 1; + } + + /// @notice ログ編集 + /// @param _index ログインデックス + /// @param _message 編集後のログ本文 + function editLog(uint256 _index, string memory _message) public onlyUnfrozen(_index) onlyAuthor(_index) { + logs[_index].message = _message; + + // イベント登録 + emit Edited( + _index, + msg.sender, + _message + ); + } + + /// @notice ログ取得 + /// @param _index ログインデックス + function getLogByIndex(uint256 _index) + public + view + returns ( + address from, + string memory message, + uint256 createdBlockNumber, + uint256 freezingGraceBlockCount + ) + { + require(logs[_index].from != address(0), "Log of that index is not stored yet."); + return ( + logs[_index].from, + logs[_index].message, + logs[_index].createdBlockNumber, + logs[_index].freezingGraceBlockCount + ); + } +} \ No newline at end of file diff --git a/tests/utils/test_LogStorage.py b/tests/utils/test_LogStorage.py new file mode 100644 index 0000000..b655900 --- /dev/null +++ b/tests/utils/test_LogStorage.py @@ -0,0 +1,258 @@ +""" +Copyright BOOSTRY Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +SPDX-License-Identifier: Apache-2.0 +""" +import brownie + + +class TestWriteLog: + + ########################################################## + # Normal + ########################################################## + + # Normal_1 + def test_normal_1(self, LogStorage, users, web3): + admin = users["admin"] + + # Deploy contract + log_storage = admin.deploy(LogStorage) + test_block = web3.eth.block_number + 1 + test_message = "test_message" + test_freezing_grace_block_count = 5 + + # Write Log + tx = log_storage.writeLog( + test_message, + test_freezing_grace_block_count + ) + + # Assertion + assert tx.events["Wrote"]["logIndex"] == 0 + assert tx.events["Wrote"]["logAuthorAddress"] == admin + assert tx.events["Wrote"]["message"] == test_message + assert tx.events["Wrote"]["createdBlockNumber"] == test_block + assert tx.events["Wrote"]["freezingGraceBlockCount"] == test_freezing_grace_block_count + + # Normal_2 + # Write twice + def test_normal_2(self, LogStorage, users, web3): + admin = users["admin"] + author = users["user1"] + + # Deploy contract + log_storage = admin.deploy(LogStorage) + test1_block = web3.eth.block_number + 1 + test1_message = "test_message" + test1_freezing_grace_block_count = 5 + + # Write Log + tx = log_storage.writeLog( + test1_message, + test1_freezing_grace_block_count, + {"from": author} + ) + + # Assertion + assert tx.events["Wrote"]["logIndex"] == 0 + assert tx.events["Wrote"]["logAuthorAddress"] == author + assert tx.events["Wrote"]["message"] == test1_message + assert tx.events["Wrote"]["createdBlockNumber"] == test1_block + assert tx.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count + + # Deploy contract + test2_block = web3.eth.block_number + 1 + test2_message = "test_message" + test2_freezing_grace_block_count = 5 + + # Write Log + tx = log_storage.writeLog( + test2_message, + test2_freezing_grace_block_count, + {"from": author} + ) + + # Assertion + assert tx.events["Wrote"]["logIndex"] == 1 + assert tx.events["Wrote"]["logAuthorAddress"] == author + assert tx.events["Wrote"]["message"] == test2_message + assert tx.events["Wrote"]["createdBlockNumber"] == test2_block + assert tx.events["Wrote"]["freezingGraceBlockCount"] == test2_freezing_grace_block_count + + def test_error_1(self, LogStorage, users, web3): + pass + + +class TestEditLog: + + ########################################################## + # Normal + ########################################################## + + # Normal_1 + def test_normal_1(self, LogStorage, users, web3): + admin = users["admin"] + author = users["user1"] + + # Deploy contract + log_storage = admin.deploy(LogStorage) + test1_block = web3.eth.block_number + 1 + test1_message = "test1 message" + test1_freezing_grace_block_count = 1 + + # Write Log + tx = log_storage.writeLog( + test1_message, + test1_freezing_grace_block_count, + {"from": author} + ) + + # Assertion + assert tx.events["Wrote"]["logIndex"] == 0 + assert tx.events["Wrote"]["logAuthorAddress"] == author + assert tx.events["Wrote"]["message"] == test1_message + assert tx.events["Wrote"]["createdBlockNumber"] == test1_block + assert tx.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count + + test1_message_edit = "test1 message edited" + tx = log_storage.editLog( + 0, + test1_message_edit, + {"from": author} + ) + assert tx.events["Edited"]["logIndex"] == 0 + assert tx.events["Edited"]["logAuthorAddress"] == author + assert tx.events["Edited"]["message"] == test1_message_edit + + ########################################################## + # Error + ########################################################## + + # Error_1 + def test_error_1(self, LogStorage, users, web3): + admin = users["admin"] + author = users["user1"] + + # Deploy contract + log_storage = admin.deploy(LogStorage) + test1_block = web3.eth.block_number + 1 + test1_message = "test1 message" + test1_freezing_grace_block_count = 1 + + # Write Log + tx1 = log_storage.writeLog( + test1_message, + test1_freezing_grace_block_count, + {"from": author} + ) + + # Assertion + assert tx1.events["Wrote"]["logIndex"] == 0 + assert tx1.events["Wrote"]["logAuthorAddress"] == author + assert tx1.events["Wrote"]["message"] == test1_message + assert tx1.events["Wrote"]["createdBlockNumber"] == test1_block + assert tx1.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count + + # Increment block number by write twice + for i in range(2): + log_storage.writeLog( + test1_message, + test1_freezing_grace_block_count, + {"from": author} + ) + with brownie.reverts(revert_msg="frozen"): + test1_message_edit = "test1 message edited" + tx3 = log_storage.editLog( + 0, + test1_message_edit, + {"from": author} + ) + + # Error_2 + def test_error_2(self, LogStorage, users, web3): + admin = users["admin"] + author = users["user1"] + + # Deploy contract + log_storage = admin.deploy(LogStorage) + test1_block = web3.eth.block_number + 1 + test1_message = "test1 message" + test1_freezing_grace_block_count = 1 + + # Write Log + tx1 = log_storage.writeLog( + test1_message, + test1_freezing_grace_block_count, + {"from": author} + ) + + # Assertion + assert tx1.events["Wrote"]["logIndex"] == 0 + assert tx1.events["Wrote"]["logAuthorAddress"] == author + assert tx1.events["Wrote"]["message"] == test1_message + assert tx1.events["Wrote"]["createdBlockNumber"] == test1_block + assert tx1.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count + + with brownie.reverts(revert_msg="Can be edited by the author."): + test1_message_edit = "test1 message edited" + log_storage.editLog( + 0, + test1_message_edit, + {"from": admin} + ) + + +class TestGetLogByIndex: + + ########################################################## + # Normal + ########################################################## + + # Normal_1 + def test_normal_1(self, LogStorage, users, web3): + admin = users["admin"] + author = users["user1"] + + # Deploy contract + log_storage = admin.deploy(LogStorage) + test1_block = web3.eth.block_number + 1 + test1_message = "test1 message" + test1_freezing_grace_block_count = 1 + + # Write Log + tx = log_storage.writeLog( + test1_message, + test1_freezing_grace_block_count, + {"from": author} + ) + + # Assertion + assert tx.events["Wrote"]["logIndex"] == 0 + assert tx.events["Wrote"]["logAuthorAddress"] == author + assert tx.events["Wrote"]["message"] == test1_message + assert tx.events["Wrote"]["createdBlockNumber"] == test1_block + assert tx.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count + log = log_storage.getLogByIndex(0) + assert log[0] == author + assert log[1] == test1_message + assert log[2] == test1_block + assert log[3] == test1_freezing_grace_block_count + + # Error_1 + def test_error_1(self, LogStorage, users, web3): + admin = users["admin"] + + # Deploy contract + log_storage = admin.deploy(LogStorage) + + with brownie.reverts(revert_msg="Log of that index is not stored yet."): + log = log_storage.getLogByIndex(0) From 7910af8e13cc89641264e24ada96198f668ac73c Mon Sep 17 00:00:00 2001 From: Yosuke Otosu Date: Tue, 5 Apr 2022 12:51:11 +0900 Subject: [PATCH 2/4] feat: Log storage contract with frozen past logs --- contracts/utils/FreezeLog.sol | 116 +++++++++++++++ contracts/utils/LogStorage.sol | 127 ---------------- tests/utils/test_FreezeLog.py | 248 +++++++++++++++++++++++++++++++ tests/utils/test_LogStorage.py | 258 --------------------------------- 4 files changed, 364 insertions(+), 385 deletions(-) create mode 100644 contracts/utils/FreezeLog.sol delete mode 100644 contracts/utils/LogStorage.sol create mode 100644 tests/utils/test_FreezeLog.py delete mode 100644 tests/utils/test_LogStorage.py diff --git a/contracts/utils/FreezeLog.sol b/contracts/utils/FreezeLog.sol new file mode 100644 index 0000000..d6ef6f4 --- /dev/null +++ b/contracts/utils/FreezeLog.sol @@ -0,0 +1,116 @@ +/** +* Copyright BOOSTRY Co., Ltd. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +* See the License for the specific language governing permissions and +* limitations under the License. +* +* SPDX-License-Identifier: Apache-2.0 +*/ + +pragma solidity ^0.8.0; + +/// @title Freeze Log +contract FreezeLog { + // Event: log recorded + event Recorded(address indexed recorder, uint256 index, uint256 _freezingGraceBlockCount); + + // Event: log updated + event Updated(address indexed recorder, uint256 index); + + struct Log { + address recorder; // Recorder + string log; // Log text + uint256 createdBlockNumber; // Created block number + uint256 freezingGraceBlockCount; // Freezing grace block count + } + + /// Recorder -> Index + mapping(address => uint) public last_log_index; + /// Recorder -> Index -> Log + mapping(address => mapping(uint256 => Log)) public logs; + + // [CONSTRUCTOR] + constructor() {} + + /// @notice Get last index + /// @param _recorder Recorder + /// @return _index Last index + function lastLogIndex(address _recorder) + public + view + returns (uint256 _index) + { + return last_log_index[_recorder]; + } + + /// @notice Record new logs + /// @param _log Log text + /// @param _freezingGraceBlockCount Freezing grace block count + function recordLog( + string memory _log, + uint256 _freezingGraceBlockCount + ) + public + { + Log storage log = logs[msg.sender][last_log_index[msg.sender]]; + + log.recorder = msg.sender; + log.log = _log; + log.createdBlockNumber = block.number; + log.freezingGraceBlockCount = _freezingGraceBlockCount; + last_log_index[msg.sender]++; + + emit Recorded(msg.sender, last_log_index[msg.sender] - 1, _freezingGraceBlockCount); + } + + /// @notice Update recorded logs + /// @param _index Index + /// @param _log Log to be updated + function updateLog( + uint256 _index, + string memory _log + ) + public + { + Log storage storageLog = logs[msg.sender][_index]; + + require( + storageLog.createdBlockNumber + storageLog.freezingGraceBlockCount >= block.number, + "frozen" + ); + + storageLog.log = _log; + + emit Updated(msg.sender, _index); + } + + /// @notice Get log + /// @param _recorder Recorder + /// @param _index Index + function getLog( + address _recorder, + uint256 _index + ) + public + view + returns ( + uint256 _createdBlockNumber, + uint256 _freezingGraceBlockCount, + string memory _log + ) + { + Log storage log = logs[_recorder][_index]; + require(log.recorder != address(0)); + return (log.createdBlockNumber, log.freezingGraceBlockCount, log.log); + } +} \ No newline at end of file diff --git a/contracts/utils/LogStorage.sol b/contracts/utils/LogStorage.sol deleted file mode 100644 index 51e2885..0000000 --- a/contracts/utils/LogStorage.sol +++ /dev/null @@ -1,127 +0,0 @@ -/** -* Copyright BOOSTRY Co., Ltd. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* -* You may obtain a copy of the License at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -* See the License for the specific language governing permissions and -* limitations under the License. -* -* SPDX-License-Identifier: Apache-2.0 -*/ - -pragma solidity ^0.8.0; - -/// @title Log Storage -contract LogStorage { - // ログレコード - struct log { - address from; // ログ出力元アドレス - string message; // ログ本文 - uint256 createdBlockNumber; // ログ出力時のブロックカウント数 - uint256 freezingGraceBlockCount; // 凍結までのブロックカウント数 - } - - uint256 public nextIndex = 0; - mapping(uint256 => log) public logs; - - // イベント:ログ書込み - event Wrote( - uint256 logIndex, - address indexed logAuthorAddress, - string message, - uint256 createdBlockNumber, - uint256 freezingGraceBlockCount - ); - - // イベント:ログ編集 - event Edited( - uint256 logIndex, - address indexed logAuthorAddress, - string message - ); - - /// @dev ログが凍結されていないことをチェック - /// @param _index チェック対象のログインデックス - modifier onlyUnfrozen(uint256 _index) { - require( - logs[_index].createdBlockNumber + logs[_index].freezingGraceBlockCount >= block.number, - "frozen" - ); - _; - } - - /// @dev 対象のログがmsg.senderによって作成されたことをチェック - /// @param _index チェック対象のログインデックス - modifier onlyAuthor(uint256 _index) { - require( - logs[_index].from == msg.sender, - "Can be edited by the author." - ); - _; - } - - // [CONSTRUCTOR] - constructor() {} - - /// @notice ログ書込み - /// @param _message ログ本文 - /// @param _freezingGraceBlockCount 凍結までのブロックカウント数 - function writeLog(string memory _message, uint256 _freezingGraceBlockCount) public returns (uint256 logIndex) { - // ログレコードをストレージに追加 - logs[nextIndex] = log(msg.sender, _message, block.number, _freezingGraceBlockCount); - - // イベント登録 - emit Wrote( - nextIndex, - msg.sender, - _message, - block.number, - _freezingGraceBlockCount - ); - nextIndex += 1; - return nextIndex - 1; - } - - /// @notice ログ編集 - /// @param _index ログインデックス - /// @param _message 編集後のログ本文 - function editLog(uint256 _index, string memory _message) public onlyUnfrozen(_index) onlyAuthor(_index) { - logs[_index].message = _message; - - // イベント登録 - emit Edited( - _index, - msg.sender, - _message - ); - } - - /// @notice ログ取得 - /// @param _index ログインデックス - function getLogByIndex(uint256 _index) - public - view - returns ( - address from, - string memory message, - uint256 createdBlockNumber, - uint256 freezingGraceBlockCount - ) - { - require(logs[_index].from != address(0), "Log of that index is not stored yet."); - return ( - logs[_index].from, - logs[_index].message, - logs[_index].createdBlockNumber, - logs[_index].freezingGraceBlockCount - ); - } -} \ No newline at end of file diff --git a/tests/utils/test_FreezeLog.py b/tests/utils/test_FreezeLog.py new file mode 100644 index 0000000..2a68c7f --- /dev/null +++ b/tests/utils/test_FreezeLog.py @@ -0,0 +1,248 @@ +""" +Copyright BOOSTRY Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +SPDX-License-Identifier: Apache-2.0 +""" +import brownie + + +class TestFreezeLog: + + ########################################################## + # Normal + ########################################################## + + # Normal_1 + def test_normal_1(self, FreezeLog, users, web3): + admin = users["admin"] + user = users["user1"] + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + test_block = web3.eth.block_number + 1 + test_message = "test_message" + test_freezing_grace_block_count = 5 + + # Record Log + tx = freeze_log.recordLog( + test_message, + test_freezing_grace_block_count, + {"from": user} + ) + + # Assertion + assert tx.events["Recorded"]["recorder"] == user + + # Normal_2 + # Write twice + def test_normal_2(self, FreezeLog, users, web3): + admin = users["admin"] + user1 = users["user1"] + user2 = users["user2"] + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + test_block = web3.eth.block_number + 1 + test_message = "test_message" + test_freezing_grace_block_count = 5 + + # Record Log + tx = freeze_log.recordLog( + test_message, + test_freezing_grace_block_count, + {"from": user1} + ) + + # Assertion + assert tx.events["Recorded"]["recorder"] == user1.address + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + test_block = web3.eth.block_number + 1 + test_message = "test_message" + test_freezing_grace_block_count = 5 + + # Record Log + tx = freeze_log.recordLog( + test_message, + test_freezing_grace_block_count, + {"from": user2} + ) + + # Assertion + assert tx.events["Recorded"]["recorder"] == user2.address + + +class TestLastLogIndex: + + ########################################################## + # Normal + ########################################################## + + # Normal_1 + def test_normal_1(self, FreezeLog, users, web3): + admin = users["admin"] + user1 = users["user1"] + user2 = users["user2"] + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + test_block = web3.eth.block_number + 1 + test_message = "test_message" + test_freezing_grace_block_count = 5 + + # Record Log + tx = freeze_log.recordLog( + test_message, + test_freezing_grace_block_count, + {"from": user1} + ) + + user1_last_log_index = freeze_log.lastLogIndex(user1, {"from": user2}) + assert user1_last_log_index == 1 + user2_last_log_index = freeze_log.lastLogIndex(user2, {"from": user2}) + assert user2_last_log_index == 0 + + +class TestUpdateLog: + + ########################################################## + # Normal + ########################################################## + + # Normal_1 + def test_normal_1(self, FreezeLog, users, web3): + admin = users["admin"] + user1 = users["user1"] + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + test_block = web3.eth.block_number + 1 + test_message = "test_message" + test_freezing_grace_block_count = 5 + + # Record Log + tx = freeze_log.recordLog( + test_message, + test_freezing_grace_block_count, + {"from": user1} + ) + # Assertion + assert tx.events["Recorded"]["recorder"] == user1 + + user1_last_index = freeze_log.lastLogIndex(user1, {"from": user1}) + + tx = freeze_log.updateLog(user1_last_index - 1, test_message[::-1], {"from": user1}) + + # Assertion + assert tx.events["Updated"]["recorder"] == user1 + assert tx.events["Updated"]["index"] == user1_last_index - 1 + + ########################################################## + # Error + ########################################################## + + # Error_1 + def test_error_1(self, FreezeLog, users, web3): + admin = users["admin"] + user1 = users["user1"] + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + + test_idx = 10 + test_message = "test1 message" + with brownie.reverts(): + freeze_log.updateLog(test_idx, test_message, {"from": user1}) + + # Error_2 + def test_error_2(self, FreezeLog, users, web3): + admin = users["admin"] + user1 = users["user1"] + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + + test1_block = web3.eth.block_number + 1 + test1_message = "test1 message" + test1_freezing_grace_block_count = 2 + + # Write Log + tx1 = freeze_log.recordLog( + test1_message, + test1_freezing_grace_block_count, + {"from": user1} + ) + + # Assertion + assert tx1.events["Recorded"]["recorder"] == user1.address + + for i in range(test1_freezing_grace_block_count): + # Write Log + tx1 = freeze_log.recordLog( + test1_message, + test1_freezing_grace_block_count, + {"from": user1} + ) + + with brownie.reverts(revert_msg="frozen"): + test1_message_update = "test1 message updated" + freeze_log.updateLog( + 0, + test1_message_update, + {"from": user1} + ) + + +class TestGetLog: + + ########################################################## + # Normal + ########################################################## + + # Normal_1 + def test_normal_1(self, FreezeLog, users, web3): + admin = users["admin"] + user1 = users["user1"] + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + test1_block = web3.eth.block_number + 1 + test1_message = "test1 message" + test1_freezing_grace_block_count = 1 + + # Write Log + tx = freeze_log.recordLog( + test1_message, + test1_freezing_grace_block_count, + {"from": user1} + ) + + # Assertion + assert tx.events["Recorded"]["recorder"] == user1.address + + user1_last_log_index = freeze_log.lastLogIndex(user1.address) + + log = freeze_log.getLog(user1.address, user1_last_log_index - 1) + + assert log[0] == test1_block + assert log[1] == test1_freezing_grace_block_count + assert log[2] == test1_message + + # Error_1 + def test_error_1(self, FreezeLog, users, web3): + admin = users["admin"] + user1 = users["user1"] + + # Deploy contract + freeze_log = admin.deploy(FreezeLog) + + with brownie.reverts(): + log = freeze_log.getLog(user1.address, 0) diff --git a/tests/utils/test_LogStorage.py b/tests/utils/test_LogStorage.py deleted file mode 100644 index b655900..0000000 --- a/tests/utils/test_LogStorage.py +++ /dev/null @@ -1,258 +0,0 @@ -""" -Copyright BOOSTRY Co., Ltd. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -SPDX-License-Identifier: Apache-2.0 -""" -import brownie - - -class TestWriteLog: - - ########################################################## - # Normal - ########################################################## - - # Normal_1 - def test_normal_1(self, LogStorage, users, web3): - admin = users["admin"] - - # Deploy contract - log_storage = admin.deploy(LogStorage) - test_block = web3.eth.block_number + 1 - test_message = "test_message" - test_freezing_grace_block_count = 5 - - # Write Log - tx = log_storage.writeLog( - test_message, - test_freezing_grace_block_count - ) - - # Assertion - assert tx.events["Wrote"]["logIndex"] == 0 - assert tx.events["Wrote"]["logAuthorAddress"] == admin - assert tx.events["Wrote"]["message"] == test_message - assert tx.events["Wrote"]["createdBlockNumber"] == test_block - assert tx.events["Wrote"]["freezingGraceBlockCount"] == test_freezing_grace_block_count - - # Normal_2 - # Write twice - def test_normal_2(self, LogStorage, users, web3): - admin = users["admin"] - author = users["user1"] - - # Deploy contract - log_storage = admin.deploy(LogStorage) - test1_block = web3.eth.block_number + 1 - test1_message = "test_message" - test1_freezing_grace_block_count = 5 - - # Write Log - tx = log_storage.writeLog( - test1_message, - test1_freezing_grace_block_count, - {"from": author} - ) - - # Assertion - assert tx.events["Wrote"]["logIndex"] == 0 - assert tx.events["Wrote"]["logAuthorAddress"] == author - assert tx.events["Wrote"]["message"] == test1_message - assert tx.events["Wrote"]["createdBlockNumber"] == test1_block - assert tx.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count - - # Deploy contract - test2_block = web3.eth.block_number + 1 - test2_message = "test_message" - test2_freezing_grace_block_count = 5 - - # Write Log - tx = log_storage.writeLog( - test2_message, - test2_freezing_grace_block_count, - {"from": author} - ) - - # Assertion - assert tx.events["Wrote"]["logIndex"] == 1 - assert tx.events["Wrote"]["logAuthorAddress"] == author - assert tx.events["Wrote"]["message"] == test2_message - assert tx.events["Wrote"]["createdBlockNumber"] == test2_block - assert tx.events["Wrote"]["freezingGraceBlockCount"] == test2_freezing_grace_block_count - - def test_error_1(self, LogStorage, users, web3): - pass - - -class TestEditLog: - - ########################################################## - # Normal - ########################################################## - - # Normal_1 - def test_normal_1(self, LogStorage, users, web3): - admin = users["admin"] - author = users["user1"] - - # Deploy contract - log_storage = admin.deploy(LogStorage) - test1_block = web3.eth.block_number + 1 - test1_message = "test1 message" - test1_freezing_grace_block_count = 1 - - # Write Log - tx = log_storage.writeLog( - test1_message, - test1_freezing_grace_block_count, - {"from": author} - ) - - # Assertion - assert tx.events["Wrote"]["logIndex"] == 0 - assert tx.events["Wrote"]["logAuthorAddress"] == author - assert tx.events["Wrote"]["message"] == test1_message - assert tx.events["Wrote"]["createdBlockNumber"] == test1_block - assert tx.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count - - test1_message_edit = "test1 message edited" - tx = log_storage.editLog( - 0, - test1_message_edit, - {"from": author} - ) - assert tx.events["Edited"]["logIndex"] == 0 - assert tx.events["Edited"]["logAuthorAddress"] == author - assert tx.events["Edited"]["message"] == test1_message_edit - - ########################################################## - # Error - ########################################################## - - # Error_1 - def test_error_1(self, LogStorage, users, web3): - admin = users["admin"] - author = users["user1"] - - # Deploy contract - log_storage = admin.deploy(LogStorage) - test1_block = web3.eth.block_number + 1 - test1_message = "test1 message" - test1_freezing_grace_block_count = 1 - - # Write Log - tx1 = log_storage.writeLog( - test1_message, - test1_freezing_grace_block_count, - {"from": author} - ) - - # Assertion - assert tx1.events["Wrote"]["logIndex"] == 0 - assert tx1.events["Wrote"]["logAuthorAddress"] == author - assert tx1.events["Wrote"]["message"] == test1_message - assert tx1.events["Wrote"]["createdBlockNumber"] == test1_block - assert tx1.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count - - # Increment block number by write twice - for i in range(2): - log_storage.writeLog( - test1_message, - test1_freezing_grace_block_count, - {"from": author} - ) - with brownie.reverts(revert_msg="frozen"): - test1_message_edit = "test1 message edited" - tx3 = log_storage.editLog( - 0, - test1_message_edit, - {"from": author} - ) - - # Error_2 - def test_error_2(self, LogStorage, users, web3): - admin = users["admin"] - author = users["user1"] - - # Deploy contract - log_storage = admin.deploy(LogStorage) - test1_block = web3.eth.block_number + 1 - test1_message = "test1 message" - test1_freezing_grace_block_count = 1 - - # Write Log - tx1 = log_storage.writeLog( - test1_message, - test1_freezing_grace_block_count, - {"from": author} - ) - - # Assertion - assert tx1.events["Wrote"]["logIndex"] == 0 - assert tx1.events["Wrote"]["logAuthorAddress"] == author - assert tx1.events["Wrote"]["message"] == test1_message - assert tx1.events["Wrote"]["createdBlockNumber"] == test1_block - assert tx1.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count - - with brownie.reverts(revert_msg="Can be edited by the author."): - test1_message_edit = "test1 message edited" - log_storage.editLog( - 0, - test1_message_edit, - {"from": admin} - ) - - -class TestGetLogByIndex: - - ########################################################## - # Normal - ########################################################## - - # Normal_1 - def test_normal_1(self, LogStorage, users, web3): - admin = users["admin"] - author = users["user1"] - - # Deploy contract - log_storage = admin.deploy(LogStorage) - test1_block = web3.eth.block_number + 1 - test1_message = "test1 message" - test1_freezing_grace_block_count = 1 - - # Write Log - tx = log_storage.writeLog( - test1_message, - test1_freezing_grace_block_count, - {"from": author} - ) - - # Assertion - assert tx.events["Wrote"]["logIndex"] == 0 - assert tx.events["Wrote"]["logAuthorAddress"] == author - assert tx.events["Wrote"]["message"] == test1_message - assert tx.events["Wrote"]["createdBlockNumber"] == test1_block - assert tx.events["Wrote"]["freezingGraceBlockCount"] == test1_freezing_grace_block_count - log = log_storage.getLogByIndex(0) - assert log[0] == author - assert log[1] == test1_message - assert log[2] == test1_block - assert log[3] == test1_freezing_grace_block_count - - # Error_1 - def test_error_1(self, LogStorage, users, web3): - admin = users["admin"] - - # Deploy contract - log_storage = admin.deploy(LogStorage) - - with brownie.reverts(revert_msg="Log of that index is not stored yet."): - log = log_storage.getLogByIndex(0) From 574f18032c0ef7855e22f5ecbd51ae39f24a66e3 Mon Sep 17 00:00:00 2001 From: Yosuke Otosu Date: Tue, 5 Apr 2022 14:02:39 +0900 Subject: [PATCH 3/4] fix comment --- tests/utils/test_FreezeLog.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/utils/test_FreezeLog.py b/tests/utils/test_FreezeLog.py index 2a68c7f..7e9d1ae 100644 --- a/tests/utils/test_FreezeLog.py +++ b/tests/utils/test_FreezeLog.py @@ -42,7 +42,6 @@ def test_normal_1(self, FreezeLog, users, web3): assert tx.events["Recorded"]["recorder"] == user # Normal_2 - # Write twice def test_normal_2(self, FreezeLog, users, web3): admin = users["admin"] user1 = users["user1"] @@ -105,8 +104,10 @@ def test_normal_1(self, FreezeLog, users, web3): {"from": user1} ) + # get last_log_index of user1 user1_last_log_index = freeze_log.lastLogIndex(user1, {"from": user2}) assert user1_last_log_index == 1 + # get last_log_index of user2 user2_last_log_index = freeze_log.lastLogIndex(user2, {"from": user2}) assert user2_last_log_index == 0 From 9c30730a9eb4a9d0743dd3cff45012e175af49b4 Mon Sep 17 00:00:00 2001 From: Yosuke Otosu Date: Tue, 5 Apr 2022 18:52:49 +0900 Subject: [PATCH 4/4] update some tests/logic and fix formatter --- contracts/utils/FreezeLog.sol | 100 ++++++++++++++++----------------- tests/utils/test_FreezeLog.py | 103 +++++++++++++++++----------------- 2 files changed, 102 insertions(+), 101 deletions(-) diff --git a/contracts/utils/FreezeLog.sol b/contracts/utils/FreezeLog.sol index d6ef6f4..d5a23b9 100644 --- a/contracts/utils/FreezeLog.sol +++ b/contracts/utils/FreezeLog.sol @@ -1,41 +1,45 @@ /** -* Copyright BOOSTRY Co., Ltd. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* -* You may obtain a copy of the License at -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -* See the License for the specific language governing permissions and -* limitations under the License. -* -* SPDX-License-Identifier: Apache-2.0 -*/ + * Copyright BOOSTRY Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ pragma solidity ^0.8.0; /// @title Freeze Log contract FreezeLog { // Event: log recorded - event Recorded(address indexed recorder, uint256 index, uint256 _freezingGraceBlockCount); + event Recorded( + address indexed recorder, + uint256 index, + uint256 _freezingGraceBlockCount + ); // Event: log updated event Updated(address indexed recorder, uint256 index); struct Log { - address recorder; // Recorder - string log; // Log text + address recorder; // Recorder + string log; // Log text uint256 createdBlockNumber; // Created block number - uint256 freezingGraceBlockCount; // Freezing grace block count + uint256 freezingGraceBlockCount; // Freezing grace block count } /// Recorder -> Index - mapping(address => uint) public last_log_index; + mapping(address => uint256) public last_log_index; /// Recorder -> Index -> Log mapping(address => mapping(uint256 => Log)) public logs; @@ -46,9 +50,9 @@ contract FreezeLog { /// @param _recorder Recorder /// @return _index Last index function lastLogIndex(address _recorder) - public - view - returns (uint256 _index) + public + view + returns (uint256 _index) { return last_log_index[_recorder]; } @@ -56,11 +60,8 @@ contract FreezeLog { /// @notice Record new logs /// @param _log Log text /// @param _freezingGraceBlockCount Freezing grace block count - function recordLog( - string memory _log, - uint256 _freezingGraceBlockCount - ) - public + function recordLog(string memory _log, uint256 _freezingGraceBlockCount) + public { Log storage log = logs[msg.sender][last_log_index[msg.sender]]; @@ -70,22 +71,23 @@ contract FreezeLog { log.freezingGraceBlockCount = _freezingGraceBlockCount; last_log_index[msg.sender]++; - emit Recorded(msg.sender, last_log_index[msg.sender] - 1, _freezingGraceBlockCount); + emit Recorded( + msg.sender, + last_log_index[msg.sender] - 1, + _freezingGraceBlockCount + ); } /// @notice Update recorded logs /// @param _index Index /// @param _log Log to be updated - function updateLog( - uint256 _index, - string memory _log - ) - public - { + function updateLog(uint256 _index, string memory _log) public { Log storage storageLog = logs[msg.sender][_index]; require( - storageLog.createdBlockNumber + storageLog.freezingGraceBlockCount >= block.number, + storageLog.createdBlockNumber + + storageLog.freezingGraceBlockCount >= + block.number, "frozen" ); @@ -97,20 +99,16 @@ contract FreezeLog { /// @notice Get log /// @param _recorder Recorder /// @param _index Index - function getLog( - address _recorder, - uint256 _index - ) - public - view - returns ( - uint256 _createdBlockNumber, - uint256 _freezingGraceBlockCount, - string memory _log - ) + function getLog(address _recorder, uint256 _index) + public + view + returns ( + uint256 _createdBlockNumber, + uint256 _freezingGraceBlockCount, + string memory _log + ) { Log storage log = logs[_recorder][_index]; - require(log.recorder != address(0)); return (log.createdBlockNumber, log.freezingGraceBlockCount, log.log); } -} \ No newline at end of file +} diff --git a/tests/utils/test_FreezeLog.py b/tests/utils/test_FreezeLog.py index 7e9d1ae..ca33b44 100644 --- a/tests/utils/test_FreezeLog.py +++ b/tests/utils/test_FreezeLog.py @@ -14,13 +14,14 @@ import brownie -class TestFreezeLog: +class TestRecordLog: ########################################################## # Normal ########################################################## # Normal_1 + # Add a record once. def test_normal_1(self, FreezeLog, users, web3): admin = users["admin"] user = users["user1"] @@ -33,15 +34,17 @@ def test_normal_1(self, FreezeLog, users, web3): # Record Log tx = freeze_log.recordLog( - test_message, - test_freezing_grace_block_count, - {"from": user} + test_message, test_freezing_grace_block_count, {"from": user} ) # Assertion assert tx.events["Recorded"]["recorder"] == user + log = freeze_log.getLog(user.address, 0, {"from": user}) + assert log == (test_block, test_freezing_grace_block_count, test_message) + # Normal_2 + # 2 person add a record each. def test_normal_2(self, FreezeLog, users, web3): admin = users["admin"] user1 = users["user1"] @@ -55,13 +58,13 @@ def test_normal_2(self, FreezeLog, users, web3): # Record Log tx = freeze_log.recordLog( - test_message, - test_freezing_grace_block_count, - {"from": user1} + test_message, test_freezing_grace_block_count, {"from": user1} ) # Assertion assert tx.events["Recorded"]["recorder"] == user1.address + log = freeze_log.getLog(user1.address, 0, {"from": user1}) + assert log == (test_block, test_freezing_grace_block_count, test_message) # Deploy contract freeze_log = admin.deploy(FreezeLog) @@ -71,13 +74,13 @@ def test_normal_2(self, FreezeLog, users, web3): # Record Log tx = freeze_log.recordLog( - test_message, - test_freezing_grace_block_count, - {"from": user2} + test_message, test_freezing_grace_block_count, {"from": user2} ) # Assertion assert tx.events["Recorded"]["recorder"] == user2.address + log = freeze_log.getLog(user2.address, 0, {"from": user2}) + assert log == (test_block, test_freezing_grace_block_count, test_message) class TestLastLogIndex: @@ -87,6 +90,7 @@ class TestLastLogIndex: ########################################################## # Normal_1 + # Get last_log_index after adding a record. def test_normal_1(self, FreezeLog, users, web3): admin = users["admin"] user1 = users["user1"] @@ -99,9 +103,7 @@ def test_normal_1(self, FreezeLog, users, web3): # Record Log tx = freeze_log.recordLog( - test_message, - test_freezing_grace_block_count, - {"from": user1} + test_message, test_freezing_grace_block_count, {"from": user1} ) # get last_log_index of user1 @@ -119,9 +121,10 @@ class TestUpdateLog: ########################################################## # Normal_1 + # After added a record, updating the record message. def test_normal_1(self, FreezeLog, users, web3): admin = users["admin"] - user1 = users["user1"] + user = users["user1"] # Deploy contract freeze_log = admin.deploy(FreezeLog) @@ -131,26 +134,32 @@ def test_normal_1(self, FreezeLog, users, web3): # Record Log tx = freeze_log.recordLog( - test_message, - test_freezing_grace_block_count, - {"from": user1} + test_message, test_freezing_grace_block_count, {"from": user} ) # Assertion - assert tx.events["Recorded"]["recorder"] == user1 + assert tx.events["Recorded"]["recorder"] == user - user1_last_index = freeze_log.lastLogIndex(user1, {"from": user1}) + user_last_log_index = freeze_log.lastLogIndex(user, {"from": user}) - tx = freeze_log.updateLog(user1_last_index - 1, test_message[::-1], {"from": user1}) + tx = freeze_log.updateLog( + user_last_log_index - 1, test_message[::-1], {"from": user} + ) # Assertion - assert tx.events["Updated"]["recorder"] == user1 - assert tx.events["Updated"]["index"] == user1_last_index - 1 + assert tx.events["Updated"]["recorder"] == user + assert tx.events["Updated"]["index"] == user_last_log_index - 1 + + log = freeze_log.getLog(user.address, user_last_log_index - 1, {"from": user}) + assert log[0] == test_block + assert log[1] == test_freezing_grace_block_count + assert log[2] == test_message[::-1] ########################################################## # Error ########################################################## # Error_1 + # Trying to update log of non-existent index, but fail. def test_error_1(self, FreezeLog, users, web3): admin = users["admin"] user1 = users["user1"] @@ -162,8 +171,11 @@ def test_error_1(self, FreezeLog, users, web3): test_message = "test1 message" with brownie.reverts(): freeze_log.updateLog(test_idx, test_message, {"from": user1}) + log = freeze_log.getLog(user1.address, 0, {"from": user1}) + assert log == (0, 0, "") # Error_2 + # Trying to update a frozen log, but fail. def test_error_2(self, FreezeLog, users, web3): admin = users["admin"] user1 = users["user1"] @@ -177,29 +189,31 @@ def test_error_2(self, FreezeLog, users, web3): # Write Log tx1 = freeze_log.recordLog( - test1_message, - test1_freezing_grace_block_count, - {"from": user1} + test1_message, test1_freezing_grace_block_count, {"from": user1} ) + log = freeze_log.getLog(user1.address, 0, {"from": user1}) # Assertion assert tx1.events["Recorded"]["recorder"] == user1.address + assert log[0] == test1_block + assert log[1] == test1_freezing_grace_block_count + assert log[2] == test1_message + # Add logs to freeze first log. for i in range(test1_freezing_grace_block_count): - # Write Log tx1 = freeze_log.recordLog( - test1_message, - test1_freezing_grace_block_count, - {"from": user1} + test1_message, test1_freezing_grace_block_count, {"from": user1} ) + # Trying to update a frozen log. with brownie.reverts(revert_msg="frozen"): test1_message_update = "test1 message updated" - freeze_log.updateLog( - 0, - test1_message_update, - {"from": user1} - ) + freeze_log.updateLog(0, test1_message_update, {"from": user1}) + + log = freeze_log.getLog(user1.address, 0, {"from": user1}) + assert log[0] == test1_block + assert log[1] == test1_freezing_grace_block_count + assert log[2] == test1_message class TestGetLog: @@ -209,6 +223,7 @@ class TestGetLog: ########################################################## # Normal_1 + # Get a log record by index. def test_normal_1(self, FreezeLog, users, web3): admin = users["admin"] user1 = users["user1"] @@ -221,9 +236,7 @@ def test_normal_1(self, FreezeLog, users, web3): # Write Log tx = freeze_log.recordLog( - test1_message, - test1_freezing_grace_block_count, - {"from": user1} + test1_message, test1_freezing_grace_block_count, {"from": user1} ) # Assertion @@ -231,19 +244,9 @@ def test_normal_1(self, FreezeLog, users, web3): user1_last_log_index = freeze_log.lastLogIndex(user1.address) - log = freeze_log.getLog(user1.address, user1_last_log_index - 1) - + log = freeze_log.getLog( + user1.address, user1_last_log_index - 1, {"from": user1} + ) assert log[0] == test1_block assert log[1] == test1_freezing_grace_block_count assert log[2] == test1_message - - # Error_1 - def test_error_1(self, FreezeLog, users, web3): - admin = users["admin"] - user1 = users["user1"] - - # Deploy contract - freeze_log = admin.deploy(FreezeLog) - - with brownie.reverts(): - log = freeze_log.getLog(user1.address, 0)