func (a *SellActivity) HandleWork(log bitwrk.Logger, workFile cafs.File, buyerSecret bitwrk.Thash) (io.ReadCloser, error) { // Wait for buyer to establish active := true var workHash, workSecretHash *bitwrk.Thash log.Printf("Watching transaction state...") a.waitWhile(func() bool { active = a.tx.State == bitwrk.StateActive workHash, workSecretHash = a.tx.WorkHash, a.tx.WorkSecretHash log.Printf(" state: %v phase: %v", a.tx.State, a.tx.Phase) return active && a.tx.Phase != bitwrk.PhaseTransmitting }) if !active { return nil, fmt.Errorf("Transaction timed out waiting for buyer to establish") } // Verify work hash if *workHash != bitwrk.Thash(workFile.Key()) { return nil, fmt.Errorf("WorkHash and received data do not match") } if err := verifyBuyerSecret(workHash, workSecretHash, &buyerSecret); err != nil { return nil, err } log.Println("Got valid work data. Publishing buyer's secret.") if err := SendTxMessagePublishBuyerSecret(a.txId, a.identity, &buyerSecret); err != nil { return nil, fmt.Errorf("Error publishing buyer's secret: %v", err) } log.Println("Starting to work...") r, err := a.dispatchWork(log, workFile) if err != nil { log.Printf("Rejecting work because of error '%v'", err) if err := SendTxMessageRejectWork(a.txId, a.identity); err != nil { log.Printf("Rejecting work failed: %v", err) } } return r, err }
func (a *BuyActivity) doPerformBuy(log bitwrk.Logger, interrupt <-chan bool) (cafs.File, error) { if err := a.beginTrade(log, interrupt); err != nil { return nil, err } // draw random bytes for buyer's secret var secret bitwrk.Thash if _, err := rand.Reader.Read(secret[:]); err != nil { return nil, err } a.execSync(func() { a.buyerSecret = &secret }) log.Printf("Computed buyer's secret.") // Get work hash var workHash, workSecretHash bitwrk.Thash workHash = bitwrk.Thash(a.workFile.Key()) // compute workSecretHash = hash(workHash | secret) hash := sha256.New() hash.Write(workHash[:]) hash.Write(secret[:]) hash.Sum(workSecretHash[:0]) // Start polling for transaction state changes in background abortPolling := make(chan bool) defer func() { abortPolling <- true // Stop polling when sell has ended }() go func() { a.pollTransaction(log, abortPolling) }() if err := SendTxMessageEstablishBuyer(a.txId, a.identity, workHash, workSecretHash); err != nil { return nil, fmt.Errorf("Error establishing buyer: %v", err) } if err := a.waitForTransactionPhase(log.New("establishing"), bitwrk.PhaseTransmitting, bitwrk.PhaseEstablishing, bitwrk.PhaseSellerEstablished, bitwrk.PhaseBuyerEstablished); err != nil { return nil, fmt.Errorf("Error awaiting TRANSMITTING phase: %v", err) } var sellerErr error if err := a.interactWithSeller(log.New("transmitting")); err != nil { sellerErr = fmt.Errorf("Error transmitting work and receiving encrypted result: %v", err) } var phaseErr error if err := a.waitForTransactionPhase(log, bitwrk.PhaseUnverified, bitwrk.PhaseTransmitting, bitwrk.PhaseWorking); err != nil { phaseErr = fmt.Errorf("Error awaiting UNVERIFIED phase: %v", err) } if sellerErr == nil && phaseErr == nil { // Everythong went fine, continue } else if sellerErr == nil { return nil, phaseErr } else if phaseErr == nil { return nil, sellerErr } else { return nil, fmt.Errorf("%v. Additionally: %v", phaseErr, sellerErr) } a.execSync(func() { a.encResultKey = a.tx.ResultDecryptionKey }) if err := a.decryptResult(); err != nil { return nil, fmt.Errorf("Error decrypting result: %v", err) } // In normal buys (without verifying), we can leave the rest as homework // for a goroutine and exit here. go func() { if err := a.finishBuy(log); err != nil { log.Printf("Error finishing buy: %v", err) } }() return a.resultFile, nil }