-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathsimulatorFacade.go
More file actions
210 lines (170 loc) · 6.59 KB
/
simulatorFacade.go
File metadata and controls
210 lines (170 loc) · 6.59 KB
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
package facade
import (
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"strconv"
"strings"
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/data/transaction"
"github.com/multiversx/mx-chain-go/node/chainSimulator/dtos"
logger "github.com/multiversx/mx-chain-logger-go"
dtoc "github.com/multiversx/mx-chain-simulator-go/pkg/dtos"
)
const (
errMsgTargetEpochLowerThanCurrentEpoch = "target epoch must be greater than current epoch"
errMsgAccountNotFound = "account was not found"
numBlocksToGenerate = 2
)
var log = logger.GetOrCreate("simulator/facade")
var errPendingTransaction = errors.New("something went wrong, transaction is still in pending")
type simulatorFacade struct {
simulator SimulatorHandler
transactionHandler ProxyTransactionsHandler
}
// NewSimulatorFacade will create a new instance of simulatorFacade
func NewSimulatorFacade(simulator SimulatorHandler, transactionHandler ProxyTransactionsHandler) (*simulatorFacade, error) {
if check.IfNil(simulator) {
return nil, errNilSimulatorHandler
}
if check.IfNilReflect(transactionHandler) {
return nil, errNilProxyTransactionsHandler
}
return &simulatorFacade{
simulator: simulator,
transactionHandler: transactionHandler,
}, nil
}
// GenerateBlocks will generate a provided number of blocks
func (sf *simulatorFacade) GenerateBlocks(numOfBlocks int) error {
if numOfBlocks <= 0 {
return errInvalidNumOfBlocks
}
return sf.simulator.GenerateBlocks(numOfBlocks)
}
// GetInitialWalletKeys will return the initial wallets
func (sf *simulatorFacade) GetInitialWalletKeys() *dtos.InitialWalletKeys {
return sf.simulator.GetInitialWalletKeys()
}
// SetKeyValueForAddress will set the provided state for an address
func (sf *simulatorFacade) SetKeyValueForAddress(address string, keyValueMap map[string]string) error {
return sf.simulator.SetKeyValueForAddress(address, keyValueMap)
}
// SetStateMultiple will set the entire state for the provided addresses
func (sf *simulatorFacade) SetStateMultiple(stateSlice []*dtos.AddressState, noGenerate bool) error {
err := sf.simulator.SetStateMultiple(stateSlice)
if err != nil {
return err
}
if noGenerate {
return nil
}
return sf.simulator.GenerateBlocks(numBlocksToGenerate)
}
// SetStateMultipleOverwrite will set the entire state for the provided address and cleanup the old state of the provided addresses
func (sf *simulatorFacade) SetStateMultipleOverwrite(stateSlice []*dtos.AddressState, noGenerate bool) error {
for _, state := range stateSlice {
// TODO MX-15414
err := sf.simulator.RemoveAccounts([]string{state.Address})
shouldReturnErr := err != nil && !strings.Contains(err.Error(), errMsgAccountNotFound)
if shouldReturnErr {
return err
}
}
err := sf.simulator.SetStateMultiple(stateSlice)
if err != nil {
return err
}
if noGenerate {
return nil
}
return sf.simulator.GenerateBlocks(numBlocksToGenerate)
}
// AddValidatorKeys will add the validator keys in the multi key handler
func (sf *simulatorFacade) AddValidatorKeys(validators *dtoc.ValidatorKeys) error {
validatorsPrivateKeys := make([][]byte, 0, len(validators.PrivateKeysBase64))
for idx, privateKeyBase64 := range validators.PrivateKeysBase64 {
privateKeyHexBytes, err := base64.StdEncoding.DecodeString(privateKeyBase64)
if err != nil {
return fmt.Errorf("cannot base64 decode key index=%d, error=%s", idx, err.Error())
}
privateKeyBytes, err := hex.DecodeString(string(privateKeyHexBytes))
if err != nil {
return fmt.Errorf("cannot hex decode key index=%d, error=%s", idx, err.Error())
}
validatorsPrivateKeys = append(validatorsPrivateKeys, privateKeyBytes)
}
return sf.simulator.AddValidatorKeys(validatorsPrivateKeys)
}
// GenerateBlocksUntilEpochIsReached will generate as many blocks are required until the target epoch is reached
func (sf *simulatorFacade) GenerateBlocksUntilEpochIsReached(targetEpoch int32) error {
return sf.simulator.GenerateBlocksUntilEpochIsReached(targetEpoch)
}
// ForceUpdateValidatorStatistics will force the reset of the cache used for the validators statistics endpoint
func (sf *simulatorFacade) ForceUpdateValidatorStatistics() error {
return sf.simulator.ForceResetValidatorStatisticsCache()
}
// ForceChangeOfEpoch will force change the current epoch
func (sf *simulatorFacade) ForceChangeOfEpoch(targetEpoch uint32) error {
if targetEpoch == 0 {
return sf.simulator.ForceChangeOfEpoch()
}
currentEpoch := sf.getCurrentEpoch()
if currentEpoch >= targetEpoch {
return fmt.Errorf("%s, current epoch: %d target epoch: %d", errMsgTargetEpochLowerThanCurrentEpoch, currentEpoch, targetEpoch)
}
for currentEpoch < targetEpoch {
err := sf.simulator.ForceChangeOfEpoch()
if err != nil {
return err
}
currentEpoch = sf.getCurrentEpoch()
}
return nil
}
// GetObserversInfo will return information about the observers
func (sf *simulatorFacade) GetObserversInfo() (map[uint32]*dtoc.ObserverInfo, error) {
restApiInterface := sf.simulator.GetRestAPIInterfaces()
response := make(map[uint32]*dtoc.ObserverInfo)
for shardID, apiInterface := range restApiInterface {
split := strings.Split(apiInterface, ":")
if len(split) != 2 {
return nil, fmt.Errorf("cannot extract port for shard ID=%d", shardID)
}
port, err := strconv.Atoi(split[1])
if err != nil {
return nil, fmt.Errorf("cannot cast port string to int for shard ID=%d", shardID)
}
response[shardID] = &dtoc.ObserverInfo{
APIPort: port,
}
}
return response, nil
}
// GenerateBlocksUntilTransactionIsProcessed generate blocks until the status of the provided transaction hash is processed
func (sf *simulatorFacade) GenerateBlocksUntilTransactionIsProcessed(txHash string, maxNumOfBlocksToGenerate int) error {
log.Debug("GenerateBlocksUntilTransactionIsProcessed", "tx hash", txHash, "maxNumOfBlocksToGenerate", maxNumOfBlocksToGenerate)
for i := 0; i < maxNumOfBlocksToGenerate; i++ {
txStatusInfo, err := sf.transactionHandler.GetProcessedTransactionStatus(txHash)
if err != nil {
return err
}
if txStatusInfo.Status != transaction.TxStatusPending.String() {
return nil
}
err = sf.GenerateBlocks(1)
if err != nil {
return err
}
}
return errors.New("something went wrong, transaction is still in pending")
}
func (sf *simulatorFacade) getCurrentEpoch() uint32 {
return sf.simulator.GetNodeHandler(core.MetachainShardId).GetProcessComponents().EpochStartTrigger().Epoch()
}
// IsInterfaceNil returns true if there is no value under the interface
func (sf *simulatorFacade) IsInterfaceNil() bool {
return sf == nil
}