diff --git a/deploy/compile/perform_compilation.go b/deploy/compile/perform_compilation.go index 8f14d4f49dd536f2d266e961307d86b105522417..dd2a385cc1ecfb1130f3c495e57664e99d4b9229 100644 --- a/deploy/compile/perform_compilation.go +++ b/deploy/compile/perform_compilation.go @@ -94,6 +94,10 @@ func RequestBinaryLinkage(file string, libraries map[string]string) (*BinaryResp if err != nil { return &BinaryResponse{}, err } + return BinaryLinkage(contract, libraries) +} + +func BinaryLinkage(contract SolidityOutputContract, libraries map[string]string) (*BinaryResponse, error) { bin := contract.Evm.Bytecode.Object if !strings.Contains(bin, "_") { return &BinaryResponse{ @@ -103,7 +107,7 @@ func RequestBinaryLinkage(file string, libraries map[string]string) (*BinaryResp }, nil } var links map[string]map[string][]struct{ Start, Length int } - err = json.Unmarshal(contract.Evm.Bytecode.LinkReferences, &links) + err := json.Unmarshal(contract.Evm.Bytecode.LinkReferences, &links) if err != nil { return &BinaryResponse{}, err } diff --git a/deploy/jobs/job_manager.go b/deploy/jobs/job_manager.go index 2fdf62d5863333359a1458f43c396424500b47b5..1c6a9096cb22d739801642f1b4ea1d784da77afc 100644 --- a/deploy/jobs/job_manager.go +++ b/deploy/jobs/job_manager.go @@ -2,13 +2,28 @@ package jobs import ( "fmt" + "path/filepath" "strings" + compilers "github.com/hyperledger/burrow/deploy/compile" "github.com/hyperledger/burrow/deploy/def" "github.com/hyperledger/burrow/deploy/util" log "github.com/sirupsen/logrus" ) +type trackJob struct { + payload def.Payload + job *def.Job + compilerResp *compilers.Response + err error + done chan struct{} +} + +func compile(contract string, track *trackJob) { + (*track).compilerResp, (*track).err = compilers.RequestCompile(contract, false, nil) + close(track.done) +} + func RunJobs(do *def.Packages) error { // Dial the chain if needed @@ -40,21 +55,51 @@ func RunJobs(do *def.Packages) error { return fmt.Errorf("error validating Burrow deploy file at %s: %v", do.YAMLPath, err) } + intermediateJobs := make([]*trackJob, 0, len(do.Package.Jobs)) + for _, job := range do.Package.Jobs { payload, err := job.Payload() if err != nil { return fmt.Errorf("could not get Job payload: %v", payload) } - err = util.PreProcessFields(payload, do) + + track := trackJob{job: job, payload: payload} + intermediateJobs = append(intermediateJobs, &track) + + // Do compilation first + switch payload.(type) { + case *def.Build: + track.done = make(chan struct{}) + go compile(job.Build.Contract, &track) + case *def.Deploy: + if filepath.Ext(job.Deploy.Contract) == ".sol" { + track.done = make(chan struct{}) + go compile(job.Deploy.Contract, &track) + } + } + } + + for _, m := range intermediateJobs { + job := m.job + + err = util.PreProcessFields(m.payload, do) if err != nil { return err } // Revalidate with possible replacements - err = payload.Validate() + err = m.payload.Validate() if err != nil { return fmt.Errorf("error validating job %s after pre-processing variables: %v", job.Name, err) } - switch payload.(type) { + + if m.done != nil { + <-m.done + if m.err != nil { + return m.err + } + } + + switch m.payload.(type) { // Meta Job case *def.Meta: announce(job.Name, "Meta") @@ -88,13 +133,13 @@ func RunJobs(do *def.Packages) error { // Contracts jobs case *def.Deploy: announce(job.Name, "Deploy") - job.Result, err = DeployJob(job.Deploy, do) + job.Result, err = DeployJob(job.Deploy, do, m.compilerResp) case *def.Call: announce(job.Name, "Call") job.Result, job.Variables, err = CallJob(job.Call, do) case *def.Build: announce(job.Name, "Build") - job.Result, err = BuildJob(job.Build, do) + job.Result, err = BuildJob(job.Build, do, m.compilerResp) // State jobs case *def.RestoreState: diff --git a/deploy/jobs/jobs_contracts.go b/deploy/jobs/jobs_contracts.go index ce6427418cf1519e83556318d67843862b8131af..0686d3ce38b5f5b77efbb8c5ab12525a6ae1b597 100644 --- a/deploy/jobs/jobs_contracts.go +++ b/deploy/jobs/jobs_contracts.go @@ -18,7 +18,7 @@ import ( log "github.com/sirupsen/logrus" ) -func BuildJob(build *def.Build, do *def.Packages) (result string, err error) { +func BuildJob(build *def.Build, do *def.Packages, resp *compilers.Response) (result string, err error) { // assemble contract contractPath, err := findContractFile(build.Contract, do.BinPath) if err != nil { @@ -28,10 +28,9 @@ func BuildJob(build *def.Build, do *def.Packages) (result string, err error) { log.WithField("=>", contractPath).Info("Contract path") // normal compilation/deploy sequence - resp, err := compilers.RequestCompile(contractPath, false, make(map[string]string)) - if err != nil { - log.Errorln("Error compiling contracts: Compilers error:") - return "", err + if resp == nil { + log.Errorln("Error compiling contracts: Missing compiler result") + return "", fmt.Errorf("internal error") } else if resp.Error != "" { log.Errorln("Error compiling contracts: Language error:") return "", fmt.Errorf("%v", resp.Error) @@ -78,7 +77,7 @@ func BuildJob(build *def.Build, do *def.Packages) (result string, err error) { return "", nil } -func DeployJob(deploy *def.Deploy, do *def.Packages) (result string, err error) { +func DeployJob(deploy *def.Deploy, do *def.Packages, resp *compilers.Response) (result string, err error) { deploy.Libraries, _ = util.PreProcessLibs(deploy.Libraries, do) // trim the extension contractName := strings.TrimSuffix(deploy.Contract, filepath.Ext(deploy.Contract)) @@ -153,11 +152,10 @@ func DeployJob(deploy *def.Deploy, do *def.Packages) (result string, err error) contractPath = deploy.Contract log.WithField("=>", contractPath).Info("Contract path") // normal compilation/deploy sequence - resp, err := compilers.RequestCompile(contractPath, false, libs) - if err != nil { - log.Errorln("Error compiling contracts: Compilers error:") - return "", err + if resp == nil { + log.Errorln("Error compiling contracts: Missing compiler result") + return "", fmt.Errorf("internal error") } else if resp.Error != "" { log.Errorln("Error compiling contracts: Language error:") return "", fmt.Errorf("%v", resp.Error) @@ -172,7 +170,7 @@ func DeployJob(deploy *def.Deploy, do *def.Packages) (result string, err error) log.WithField("=>", string(response.Binary.Abi)).Info("Abi") log.WithField("=>", response.Binary.Evm.Bytecode.Object).Info("Bin") if response.Binary.Evm.Bytecode.Object != "" { - result, err = deployContract(deploy, do, response) + result, err = deployContract(deploy, do, response, libs) if err != nil { return "", err } @@ -184,7 +182,7 @@ func DeployJob(deploy *def.Deploy, do *def.Packages) (result string, err error) if response.Binary.Evm.Bytecode.Object == "" { continue } - result, err = deployContract(deploy, do, response) + result, err = deployContract(deploy, do, response, libs) if err != nil { return "", err } @@ -205,7 +203,7 @@ func DeployJob(deploy *def.Deploy, do *def.Packages) (result string, err error) if matchInstanceName(response.Objectname, deploy.Instance) { log.WithField("=>", string(response.Binary.Abi)).Info("Abi") log.WithField("=>", response.Binary.Evm.Bytecode.Object).Info("Bin") - result, err = deployContract(deploy, do, response) + result, err = deployContract(deploy, do, response, libs) if err != nil { return "", err } @@ -241,9 +239,14 @@ func findContractFile(contract, binPath string) (string, error) { } // TODO [rj] refactor to remove [contractPath] from functions signature => only used in a single error throw. -func deployContract(deploy *def.Deploy, do *def.Packages, compilersResponse compilers.ResponseItem) (string, error) { +func deployContract(deploy *def.Deploy, do *def.Packages, compilersResponse compilers.ResponseItem, libs map[string]string) (string, error) { log.WithField("=>", string(compilersResponse.Binary.Abi)).Debug("Specification (From Compilers)") - contractCode := compilersResponse.Binary.Evm.Bytecode.Object + + linked, err := compilers.BinaryLinkage(compilersResponse.Binary, libs) + if err != nil { + return "", err + } + contractCode := linked.Binary // Save if _, err := os.Stat(do.BinPath); os.IsNotExist(err) {