forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 34
/
operation.go
158 lines (130 loc) · 4.22 KB
/
operation.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
150
151
152
153
154
155
156
157
158
package simulation
import (
"encoding/json"
"math/rand"
"sort"
"github.com/cosmos/cosmos-sdk/types/simulation"
)
// entry kinds for use within OperationEntry
const (
BeginBlockEntryKind = "begin_block"
EndBlockEntryKind = "end_block"
MsgEntryKind = "msg"
QueuedMsgEntryKind = "queued_msg"
)
// OperationEntry - an operation entry for logging (ex. BeginBlock, EndBlock, XxxMsg, etc)
type OperationEntry struct {
EntryKind string `json:"entry_kind" yaml:"entry_kind"`
Height int64 `json:"height" yaml:"height"`
Order int64 `json:"order" yaml:"order"`
Operation json.RawMessage `json:"operation" yaml:"operation"`
}
// NewOperationEntry creates a new OperationEntry instance
func NewOperationEntry(entry string, height, order int64, op json.RawMessage) OperationEntry {
return OperationEntry{
EntryKind: entry,
Height: height,
Order: order,
Operation: op,
}
}
// BeginBlockEntry - operation entry for begin block
func BeginBlockEntry(height int64) OperationEntry {
return NewOperationEntry(BeginBlockEntryKind, height, -1, nil)
}
// EndBlockEntry - operation entry for end block
func EndBlockEntry(height int64) OperationEntry {
return NewOperationEntry(EndBlockEntryKind, height, -1, nil)
}
// MsgEntry - operation entry for standard msg
func MsgEntry(height, order int64, opMsg simulation.OperationMsg) OperationEntry {
return NewOperationEntry(MsgEntryKind, height, order, opMsg.MustMarshal())
}
// QueuedMsgEntry creates an operation entry for a given queued message.
func QueuedMsgEntry(height int64, opMsg simulation.OperationMsg) OperationEntry {
return NewOperationEntry(QueuedMsgEntryKind, height, -1, opMsg.MustMarshal())
}
// MustMarshal marshals the operation entry, panic on error.
func (oe OperationEntry) MustMarshal() json.RawMessage {
out, err := json.Marshal(oe)
if err != nil {
panic(err)
}
return out
}
// OperationQueue defines an object for a queue of operations
type OperationQueue map[int][]simulation.Operation
// NewOperationQueue creates a new OperationQueue instance.
func NewOperationQueue() OperationQueue {
return make(OperationQueue)
}
// queueOperations adds all future operations into the operation queue.
func queueOperations(queuedOps OperationQueue, queuedTimeOps []simulation.FutureOperation, futureOps []simulation.FutureOperation) {
if futureOps == nil {
return
}
for _, futureOp := range futureOps {
futureOp := futureOp
if futureOp.BlockHeight != 0 {
if val, ok := queuedOps[futureOp.BlockHeight]; ok {
queuedOps[futureOp.BlockHeight] = append(val, futureOp.Op)
} else {
queuedOps[futureOp.BlockHeight] = []simulation.Operation{futureOp.Op}
}
continue
}
// TODO: Replace with proper sorted data structure, so don't have the
// copy entire slice
index := sort.Search(
len(queuedTimeOps),
func(i int) bool {
return queuedTimeOps[i].BlockTime.After(futureOp.BlockTime)
},
)
queuedTimeOps = append(queuedTimeOps, simulation.FutureOperation{})
copy(queuedTimeOps[index+1:], queuedTimeOps[index:])
queuedTimeOps[index] = futureOp
}
}
// WeightedOperation is an operation with associated weight.
// This is used to bias the selection operation within the simulator.
type WeightedOperation struct {
weight int
op simulation.Operation
}
func (w WeightedOperation) Weight() int {
return w.weight
}
func (w WeightedOperation) Op() simulation.Operation {
return w.op
}
// NewWeightedOperation creates a new WeightedOperation instance
func NewWeightedOperation(weight int, op simulation.Operation) WeightedOperation {
return WeightedOperation{
weight: weight,
op: op,
}
}
// WeightedOperations is the group of all weighted operations to simulate.
type WeightedOperations []simulation.WeightedOperation
func (ops WeightedOperations) totalWeight() int {
totalOpWeight := 0
for _, op := range ops {
totalOpWeight += op.Weight()
}
return totalOpWeight
}
func (ops WeightedOperations) getSelectOpFn() simulation.SelectOpFn {
totalOpWeight := ops.totalWeight()
return func(r *rand.Rand) simulation.Operation {
x := r.Intn(totalOpWeight)
for i := 0; i < len(ops); i++ {
if x <= ops[i].Weight() {
return ops[i].Op()
}
x -= ops[i].Weight()
}
// shouldn't happen
return ops[0].Op()
}
}