-
Notifications
You must be signed in to change notification settings - Fork 45
/
relay_chain_links.go
81 lines (69 loc) · 2.9 KB
/
relay_chain_links.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package keeper
import (
"bytes"
"encoding/hex"
"cosmossdk.io/errors"
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/desmos-labs/desmos/v7/x/profiles/types"
)
// OnRecvLinkChainAccountPacket processes the reception of a LinkChainAccountPacket
// To be properly accepted, the packet must be created by signing two different things:
//
// 1. the source proof, which is obtained by signing the destination (Desmos) address using the
// private key of the external chain account;
// 2. the destination proof, which is obtained by signing the external chain address using the
// private key of the Desmos address for which the link should be created.
//
// This way we can make sure the user owns both private keys and no one is trying to pull a replay attack.
func (k Keeper) OnRecvLinkChainAccountPacket(
ctx sdk.Context,
data types.LinkChainAccountPacketData,
) (packetAck types.LinkChainAccountPacketAck, err error) {
// Validate the packet data upon receiving
if err := data.Validate(); err != nil {
return packetAck, err
}
srcAddrData, err := types.UnpackAddressData(k.cdc, data.SourceAddress)
if err != nil {
return packetAck, err
}
// Get the destination address and make sure it has a profile
addr, err := sdk.AccAddressFromBech32(data.DestinationAddress)
if err != nil {
return packetAck, errors.Wrap(sdkerrors.ErrInvalidAddress, data.DestinationAddress)
}
account := k.ak.GetAccount(ctx, addr)
profile, ok := account.(*types.Profile)
if !ok {
return packetAck, errors.Wrap(types.ErrProfileNotFound, addr.String())
}
// Get the destination proof public key
var pubKey cryptotypes.PubKey
err = k.cdc.UnpackAny(data.DestinationProof.PubKey, &pubKey)
if err != nil {
return packetAck, errors.Wrap(sdkerrors.ErrInvalidType, "invalid public key type")
}
// Make sure the profile public key and the one provided are equals
if !bytes.Equal(pubKey.Bytes(), profile.GetPubKey().Bytes()) {
return packetAck, errors.Wrapf(sdkerrors.ErrInvalidRequest,
"invalid pub key value: expected %s but got %s instead",
hex.EncodeToString(profile.GetPubKey().Bytes()), hex.EncodeToString(pubKey.Bytes()))
}
// Verify the destination proof by making sure the user has signed the source
// address using the destination address private key
destAddrData := types.NewBech32Address(data.DestinationAddress, sdk.GetConfig().GetBech32AccountAddrPrefix())
err = data.DestinationProof.Verify(k.cdc, k.legacyAmino, srcAddrData.GetValue(), destAddrData)
if err != nil {
return packetAck, err
}
// Store the link
chainLink := types.NewChainLink(data.DestinationAddress, srcAddrData, data.SourceProof, data.SourceChainConfig, ctx.BlockTime())
err = k.SaveChainLink(ctx, chainLink)
if err != nil {
return packetAck, err
}
packetAck.SourceAddress = srcAddrData.GetValue()
return packetAck, nil
}