-
Notifications
You must be signed in to change notification settings - Fork 142
/
Copy pathstate.go
244 lines (201 loc) · 8.05 KB
/
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
package main
import (
"fmt"
"log"
"regexp"
"time"
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
e2e "github.com/cosmos/interchain-security/v6/tests/e2e/testlib"
)
// type aliases
type (
ChainState = e2e.ChainState
ConsumerAdditionProposal = e2e.ConsumerAdditionProposal
ConsumerRemovalProposal = e2e.ConsumerRemovalProposal
ConsumerModificationProposal = e2e.ConsumerModificationProposal
IBCTransferParams = e2e.IBCTransferParams
IBCTransferParamsProposal = e2e.IBCTransferParamsProposal
Param = e2e.Param
ParamsProposal = e2e.ParamsProposal
Proposal = e2e.Proposal
Rewards = e2e.Rewards
TargetDriver = e2e.TargetDriver
TextProposal = e2e.TextProposal
TxResponse = e2e.TxResponse
UpgradeProposal = e2e.UpgradeProposal
)
type State map[ChainID]ChainState
type Chain struct {
target TargetDriver
testConfig *TestConfig
}
// waitForTx waits until a transaction is seen in a block or panics if a timeout occurs
func (tr Chain) waitForTx(chain ChainID, txResponse []byte, timeout time.Duration) TxResponse {
// remove any gas estimate as when command is run with gas=auto the output contains gas estimation mixed with json output
re, err := regexp.Compile("gas estimate: [0-9]+")
if err != nil {
panic(fmt.Sprintf("error compiling regexp: %s", err.Error()))
}
txResponse = re.ReplaceAll(txResponse, []byte{})
// check transaction
response := e2e.GetTxResponse(txResponse)
if response.Code != 0 {
log.Fatalf("sending transaction failed with error code %d, Log:'%s'", response.Code, response.RawLog)
}
// wait for the transaction
start := time.Now()
for {
res, err := tr.target.QueryTransaction(chain, response.TxHash)
if err == nil {
return e2e.GetTxResponse(res)
}
if time.Since(start) > timeout {
log.Printf("query transaction failed with err=%s, resp=%s", err.Error(), res)
panic(fmt.Sprintf("\n\nwaitForTx on chain '%s' has timed out after: %s\n\n", chain, timeout))
}
time.Sleep(1 * time.Second)
}
}
func (tr Chain) waitBlocks(chain ChainID, blocks uint, timeout time.Duration) {
if tr.testConfig.UseCometmock {
// call advance_blocks method on cometmock
// curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{"jsonrpc":"2.0","method":"advance_blocks","params":{"num_blocks": "36000000"},"id":1}' 127.0.0.1:22331
tcpAddress := tr.target.GetQueryNodeRPCAddress(chain)
method := "advance_blocks"
params := fmt.Sprintf(`{"num_blocks": "%d"}`, blocks)
tr.curlJsonRPCRequest(method, params, tcpAddress)
return
}
startBlock := tr.target.GetBlockHeight(chain)
tr.waitUntilBlock(chain, startBlock+blocks, timeout)
}
func (tr Chain) waitUntilBlock(chain ChainID, block uint, timeout time.Duration) {
start := time.Now()
for {
thisBlock := tr.target.GetBlockHeight(chain)
if thisBlock >= block {
return
}
if time.Since(start) > timeout {
panic(fmt.Sprintf("\n\n\nwaitBlocks method has timed out after: %s\n\n", timeout))
}
time.Sleep(500 * time.Millisecond)
}
}
func (tr Chain) GetBalances(chain ChainID, modelState map[ValidatorID]uint) map[ValidatorID]uint {
actualState := map[ValidatorID]uint{}
for k := range modelState {
actualState[k] = tr.target.GetBalance(chain, k)
}
return actualState
}
func (tr Chain) GetClientFrozenHeight(chain ChainID, clientID string) clienttypes.Height {
revNumber, revHeight := tr.target.GetClientFrozenHeight(chain, clientID)
return clienttypes.Height{RevisionHeight: revHeight, RevisionNumber: revNumber}
}
func (tr Chain) GetProposedConsumerChains(chain ChainID) []string {
tr.waitBlocks(chain, 1, 10*time.Second)
return tr.target.GetProposedConsumerChains(chain)
}
func (tr Chain) GetProposals(chain ChainID, modelState map[uint]Proposal) map[uint]Proposal {
actualState := map[uint]Proposal{}
for k := range modelState {
actualState[k] = tr.target.GetProposal(chain, k)
}
return actualState
}
func (tr Chain) GetValPowers(chain ChainID, modelState map[ValidatorID]uint) map[ValidatorID]uint {
actualState := map[ValidatorID]uint{}
validatorConfigs := tr.testConfig.ValidatorConfigs
for k := range modelState {
valAddresses := map[string]bool{}
if chain == ChainID("provi") {
// use binary with Bech32Prefix set to ProviderAccountPrefix
valAddresses[validatorConfigs[k].ValconsAddress] = true
} else {
// use binary with Bech32Prefix set to ConsumerAccountPrefix
valAddresses[validatorConfigs[k].ValconsAddressOnConsumer] = true
valAddresses[validatorConfigs[k].ConsumerValconsAddress] = true
}
actualState[k] = tr.target.GetValPower(chain, k)
}
return actualState
}
func (tr Chain) GetStakedTokens(chain ChainID, modelState map[ValidatorID]uint) map[ValidatorID]uint {
actualState := map[ValidatorID]uint{}
for validator := range modelState {
validatorConfigs := tr.testConfig.ValidatorConfigs
valoperAddress := validatorConfigs[validator].ValoperAddress
if chain != ChainID("provi") {
// use binary with Bech32Prefix set to ConsumerAccountPrefix
if validatorConfigs[validator].UseConsumerKey {
valoperAddress = validatorConfigs[validator].ConsumerValoperAddress
} else {
// use the same address as on the provider but with different prefix
valoperAddress = validatorConfigs[validator].ValoperAddressOnConsumer
}
}
actualState[validator] = tr.target.GetValStakedTokens(chain, valoperAddress)
}
return actualState
}
func (tr Chain) GetRewards(chain ChainID, modelState Rewards) Rewards {
receivedRewards := map[ValidatorID]bool{}
currentBlock := tr.target.GetBlockHeight(chain)
tr.waitBlocks(chain, 1, 10*time.Second)
nextBlock := tr.target.GetBlockHeight(chain)
tr.waitBlocks(chain, 1, 10*time.Second)
if !modelState.IsIncrementalReward {
currentBlock = 1
}
for k := range modelState.IsRewarded {
receivedRewards[k] = tr.target.GetReward(chain, k, nextBlock, modelState.Denom) > tr.target.GetReward(chain, k, currentBlock, modelState.Denom)
}
return Rewards{IsRewarded: receivedRewards, IsIncrementalReward: modelState.IsIncrementalReward, Denom: modelState.Denom}
}
func (tr Chain) GetConsumerAddresses(chain ChainID, modelState map[ValidatorID]string) map[ValidatorID]string {
actualState := map[ValidatorID]string{}
for k := range modelState {
actualState[k] = tr.target.GetConsumerAddress(chain, k)
}
return actualState
}
func (tr Chain) GetProviderAddresses(chain ChainID, modelState map[ValidatorID]string) map[ValidatorID]string {
actualState := map[ValidatorID]string{}
for k := range modelState {
actualState[k] = tr.target.GetProviderAddressFromConsumer(chain, k)
}
return actualState
}
func (tr Chain) getValidatorNode(chain ChainID, validator ValidatorID) string {
// for CometMock, validatorNodes are all the same address as the query node (which is CometMocks address)
if tr.testConfig.UseCometmock {
return tr.target.GetQueryNode(chain)
}
return "tcp://" + tr.getValidatorIP(chain, validator) + ":26658"
}
func (tr Chain) getValidatorIP(chain ChainID, validator ValidatorID) string {
return tr.testConfig.ChainConfigs[chain].IpPrefix + "." + tr.testConfig.ValidatorConfigs[validator].IpSuffix
}
func (tr Chain) getValidatorHome(chain ChainID, validator ValidatorID) string {
return `/` + string(chain) + `/validator` + fmt.Sprint(validator)
}
func (tr Chain) curlJsonRPCRequest(method, params, address string) {
cmd_template := `curl -H 'Content-Type: application/json' -H 'Accept:application/json' --data '{"jsonrpc":"2.0","method":"%s","params":%s,"id":1}' %s`
cmd := tr.target.ExecCommand("bash", "-c", fmt.Sprintf(cmd_template, method, params, address))
verbosity := false
e2e.ExecuteCommand(cmd, "curlJsonRPCRequest", verbosity)
}
func (tr Chain) GetConsumerCommissionRates(chain ChainID, modelState map[ValidatorID]float64) map[ValidatorID]float64 {
actualState := map[ValidatorID]float64{}
for k := range modelState {
actualState[k] = tr.target.GetConsumerCommissionRate(chain, k)
}
return actualState
}
func uintPtr(i uint) *uint {
return &i
}
func intPtr(i int) *int {
return &i
}