func assembleTypesChainsTypesDefs(accountT []*definitions.AccountType, do *definitions.Do) error { clearDefaultNumbers(accountT) chainTypeAccounts, err := LoadChainTypes(do.ChainType) if err != nil { return err } log.WithFields(log.Fields{ "chainType": do.ChainType, }).Debug("Chain Type Loaded") for act, num := range chainTypeAccounts.AccountTypes { for _, thisActT := range accountT { // we match against the accountType we get from the chain-type file // which will be upper case, however the current yaml unmarshal sequence // seems to lower case this for some odd reason. // TODO: see if burntsushi's toml renderer will handle this better in the future if thisActT.Name == strings.Title(act) { thisActT.Number = num log.WithFields(log.Fields{ "name": thisActT.Name, "number": thisActT.Number, }).Debug("Setting Account Type Number") } } } return nil }
func assembleTypesFlags(accountT []*definitions.AccountType, do *definitions.Do) error { clearDefaultNumbers(accountT) for _, acctT := range do.AccountTypes { tmp := strings.Split(acctT, ":") act := tmp[0] var ( err error // If the number of account types is missing, // assuming 1. num int = 1 ) if len(tmp) > 1 { num, err = strconv.Atoi(tmp[1]) if err != nil { return err } } for _, thisActT := range accountT { if thisActT.Name == act { thisActT.Number = num log.WithFields(log.Fields{ "name": thisActT.Name, "number": thisActT.Number, }).Debug("Setting Account Type Number") } } } return nil }
func LoadPackage(fileName string) (*definitions.Package, error) { log.Info("Loading eris-pm Package Definition File.") var pkg = definitions.BlankPackage() var epmJobs = viper.New() // setup file abs, err := filepath.Abs(fileName) if err != nil { return nil, fmt.Errorf("Sorry, the marmots were unable to find the absolute path to the eris-pm jobs file.") } path := filepath.Dir(abs) file := filepath.Base(abs) extName := filepath.Ext(file) bName := file[:len(file)-len(extName)] log.WithFields(log.Fields{ "path": path, "name": bName, }).Debug("Loading eris-pm file") epmJobs.AddConfigPath(path) epmJobs.SetConfigName(bName) // load file if err := epmJobs.ReadInConfig(); err != nil { return nil, fmt.Errorf("Sorry, the marmots were unable to load the eris-pm jobs file. Please check your path.\nERROR =>\t\t\t%v", err) } // marshall file if err := epmJobs.Unmarshal(pkg); err != nil { return nil, fmt.Errorf("Sorry, the marmots could not figure that eris-pm jobs file out.\nPlease check your epm.yaml is properly formatted.\n") } return pkg, nil }
func BondJob(bond *definitions.Bond, do *definitions.Do) (string, error) { // Process Variables bond.Account, _ = util.PreProcess(bond.Account, do) bond.Amount, _ = util.PreProcess(bond.Amount, do) bond.PublicKey, _ = util.PreProcess(bond.PublicKey, do) // Use Defaults bond.Account = useDefault(bond.Account, do.Package.Account) do.PublicKey = useDefault(do.PublicKey, bond.PublicKey) // Formulate tx log.WithFields(log.Fields{ "public key": do.PublicKey, "amount": bond.Amount, }).Infof("Bond Transaction") erisNodeClient := client.NewErisNodeClient(do.Chain) erisKeyClient := keys.NewErisKeyClient(do.Signer) tx, err := core.Bond(erisNodeClient, erisKeyClient, do.PublicKey, bond.Account, bond.Amount, bond.Nonce) if err != nil { return util.MintChainErrorHandler(do, err) } // Sign, broadcast, display return txFinalize(do, tx, bond.Wait) }
func assembleTypesCSV(accountT []*definitions.AccountType, do *definitions.Do) error { clearDefaultNumbers(accountT) csvfile, err := os.Open(do.CSV) if err != nil { return err } defer csvfile.Close() reader := csv.NewReader(csvfile) reader.TrimLeadingSpace = true rawCSVdata, err := reader.ReadAll() if err != nil { return err } log.WithField("rawCSVdata", rawCSVdata).Debug("Data read.") for _, record := range rawCSVdata { act, num, tokens, toBond, perms := record[0], record[1], record[2], record[3], record[4:] for _, thisActT := range accountT { if thisActT.Name == act { var err error thisActT.Number, err = strconv.Atoi(num) if err != nil { return err } thisActT.Tokens, err = strconv.Atoi(tokens) if err != nil { return err } thisActT.ToBond, err = strconv.Atoi(toBond) if err != nil { return err } permsPrime := make(map[string]int) for i := 0; i < len(perms); i++ { p, err := strconv.Atoi(perms[i+1]) if err != nil { return err } permsPrime[perms[i]] = p i++ } thisActT.Perms = permsPrime log.WithFields(log.Fields{ "name": thisActT.Name, "number": thisActT.Number, "tokens": thisActT.Tokens, "toBond": thisActT.ToBond, "perms": thisActT.Perms, }).Debug("Setting Account Type Number") } } } return nil }
// ensures that the files which are included in this repository (`defaultTyps`) are also // present in the user's .eris/chains/account_types directory. // // does not ensure that the contents of the files are the same so will not affect user // defined settings around these files. // // does not check if the user has more account_types files in their .eris/chains/account_types // directory either so users can safely add additional account_types beyond the marmot // established defaults. func CheckDefaultTypes(erisPath, myPath string) error { // by default the dockerimage will move the default files to /default // however if anyone installs by binary then these files will be located // in the repo. defaultTypsPath := filepath.Join("/defaults", myPath, "*.toml") if _, err := os.Stat(filepath.Dir(defaultTypsPath)); os.IsNotExist(err) { log.WithField("path", defaultTypsPath).Warn("Default types path does not exist. Trying GOPATH.") defaultTypsPath = filepath.Join(ErisGo, version.NAME, myPath, "*.toml") } if _, err := os.Stat(filepath.Dir(defaultTypsPath)); os.IsNotExist(err) { log.WithField("path", defaultTypsPath).Info("Default types path does not exist. Exiting.") return fmt.Errorf("Could not locate default directory for %s", myPath) } // files in the default location which is /defaults in the docker image and $GOPATH/src/github.com/.../ // if binary install defaultTyps, err := filepath.Glob(defaultTypsPath) if err != nil { return err } // these are files which are in ~/.eris/chains/XXXXX and imported to the data container // by cli haveTyps, err := AccountTypesNames(erisPath, true) if err != nil { return err } // fail fast if there are not files present in either imported or in default directory if len(defaultTyps) == 0 && len(haveTyps) == 0 { return fmt.Errorf("There are no default or custom types to use.") } for _, file := range defaultTyps { f := filepath.Base(file) itsThere := false // check if present for _, b := range haveTyps { if f == b { itsThere = true } } if !itsThere { log.WithFields(log.Fields{ "file": file, "path": filepath.Join(erisPath, f), }).Debug("Copying default file") Copy(file, filepath.Join(erisPath, f)) } } return nil }
func deployRaw(do *definitions.Do, deploy *definitions.Deploy, contractName, contractCode string) (*txs.CallTx, error) { // Deploy contract log.WithFields(log.Fields{ "name": contractName, }).Warn("Deploying Contract") log.WithFields(log.Fields{ "source": deploy.Source, "code": contractCode, }).Info() erisNodeClient := client.NewErisNodeClient(do.Chain) erisKeyClient := keys.NewErisKeyClient(do.Signer) tx, err := core.Call(erisNodeClient, erisKeyClient, do.PublicKey, deploy.Source, "", deploy.Amount, deploy.Nonce, deploy.Gas, deploy.Fee, contractCode) if err != nil { return &txs.CallTx{}, fmt.Errorf("Error deploying contract %s: %v", contractName, err) } return tx, err }
func replaceBlockVariable(toReplace string, do *definitions.Do) (string, error) { log.WithFields(log.Fields{ "chain": do.Chain, "var": toReplace, }).Debug("Correcting $block variable") blockHeight, err := GetBlockHeight(do) block := strconv.Itoa(blockHeight) log.WithField("=>", block).Debug("Current height is") if err != nil { return "", err } if toReplace == "$block" { log.WithField("=>", block).Debug("Replacement (=)") return block, nil } catchEr := regexp.MustCompile("\\$block\\+(\\d*)") if catchEr.MatchString(toReplace) { height := catchEr.FindStringSubmatch(toReplace)[1] h1, err := strconv.Atoi(height) if err != nil { return "", err } h2, err := strconv.Atoi(block) if err != nil { return "", err } height = strconv.Itoa(h1 + h2) log.WithField("=>", height).Debug("Replacement (+)") return height, nil } catchEr = regexp.MustCompile("\\$block\\-(\\d*)") if catchEr.MatchString(toReplace) { height := catchEr.FindStringSubmatch(toReplace)[1] h1, err := strconv.Atoi(height) if err != nil { return "", err } h2, err := strconv.Atoi(block) if err != nil { return "", err } height = strconv.Itoa(h1 - h2) log.WithField("=>", height).Debug("Replacement (-)") return height, nil } log.WithField("=>", toReplace).Debug("Replacement (unknown)") return toReplace, nil }
func ReadAbiFormulateCall(abiLocation string, funcName string, args []string, do *definitions.Do) ([]byte, error) { abiSpecBytes, err := readAbi(do.ABIPath, abiLocation) if err != nil { return []byte{}, err } log.WithField("=>", string(abiSpecBytes)).Debug("ABI Specification (Formulate)") log.WithFields(log.Fields{ "function": funcName, "arguments": fmt.Sprintf("%v", args), }).Debug("Packing Call via ABI") return ebi.Packer(abiSpecBytes, funcName, args...) }
func ABIErrorHandler(do *definitions.Do, err error, call *definitions.Call, query *definitions.QueryContract) (string, error) { switch { case call != nil: log.WithFields(log.Fields{ "data": call.Data, "abi": call.ABI, "dest": call.Destination, "rawErr": err, }).Error("ABI Error") case query != nil: log.WithFields(log.Fields{ "data": query.Data, "abi": query.ABI, "dest": query.Destination, "rawErr": err, }).Error("ABI Error") } return "", fmt.Errorf(` There has been an error in finding or in using your ABI. ABI's are "Application Binary Interface" and they are what let us know how to talk to smart contracts. These little json files can be read by a variety of things which need to talk to smart contracts so they are quite necessary to be able to find and use properly. The ABIs are saved after the deploy events. So if there was a glitch in the matrix, we apologize in advance. The marmot recovery checklist is... * ensure your chain is running and you have enough validators online * ensure that your contracts successfully deployed * if you used imports or have multiple contracts in one file check the instance variable in the deploy and the abi variable in the call/query-contract * make sure you're calling or querying the right function * make sure you're using the correct variables for job results `) }
func makeKey(keyType string, account *definitions.Account) error { log.WithFields(log.Fields{ "path": keys.DaemonAddr, "type": keyType, }).Debug("Sending Call to eris-keys server") var err error log.WithField("endpoint", "gen").Debug() account.Address, err = keys.Call("gen", map[string]string{"auth": "", "type": keyType, "name": account.Name}) // note, for now we use not password to lock/unlock keys if _, ok := err.(keys.ErrConnectionRefused); ok { return fmt.Errorf("Could not connect to eris-keys server. Start it with `eris services start keys`. Error: %v", err) } if err != nil { return err } log.WithField("endpoint", "pub").Debug() account.PubKey, err = keys.Call("pub", map[string]string{"addr": account.Address, "name": account.Name}) if _, ok := err.(keys.ErrConnectionRefused); ok { return fmt.Errorf("Could not connect to eris-keys server. Start it with `eris services start keys`. Error: %v", err) } if err != nil { return err } // log.WithField("endpoint", "to-mint").Debug() // mint, err := keys.Call("to-mint", map[string]string{"addr": account.Address, "name": account.Name}) log.WithField("endpoint", "mint").Debug() mint, err := keys.Call("mint", map[string]string{"addr": account.Address, "name": account.Name}) if _, ok := err.(keys.ErrConnectionRefused); ok { return fmt.Errorf("Could not connect to eris-keys server. Start it with `eris services start keys`. Error: %v", err) } if err != nil { return err } account.MintKey = &definitions.MintPrivValidator{} err = json.Unmarshal([]byte(mint), account.MintKey) if err != nil { log.Error(string(mint)) log.Error(account.MintKey) return err } account.MintKey.Address = account.Address return nil }
// Runs an individual nametx. func registerNameTx(name *definitions.RegisterName, do *definitions.Do) (string, error) { // Process Variables name.Source, _ = util.PreProcess(name.Source, do) name.Name, _ = util.PreProcess(name.Name, do) name.Data, _ = util.PreProcess(name.Data, do) name.Amount, _ = util.PreProcess(name.Amount, do) name.Fee, _ = util.PreProcess(name.Fee, do) // Set Defaults name.Source = useDefault(name.Source, do.Package.Account) name.Fee = useDefault(name.Fee, do.DefaultFee) name.Amount = useDefault(name.Amount, do.DefaultAmount) // Don't use pubKey if account override var oldKey string if name.Source != do.Package.Account { oldKey = do.PublicKey do.PublicKey = "" } // Formulate tx log.WithFields(log.Fields{ "name": name.Name, "data": name.Data, "amount": name.Amount, }).Info("NameReg Transaction") erisNodeClient := client.NewErisNodeClient(do.Chain) erisKeyClient := keys.NewErisKeyClient(do.Signer) tx, err := core.Name(erisNodeClient, erisKeyClient, do.PublicKey, name.Source, name.Amount, name.Nonce, name.Fee, name.Name, name.Data) if err != nil { return util.MintChainErrorHandler(do, err) } // Don't use pubKey if account override if name.Source != do.Package.Account { do.PublicKey = oldKey } // Sign, broadcast, display return txFinalize(do, tx, name.Wait) }
func MintChainErrorHandler(do *definitions.Do, err error) (string, error) { log.WithFields(log.Fields{ "defAddr": do.Package.Account, "chainID": do.ChainID, "chainURL": do.Chain, "rawErr": err, }).Error("") return "", fmt.Errorf(` There has been an error talking to your eris chain. %v Debugging this error is tricky, but don't worry the marmot recovery checklist is... * is the %s account right? * is the account you want to use in your keys service: eris keys ls ? * is the account you want to use in your genesis.json: eris chains cat %s genesis ? * is your chain making blocks: eris chains logs -f %s ? * do you have permissions to do what you're trying to do on the chain? `, err, do.Package.Account, do.ChainID, do.ChainID) }
func QueryNameJob(query *definitions.QueryName, do *definitions.Do) (string, error) { // Preprocess variables query.Name, _ = util.PreProcess(query.Name, do) query.Field, _ = util.PreProcess(query.Field, do) // Peform query log.WithFields(log.Fields{ "name": query.Name, "field": query.Field, }).Info("Querying") result, err := util.NamesInfo(query.Name, query.Field, do) if err != nil { return "", err } if result != "" { log.WithField("=>", result).Warn("Return Value") } else { log.Debug("No return.") } return result, nil }
func SendJob(send *definitions.Send, do *definitions.Do) (string, error) { // Process Variables send.Source, _ = util.PreProcess(send.Source, do) send.Destination, _ = util.PreProcess(send.Destination, do) send.Amount, _ = util.PreProcess(send.Amount, do) // Use Default send.Source = useDefault(send.Source, do.Package.Account) // Don't use pubKey if account override var oldKey string if send.Source != do.Package.Account { oldKey = do.PublicKey do.PublicKey = "" } // Formulate tx log.WithFields(log.Fields{ "source": send.Source, "destination": send.Destination, "amount": send.Amount, }).Info("Sending Transaction") erisNodeClient := client.NewErisNodeClient(do.Chain) erisKeyClient := keys.NewErisKeyClient(do.Signer) tx, err := core.Send(erisNodeClient, erisKeyClient, do.PublicKey, send.Source, send.Destination, send.Amount, send.Nonce) if err != nil { return util.MintChainErrorHandler(do, err) } // Don't use pubKey if account override if send.Source != do.Package.Account { do.PublicKey = oldKey } // Sign, broadcast, display return txFinalize(do, tx, send.Wait) }
func MakeMintChain(name string, accounts []*definitions.Account, chainImageName string, useDataContainer bool, exportedPorts []string, containerEntrypoint string) error { genesis := definitions.BlankGenesis() genesis.ChainID = name for _, account := range accounts { log.WithFields(log.Fields{ "name": account.Name, "address": account.Address, "tokens": account.Tokens, "perms": account.MintPermissions.MintBase.MintPerms, }).Debug("Making a Mint Account") thisAct := MakeMintAccount(account) genesis.Accounts = append(genesis.Accounts, thisAct) if account.Validator { thisVal := MakeMintValidator(account) genesis.Validators = append(genesis.Validators, thisVal) } } for _, account := range accounts { if err := util.WritePrivVals(genesis.ChainID, account, len(accounts) == 1); err != nil { return err } if err := util.WriteGenesisFile(genesis.ChainID, genesis, account, len(accounts) == 1); err != nil { return err } // TODO: [ben] we can expose seeds to be written into the configuration file // here, but currently not used and we'll overwrite the configuration file // with flag or environment variable in eris-db container if err := util.WriteConfigurationFile(genesis.ChainID, account.Name, "", len(accounts) == 1, chainImageName, useDataContainer, exportedPorts, containerEntrypoint); err != nil { return err } } return nil }
func RebondJob(rebond *definitions.Rebond, do *definitions.Do) (string, error) { // Process Variables var err error rebond.Account, err = util.PreProcess(rebond.Account, do) rebond.Height, err = util.PreProcess(rebond.Height, do) if err != nil { return "", err } // Use defaults rebond.Account = useDefault(rebond.Account, do.Package.Account) // Don't use pubKey if account override var oldKey string if rebond.Account != do.Package.Account { oldKey = do.PublicKey do.PublicKey = "" } // Formulate tx log.WithFields(log.Fields{ "account": rebond.Account, "height": rebond.Height, }).Info("Rebond Transaction") tx, err := core.Rebond(rebond.Account, rebond.Height) if err != nil { return util.MintChainErrorHandler(do, err) } // Don't use pubKey if account override if rebond.Account != do.Package.Account { do.PublicKey = oldKey } // Sign, broadcast, display return txFinalize(do, tx, rebond.Wait) }
func KeysErrorHandler(do *definitions.Do, err error) (string, error) { log.WithFields(log.Fields{ "defAddr": do.Package.Account, }).Error("") r := regexp.MustCompile(fmt.Sprintf("open /home/eris/.eris/keys/data/%s/%s: no such file or directory", do.Package.Account, do.Package.Account)) if r.MatchString(fmt.Sprintf("%v", err)) { return "", fmt.Errorf(` Unfortunately the marmots could not find the key you are trying to use in the keys service. There are two ways to fix this. 1. Import your keys from your host: eris keys import %s 2. Import your keys from your chain: eris chains exec %s "mintkey eris chains/%s/priv_validator.json" && \ eris services exec keys "chown eris:eris -R /home/eris" Now, run eris keys ls to check that the keys are available. If they are not there then change the account. Once you have verified that the keys for account %s are in the keys service, then rerun me. `, do.Package.Account, do.ChainID, do.ChainID, do.Package.Account) } return "", fmt.Errorf(` There has been an error talking to your eris keys service. %v Debugging this error is tricky, but don't worry the marmot recovery checklist is... * is your %s account right? * is the key for %s in your keys service: eris keys ls ? `, err, do.Package.Account, do.Package.Account) }
func Tarball(do *definitions.Do) error { paths, err := filepath.Glob(filepath.Join(ChainsPath, do.Name, "*")) if err != nil { return err } for _, path := range paths { fileP := fmt.Sprintf("%s.tar.gz", path) log.WithFields(log.Fields{ // "path": path, "file": fileP, }).Debug("Making A Tarball") dir, err := os.Open(path) if err != nil { return err } defer dir.Close() files, err := dir.Readdir(0) // grab the files list if err != nil { return err } tarfile, err := os.Create(fileP) if err != nil { return err } defer tarfile.Close() var fileWriter io.WriteCloser = tarfile fileWriter = gzip.NewWriter(tarfile) defer fileWriter.Close() tarfileWriter := tar.NewWriter(fileWriter) defer tarfileWriter.Close() for _, fileInfo := range files { if fileInfo.IsDir() { continue } file, err := os.Open(dir.Name() + string(filepath.Separator) + fileInfo.Name()) if err != nil { return err } defer file.Close() // log.WithField("file", fileInfo.Name()).Debug("Adding File Info to Tarball") header := new(tar.Header) header.Name = filepath.Base(file.Name()) header.Size = fileInfo.Size() header.Mode = int64(fileInfo.Mode()) header.ModTime = fileInfo.ModTime() if err := tarfileWriter.WriteHeader(header); err != nil { return err } _, err = io.Copy(tarfileWriter, file) if err != nil { return err } } log.WithField("dir", path).Debug("Removing Directory.") if err := os.RemoveAll(path); err != nil { return err } } return nil }
func Zip(do *definitions.Do) error { paths, err := filepath.Glob(filepath.Join(ChainsPath, do.Name, "*")) if err != nil { return err } for _, path := range paths { fileP := fmt.Sprintf("%s.zip", path) log.WithFields(log.Fields{ "path": path, "file": fileP, }).Debug("Making A ZipFile") dir, err := os.Open(path) if err != nil { return err } defer dir.Close() files, err := dir.Readdir(0) // grab the files list if err != nil { return err } newfile, err := os.Create(fileP) if err != nil { return err } defer newfile.Close() zipit := zip.NewWriter(newfile) defer zipit.Close() for _, fileInfo := range files { // log.WithField("file", fileInfo.Name()).Debug("Adding File Info to ZipFile") if fileInfo.IsDir() { continue } file, err := os.Open(dir.Name() + string(filepath.Separator) + fileInfo.Name()) if err != nil { return err } defer file.Close() header, err := zip.FileInfoHeader(fileInfo) if err != nil { return err } header.Method = zip.Deflate writer, err := zipit.CreateHeader(header) if err != nil { return err } _, err = io.Copy(writer, file) if err != nil { return err } } log.WithField("dir", path).Debug("Removing Directory.") if err := os.RemoveAll(path); err != nil { return err } } return nil }
func CallJob(call *definitions.Call, do *definitions.Do) (string, []*definitions.Variable, error) { var err error var callData string var callDataArray []string // Preprocess variables call.Source, _ = util.PreProcess(call.Source, do) call.Destination, _ = util.PreProcess(call.Destination, do) //todo: find a way to call the fallback function here call.Function, callDataArray, err = util.PreProcessInputData(call.Function, call.Data, do, false) if err != nil { return "", make([]*definitions.Variable, 0), err } call.Function, _ = util.PreProcess(call.Function, do) call.Amount, _ = util.PreProcess(call.Amount, do) call.Nonce, _ = util.PreProcess(call.Nonce, do) call.Fee, _ = util.PreProcess(call.Fee, do) call.Gas, _ = util.PreProcess(call.Gas, do) call.ABI, _ = util.PreProcess(call.ABI, do) // Use default call.Source = useDefault(call.Source, do.Package.Account) call.Amount = useDefault(call.Amount, do.DefaultAmount) call.Fee = useDefault(call.Fee, do.DefaultFee) call.Gas = useDefault(call.Gas, do.DefaultGas) // formulate call var packedBytes []byte if call.ABI == "" { packedBytes, err = util.ReadAbiFormulateCall(call.Destination, call.Function, callDataArray, do) callData = hex.EncodeToString(packedBytes) } else { packedBytes, err = util.ReadAbiFormulateCall(call.ABI, call.Function, callDataArray, do) callData = hex.EncodeToString(packedBytes) } if err != nil { if call.Function == "()" { log.Warn("Calling the fallback function") } else { var str, err = util.ABIErrorHandler(do, err, call, nil) return str, make([]*definitions.Variable, 0), err } } // Don't use pubKey if account override var oldKey string if call.Source != do.Package.Account { oldKey = do.PublicKey do.PublicKey = "" } log.WithFields(log.Fields{ "destination": call.Destination, "function": call.Function, "data": callData, }).Info("Calling") erisNodeClient := client.NewErisNodeClient(do.Chain) erisKeyClient := keys.NewErisKeyClient(do.Signer) tx, err := core.Call(erisNodeClient, erisKeyClient, do.PublicKey, call.Source, call.Destination, call.Amount, call.Nonce, call.Gas, call.Fee, callData) if err != nil { return "", make([]*definitions.Variable, 0), err } // Don't use pubKey if account override if call.Source != do.Package.Account { do.PublicKey = oldKey } // Sign, broadcast, display res, err := core.SignAndBroadcast(do.ChainID, erisNodeClient, erisKeyClient, tx, true, true, call.Wait) if err != nil { var str, err = util.MintChainErrorHandler(do, err) return str, make([]*definitions.Variable, 0), err } txResult := res.Return var result string log.Debug(txResult) // Formally process the return if txResult != nil { log.WithField("=>", result).Debug("Decoding Raw Result") if call.ABI == "" { call.Variables, err = util.ReadAndDecodeContractReturn(call.Destination, call.Function, txResult, do) } else { call.Variables, err = util.ReadAndDecodeContractReturn(call.ABI, call.Function, txResult, do) } if err != nil { return "", make([]*definitions.Variable, 0), err } log.WithField("=>", call.Variables).Debug("call variables:") result = util.GetReturnValue(call.Variables) if result != "" { log.WithField("=>", result).Warn("Return Value") } else { log.Debug("No return.") } } else { log.Debug("No return from contract.") } if call.Save == "tx" { log.Info("Saving tx hash instead of contract return") result = fmt.Sprintf("%X", res.Hash) } return result, call.Variables, nil }
func PreProcess(toProcess string, do *definitions.Do) (string, error) { // $block.... $account.... etc. should be caught. hell$$o should not // :$libAddr needs to be caught catchEr := regexp.MustCompile("(^|\\s|:)\\$([a-zA-Z0-9_.]+)") // If there's a match then run through the replacement process if catchEr.MatchString(toProcess) { log.WithField("match", toProcess).Debug("Replacement Match Found") // find what we need to catch. processedString := toProcess for _, jobMatch := range catchEr.FindAllStringSubmatch(toProcess, -1) { jobName := jobMatch[2] varName := "$" + jobName var innerVarName string var wantsInnerValues bool = false /* log.WithFields(log.Fields{ "var": varName, "job": jobName, }).Debugf("Correcting match %d", i+1) */ // first parse the reserved words. if strings.Contains(jobName, "block") { block, err := replaceBlockVariable(toProcess, do) if err != nil { log.WithField("err", err).Error("Error replacing block variable.") return "", err } /*log.WithFields(log.Fields{ "var": toProcess, "res": block, }).Debug("Fixing Variables =>")*/ processedString = strings.Replace(processedString, toProcess, block, 1) } if strings.Contains(jobName, ".") { //for functions with multiple returns wantsInnerValues = true var splitStr = strings.Split(jobName, ".") jobName = splitStr[0] innerVarName = splitStr[1] } // second we loop through the jobNames to do a result replace for _, job := range do.Package.Jobs { if string(jobName) == job.JobName { if wantsInnerValues { for _, innerVal := range job.JobVars { if innerVal.Name == innerVarName { //find the value we want from the bunch processedString = strings.Replace(processedString, varName, innerVal.Value, 1) log.WithFields(log.Fields{ "job": string(jobName), "varName": innerVarName, "result": innerVal.Value, }).Debug("Fixing Inner Vars =>") } } } else { log.WithFields(log.Fields{ "var": string(jobName), "res": job.JobResult, }).Debug("Fixing Variables =>") processedString = strings.Replace(processedString, varName, job.JobResult, 1) } } } } return processedString, nil } // if no matches, return original return toProcess, nil }
func AssertJob(assertion *definitions.Assert, do *definitions.Do) (string, error) { var result string // Preprocess variables assertion.Key, _ = util.PreProcess(assertion.Key, do) assertion.Relation, _ = util.PreProcess(assertion.Relation, do) assertion.Value, _ = util.PreProcess(assertion.Value, do) // Switch on relation log.WithFields(log.Fields{ "key": assertion.Key, "relation": assertion.Relation, "value": assertion.Value, }).Info("Assertion =>") switch assertion.Relation { case "==", "eq": /*log.Debug("Compare", strings.Compare(assertion.Key, assertion.Value)) log.Debug("UTF8?: ", utf8.ValidString(assertion.Key)) log.Debug("UTF8?: ", utf8.ValidString(assertion.Value)) log.Debug("UTF8?: ", utf8.RuneCountInString(assertion.Key)) log.Debug("UTF8?: ", utf8.RuneCountInString(assertion.Value))*/ if assertion.Key == assertion.Value { return assertPass("==", assertion.Key, assertion.Value) } else { return assertFail("==", assertion.Key, assertion.Value) } case "!=", "ne": if assertion.Key != assertion.Value { return assertPass("!=", assertion.Key, assertion.Value) } else { return assertFail("!=", assertion.Key, assertion.Value) } case ">", "gt": k, v, err := bulkConvert(assertion.Key, assertion.Value) if err != nil { return convFail() } if k > v { return assertPass(">", assertion.Key, assertion.Value) } else { return assertFail(">", assertion.Key, assertion.Value) } case ">=", "ge": k, v, err := bulkConvert(assertion.Key, assertion.Value) if err != nil { return convFail() } if k >= v { return assertPass(">=", assertion.Key, assertion.Value) } else { return assertFail(">=", assertion.Key, assertion.Value) } case "<", "lt": k, v, err := bulkConvert(assertion.Key, assertion.Value) if err != nil { return convFail() } if k < v { return assertPass("<", assertion.Key, assertion.Value) } else { return assertFail("<", assertion.Key, assertion.Value) } case "<=", "le": k, v, err := bulkConvert(assertion.Key, assertion.Value) if err != nil { return convFail() } if k <= v { return assertPass("<=", assertion.Key, assertion.Value) } else { return assertFail("<=", assertion.Key, assertion.Value) } } return result, nil }