-
Notifications
You must be signed in to change notification settings - Fork 174
/
side_handler.go
146 lines (126 loc) · 5.14 KB
/
side_handler.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
package bor
import (
"bytes"
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/maticnetwork/heimdall/bor/types"
"github.com/maticnetwork/heimdall/common"
hmCommon "github.com/maticnetwork/heimdall/common"
"github.com/maticnetwork/heimdall/helper"
hmTypes "github.com/maticnetwork/heimdall/types"
abci "github.com/tendermint/tendermint/abci/types"
tmTypes "github.com/tendermint/tendermint/types"
)
// NewSideTxHandler returns a side handler for "span" type messages.
func NewSideTxHandler(k Keeper, contractCaller helper.IContractCaller) hmTypes.SideTxHandler {
return func(ctx sdk.Context, msg sdk.Msg) abci.ResponseDeliverSideTx {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case types.MsgProposeSpan:
return SideHandleMsgSpan(ctx, k, msg, contractCaller)
default:
return abci.ResponseDeliverSideTx{
Code: uint32(sdk.CodeUnknownRequest),
}
}
}
}
// NewPostTxHandler returns a side handler for "span" type messages.
func NewPostTxHandler(k Keeper, contractCaller helper.IContractCaller) hmTypes.PostTxHandler {
return func(ctx sdk.Context, msg sdk.Msg, sideTxResult abci.SideTxResultType) sdk.Result {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case types.MsgProposeSpan:
return PostHandleMsgEventSpan(ctx, k, msg, sideTxResult)
default:
errMsg := "Unrecognized Span Msg type: %s" + msg.Type()
return sdk.ErrUnknownRequest(errMsg).Result()
}
}
}
// SideHandleMsgSpan validates external calls required for processing proposed span
func SideHandleMsgSpan(ctx sdk.Context, k Keeper, msg types.MsgProposeSpan, contractCaller helper.IContractCaller) (result abci.ResponseDeliverSideTx) {
k.Logger(ctx).Debug("✅ Validating External call for span msg",
"msgSeed", msg.Seed.String(),
)
// calculate next span seed locally
nextSpanSeed, err := k.GetNextSpanSeed(ctx)
if err != nil {
k.Logger(ctx).Error("Error fetching next span seed from mainchain")
return hmCommon.ErrorSideTx(k.Codespace(), common.CodeInvalidMsg)
}
// check if span seed matches or not.
if !bytes.Equal(msg.Seed.Bytes(), nextSpanSeed.Bytes()) {
k.Logger(ctx).Error(
"Span Seed does not match",
"msgSeed", msg.Seed.String(),
"mainchainSeed", nextSpanSeed.String(),
)
return hmCommon.ErrorSideTx(k.Codespace(), common.CodeInvalidMsg)
}
// fetch current child block
childBlock, err := contractCaller.GetMaticChainBlock(nil)
if err != nil {
k.Logger(ctx).Error("Error fetching current child block", "error", err)
return hmCommon.ErrorSideTx(k.Codespace(), common.CodeInvalidMsg)
}
lastSpan, err := k.GetLastSpan(ctx)
if err != nil {
k.Logger(ctx).Error("Error fetching last span", "error", err)
return hmCommon.ErrorSideTx(k.Codespace(), common.CodeInvalidMsg)
}
currentBlock := childBlock.Number.Uint64()
// check if span proposed is in-turn or not
if !(lastSpan.StartBlock <= currentBlock && currentBlock <= lastSpan.EndBlock) {
k.Logger(ctx).Error(
"Span proposed is not in-turn",
"currentChildBlock", currentBlock,
"msgStartblock", msg.StartBlock,
"msgEndBlock", msg.EndBlock,
)
return hmCommon.ErrorSideTx(k.Codespace(), common.CodeInvalidMsg)
}
k.Logger(ctx).Debug("✅ Succesfully validated External call for span msg")
result.Result = abci.SideTxResultType_Yes
return
}
// PostHandleMsgEventSpan handles state persisting span msg
func PostHandleMsgEventSpan(ctx sdk.Context, k Keeper, msg types.MsgProposeSpan, sideTxResult abci.SideTxResultType) sdk.Result {
// Skip handler if span is not approved
if sideTxResult != abci.SideTxResultType_Yes {
k.Logger(ctx).Debug("Skipping new span since side-tx didn't get yes votes")
return common.ErrSideTxValidation(k.Codespace()).Result()
}
// check for replay
if k.HasSpan(ctx, msg.ID) {
k.Logger(ctx).Debug("Skipping new span as it's already processed")
return hmCommon.ErrOldTx(k.Codespace()).Result()
}
k.Logger(ctx).Debug("Persisting span state", "sideTxResult", sideTxResult)
// freeze for new span
err := k.FreezeSet(ctx, msg.ID, msg.StartBlock, msg.EndBlock, msg.ChainID, msg.Seed)
if err != nil {
k.Logger(ctx).Error("Unable to freeze validator set for span", "Error", err)
return common.ErrUnableToFreezeValSet(k.Codespace()).Result()
}
// TX bytes
txBytes := ctx.TxBytes()
hash := tmTypes.Tx(txBytes).Hash()
// add events
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeProposeSpan,
sdk.NewAttribute(sdk.AttributeKeyAction, msg.Type()), // action
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), // module name
sdk.NewAttribute(hmTypes.AttributeKeyTxHash, hmTypes.BytesToHeimdallHash(hash).Hex()), // tx hash
sdk.NewAttribute(hmTypes.AttributeKeySideTxResult, sideTxResult.String()), // result
sdk.NewAttribute(types.AttributeKeySpanID, strconv.FormatUint(msg.ID, 10)),
sdk.NewAttribute(types.AttributeKeySpanStartBlock, strconv.FormatUint(msg.StartBlock, 10)),
sdk.NewAttribute(types.AttributeKeySpanEndBlock, strconv.FormatUint(msg.EndBlock, 10)),
),
})
// draft result with events
return sdk.Result{
Events: ctx.EventManager().Events(),
}
}