Commit 1cb9da0c authored by Luke Champine's avatar Luke Champine

contract cleanup

parent 21806ac7
......@@ -37,10 +37,6 @@ func (h *Host) nextFilename() string {
// burn part of the contract fund, then the updated contract is signed and
// returned.
//
// TODO: Need to save the space before the file is uploaded, not register it as
// used after the file is uploaded, otherwise there could be a race condition
// that uses more than the available space.
//
// TODO: Make the host able to parse multiple contracts at once.
func (h *Host) considerContract(t consensus.Transaction, startBlock consensus.BlockHeight) (updatedTransaction consensus.Transaction, err error) {
// Check that there is exactly one file contract.
......@@ -100,27 +96,24 @@ func (h *Host) considerContract(t consensus.Transaction, startBlock consensus.Bl
}
// Add enough funds to the transaction to cover the penalty half of the
// agreement.
// agreement. If we encounter an error here, we return a HostCapacityError to hide the fact that we're experience internal problems.
penalty := h.Burn * consensus.Currency(fileSize) * consensus.Currency(duration)
id, err := h.wallet.RegisterTransaction(t)
if err != nil {
err = HostCapacityErr // hide the fact that the host is having wallet issues.
err = HostCapacityErr
return
}
err = h.wallet.FundTransaction(id, penalty)
if err != nil {
err = HostCapacityErr // hide the fact that the host is having wallet issues.
err = HostCapacityErr
return
}
updatedTransaction, err = h.wallet.SignTransaction(id, true)
if err != nil {
err = HostCapacityErr // hide the fact that the host is having wallet issues.
err = HostCapacityErr
return
}
// Update the amount of space the host has for sale.
h.spaceRemaining -= int64(fileSize)
return
}
......@@ -133,125 +126,127 @@ func (h *Host) considerContract(t consensus.Transaction, startBlock consensus.Bl
// reason, all of the locking in this function is done manually. Edit with
// caution, review with caution.
//
// TODO: Order of events: (not currently followed)
// 1. Contract is sent over without signatures, and doesn't need an
// acurate merkle hash of the file. It's just for the host and client
// to confirm that the terms of the contract are correct and make
// sens.
// Order of events:
// 1. Contract is sent over without signatures, and doesn't need an
// acurate Merkle hash of the file. It's just for the host and client
// to confirm that the terms of the contract are correct and make
// sense.
//
// 2. Host sends a confirmation, along with an indication of how much
// the client should contribute for payment, and how much is available
// for burn.
// 2. Host sends a confirmation, along with an indication of how much
// the client should contribute for payment, and how much is available
// for burn.
//
// 3. File is sent over and loaded onto the host's disk. Eventually,
// micropayments will be worked into this situation to pay the host
// for bandwidth and whatever storage time.
// 3. File is sent over and loaded onto the host's disk. Eventually,
// micropayments will be worked into this situation to pay the host
// for bandwidth and whatever storage time.
//
// 4. Client sends over the final client version of the contract
// containing the appropriate price and burn, with signatures and the
// correct merkle root hash.
// 4. Client sends over the final client version of the contract
// containing the appropriate price and burn, with signatures and the
// correct Merkle root hash.
//
// 5. Host compares the contract with the earlier negotiations and
// confirms that everything is still the same. Host then verifies that
// the file which was uploaded has a matching hash to the file in the
// contract. Host will add burn dollars and submit the contract to the
// blockchain.
// 5. Host compares the contract with the earlier negotiations and
// confirms that everything is still the same. Host then verifies that
// the file which was uploaded has a matching hash to the file in the
// contract. Host will add burn coins and submit the contract to the
// blockchain.
//
// 6. If the client double-spends, the host will remove the file. If
// the host holds the transaction hostage and does not submit it to
// the blockchain, it will become void.
// 6. If the client double-spends, the host will remove the file. If
// the host holds the transaction hostage and does not submit it to
// the blockchain, it will become void.
//
// TODO: This functions error handling isn't safe, reveals too much info to the
// TODO: This function's error handling isn't safe; reveals too much info to the
// other party.
func (h *Host) NegotiateContract(conn net.Conn) (err error) {
/*
// Read the transaction from the connection.
var txn consensus.Transaction
err = encoding.ReadObject(conn, &txn, maxContractLen)
if err != nil {
return
}
var startBlock consensus.BlockHeight
err = encoding.ReadObject(conn, &startBlock, maxContractLen) // what should be the maxlen here?
if err != nil {
return
}
contract := txn.FileContracts[0]
// Read the transaction from the connection.
var txn consensus.Transaction
err = encoding.ReadObject(conn, &txn, maxContractLen)
if err != nil {
return
}
var startBlock consensus.BlockHeight
err = encoding.ReadObject(conn, &startBlock, 8) // consensus.BlockHeight is a uint64
if err != nil {
return
}
contract := txn.FileContracts[0]
// Check that the contained FileContract fits host criteria for taking
// files, replying with the error if there's a problem.
h.mu.Lock()
txn, err = h.considerContract(txn, startBlock)
h.mu.Unlock()
if err != nil {
_, err = encoding.WriteObject(conn, err.Error())
return
}
_, err = encoding.WriteObject(conn, modules.AcceptContractResponse)
if err != nil {
return
}
// Check that the contained FileContract fits host criteria for taking
// files, replying with the error if there's a problem.
h.mu.Lock()
txn, err = h.considerContract(txn, startBlock)
h.mu.Unlock()
if err != nil {
_, err = encoding.WriteObject(conn, err.Error())
return
}
// Create file.
h.mu.Lock()
filename := h.nextFilename()
fullname := filepath.Join(h.hostDir, filename)
h.mu.Unlock()
file, err := os.Create(fullname)
// Create file.
h.mu.Lock()
h.spaceRemaining -= int64(contract.FileSize)
filename := h.nextFilename()
path := filepath.Join(h.hostDir, filename)
h.mu.Unlock()
file, err := os.Create(path)
if err != nil {
return
}
defer file.Close()
// rollback everything if something goes wrong
defer func() {
if err != nil {
return
_, err = encoding.WriteObject(conn, err.Error())
os.Remove(path)
h.mu.Lock()
h.fileCounter--
h.spaceRemaining -= int64(contract.FileSize)
h.mu.Unlock()
}
defer file.Close()
}()
// If there's an error upon return, delete the file that's been created.
defer func() {
if err != nil {
_, err = encoding.WriteObject(conn, err.Error())
os.Remove(fullname)
h.mu.Lock()
h.spaceRemaining -= int64(contract.FileSize)
h.mu.Unlock()
}
}()
// signal that we are ready to download file
_, err = encoding.WriteObject(conn, modules.AcceptContractResponse)
if err != nil {
return
}
// Download file contents.
_, err = io.CopyN(file, conn, int64(contract.FileSize))
if err != nil {
return
}
// Download file contents.
_, err = io.CopyN(file, conn, int64(contract.FileSize))
if err != nil {
return
}
// Check that the file matches the merkle root in the contract.
_, err = file.Seek(0, 0)
if err != nil {
return
}
merkleRoot, err := hash.ReaderMerkleRoot(file, hash.CalculateSegments(contract.FileSize))
if err != nil {
return
}
if merkleRoot != contract.FileMerkleRoot {
err = errors.New("uploaded file has wrong merkle root")
return
}
// Check that the file matches the Merkle root in the contract.
_, err = file.Seek(0, 0)
if err != nil {
return
}
merkleRoot, err := hash.ReaderMerkleRoot(file, hash.CalculateSegments(contract.FileSize))
if err != nil {
return
}
if merkleRoot != contract.FileMerkleRoot {
err = errors.New("uploaded file has wrong Merkle root")
return
}
// Check that the file arrived in time.
if h.state.Height() >= contract.Start-2 {
err = errors.New("file not uploaded in time, refusing to go forward with contract")
return
}
// Download file contents.
_, err = io.CopyN(file, conn, int64(contract.FileSize))
if err != nil {
return
}
// Put the contract in a list where the host will be performing proofs of
// storage.
h.mu.Lock()
h.contracts[txn.FileContractID(0)] = contractObligation{
filename: filename,
}
h.mu.Unlock()
fmt.Println("Accepted contract")
// Put the contract in a list where the host will be performing proofs of
// storage.
h.mu.Lock()
h.contracts[txn.FileContractID(0)] = contractObligation{
filename: filename,
}
h.mu.Unlock()
//fmt.Println("Accepted contract")
// Submit the transaction.
h.state.AcceptTransaction(txn)
*/
// Submit the transaction.
h.state.AcceptTransaction(txn)
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment