github.com/smartcontractkit/chainlink-terra@v0.1.4/tests/e2e/gauntlet_deployer.go (about) 1 package e2e 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/url" 8 "os" 9 "path/filepath" 10 "regexp" 11 "strings" 12 13 . "github.com/onsi/gomega" 14 "github.com/smartcontractkit/chainlink-terra/tests/e2e/utils" 15 "github.com/smartcontractkit/integrations-framework/gauntlet" 16 ) 17 18 const TERRA_COMMAND_ERROR = "Terra Command execution error" 19 const RETRY_COUNT = 5 20 21 type GauntletDeployer struct { 22 Cli *gauntlet.Gauntlet 23 Version string 24 LinkToken string 25 BillingAccessController string 26 RequesterAccessController string 27 Flags string 28 DeviationFlaggingValidator string 29 OCR string 30 RddPath string 31 ProposalId string 32 ProposalDigest string 33 } 34 35 type InspectionResult struct { 36 Pass bool 37 Key string 38 Expected string 39 Actual string 40 } 41 42 // GetDefaultGauntletConfig gets the default config gauntlet will need to start making commands 43 // against the environment 44 func GetDefaultGauntletConfig(nodeUrl *url.URL) map[string]string { 45 networkConfig := map[string]string{ 46 "NODE_URL": nodeUrl.String(), 47 "CHAIN_ID": "localterra", 48 "DEFAULT_GAS_PRICE": "1", 49 "MNEMONIC": "symbol force gallery make bulk round subway violin worry mixture penalty kingdom boring survey tool fringe patrol sausage hard admit remember broken alien absorb", 50 } 51 52 return networkConfig 53 } 54 55 // UpdateReportName updates the report name to be used by gauntlet on completion 56 func UpdateReportName(reportName string, g *gauntlet.Gauntlet) { 57 g.NetworkConfig["REPORT_NAME"] = filepath.Join(utils.Reports, reportName) 58 err := g.WriteNetworkConfigMap(utils.Networks) 59 Expect(err).ShouldNot(HaveOccurred(), "Failed to write the updated .env file") 60 } 61 62 // GetInspectionResultsFromOutput parses the inpsectiond data from the output 63 // TODO we should really update the inspection command to just output json in the future 64 func GetInspectionResultsFromOutput(output string) (map[string]InspectionResult, error) { 65 lines := strings.Split(output, "\n") 66 passRegex, err := regexp.Compile("✅ (.+) matches: (.+)$") 67 if err != nil { 68 return map[string]InspectionResult{}, err 69 } 70 failRegex, err := regexp.Compile("⚠️ (.+) invalid: expected (.+) but actually (.*)$") 71 if err != nil { 72 return map[string]InspectionResult{}, err 73 } 74 results := map[string]InspectionResult{} 75 for _, l := range lines { 76 passMatches := passRegex.FindStringSubmatch(l) 77 failMatches := failRegex.FindStringSubmatch(l) 78 if len(passMatches) == 3 { 79 results[passMatches[1]] = InspectionResult{ 80 Pass: true, 81 Key: passMatches[1], 82 Expected: "", 83 Actual: passMatches[2], 84 } 85 } else if len(failMatches) == 4 { 86 results[failMatches[1]] = InspectionResult{ 87 Pass: false, 88 Key: failMatches[1], 89 Expected: failMatches[2], 90 Actual: failMatches[3], 91 } 92 } 93 } 94 95 return results, nil 96 } 97 98 // LoadReportJson loads a gauntlet report into a generic map 99 func LoadReportJson(file string) (map[string]interface{}, error) { 100 jsonFile, err := os.Open(filepath.Join(utils.Reports, file)) 101 if err != nil { 102 return map[string]interface{}{}, err 103 } 104 defer jsonFile.Close() 105 106 byteValue, err := ioutil.ReadAll(jsonFile) 107 if err != nil { 108 return map[string]interface{}{}, err 109 } 110 111 var data map[string]interface{} 112 err = json.Unmarshal([]byte(byteValue), &data) 113 114 return data, err 115 } 116 117 // GetTxAddressFromReport gets the address from the typical place in the json report data 118 func GetTxAddressFromReport(report map[string]interface{}) string { 119 return report["responses"].([]interface{})[0].(map[string]interface{})["tx"].(map[string]interface{})["address"].(string) 120 } 121 122 // DeployToken deploys the link token 123 func (gd *GauntletDeployer) DeployToken() string { 124 codeIds := gd.Cli.Flag("codeIDs", filepath.Join(utils.CodeIds, fmt.Sprintf("%s%s", gd.Cli.Network, ".json"))) 125 artifacts := gd.Cli.Flag("artifacts", filepath.Join(utils.GauntletTerraContracts, "artifacts", "bin")) 126 reportName := "deploy_token" 127 UpdateReportName(reportName, gd.Cli) 128 _, err := gd.Cli.ExecCommandWithRetries([]string{ 129 "token:deploy", 130 gd.Cli.Flag("version", gd.Version), 131 codeIds, 132 artifacts, 133 }, []string{ 134 TERRA_COMMAND_ERROR, 135 }, RETRY_COUNT) 136 Expect(err).ShouldNot(HaveOccurred(), "Failed to deploy link token") 137 report, err := LoadReportJson(reportName + ".json") 138 Expect(err).ShouldNot(HaveOccurred()) 139 return GetTxAddressFromReport(report) 140 } 141 142 // Upload uploads the terra contracts 143 func (gd *GauntletDeployer) Upload() { 144 UpdateReportName("upload", gd.Cli) 145 _, err := gd.Cli.ExecCommandWithRetries([]string{ 146 "upload", 147 gd.Cli.Flag("version", gd.Version), 148 gd.Cli.Flag("maxRetry", "10"), 149 }, []string{ 150 TERRA_COMMAND_ERROR, 151 }, RETRY_COUNT) 152 Expect(err).ShouldNot(HaveOccurred(), "Failed to upload contracts") 153 } 154 155 // deployAccessController deploys an access controller 156 func (gd *GauntletDeployer) deployAccessController(name string) string { 157 codeIds := gd.Cli.Flag("codeIDs", filepath.Join(utils.CodeIds, fmt.Sprintf("%s%s", gd.Cli.Network, ".json"))) 158 UpdateReportName(name, gd.Cli) 159 _, err := gd.Cli.ExecCommandWithRetries([]string{ 160 "access_controller:deploy", 161 gd.Cli.Flag("version", gd.Version), 162 codeIds, 163 }, []string{ 164 TERRA_COMMAND_ERROR, 165 }, RETRY_COUNT) 166 Expect(err).ShouldNot(HaveOccurred(), "Failed to deploy the billing access controller") 167 report, err := LoadReportJson(name + ".json") 168 Expect(err).ShouldNot(HaveOccurred()) 169 return GetTxAddressFromReport(report) 170 } 171 172 // DeployBillingAccessController deploys a biller 173 func (gd *GauntletDeployer) DeployBillingAccessController() string { 174 billingAccessController := gd.deployAccessController("billing_ac_deploy") 175 gd.Cli.NetworkConfig["BILLING_ACCESS_CONTROLLER"] = billingAccessController 176 return billingAccessController 177 } 178 179 // DeployRequesterAccessController deploys a requester 180 func (gd *GauntletDeployer) DeployRequesterAccessController() string { 181 requesterAccessController := gd.deployAccessController("requester_ac_deploy") 182 gd.Cli.NetworkConfig["REQUESTER_ACCESS_CONTROLLER"] = requesterAccessController 183 return requesterAccessController 184 } 185 186 // DeployFlags deploys the flags for the lowering and raising access controllers 187 func (gd *GauntletDeployer) DeployFlags(billingAccessController, requesterAccessController string) string { 188 reportName := "flags_deploy" 189 UpdateReportName(reportName, gd.Cli) 190 _, err := gd.Cli.ExecCommandWithRetries([]string{ 191 "flags:deploy", 192 gd.Cli.Flag("loweringAccessController", billingAccessController), 193 gd.Cli.Flag("raisingAccessController", requesterAccessController), 194 gd.Cli.Flag("version", gd.Version), 195 }, []string{ 196 TERRA_COMMAND_ERROR, 197 }, RETRY_COUNT) 198 Expect(err).ShouldNot(HaveOccurred(), "Failed to deploy the flag") 199 flagsReport, err := LoadReportJson(reportName + ".json") 200 Expect(err).ShouldNot(HaveOccurred()) 201 flags := GetTxAddressFromReport(flagsReport) 202 return flags 203 } 204 205 // DeployDeviationFlaggingValidator deploys the deviation flagging validator with the threshold provided 206 func (gd *GauntletDeployer) DeployDeviationFlaggingValidator(flags string, flaggingThreshold int) string { 207 reportName := "dfv_deploy" 208 UpdateReportName(reportName, gd.Cli) 209 _, err := gd.Cli.ExecCommandWithRetries([]string{ 210 "deviation_flagging_validator:deploy", 211 gd.Cli.Flag("flaggingThreshold", fmt.Sprintf("%v", uint32(flaggingThreshold))), 212 gd.Cli.Flag("flags", flags), 213 gd.Cli.Flag("version", gd.Version), 214 }, []string{ 215 TERRA_COMMAND_ERROR, 216 }, RETRY_COUNT) 217 Expect(err).ShouldNot(HaveOccurred(), "Failed to deploy the deviation flagging validator") 218 dfvReport, err := LoadReportJson(reportName + ".json") 219 Expect(err).ShouldNot(HaveOccurred()) 220 return GetTxAddressFromReport(dfvReport) 221 } 222 223 // DeployOcr deploys ocr, it creates an rdd file in the process and updates it with the ocr address on completion 224 func (gd *GauntletDeployer) DeployOcr() (string, string) { 225 rddPath := filepath.Join(utils.Rdd, fmt.Sprintf("directory-terra-%s.json", gd.Cli.Network)) 226 tmpId := "terra1test0000000000000000000000000000000000" 227 ocrRddContract := NewRddContract(tmpId) 228 err := WriteRdd(ocrRddContract, rddPath) 229 Expect(err).ShouldNot(HaveOccurred(), "Did not write the rdd json correctly") 230 reportName := "ocr_deploy" 231 UpdateReportName(reportName, gd.Cli) 232 _, err = gd.Cli.ExecCommandWithRetries([]string{ 233 "ocr2:deploy", 234 gd.Cli.Flag("rdd", rddPath), 235 gd.Cli.Flag("version", gd.Version), 236 tmpId, 237 }, []string{ 238 TERRA_COMMAND_ERROR, 239 }, RETRY_COUNT) 240 Expect(err).ShouldNot(HaveOccurred(), "Failed to deploy ocr2") 241 ocrReport, err := LoadReportJson(reportName + ".json") 242 Expect(err).ShouldNot(HaveOccurred()) 243 ocr := GetTxAddressFromReport(ocrReport) 244 245 // add the new contract to the rdd 246 ocrRddContract.Contracts[ocr] = ocrRddContract.Contracts[tmpId] 247 err = WriteRdd(ocrRddContract, rddPath) 248 Expect(err).ShouldNot(HaveOccurred(), "Did not write the rdd json correctly") 249 return ocr, rddPath 250 } 251 252 // SetBiling sets the billing info that exists in the rdd file for the ocr address you pass in 253 func (gd *GauntletDeployer) SetBilling(ocr, rddPath string) { 254 UpdateReportName("set_billing", gd.Cli) 255 _, err := gd.Cli.ExecCommandWithRetries([]string{ 256 "ocr2:set_billing", 257 gd.Cli.Flag("version", gd.Version), 258 gd.Cli.Flag("rdd", rddPath), 259 ocr, 260 }, []string{ 261 TERRA_COMMAND_ERROR, 262 }, RETRY_COUNT) 263 Expect(err).ShouldNot(HaveOccurred(), "Failed to set billing") 264 } 265 266 // BeginProposal begins the proposal 267 func (gd *GauntletDeployer) BeginProposal(ocr, rddPath string) string { 268 reportName := "begin_proposal" 269 UpdateReportName(reportName, gd.Cli) 270 _, err := gd.Cli.ExecCommandWithRetries([]string{ 271 "ocr2:begin_proposal", 272 gd.Cli.Flag("version", gd.Version), 273 gd.Cli.Flag("rdd", rddPath), 274 ocr, 275 }, []string{ 276 TERRA_COMMAND_ERROR, 277 }, RETRY_COUNT) 278 Expect(err).ShouldNot(HaveOccurred(), "Failed to begin proposal") 279 beginProposalReport, err := LoadReportJson(reportName + ".json") 280 Expect(err).ShouldNot(HaveOccurred()) 281 return beginProposalReport["data"].(map[string]interface{})["proposalId"].(string) 282 } 283 284 // ProposeConfig proposes the config 285 func (gd *GauntletDeployer) ProposeConfig(ocr, proposalId, rddPath string) { 286 reportName := "propose_config" 287 UpdateReportName(reportName, gd.Cli) 288 _, err := gd.Cli.ExecCommandWithRetries([]string{ 289 "ocr2:propose_config", 290 gd.Cli.Flag("version", gd.Version), 291 gd.Cli.Flag("rdd", rddPath), 292 gd.Cli.Flag("proposalId", proposalId), 293 gd.OCR, 294 }, []string{ 295 TERRA_COMMAND_ERROR, 296 }, RETRY_COUNT) 297 Expect(err).ShouldNot(HaveOccurred(), "Failed to propose config") 298 } 299 300 // ProposeOffchainConfig proposes the offchain config 301 func (gd *GauntletDeployer) ProposeOffchainConfig(ocr, proposalId, rddPath string) { 302 reportName := "propose_offchain_config" 303 gd.Cli.NetworkConfig["SECRET"] = gd.Cli.NetworkConfig["MNEMONIC"] 304 UpdateReportName(reportName, gd.Cli) 305 _, err := gd.Cli.ExecCommandWithRetries([]string{ 306 "ocr2:propose_offchain_config", 307 gd.Cli.Flag("version", gd.Version), 308 gd.Cli.Flag("rdd", rddPath), 309 gd.Cli.Flag("proposalId", proposalId), 310 ocr, 311 }, []string{ 312 TERRA_COMMAND_ERROR, 313 }, RETRY_COUNT) 314 Expect(err).ShouldNot(HaveOccurred(), "Failed to propose offchain config") 315 } 316 317 // FinalizeProposal finalizes the proposal 318 func (gd *GauntletDeployer) FinalizeProposal(ocr, proposalId, rddPath string) string { 319 reportName := "finalize_proposal" 320 UpdateReportName(reportName, gd.Cli) 321 _, err := gd.Cli.ExecCommandWithRetries([]string{ 322 "ocr2:finalize_proposal", 323 gd.Cli.Flag("version", gd.Version), 324 gd.Cli.Flag("rdd", rddPath), 325 gd.Cli.Flag("proposalId", proposalId), 326 ocr, 327 }, []string{ 328 TERRA_COMMAND_ERROR, 329 }, RETRY_COUNT) 330 Expect(err).ShouldNot(HaveOccurred(), "Failed to finalize proposal") 331 finalizeProposalReport, err := LoadReportJson(reportName + ".json") 332 Expect(err).ShouldNot(HaveOccurred()) 333 return finalizeProposalReport["data"].(map[string]interface{})["digest"].(string) 334 } 335 336 // AcceptProposal accepts the proposal 337 func (gd *GauntletDeployer) AcceptProposal(ocr, proposalId, proposalDigest, rddPath string) string { 338 reportName := "accept_proposal" 339 UpdateReportName(reportName, gd.Cli) 340 _, err := gd.Cli.ExecCommandWithRetries([]string{ 341 "ocr2:accept_proposal", 342 gd.Cli.Flag("version", gd.Version), 343 gd.Cli.Flag("rdd", rddPath), 344 gd.Cli.Flag("proposalId", proposalId), 345 gd.Cli.Flag("digest", proposalDigest), 346 ocr, 347 }, []string{ 348 TERRA_COMMAND_ERROR, 349 }, RETRY_COUNT) 350 Expect(err).ShouldNot(HaveOccurred(), "Failed to accept proposal") 351 acceptProposalReport, err := LoadReportJson(reportName + ".json") 352 Expect(err).ShouldNot(HaveOccurred()) 353 return acceptProposalReport["data"].(map[string]interface{})["digest"].(string) 354 } 355 356 // OcrInspect gets the inspections results data 357 func (gd *GauntletDeployer) OcrInspect(ocr, rddPath string) map[string]InspectionResult { 358 UpdateReportName("inspect", gd.Cli) 359 output, err := gd.Cli.ExecCommandWithRetries([]string{ 360 "ocr2:inspect", 361 gd.Cli.Flag("version", gd.Version), 362 gd.Cli.Flag("rdd", rddPath), 363 ocr, 364 }, []string{ 365 TERRA_COMMAND_ERROR, 366 }, RETRY_COUNT) 367 Expect(err).ShouldNot(HaveOccurred(), "Failed to inspect") 368 369 results, err := GetInspectionResultsFromOutput(output) 370 Expect(err).ShouldNot(HaveOccurred()) 371 return results 372 }