-
Notifications
You must be signed in to change notification settings - Fork 18
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
feat: implement approve oracle upgrade tx #582
Changes from all commits
3893eae
8330472
eda304c
fecab14
af4a238
402eeb1
468a132
31557d5
ec72841
8eec577
69bc58b
860223d
909c3d8
07b94cc
cb6b661
1ee72d5
34fee18
660d959
12f0e02
c634f6f
6ebe8b6
f290bf2
61e8e4e
c66ff61
f73a2ca
44a3f47
442479b
5da5d80
b7a94d9
9630dfb
db97922
0b4fae8
d5866b7
ea8f814
c2d2532
a3cd3e3
9b5944b
115bb01
d462a4c
b54727f
a23289e
4fe4352
df49732
159a4fe
1c69a6d
41d0d4b
272412f
7ed8894
e992219
19d1163
b283a3e
dbd7886
1fceade
0104a89
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,25 +12,21 @@ import ( | |
func (k Keeper) RegisterOracle(ctx sdk.Context, msg *types.MsgRegisterOracle) error { | ||
oracleRegistration := types.NewOracleRegistration(msg) | ||
|
||
if err := oracleRegistration.ValidateBasic(); err != nil { | ||
return err | ||
} | ||
|
||
params := k.GetParams(ctx) | ||
if params.UniqueId != oracleRegistration.UniqueId { | ||
return sdkerrors.Wrapf(types.ErrOracleRegistration, "is not match the currently active uniqueID") | ||
if params.UniqueId != msg.UniqueId { | ||
return sdkerrors.Wrapf(types.ErrRegisterOracle, types.ErrInvalidUniqueID.Error()) | ||
} | ||
|
||
if oracle, err := k.GetOracle(ctx, oracleRegistration.OracleAddress); !errors.Is(types.ErrOracleNotFound, err) { | ||
if oracle != nil { | ||
return sdkerrors.Wrapf(types.ErrOracleRegistration, "already registered oracle. address(%s)", oracleRegistration.OracleAddress) | ||
} else { | ||
return sdkerrors.Wrapf(types.ErrOracleRegistration, err.Error()) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Modified to return an error if the For example, an oracle may be free to set a new commission rate overriding the commission max rate and commission max change rate initially set via a Since there is no way for oracles to be re-shared the oracle private key, it is necessary to safely manage the shared oracle private key or the node private key that can decrypt the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. understand. In the current situation, if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Exactly. |
||
existing, err := k.GetOracleRegistration(ctx, msg.GetUniqueId(), msg.GetOracleAddress()) | ||
if err != nil && !errors.Is(err, types.ErrOracleRegistrationNotFound) { | ||
return sdkerrors.Wrapf(types.ErrRegisterOracle, err.Error()) | ||
} | ||
if existing != nil { | ||
return sdkerrors.Wrapf(types.ErrRegisterOracle, fmt.Sprintf("already registered oracle. address(%s)", msg.OracleAddress)) | ||
} | ||
|
||
if err := k.SetOracleRegistration(ctx, oracleRegistration); err != nil { | ||
return err | ||
return sdkerrors.Wrapf(types.ErrRegisterOracle, err.Error()) | ||
} | ||
|
||
ctx.EventManager().EmitEvent( | ||
|
@@ -40,20 +36,27 @@ func (k Keeper) RegisterOracle(ctx sdk.Context, msg *types.MsgRegisterOracle) er | |
sdk.NewAttribute(types.AttributeKeyOracleAddress, oracleRegistration.OracleAddress), | ||
), | ||
) | ||
|
||
return nil | ||
} | ||
|
||
func (k Keeper) ApproveOracleRegistration(ctx sdk.Context, msg *types.MsgApproveOracleRegistration) error { | ||
|
||
if err := k.validateApproveOracleRegistration(ctx, msg); err != nil { | ||
// validate approval for oracle registration | ||
if err := k.validateApprovalSharingOracleKey(ctx, msg.GetApprovalSharingOracleKey(), msg.GetSignature()); err != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleRegistration, err.Error()) | ||
} | ||
|
||
// get oracle registration | ||
oracleRegistration, err := k.GetOracleRegistration(ctx, msg.ApprovalSharingOracleKey.UniqueId, msg.ApprovalSharingOracleKey.TargetOracleAddress) | ||
if err != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleRegistration, err.Error()) | ||
} | ||
|
||
// if EncryptedOraclePrivKey is already set, return error | ||
if oracleRegistration.EncryptedOraclePrivKey != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleRegistration, "already approved oracle registration. if you want to be shared oracle private key again, please register oracle again") | ||
} | ||
|
||
Comment on lines
+56
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of checking that if oracle is set by |
||
oracleRegistration.EncryptedOraclePrivKey = msg.ApprovalSharingOracleKey.EncryptedOraclePrivKey | ||
|
||
// add an encrypted oracle private key to oracleRegistration | ||
|
@@ -88,33 +91,31 @@ func (k Keeper) ApproveOracleRegistration(ctx sdk.Context, msg *types.MsgApprove | |
|
||
} | ||
|
||
// validateApproveOracleRegistration checks signature | ||
func (k Keeper) validateApproveOracleRegistration(ctx sdk.Context, msg *types.MsgApproveOracleRegistration) error { | ||
|
||
// validateApprovalSharingOracleKey validate unique ID of ApprovalSharingOracleKey and its signature | ||
func (k Keeper) validateApprovalSharingOracleKey(ctx sdk.Context, approval *types.ApprovalSharingOracleKey, signature []byte) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This validation function is used in both |
||
params := k.GetParams(ctx) | ||
targetOracleAddress := msg.ApprovalSharingOracleKey.TargetOracleAddress | ||
|
||
// check unique id | ||
if msg.ApprovalSharingOracleKey.UniqueId != params.UniqueId { | ||
if approval.UniqueId != params.UniqueId { | ||
return types.ErrInvalidUniqueID | ||
} | ||
|
||
// verify signature | ||
if err := k.VerifyOracleSignature(ctx, msg.ApprovalSharingOracleKey, msg.Signature); err != nil { | ||
return err | ||
// check if the approver oracle exists | ||
isActive, err := k.IsActiveOracle(ctx, approval.ApproverOracleAddress) | ||
if err != nil { | ||
return fmt.Errorf("error occurs while checking if the oracle(%s) exists: %w", approval.ApproverOracleAddress, err) | ||
} | ||
|
||
if msg.ApprovalSharingOracleKey.EncryptedOraclePrivKey == nil { | ||
return fmt.Errorf("encrypted oracle private key is nil") | ||
if !isActive { | ||
return fmt.Errorf("oracle(%s) is not an active oracle", approval.ApproverOracleAddress) | ||
} | ||
|
||
// check if the oracle has been already registered | ||
hasOracle, err := k.HasOracle(ctx, targetOracleAddress) | ||
if err != nil { | ||
// verify signature | ||
if err := k.VerifyOracleSignature(ctx, approval, signature); err != nil { | ||
return err | ||
} | ||
if hasOracle { | ||
return fmt.Errorf("already registered oracle. address(%s)", targetOracleAddress) | ||
|
||
if approval.EncryptedOraclePrivKey == nil { | ||
return fmt.Errorf("encrypted oracle private key is empty") | ||
} | ||
|
||
return nil | ||
|
@@ -189,12 +190,12 @@ func (k Keeper) GetOracleRegistration(ctx sdk.Context, uniqueID, address string) | |
store := ctx.KVStore(k.storeKey) | ||
accAddr, err := sdk.AccAddressFromBech32(address) | ||
if err != nil { | ||
return nil, err | ||
return nil, sdkerrors.Wrapf(types.ErrGetOracleRegistration, err.Error()) | ||
} | ||
key := types.GetOracleRegistrationKey(uniqueID, accAddr) | ||
bz := store.Get(key) | ||
if bz == nil { | ||
return nil, sdkerrors.Wrapf(types.ErrGetOracleRegistration, "oracle registration not found") | ||
return nil, types.ErrOracleRegistrationNotFound | ||
} | ||
|
||
oracleRegistration := &types.OracleRegistration{} | ||
|
@@ -249,7 +250,7 @@ func (k Keeper) GetOracle(ctx sdk.Context, address string) (*types.Oracle, error | |
store := ctx.KVStore(k.storeKey) | ||
accAddr, err := sdk.AccAddressFromBech32(address) | ||
if err != nil { | ||
return nil, err | ||
return nil, sdkerrors.Wrapf(types.ErrGetOracle, err.Error()) | ||
} | ||
key := types.GetOracleKey(accAddr) | ||
bz := store.Get(key) | ||
|
@@ -267,12 +268,17 @@ func (k Keeper) GetOracle(ctx sdk.Context, address string) (*types.Oracle, error | |
return oracle, nil | ||
} | ||
|
||
func (k Keeper) HasOracle(ctx sdk.Context, address string) (bool, error) { | ||
store := ctx.KVStore(k.storeKey) | ||
accAddr, err := sdk.AccAddressFromBech32(address) | ||
func (k Keeper) IsActiveOracle(ctx sdk.Context, oracleAddress string) (bool, error) { | ||
oracle, err := k.GetOracle(ctx, oracleAddress) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
return store.Has(types.GetOracleKey(accAddr)), nil | ||
params := k.GetParams(ctx) | ||
|
||
if oracle.GetUniqueId() != params.GetUniqueId() { | ||
return false, types.ErrInvalidUniqueID | ||
} | ||
|
||
return true, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,6 @@ import ( | |
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" | ||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/medibloc/panacea-core/v2/types/testsuite" | ||
"github.com/medibloc/panacea-core/v2/x/oracle/types" | ||
"github.com/stretchr/testify/suite" | ||
|
@@ -133,10 +132,11 @@ func (suite *oracleTestSuite) TestRegisterOracleSuccess() { | |
suite.Require().Equal(suite.oracleCommissionMaxChangeRate, oracleFromKeeper.OracleCommissionMaxChangeRate) | ||
} | ||
|
||
func (suite *oracleTestSuite) TestRegisterOracleFailedValidateToMsgOracleRegistration() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Accordingly this, deleted validation test code. |
||
func (suite *oracleTestSuite) TestRegisterOracleAlreadyExistOracleRegistration() { | ||
ctx := suite.Ctx | ||
|
||
msgRegisterOracle := &types.MsgRegisterOracle{ | ||
UniqueId: suite.uniqueID, | ||
OracleAddress: suite.oracleAccAddr.String(), | ||
NodePubKey: suite.nodePubKey.SerializeCompressed(), | ||
NodePubKeyRemoteReport: suite.nodePubKeyRemoteReport, | ||
|
@@ -148,76 +148,12 @@ func (suite *oracleTestSuite) TestRegisterOracleFailedValidateToMsgOracleRegistr | |
OracleCommissionMaxChangeRate: suite.oracleCommissionMaxChangeRate, | ||
} | ||
|
||
// first registration | ||
err := suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "uniqueID is empty") | ||
|
||
msgRegisterOracle.UniqueId = suite.uniqueID | ||
msgRegisterOracle.NodePubKey = nil | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "node public key is empty") | ||
|
||
msgRegisterOracle.NodePubKey = []byte("invalidNodePubKey") | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "invalid node public key") | ||
|
||
msgRegisterOracle.NodePubKey = suite.nodePubKey.SerializeCompressed() | ||
msgRegisterOracle.NodePubKeyRemoteReport = nil | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "remote report of node public key is empty") | ||
|
||
msgRegisterOracle.NodePubKeyRemoteReport = suite.nodePubKeyRemoteReport | ||
msgRegisterOracle.TrustedBlockHeight = 0 | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "trusted block height must be greater than zero") | ||
|
||
msgRegisterOracle.TrustedBlockHeight = suite.trustedBlockHeight | ||
msgRegisterOracle.TrustedBlockHash = nil | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "trusted block hash should not be nil") | ||
|
||
msgRegisterOracle.TrustedBlockHash = suite.trustedBlockHash | ||
msgRegisterOracle.OracleCommissionRate = sdk.NewInt(-1).ToDec() | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "oracleCommissionRate must be between 0 and OracleCommissionMaxRate") | ||
|
||
msgRegisterOracle.OracleCommissionRate = sdk.NewInt(2).ToDec() | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, sdkerrors.ErrInvalidRequest) | ||
suite.Require().ErrorContains(err, "oracleCommissionRate must be between 0 and OracleCommissionMaxRate") | ||
|
||
events := suite.Ctx.EventManager().Events() | ||
suite.Require().Equal(0, len(events)) | ||
} | ||
|
||
func (suite *oracleTestSuite) TestRegisterOracleAlreadyExistOracle() { | ||
ctx := suite.Ctx | ||
|
||
oracle := types.NewOracle(suite.oracleAccAddr.String(), suite.uniqueID, suite.endpoint, suite.oracleCommissionRate, suite.oracleCommissionMaxRate, suite.oracleCommissionMaxChangeRate, ctx.BlockTime()) | ||
err := suite.OracleKeeper.SetOracle(ctx, oracle) | ||
suite.Require().NoError(err) | ||
|
||
msgRegisterOracle := &types.MsgRegisterOracle{ | ||
UniqueId: suite.uniqueID, | ||
OracleAddress: suite.oracleAccAddr.String(), | ||
NodePubKey: suite.nodePubKey.SerializeCompressed(), | ||
NodePubKeyRemoteReport: suite.nodePubKeyRemoteReport, | ||
TrustedBlockHeight: suite.trustedBlockHeight, | ||
TrustedBlockHash: suite.trustedBlockHash, | ||
Endpoint: suite.endpoint, | ||
OracleCommissionRate: suite.oracleCommissionRate, | ||
OracleCommissionMaxRate: suite.oracleCommissionMaxRate, | ||
OracleCommissionMaxChangeRate: suite.oracleCommissionMaxChangeRate, | ||
} | ||
|
||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, types.ErrOracleRegistration) | ||
suite.Require().Error(err, types.ErrRegisterOracle) | ||
suite.Require().ErrorContains(err, fmt.Sprintf("already registered oracle. address(%s)", msgRegisterOracle.OracleAddress)) | ||
} | ||
|
||
|
@@ -238,13 +174,17 @@ func (suite *oracleTestSuite) TestRegisterOracleNotSameUniqueID() { | |
} | ||
|
||
err := suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().Error(err, types.ErrOracleRegistration) | ||
suite.Require().ErrorContains(err, "is not match the currently active uniqueID") | ||
suite.Require().Error(err, types.ErrRegisterOracle) | ||
suite.Require().ErrorContains(err, types.ErrInvalidUniqueID.Error()) | ||
} | ||
|
||
func (suite *oracleTestSuite) TestApproveOracleRegistrationSuccess() { | ||
ctx := suite.Ctx | ||
|
||
oracle := types.NewOracle(suite.oracleAccAddr.String(), suite.uniqueID, suite.endpoint, suite.oracleCommissionRate, suite.oracleCommissionMaxRate, suite.oracleCommissionMaxChangeRate, ctx.BlockTime()) | ||
err := suite.OracleKeeper.SetOracle(ctx, oracle) | ||
suite.Require().NoError(err) | ||
|
||
msgRegisterOracle := &types.MsgRegisterOracle{ | ||
UniqueId: suite.uniqueID, | ||
OracleAddress: suite.oracleAccAddr.String(), | ||
|
@@ -258,7 +198,7 @@ func (suite *oracleTestSuite) TestApproveOracleRegistrationSuccess() { | |
OracleCommissionMaxChangeRate: suite.oracleCommissionMaxChangeRate, | ||
} | ||
|
||
err := suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
err = suite.OracleKeeper.RegisterOracle(ctx, msgRegisterOracle) | ||
suite.Require().NoError(err) | ||
|
||
encryptedOraclePrivKey, err := btcec.Encrypt(suite.nodePubKey, suite.oraclePrivKey.Serialize()) | ||
|
@@ -384,7 +324,7 @@ func (suite *oracleTestSuite) TestApproveOracleRegistrationFailedInvalidSignatur | |
suite.Require().Error(err, "failed to signature validation") | ||
} | ||
|
||
func (suite *oracleTestSuite) TestApproveOracleRegistrationFailedAlreadyExistOracle() { | ||
func (suite *oracleTestSuite) TestApproveOracleRegistrationFailedAlreadyApprovedOracleRegistration() { | ||
ctx := suite.Ctx | ||
|
||
oracle := types.NewOracle(suite.oracleAccAddr.String(), suite.uniqueID, suite.endpoint, suite.oracleCommissionRate, suite.oracleCommissionMaxRate, suite.oracleCommissionMaxChangeRate, ctx.BlockTime()) | ||
|
@@ -405,6 +345,7 @@ func (suite *oracleTestSuite) TestApproveOracleRegistrationFailedAlreadyExistOra | |
} | ||
|
||
oracleRegistration := types.NewOracleRegistration(msgRegisterOracle) | ||
oracleRegistration.EncryptedOraclePrivKey = []byte("already registered") | ||
|
||
err = suite.OracleKeeper.SetOracleRegistration(ctx, oracleRegistration) | ||
suite.Require().NoError(err) | ||
|
@@ -426,8 +367,8 @@ func (suite *oracleTestSuite) TestApproveOracleRegistrationFailedAlreadyExistOra | |
msgApproveOracleRegistration := types.NewMsgApproveOracleRegistration(approveOracleRegistration, signature.Serialize()) | ||
|
||
err = suite.OracleKeeper.ApproveOracleRegistration(ctx, msgApproveOracleRegistration) | ||
suite.Require().Error(err, types.ErrOracleRegistration) | ||
suite.Require().ErrorContains(err, fmt.Sprintf("already registered oracle. address(%s)", msgRegisterOracle.OracleAddress)) | ||
suite.Require().Error(err, types.ErrRegisterOracle) | ||
suite.Require().ErrorContains(err, "already approved oracle registration") | ||
} | ||
|
||
func (suite *oracleTestSuite) TestUpdateOracleInfoSuccess() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -156,3 +156,47 @@ func (k Keeper) GetAllOracleUpgradeList(ctx sdk.Context) ([]types.OracleUpgrade, | |
|
||
return oracleUpgrades, nil | ||
} | ||
|
||
func (k Keeper) ApproveOracleUpgrade(ctx sdk.Context, msg *types.MsgApproveOracleUpgrade) error { | ||
// validate approval for oracle upgrade | ||
if err := k.validateApprovalSharingOracleKey(ctx, msg.GetApprovalSharingOracleKey(), msg.GetSignature()); err != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleUpgrade, err.Error()) | ||
} | ||
|
||
// get oracle upgrade and upgrade info | ||
upgradeInfo, err := k.GetOracleUpgradeInfo(ctx) | ||
if err != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleUpgrade, err.Error()) | ||
} | ||
|
||
oracleUpgrade, err := k.GetOracleUpgrade(ctx, upgradeInfo.GetUniqueId(), msg.GetApprovalSharingOracleKey().GetTargetOracleAddress()) | ||
if err != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleUpgrade, err.Error()) | ||
} | ||
|
||
// if EncryptedOraclePrivKey is already set, return error | ||
if oracleUpgrade.EncryptedOraclePrivKey != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleUpgrade, "already approved oracle upgrade. if you want to be shared oracle private key again, please upgrade oracle again") | ||
} | ||
|
||
// update encrypted oracle private key | ||
oracleUpgrade.EncryptedOraclePrivKey = msg.GetApprovalSharingOracleKey().EncryptedOraclePrivKey | ||
|
||
// set oracle upgrade | ||
if err := k.SetOracleUpgrade(ctx, oracleUpgrade); err != nil { | ||
return sdkerrors.Wrapf(types.ErrApproveOracleUpgrade, err.Error()) | ||
} | ||
|
||
// emit event | ||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
types.EventTypeApproveOracleUpgrade, | ||
sdk.NewAttribute(types.AttributeKeyOracleAddress, msg.GetApprovalSharingOracleKey().GetTargetOracleAddress()), | ||
sdk.NewAttribute(types.AttributeKeyUniqueID, upgradeInfo.GetUniqueId()), | ||
), | ||
) | ||
|
||
// TODO: add to queue(?) for update unique ID | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed offline, it seems that you can check if the encryptedOraclePrivKey of OracleUpgrade is not nil without putting it in the queue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I understand. I will reflect it in PR #584. |
||
|
||
return nil | ||
} |
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.
As commented in the previous PR, I deleted this validation.