wormhole/wormchain/x/wormhole/keeper/msg_server_register_account...

89 lines
2.7 KiB
Go

package keeper
import (
"bytes"
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/wormhole-foundation/wormchain/x/wormhole/types"
wormholesdk "github.com/wormhole-foundation/wormhole/sdk"
)
// TODO(csongor): high-level overview of what this does
func (k msgServer) RegisterAccountAsGuardian(goCtx context.Context, msg *types.MsgRegisterAccountAsGuardian) (*types.MsgRegisterAccountAsGuardianResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
signer, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
return nil, err
}
// recover guardian key from signature
signerHash := crypto.Keccak256Hash(wormholesdk.SignedWormchainAddressPrefix, signer)
guardianKey, err := crypto.Ecrecover(signerHash.Bytes(), msg.Signature)
if err != nil {
return nil, err
}
// ecrecover gave us a 65-byte public key, which we first need to
// convert to a 20 byte ethereum-style address. The first byte of the
// public key is just the prefix byte '0x04' which we drop first. Then
// hash the public key, and take the last 20 bytes of the hash
// (according to
// https://ethereum.org/en/developers/docs/accounts/#account-creation)
guardianKeyAddr := common.BytesToAddress(crypto.Keccak256(guardianKey[1:])[12:])
// next we check if this guardian key is in the most recent guardian set.
// we don't allow registration of arbitrary public keys, since that would
// enable a DoS vector
latestGuardianSetIndex := k.Keeper.GetLatestGuardianSetIndex(ctx)
consensusGuardianSetIndex, found := k.GetConsensusGuardianSetIndex(ctx)
if found && latestGuardianSetIndex == consensusGuardianSetIndex.Index {
return nil, types.ErrConsensusSetNotUpdatable
}
latestGuardianSet, found := k.Keeper.GetGuardianSet(ctx, latestGuardianSetIndex)
if !found {
return nil, types.ErrGuardianSetNotFound
}
if !latestGuardianSet.ContainsKey(guardianKeyAddr) {
return nil, types.ErrGuardianNotFound
}
// Check if the tx signer was already registered as a guardian validator.
for _, gv := range k.GetAllGuardianValidator(ctx) {
if bytes.Equal(gv.ValidatorAddr, signer) {
return nil, types.ErrSignerAlreadyRegistered
}
}
// register validator in store for guardian
k.Keeper.SetGuardianValidator(ctx, types.GuardianValidator{
GuardianKey: guardianKeyAddr.Bytes(),
ValidatorAddr: signer,
})
err = ctx.EventManager().EmitTypedEvent(&types.EventGuardianRegistered{
GuardianKey: guardianKeyAddr.Bytes(),
ValidatorKey: signer,
})
if err != nil {
return nil, err
}
err = k.Keeper.TrySwitchToNewConsensusGuardianSet(ctx)
if err != nil {
return nil, err
}
return &types.MsgRegisterAccountAsGuardianResponse{}, nil
}