-
Notifications
You must be signed in to change notification settings - Fork 0
/
msg_server_update_state.go
149 lines (131 loc) · 5.29 KB
/
msg_server_update_state.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
148
149
package keeper
import (
"context"
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/furychain/furya/x/rollapp/types"
)
func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) (*types.MsgUpdateStateResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// load rollapp object for stateful validations
rollapp, isFound := k.GetRollapp(ctx, msg.RollappId)
if !isFound {
return nil, types.ErrUnknownRollappID
}
// check rollapp version
if rollapp.Version != msg.Version {
return nil, sdkerrors.Wrapf(types.ErrVersionMismatch, "rollappId(%s) current version is %d, but got %d", msg.RollappId, rollapp.Version, msg.Version)
}
// call the before-update-state hook
err := k.BeforeUpdateStateRecoverable(ctx, msg.Creator, msg.RollappId)
if err != nil {
return nil, err
}
// Logic Error check - must be done after BeforeUpdateStateRecoverable
// check if there are permissionedAddresses.
// if the list is not empty, it means that only premissioned sequencers can be added
permissionedAddresses := rollapp.PermissionedAddresses.Addresses
if len(permissionedAddresses) > 0 {
bPermissioned := false
// check to see if the sequencer is in the permissioned list
for i := range permissionedAddresses {
if permissionedAddresses[i] == msg.Creator {
// Found!
bPermissioned = true
break
}
}
// Check Error: only permissioned sequencers allowed to update and this one is not in the list
if !bPermissioned {
// this is a logic error, as the sequencer modules' BeforeUpdateState hook
// should check that the sequencer exists and register for serving this rollapp
// so if this check passed, an unpermissioned sequencer is registered
return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic,
"unpermissioned sequencer (%s) is registered for rollappId(%s)",
msg.Creator, msg.RollappId)
}
}
// retrieve last updating index
latestStateInfoIndex, isFound := k.GetLatestStateInfoIndex(ctx, msg.RollappId)
var newIndex uint64
if !isFound {
// check to see if it's the first update
if msg.StartHeight != 1 {
// if not, it's an error
return nil, sdkerrors.Wrapf(types.ErrWrongBlockHeight,
"expected height 1, but received (%d)",
msg.StartHeight)
}
// else, it's the first update
newIndex = 1
} else {
// retrieve last updating index
stateInfo, isFound := k.GetStateInfo(ctx, msg.RollappId, latestStateInfoIndex.Index)
// Check Error: if latestStateInfoIndex exists, there must me an info for this state
if !isFound {
// if not, it's a logic error
return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic,
"missing stateInfo for state-index (%d) of rollappId(%s)",
latestStateInfoIndex.Index, msg.RollappId)
}
// Unnecessary validations if the tx not running in delivery mode
if !ctx.IsCheckTx() && !ctx.IsReCheckTx() {
// check to see if we have already got an update for current block
if stateInfo.CreationHeight == uint64(ctx.BlockHeight()) {
// only one update is allowed in a block
return nil, types.ErrMultiUpdateStateInBlock
}
// check to see if received height is the one we expected
expectedStartHeight := stateInfo.StartHeight + stateInfo.NumBlocks
if expectedStartHeight != msg.StartHeight {
return nil, sdkerrors.Wrapf(types.ErrWrongBlockHeight,
"expected height (%d), but received (%d)",
expectedStartHeight, msg.StartHeight)
}
}
// bump state index
newIndex = latestStateInfoIndex.Index + 1
}
// Write new index information to the store
k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{
RollappId: msg.RollappId,
Index: newIndex,
})
// Write new state information to the store indexed by <RollappId,LatestStateInfoIndex>
stateInfoIndex := types.StateInfoIndex{RollappId: msg.RollappId, Index: newIndex}
k.SetStateInfo(ctx, types.StateInfo{
StateInfoIndex: stateInfoIndex,
Sequencer: msg.Creator,
StartHeight: msg.StartHeight,
NumBlocks: msg.NumBlocks,
DAPath: msg.DAPath,
Version: msg.Version,
CreationHeight: uint64(ctx.BlockHeight()),
Status: types.STATE_STATUS_RECEIVED,
BDs: msg.BDs},
)
// calculate finalization
finalizationHeight := uint64(ctx.BlockHeight()) + k.DisputePeriodInBlocks(ctx)
newFinalizationQueue := []types.StateInfoIndex{stateInfoIndex}
// load FinalizationQueue and update
blockHeightToFinalizationQueue, found := k.GetBlockHeightToFinalizationQueue(ctx, finalizationHeight)
if found {
newFinalizationQueue = append(blockHeightToFinalizationQueue.FinalizationQueue, newFinalizationQueue...)
}
// Write new BlockHeightToFinalizationQueue
k.SetBlockHeightToFinalizationQueue(ctx, types.BlockHeightToFinalizationQueue{
FinalizationHeight: finalizationHeight,
FinalizationQueue: newFinalizationQueue,
})
ctx.EventManager().EmitEvent(
sdk.NewEvent(types.EventTypeStateUpdate,
sdk.NewAttribute(types.AttributeKeyRollappId, msg.RollappId),
sdk.NewAttribute(types.AttributeKeyStateInfoIndex, strconv.FormatUint(stateInfoIndex.Index, 10)),
sdk.NewAttribute(types.AttributeKeyStartHeight, strconv.FormatUint(msg.StartHeight, 10)),
sdk.NewAttribute(types.AttributeKeyNumBlocks, strconv.FormatUint(msg.NumBlocks, 10)),
sdk.NewAttribute(types.AttributeKeyDAPath, msg.DAPath),
),
)
return &types.MsgUpdateStateResponse{}, nil
}