Commit 930217c0 authored by David Vorick's avatar David Vorick

test and fix renter download

parent bb823280
renterDownload
hostdir
release
whitepaper.aux
......
......@@ -127,7 +127,7 @@ func (s *State) invertStorageProof(sp StorageProof) (diff OutputDiff) {
// context of the state, and returns an error if something about the contract
// is invalid.
func (s *State) validContract(c FileContract) (err error) {
if c.ContractFund < 0 {
if c.ContractFund <= 0 {
err = errors.New("contract must be funded.")
return
}
......
......@@ -267,7 +267,8 @@ func (sc *SpendConditions) CoinAddress() CoinAddress {
// Transaction.fileContractID returns the id of a file contract given the index of the contract.
func (t Transaction) FileContractID(index int) ContractID {
return ContractID(hash.HashAll(
encoding.Marshal(t),
encoding.Marshal(t.Outputs[0]),
encoding.Marshal(t.FileContracts[index]),
[]byte("contract"),
encoding.Marshal(index),
))
......
......@@ -25,7 +25,7 @@ type ContractEntry struct {
func (h *Host) nextFilename() string {
h.fileCounter++
return filepath.Join(h.hostDir, strconv.Itoa(h.fileCounter))
return strconv.Itoa(h.fileCounter)
}
// considerContract takes a contract and verifies that the terms such as price
......@@ -155,8 +155,9 @@ func (h *Host) NegotiateContract(conn net.Conn) (err error) {
// Create file.
h.mu.Lock()
filename := h.nextFilename()
fullname := filepath.Join(h.hostDir, filename)
h.mu.Unlock()
file, err := os.Create(filename)
file, err := os.Create(fullname)
if err != nil {
return
}
......@@ -166,7 +167,7 @@ func (h *Host) NegotiateContract(conn net.Conn) (err error) {
defer func() {
if err != nil {
panic(err)
os.Remove(filename)
os.Remove(fullname)
}
}()
......
......@@ -5,6 +5,7 @@ import (
"io"
"net"
"os"
"path/filepath"
"sync"
"github.com/NebulousLabs/Sia/consensus"
......@@ -59,7 +60,7 @@ func New(state *consensus.State, wallet components.Wallet) (h *Host, err error)
announcement: components.HostAnnouncement{
MaxFilesize: 4 * 1000 * 1000,
MaxDuration: 1008,
MaxDuration: 1008, // One week.
MinChallengeWindow: 3,
MinTolerance: 1,
Price: 1,
......@@ -118,10 +119,10 @@ func (h *Host) RetrieveFile(conn net.Conn) (err error) {
h.mu.RUnlock()
return errors.New("no record of that file")
}
fullname := h.hostDir + contractObligation.filename
h.mu.RUnlock()
// Open the file.
fullname := filepath.Join(h.hostDir, contractObligation.filename)
file, err := os.Open(fullname)
if err != nil {
return
......
......@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/NebulousLabs/Sia/consensus"
"github.com/NebulousLabs/Sia/hash"
......@@ -100,11 +101,12 @@ func (h *Host) consensusListen(updateChan chan consensus.ConsensusChange) {
for _, contractID := range deletions {
expiredContract := h.contracts[contractID]
stat, err := os.Stat(h.hostDir + expiredContract.filename)
fullpath := filepath.Join(h.hostDir, expiredContract.filename)
stat, err := os.Stat(fullpath)
if err != nil {
fmt.Println(err)
}
err = os.Remove(h.hostDir + expiredContract.filename)
err = os.Remove(fullpath)
h.spaceRemaining += stat.Size()
if err != nil {
fmt.Println(err)
......
......@@ -3,9 +3,9 @@ package renter
import (
"errors"
"fmt"
"io"
// "io"
"net"
"os"
// "os"
"github.com/NebulousLabs/Sia/consensus"
"github.com/NebulousLabs/Sia/encoding"
......@@ -24,118 +24,123 @@ import (
// TODO: We need to get the id of the contract before we can start doing
// re-uploading.
func (r *Renter) proposeContract(filename string, duration consensus.BlockHeight) (fp FilePiece, err error) {
// Open the file, create a merkle hash.
file, err := os.Open(filename)
if err != nil {
return
}
defer file.Close()
info, err := file.Stat()
if err != nil {
return
}
merkle, err := hash.ReaderMerkleRoot(file, hash.CalculateSegments(uint64(info.Size())))
if err != nil {
return
}
// reset read position
if _, err = file.Seek(0, 0); err != nil {
return
}
err = errors.New("proposeContract is not implemented - needs to be merged with other code")
return
// Find a host. If the search or the negotiation is unsuccessful,
// hostdb.FlagHost() will be called and another host will be requested. If
// there is an internal error (no hosts, or an unsuccessful flagging for
// example), the loop will break.
var host components.HostEntry
var fileContract consensus.FileContract
for {
host, err = r.hostDB.RandomHost()
/*
// Open the file, create a merkle hash.
file, err := os.Open(filename)
if err != nil {
return
}
// Fill out the contract according to the whims of the host.
// The contract fund: (burn * duration + price * full duration) * filesize
delay := consensus.BlockHeight(20)
contractFund := (host.Price*consensus.Currency(duration+delay) + host.Burn*consensus.Currency(duration)) * consensus.Currency(info.Size())
fileContract = consensus.FileContract{
ContractFund: contractFund,
FileMerkleRoot: merkle,
FileSize: uint64(info.Size()),
Start: r.state.Height() + delay,
End: r.state.Height() + duration + delay,
ChallengeWindow: host.Window,
Tolerance: host.Tolerance,
ValidProofPayout: host.Price * consensus.Currency(info.Size()) * consensus.Currency(host.Window),
ValidProofAddress: host.CoinAddress,
MissedProofPayout: host.Burn * consensus.Currency(info.Size()) * consensus.Currency(host.Window),
MissedProofAddress: consensus.CoinAddress{}, // The empty address is the burn address.
}
// Fund the client portion of the transaction.
minerFee := consensus.Currency(10) // TODO: ask wallet.
renterPortion := host.Price * consensus.Currency(duration+delay) * consensus.Currency(fileContract.FileSize)
var id string
id, err = r.wallet.RegisterTransaction(consensus.Transaction{})
defer file.Close()
info, err := file.Stat()
if err != nil {
return
}
err = r.wallet.FundTransaction(id, renterPortion+minerFee)
merkle, err := hash.ReaderMerkleRoot(file, hash.CalculateSegments(uint64(info.Size())))
if err != nil {
return
}
err = r.wallet.AddMinerFee(id, minerFee)
if err != nil {
return
}
err = r.wallet.AddFileContract(id, fileContract)
if err != nil {
return
}
var transaction consensus.Transaction
transaction, err = r.wallet.SignTransaction(id, false)
if err != nil {
// reset read position
if _, err = file.Seek(0, 0); err != nil {
return
}
// Negotiate the contract to the host.
err = host.IPAddress.Call("NegotiateContract", func(conn net.Conn) error {
// send contract
if _, err := encoding.WriteObject(conn, transaction); err != nil {
return err
// Find a host. If the search or the negotiation is unsuccessful,
// hostdb.FlagHost() will be called and another host will be requested. If
// there is an internal error (no hosts, or an unsuccessful flagging for
// example), the loop will break.
var host components.HostEntry
var fileContract consensus.FileContract
for {
host, err = r.hostDB.RandomHost()
if err != nil {
return
}
// read response
var response string
if err := encoding.ReadObject(conn, &response, 128); err != nil {
// Fill out the contract according to the whims of the host.
// The contract fund: (burn * duration + price * full duration) * filesize
delay := consensus.BlockHeight(20)
contractFund := (host.Price*consensus.Currency(duration+delay) + host.Burn*consensus.Currency(duration)) * consensus.Currency(info.Size())
fileContract = consensus.FileContract{
ContractFund: contractFund,
FileMerkleRoot: merkle,
FileSize: uint64(info.Size()),
Start: r.state.Height() + delay,
End: r.state.Height() + duration + delay,
ChallengeWindow: host.Window,
Tolerance: host.Tolerance,
ValidProofPayout: host.Price * consensus.Currency(info.Size()) * consensus.Currency(host.Window),
ValidProofAddress: host.CoinAddress,
MissedProofPayout: host.Burn * consensus.Currency(info.Size()) * consensus.Currency(host.Window),
MissedProofAddress: consensus.CoinAddress{}, // The empty address is the burn address.
}
// Fund the client portion of the transaction.
minerFee := consensus.Currency(10) // TODO: ask wallet.
renterPortion := host.Price * consensus.Currency(duration+delay) * consensus.Currency(fileContract.FileSize)
var id string
id, err = r.wallet.RegisterTransaction(consensus.Transaction{})
if err != nil {
return
}
err = r.wallet.FundTransaction(id, renterPortion+minerFee)
if err != nil {
return
}
err = r.wallet.AddMinerFee(id, minerFee)
if err != nil {
return
}
err = r.wallet.AddFileContract(id, fileContract)
if err != nil {
return
}
var transaction consensus.Transaction
transaction, err = r.wallet.SignTransaction(id, false)
if err != nil {
return
}
// Negotiate the contract to the host.
err = host.IPAddress.Call("NegotiateContract", func(conn net.Conn) error {
// send contract
if _, err := encoding.WriteObject(conn, transaction); err != nil {
return err
}
// read response
var response string
if err := encoding.ReadObject(conn, &response, 128); err != nil {
return err
}
if response != components.AcceptContractResponse {
return errors.New(response)
}
// host accepted, so transmit file data
// (no prefix needed, since FileSize is included in the metadata)
_, err = io.CopyN(conn, file, info.Size())
return err
})
if err == nil {
break
}
if response != components.AcceptContractResponse {
return errors.New(response)
fmt.Println("Problem from NegotiateContract:", err)
err = r.hostDB.FlagHost(host.ID)
if err != nil {
return
}
// host accepted, so transmit file data
// (no prefix needed, since FileSize is included in the metadata)
_, err = io.CopyN(conn, file, info.Size())
return err
})
if err == nil {
break
}
fmt.Println("Problem from NegotiateContract:", err)
err = r.hostDB.FlagHost(host.ID)
if err != nil {
return
// Record the file into the renter database.
fp = FilePiece{
Host: host,
Contract: fileContract,
}
}
// Record the file into the renter database.
fp = FilePiece{
Host: host,
Contract: fileContract,
}
return
return
*/
}
// TODO: Do the uploading in parallel.
......@@ -200,6 +205,7 @@ func (r *Renter) proposeSmallContract(fullFile []byte, duration consensus.BlockH
// example), the loop will break.
var host components.HostEntry
var fileContract consensus.FileContract
var contractID consensus.ContractID
for {
host, err = r.hostDB.RandomHost()
if err != nil {
......@@ -249,6 +255,7 @@ func (r *Renter) proposeSmallContract(fullFile []byte, duration consensus.BlockH
if err != nil {
return
}
contractID = transaction.FileContractID(0)
// Negotiate the contract to the host.
err = host.IPAddress.Call("NegotiateContract", func(conn net.Conn) error {
......@@ -282,8 +289,9 @@ func (r *Renter) proposeSmallContract(fullFile []byte, duration consensus.BlockH
// Record the file into the renter database.
fp = FilePiece{
Host: host,
Contract: fileContract,
Host: host,
Contract: fileContract,
ContractID: contractID,
}
return
......
......@@ -14,8 +14,9 @@ import (
)
type FilePiece struct {
Host components.HostEntry // Where to find the file.
Contract consensus.FileContract // The contract being enforced.
Host components.HostEntry // Where to find the file.
Contract consensus.FileContract // The contract being enforced.
ContractID consensus.ContractID // The ID of the contract.
}
type FileEntry struct {
......@@ -81,7 +82,7 @@ func (r *Renter) RenameFile(currentName, newName string) error {
func (r *Renter) downloadPiece(piece FilePiece, destination string) (err error) {
return piece.Host.IPAddress.Call("RetrieveFile", func(conn net.Conn) error {
// send filehash
if _, err := encoding.WriteObject(conn, piece.Contract.FileMerkleRoot); err != nil {
if _, err := encoding.WriteObject(conn, piece.ContractID); err != nil {
return err
}
// TODO: read error
......@@ -114,7 +115,7 @@ func (r *Renter) Download(nickname, filename string) (err error) {
if err == nil {
return
} else {
fmt.Println(err)
fmt.Println("Renter got error:", err)
r.hostDB.FlagHost(piece.Host.ID)
}
}
......
package sia
import (
"crypto/rand"
"testing"
"time"
......@@ -16,9 +17,18 @@ func testUploadFile(t *testing.T, c *Core) {
t.Fatal("Hostdb needs at least 1 host to perform testUploadFile")
}
// Get the initial volume of files in the renter dataset.
rentInfo, err := c.renter.RentInfo()
if err != nil {
t.Fatal(err)
}
fileCount := len(rentInfo.Files)
// Have the renter negotiate a contract with the host in the hostDB.
err := c.renter.RentFile(components.RentFileParameters{
Filepath: "sia.go",
randData := make([]byte, 216)
rand.Read(randData)
err = c.renter.RentSmallFile(components.RentSmallFileParameters{
FullFile: randData,
Nickname: "one",
TotalPieces: 1,
})
......@@ -28,7 +38,14 @@ func testUploadFile(t *testing.T, c *Core) {
time.Sleep(10 * time.Second)
// TODO: Check that the file has been added to the renter fileset.
// Check that the file has been added to the renter fileset.
rentInfo, err = c.renter.RentInfo()
if err != nil {
t.Fatal(err)
}
if len(rentInfo.Files) != fileCount+1 {
t.Error("Renter fileset did not increase after uploading")
}
// Check that the file has been added to the host.
if c.host.NumContracts() == 0 {
......@@ -39,4 +56,10 @@ func testUploadFile(t *testing.T, c *Core) {
if c.hostDB.Size() < 1 {
t.Fatal("Hostdb got pruned while trying to make a contract?")
}
// Check that the file can be downloaded.
err = c.renter.Download("one", "renterDownload")
if err != nil {
t.Error(err)
}
}
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