-
Notifications
You must be signed in to change notification settings - Fork 42
/
evmslashing.go
147 lines (120 loc) · 3.96 KB
/
evmslashing.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Package evmslashing monitors the Slashing pre-deploy contract and converts
// its log events to cosmosSDK x/slashing logic.
package evmslashing
import (
"context"
"github.com/omni-network/omni/contracts/bindings"
"github.com/omni-network/omni/halo/genutil/evm/predeploys"
"github.com/omni-network/omni/lib/errors"
"github.com/omni-network/omni/lib/ethclient"
"github.com/omni-network/omni/lib/log"
evmenginetypes "github.com/omni-network/omni/octane/evmengine/types"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
sdk "github.com/cosmos/cosmos-sdk/types"
skeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper"
stypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
)
const ModuleName = "evmslashing"
var _ evmenginetypes.EvmEventProcessor = EventProcessor{}
var (
slashingABI = mustGetABI(bindings.SlashingMetaData)
unjailEvent = mustGetEvent(slashingABI, "Unjail")
)
// EventProcessor implements the evmenginetypes.EvmEventProcessor interface.
type EventProcessor struct {
contract *bindings.Slashing
ethCl ethclient.Client
address common.Address
sKeeper skeeper.Keeper
}
// New returns a new EventProcessor.
func New(ethCl ethclient.Client, sKeeper skeeper.Keeper) (EventProcessor, error) {
address := common.HexToAddress(predeploys.Slashing)
contract, err := bindings.NewSlashing(address, ethCl)
if err != nil {
return EventProcessor{}, errors.Wrap(err, "new staking")
}
return EventProcessor{
contract: contract,
ethCl: ethCl,
address: address,
sKeeper: sKeeper,
}, nil
}
// Prepare returns all omni stake contract EVM event logs from the provided block hash.
func (p EventProcessor) Prepare(ctx context.Context, blockHash common.Hash) ([]*evmenginetypes.EVMEvent, error) {
logs, err := p.ethCl.FilterLogs(ctx, ethereum.FilterQuery{
BlockHash: &blockHash,
Addresses: p.Addresses(),
Topics: [][]common.Hash{{unjailEvent.ID}},
})
if err != nil {
return nil, errors.Wrap(err, "filter logs")
}
resp := make([]*evmenginetypes.EVMEvent, 0, len(logs))
for _, l := range logs {
topics := make([][]byte, 0, len(l.Topics))
for _, t := range l.Topics {
topics = append(topics, t.Bytes())
}
resp = append(resp, &evmenginetypes.EVMEvent{
Address: l.Address.Bytes(),
Topics: topics,
Data: l.Data,
})
}
return resp, nil
}
func (EventProcessor) Name() string {
return ModuleName
}
func (p EventProcessor) Addresses() []common.Address {
return []common.Address{p.address}
}
// Deliver processes a omni deposit log event, which must be one of:
// - Unjail.
func (p EventProcessor) Deliver(ctx context.Context, _ common.Hash, elog *evmenginetypes.EVMEvent) error {
ethlog := elog.ToEthLog()
switch ethlog.Topics[0] {
case unjailEvent.ID:
ev, err := p.contract.ParseUnjail(ethlog)
if err != nil {
return errors.Wrap(err, "parse create validator")
}
return p.deliverUnjail(ctx, ev)
default:
return errors.New("unknown event")
}
}
// deliverUnjail processes a Unjail event, and unjails an existing validator.
func (p EventProcessor) deliverUnjail(ctx context.Context, ev *bindings.SlashingUnjail) error {
valAddr := sdk.ValAddress(ev.Validator.Bytes())
log.Info(ctx, "EVM unjail detected, unjailing validator", "validator", ev.Validator.Hex())
msg := stypes.NewMsgUnjail(valAddr.String())
_, err := skeeper.NewMsgServerImpl(p.sKeeper).Unjail(ctx, msg)
if err != nil {
return errors.Wrap(err, "unjail validator")
}
return nil
}
// mustGetABI returns the metadata's ABI as an abi.ABI type.
// It panics on error.
func mustGetABI(metadata *bind.MetaData) *abi.ABI {
abi, err := metadata.GetAbi()
if err != nil {
panic(err)
}
return abi
}
// mustGetEvent returns the event with the given name from the ABI.
// It panics if the event is not found.
func mustGetEvent(abi *abi.ABI, name string) abi.Event {
event, ok := abi.Events[name]
if !ok {
panic("event not found")
}
return event
}