-
Notifications
You must be signed in to change notification settings - Fork 46
Inheritence Refactoring #442
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
base: next/3.0
Are you sure you want to change the base?
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Hey @guidanoli! Great work on this PR :) I've a few requests and comments! Do you have some schematics/diagrams of this inheritance design? I'm having difficulties seeing who inherits who, and where the functions are being implemented. I think with such a diagram, we'd be able to have a high-level view of the architecture as a whole. Take the I see a pattern where view functions called Can you describe, perhaps also with the aid of a schematic, the design of epochs closing and finalizing? |
|
Thanks for the valuable feedback, @GCdePaula ! I have simplified the inheritance graph, I hope you can see it clearly in the source code. Could you expand on why the pattern of view methods that revert if an action cannot be performed might cause troubles with the node? This strategy aimed to simplify the implementation and readability of the contracts. On |
|
Ok! Thank you. I'm taking a look :) Is the epoch close+finalize design described anywhere? |
|
I am not sure I like the name EventEmitter. Its not at all related to what the contract does, which is store the deployment block number. The name is related to the offchain client but it doesn't make a lot of sense in this codebase. Also, every smart contract is a event emitter. Maybe something like |
|
Every contract can emit events, but not every contract does. In the code base, it's easier to understand why |
It is thoroughly described in the documentation of the |
🌳 Inheritance TreeHere is the inheritance tree in Mermaid.
graph TD
OutboxImpl --> EpochManagerImpl & ReentrancyGuard:::oz
EpochManagerImpl --> InboxImpl
InboxImpl --> DeploymentInfoProviderImpl
TokenReceiverImpl --> ERC721Holder:::oz & ERC1155Holder:::oz
AppImpl["{Dave,Quorum}AppImpl"] --> OutboxImpl & TokenReceiverImpl
classDef oz fill:cyan,color:black
PS: OpenZeppelin contracts are colored cyan. 🧠 Rationale
🗒️ Notes
|
|
I've renamed
|
| function getInputCount() external view returns (uint256); | ||
|
|
||
| /// @notice Get the number of inputs before the current block. | ||
| function getInputCountBeforeCurrentBlock() external view returns (uint256); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why "BeforeCurrentBlock"? Isn't that implicit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A transaction in the same block may alter the count. This function will ignore it if it happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used internally to determine epoch boundaries in terms of inputs.
| interface EpochManager is EventEmitter { | ||
| /// @notice An epoch has been closed. | ||
| /// @param epochIndex The index of the epoch | ||
| /// @param epochFinalizer The contract that makes the epoch reach finality |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it's a contract why is it an address and not a contract interface?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because Solidity doesn't support generics, like EpochManager<T>, where T is the type of the epoch finalizer contract. The interface ID of the epoch finalizer contract is provided by the getEpochFinalizerInterfaceId view function.
| // If not, mark the validator as having already voted in the epoch. | ||
| { | ||
| bytes32 bitmap = getAggregatedVoteBitmap(epochIndex); | ||
| require(!bitmap.getBitAt(validatorId), VoteAlreadyCastForEpoch()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this error necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this error actually ensures that a validator cannot vote on multiple post-epoch state roots for any given epoch.
I also think |
Okay, how about |
| public | ||
| view | ||
| override | ||
| returns (uint256 deploymentBlockNumber) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably no need for variable deploymentBlockNumber
| using LibBinaryMerkleTree for bytes32[]; | ||
|
|
||
| uint256 private _finalizedEpochCount; | ||
| bool private __isFirstNonFinalizedEpochClosed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this variable has one extra _
| public | ||
| view | ||
| override | ||
| returns (uint256 closedEpochCount) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably no need for variable closedEpochCount, same for its interface function
| returns (uint256 inputIndexInclusiveLowerBound) | ||
| { | ||
| return _inputIndexInclusiveLowerBound; | ||
| } | ||
|
|
||
| /// @notice Get the input index exclusive upper bound. | ||
| function _getInputIndexExclusiveUpperBound() | ||
| internal | ||
| view | ||
| returns (uint256 inputIndexExclusiveUpperBound) | ||
| { | ||
| return _inputIndexExclusiveUpperBound; | ||
| } | ||
|
|
||
| /// @notice Check whether the first non-finalized epoch is closed. | ||
| function _isFirstNonFinalizedEpochClosed() | ||
| internal | ||
| view | ||
| returns (bool isFirstNonFinalizedEpochClosed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same for these variables
| internal | ||
| { | ||
| uint256 epochIndex = _finalizedEpochCount; | ||
| _finalizedEpochCount = epochIndex + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it may be easier to read if we write it as ++_finalizedEpochCount;
| returns (uint256 deployedAppCount) | ||
| { | ||
| return _deployedAppCount; | ||
| } | ||
|
|
||
| function computeDaveAppAddress(bytes32 genesisStateRoot, bytes32 salt) | ||
| external | ||
| view | ||
| override | ||
| returns (address appAddress) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
No description provided.