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  }