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
ValidatorProxy
contract 🔀 (& Hardhat support for v0.8 contracts 👷♂️👀)
#4265
Conversation
This pull request has been linked to Clubhouse Story #7923: Create a |
I see that you haven't updated any CHANGELOG files. Would it make sense to do so? |
ValidatorProxy
contract 🔀ValidatorProxy
contract 🔀 (& Hardhat support for v0.8 contracts 👀)
6796c0c
to
9c885ba
Compare
429ade8
to
1042f3b
Compare
84f4303
to
e0cf07d
Compare
ValidatorProxy
contract 🔀 (& Hardhat support for v0.8 contracts 👀)ValidatorProxy
contract 🔀 (& Hardhat support for v0.8 contracts 👷♂️👀)
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.
more feedback
|
||
/// @notice Uses a single storage slot to store the current address | ||
struct ProxyConfiguration { | ||
address target; |
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.
You could make this AggregatorValidatorInterface target
to save yourself some casts
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 isn't ideal because this struct is also used for the aggregator, which doesn't conform to that interface.
Since this is the case, I don't like the idea of using addresses for some state variables and AggregatorValidatorInterface
for others.
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.
How about separate structs for separate purposes?
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.
We could, but they are essentially the same thing, and it would make other state vars mismatch. So this:
/// @notice Uses a single storage slot to store the current address
struct ProxyConfiguration {
address target;
bool hasNewProposal;
}
// Configuration for the current aggregator
ProxyConfiguration private s_currentAggregator;
// Proposed aggregator address
address private s_proposedAggregator;
// Configuration for the current validator
ProxyConfiguration private s_currentValidator;
// Proposed validator address
address private s_proposedValidator;
event AggregatorProposed(
address indexed aggregator
);
event AggregatorUpgraded(
address indexed previous,
address indexed current
);
event ValidatorProposed(
address indexed validator
);
event ValidatorUpgraded(
address indexed previous,
address indexed current
);
/// @notice The proposed aggregator called validate, but the call was not passed on to any validators
event ProposedAggregatorValidateCall(
address indexed proposed,
uint256 previousRoundId,
int256 previousAnswer,
uint256 currentRoundId,
int256 currentAnswer
);
becomes a bit messier:
/// @notice Uses a single storage slot to store the current address
struct AggregatorConfiguration {
address target;
bool hasNewProposal;
}
struct ValidatorConfiguration {
AggregatorValidatorInterface target;
bool hasNewProposal;
}
// Configuration for the current aggregator
AggregatorConfiguration private s_currentAggregator;
// Proposed aggregator address
address private s_proposedAggregator;
// Configuration for the current validator
ValidatorConfiguration private s_currentValidator;
// Proposed validator address
AggregatorValidatorInterface private s_proposedValidator;
event AggregatorProposed(
address indexed aggregator
);
event AggregatorUpgraded(
address indexed previous,
address indexed current
);
event ValidatorProposed(
AggregatorValidatorInterface indexed validator
);
event ValidatorUpgraded(
AggregatorValidatorInterface indexed previous,
AggregatorValidatorInterface indexed current
);
/// @notice The proposed aggregator called validate, but the call was not passed on to any validators
event ProposedAggregatorValidateCall(
address indexed proposed,
uint256 previousRoundId,
int256 previousAnswer,
uint256 currentRoundId,
int256 currentAnswer
);
Since aggregators will be the address
type anyway, it starts to get a bit messy. It's purely aesthetic, but I feel using address
across the board and having a single struct is more elegant.
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.
To me the second looks cleaner plus you get more type safety.
// Configuration for the current validator | ||
ProxyConfiguration private s_currentValidator; | ||
// Proposed validator address | ||
address private s_proposedValidator; |
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.
Ditto, could be AggregatorValidatorInterface
address indexed current | ||
); | ||
event ValidatorProposed( | ||
address indexed validator |
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.
ditto
address proposed = s_proposedAggregator; | ||
|
||
// Perform the upgrade | ||
require(current.hasNewProposal == true, "No proposal"); |
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.
require(current.hasNewProposal == true, "No proposal"); | |
require(current.hasNewProposal, "No proposal"); |
current.target = proposed; | ||
current.hasNewProposal = false; | ||
|
||
s_currentAggregator = current; |
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.
I would prefer initializing a new struct here since it forces you to not forget any fields
s_currentAggregator = current; | |
s_currentAggregator = ProxyConfiguration({ | |
target: proposed, | |
hasNewProposal: false | |
}); |
current.target = proposed; | ||
current.hasNewProposal = false; | ||
|
||
s_currentValidator = current; |
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.
ditto struct initializer
s_proposedAggregator = proposed; | ||
// If proposed is zero address, hasNewProposal = false | ||
s_currentAggregator.hasNewProposal = (proposed != address(0)); | ||
emit AggregatorProposed(proposed); |
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.
we usually try to filter duplicate logs
s_proposedValidator = proposed; | ||
// If proposed is zero address, hasNewProposal = false | ||
s_currentValidator.hasNewProposal = (proposed != address(0)); | ||
emit ValidatorProposed(proposed); |
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.
ditto duplicate logs
s_currentAggregator.target = aggregator; | ||
s_currentValidator.target = validator; |
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.
Could you initialize these using the full struct initializer syntax as well?
No description provided.