This repository has been archived by the owner on Nov 16, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 51
/
ante.go
92 lines (84 loc) · 2.51 KB
/
ante.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
package ante
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
lru "github.com/hashicorp/golang-lru"
"github.com/bandprotocol/bandchain/chain/x/oracle"
"github.com/bandprotocol/bandchain/chain/x/oracle/keeper"
)
var (
repTxCount *lru.Cache
nextRepOnlyBlock int64
)
func init() {
var err error
repTxCount, err = lru.New(20000)
if err != nil {
panic(err)
}
}
func checkValidReportMsg(ctx sdk.Context, oracleKeeper oracle.Keeper, rep oracle.MsgReportData) bool {
if !oracleKeeper.IsReporter(ctx, rep.Validator, rep.Reporter) {
return false
}
if rep.RequestID <= oracleKeeper.GetRequestLastExpired(ctx) {
return false
}
req, err := oracleKeeper.GetRequest(ctx, rep.RequestID)
if err != nil {
return false
}
if !keeper.ContainsVal(req.RequestedValidators, rep.Validator) {
return false
}
if len(rep.RawReports) != len(req.RawRequests) {
return false
}
for _, report := range rep.RawReports {
if !keeper.ContainsEID(req.RawRequests, report.ExternalID) {
return false
}
}
return true
}
// NewFeelessReportsAnteHandler returns a new ante handler that waives minimum gas price
// requirement if the incoming tx is a valid report transaction.
func NewFeelessReportsAnteHandler(ante sdk.AnteHandler, oracleKeeper oracle.Keeper) sdk.AnteHandler {
return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) {
if ctx.IsCheckTx() && !simulate {
// TODO: Move this out of "FeelessReports" ante handler.
isRepOnlyBlock := ctx.BlockHeight() == nextRepOnlyBlock
isValidReportTx := true
for _, msg := range tx.GetMsgs() {
rep, ok := msg.(oracle.MsgReportData)
if !ok || !checkValidReportMsg(ctx, oracleKeeper, rep) {
isValidReportTx = false
break
}
if !isRepOnlyBlock {
key := fmt.Sprintf("%s:%d", rep.Validator.String(), rep.RequestID)
val, ok := repTxCount.Get(key)
nextVal := 1
if ok {
nextVal = val.(int) + 1
}
repTxCount.Add(key, nextVal)
if nextVal > 20 {
nextRepOnlyBlock = ctx.BlockHeight() + 1
}
}
}
if isRepOnlyBlock && !isValidReportTx {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Block reserved for report txs")
}
if isValidReportTx {
minGas := ctx.MinGasPrices()
newCtx, err := ante(ctx.WithMinGasPrices(sdk.DecCoins{}), tx, simulate)
// Set minimum gas price context and return context to caller.
return newCtx.WithMinGasPrices(minGas), err
}
}
return ante(ctx, tx, simulate)
}
}