-
Notifications
You must be signed in to change notification settings - Fork 1
/
evidence.go
102 lines (83 loc) · 3.57 KB
/
evidence.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package keeper
import (
"bytes"
"encoding/hex"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/onomyprotocol/near-aurora-bridge/module/x/nab/types"
)
func (k Keeper) CheckBadSignatureEvidence(
ctx sdk.Context,
msg *types.MsgSubmitBadSignatureEvidence) error {
var subject types.EthereumSigned
err := k.cdc.UnpackAny(msg.Subject, &subject)
if err != nil {
return sdkerrors.Wrap(types.ErrInvalid, fmt.Sprintf("Invalid Any encoded evidence %s", err))
}
switch subject := subject.(type) {
case *types.OutgoingTxBatch:
return k.checkBadSignatureEvidenceInternal(ctx, subject, msg.Signature)
case *types.Valset:
return k.checkBadSignatureEvidenceInternal(ctx, subject, msg.Signature)
case *types.OutgoingLogicCall:
return k.checkBadSignatureEvidenceInternal(ctx, subject, msg.Signature)
default:
return sdkerrors.Wrap(types.ErrInvalid, fmt.Sprintf("Bad signature must be over a batch, valset, or logic call got %s", subject))
}
}
func (k Keeper) checkBadSignatureEvidenceInternal(ctx sdk.Context, subject types.EthereumSigned, signature string) error {
// Get checkpoint of the supposed bad signature (fake valset, batch, or logic call submitted to eth)
gravityID := k.GetGravityID(ctx)
checkpoint := subject.GetCheckpoint(gravityID)
// Try to find the checkpoint in the archives. If it exists, we don't slash because
// this is not a bad signature
if k.GetPastEthSignatureCheckpoint(ctx, checkpoint) {
return sdkerrors.Wrap(types.ErrInvalid, "Checkpoint exists, cannot slash")
}
// Decode Eth signature to bytes
// strip 0x prefix if needed
if signature[:2] == "0x" {
signature = signature[2:]
}
sigBytes, err := hex.DecodeString(signature)
if err != nil {
return sdkerrors.Wrap(types.ErrInvalid, fmt.Sprintf("signature decoding %s", signature))
}
// Get eth address of the offending validator using the checkpoint and the signature
ethAddress, err := types.EthAddressFromSignature(checkpoint, sigBytes)
if err != nil {
return sdkerrors.Wrap(types.ErrInvalid, fmt.Sprintf("signature to eth address failed with checkpoint %s and signature %s", hex.EncodeToString(checkpoint), signature))
}
// Find the offending validator by eth address
val, found := k.GetValidatorByEthAddress(ctx, ethAddress)
if !found {
return sdkerrors.Wrap(types.ErrInvalid, fmt.Sprintf("Did not find validator for eth address %s from signature %s with checkpoint %s and GravityID %s", ethAddress, signature, hex.EncodeToString(checkpoint), gravityID))
}
// Slash the offending validator
cons, err := val.GetConsAddr()
if err != nil {
return sdkerrors.Wrap(err, "Could not get consensus key address for validator")
}
params := k.GetParams(ctx)
k.StakingKeeper.Slash(ctx, cons, ctx.BlockHeight(), val.ConsensusPower(), params.SlashFractionBadEthSignature)
if !val.IsJailed() {
k.StakingKeeper.Jail(ctx, cons)
}
return nil
}
// SetPastEthSignatureCheckpoint puts the checkpoint of a valset, batch, or logic call into a set
// in order to prove later that it existed at one point.
func (k Keeper) SetPastEthSignatureCheckpoint(ctx sdk.Context, checkpoint []byte) {
store := ctx.KVStore(k.storeKey)
store.Set(types.GetPastEthSignatureCheckpointKey(checkpoint), []byte{0x1})
}
// GetPastEthSignatureCheckpoint tells you whether a given checkpoint has ever existed
func (k Keeper) GetPastEthSignatureCheckpoint(ctx sdk.Context, checkpoint []byte) (found bool) {
store := ctx.KVStore(k.storeKey)
if bytes.Equal(store.Get(types.GetPastEthSignatureCheckpointKey(checkpoint)), []byte{0x1}) {
return true
} else {
return false
}
}