-
Notifications
You must be signed in to change notification settings - Fork 442
add RPC call Metadata requesting sector IDs #2584
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package host | ||
|
||
import ( | ||
"errors" | ||
"net" | ||
|
||
"github.com/NebulousLabs/Sia/encoding" | ||
"github.com/NebulousLabs/Sia/modules" | ||
) | ||
|
||
// managedRPCMetadata accepts a request to get list of sector ids. | ||
func (h *Host) managedRPCMetadata(conn net.Conn) error { | ||
// Perform the file contract revision exchange, giving the renter the most | ||
// recent file contract revision and getting the storage obligation that | ||
// will be used to get sector ids. | ||
_, so, err := h.managedRPCRecentRevision(conn) | ||
if err != nil { | ||
return extendErr("RPCRecentRevision failed: ", err) | ||
} | ||
// The storage obligation is received with a lock on it. Defer a call to | ||
// unlock the storage obligation. | ||
defer func() { | ||
h.managedUnlockStorageObligation(so.id()) | ||
}() | ||
// Receive boundaries of so.SectorRoots to return. | ||
var begin, end uint64 | ||
err = encoding.ReadObject(conn, &begin, 8) | ||
if err != nil { | ||
return extendErr("unable to read 'begin': ", ErrorConnection(err.Error())) | ||
} | ||
err = encoding.ReadObject(conn, &end, 8) | ||
if err != nil { | ||
return extendErr("unable to read 'end': ", ErrorConnection(err.Error())) | ||
} | ||
if end < begin { | ||
err = errors.New("Range error") | ||
modules.WriteNegotiationRejection(conn, err) | ||
return err | ||
} | ||
if end > uint64(len(so.SectorRoots)) { | ||
err = errors.New("Range out of bounds error") | ||
modules.WriteNegotiationRejection(conn, err) | ||
return err | ||
} | ||
if end-begin > modules.NegotiateMetadataMaxSliceSize { | ||
err = errors.New("The range is too long") | ||
modules.WriteNegotiationRejection(conn, err) | ||
return err | ||
} | ||
if err = modules.WriteNegotiationAcceptance(conn); err != nil { | ||
return extendErr("failed to write [begin,end) acceptance: ", ErrorConnection(err.Error())) | ||
} | ||
// Write roots of all sectors. | ||
err = encoding.WriteObject(conn, so.SectorRoots[begin:end]) | ||
if err != nil { | ||
return extendErr("cound not write sectors: ", ErrorConnection(err.Error())) | ||
} | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -237,6 +237,7 @@ type RenterContract struct { | |
ID types.FileContractID | ||
HostPublicKey types.SiaPublicKey | ||
Transaction types.Transaction | ||
SecretKey crypto.SecretKey | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be necessary There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is used in |
||
|
||
StartHeight types.BlockHeight | ||
EndHeight types.BlockHeight | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package proto | ||
|
||
import ( | ||
"errors" | ||
"net" | ||
"time" | ||
|
||
"github.com/NebulousLabs/Sia/crypto" | ||
"github.com/NebulousLabs/Sia/encoding" | ||
"github.com/NebulousLabs/Sia/modules" | ||
"github.com/NebulousLabs/Sia/types" | ||
) | ||
|
||
// GetMetadata downloads sector IDs from the host. | ||
func GetMetadata(host modules.HostDBEntry, fcid types.FileContractID, sk crypto.SecretKey, windowStart types.BlockHeight, begin, end uint64, cancel <-chan struct{}) (lastRevision types.FileContractRevision, ids []crypto.Hash, err error) { | ||
conn, err := (&net.Dialer{ | ||
Cancel: cancel, | ||
Timeout: 15 * time.Second, | ||
}).Dial("tcp", string(host.NetAddress)) | ||
if err != nil { | ||
return | ||
} | ||
defer conn.Close() | ||
// allot 2 minutes for RPC request + revision exchange | ||
extendDeadline(conn, modules.NegotiateMetadataTime) | ||
if err = encoding.WriteObject(conn, modules.RPCMetadata); err != nil { | ||
err = errors.New("couldn't initiate RPC: " + err.Error()) | ||
return | ||
} | ||
lastRevision, err = getRecentRevision(conn, fcid, sk, windowStart, host.Version) | ||
if err != nil { | ||
return | ||
} | ||
if err = encoding.WriteObject(conn, begin); err != nil { | ||
err = errors.New("unable to write 'begin': " + err.Error()) | ||
return | ||
} | ||
if err = encoding.WriteObject(conn, end); err != nil { | ||
err = errors.New("unable to write 'end': " + err.Error()) | ||
return | ||
} | ||
// read acceptance | ||
if err = modules.ReadNegotiationAcceptance(conn); err != nil { | ||
err = errors.New("host did not accept [begin,end): " + err.Error()) | ||
return | ||
} | ||
numSectors := end - begin | ||
if err = encoding.ReadObject(conn, &ids, numSectors*crypto.HashSize+8); err != nil { | ||
err = errors.New("unable to read 'ids': " + err.Error()) | ||
return | ||
} | ||
if uint64(len(ids)) != end-begin { | ||
err = errors.New("the host returned too short list of sector IDs") | ||
return | ||
} | ||
return | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,38 +66,54 @@ func verifySettings(conn net.Conn, host modules.HostDBEntry) (modules.HostDBEntr | |
return host, nil | ||
} | ||
|
||
// verifyRecentRevision confirms that the host and contractor agree upon the current | ||
// state of the contract being revised. | ||
func verifyRecentRevision(conn net.Conn, contract contractHeader, hostVersion string) error { | ||
// getRecentRevision downloads the current revision from the host | ||
// and checks signatures. | ||
func getRecentRevision(conn net.Conn, fcid types.FileContractID, sk crypto.SecretKey, windowStart types.BlockHeight, hostVersion string) (types.FileContractRevision, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why it's necessary to change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The caller of |
||
// send contract ID | ||
if err := encoding.WriteObject(conn, contract.ID()); err != nil { | ||
return errors.New("couldn't send contract ID: " + err.Error()) | ||
if err := encoding.WriteObject(conn, fcid); err != nil { | ||
return types.FileContractRevision{}, errors.New("couldn't send contract ID: " + err.Error()) | ||
} | ||
// read challenge | ||
var challenge crypto.Hash | ||
if err := encoding.ReadObject(conn, &challenge, 32); err != nil { | ||
return errors.New("couldn't read challenge: " + err.Error()) | ||
return types.FileContractRevision{}, errors.New("couldn't read challenge: " + err.Error()) | ||
} | ||
if build.VersionCmp(hostVersion, "1.3.0") >= 0 { | ||
crypto.SecureWipe(challenge[:16]) | ||
} | ||
// sign and return | ||
sig := crypto.SignHash(challenge, contract.SecretKey) | ||
sig := crypto.SignHash(challenge, sk) | ||
if err := encoding.WriteObject(conn, sig); err != nil { | ||
return errors.New("couldn't send challenge response: " + err.Error()) | ||
return types.FileContractRevision{}, errors.New("couldn't send challenge response: " + err.Error()) | ||
} | ||
// read acceptance | ||
if err := modules.ReadNegotiationAcceptance(conn); err != nil { | ||
return errors.New("host did not accept revision request: " + err.Error()) | ||
return types.FileContractRevision{}, errors.New("host did not accept revision request: " + err.Error()) | ||
} | ||
// read last revision and signatures | ||
var lastRevision types.FileContractRevision | ||
var hostSignatures []types.TransactionSignature | ||
if err := encoding.ReadObject(conn, &lastRevision, 2048); err != nil { | ||
return errors.New("couldn't read last revision: " + err.Error()) | ||
return types.FileContractRevision{}, errors.New("couldn't read last revision: " + err.Error()) | ||
} | ||
if err := encoding.ReadObject(conn, &hostSignatures, 2048); err != nil { | ||
return errors.New("couldn't read host signatures: " + err.Error()) | ||
return types.FileContractRevision{}, errors.New("couldn't read host signatures: " + err.Error()) | ||
} | ||
// NOTE: we can fake the blockheight here because it doesn't affect | ||
// verification; it just needs to be above the fork height and below the | ||
// contract expiration (which was checked earlier). | ||
if err := modules.VerifyFileContractRevisionTransactionSignatures(lastRevision, hostSignatures, windowStart-1); err != nil { | ||
return types.FileContractRevision{}, err | ||
} | ||
return lastRevision, nil | ||
} | ||
|
||
// verifyRecentRevision confirms that the host and contractor agree upon the current | ||
// state of the contract being revised. | ||
func verifyRecentRevision(conn net.Conn, contract contractHeader, hostVersion string) error { | ||
lastRevision, err := getRecentRevision(conn, contract.ID(), contract.SecretKey, contract.EndHeight(), hostVersion) | ||
if err != nil { | ||
return err | ||
} | ||
// Check that the unlock hashes match; if they do not, something is | ||
// seriously wrong. Otherwise, check that the revision numbers match. | ||
|
@@ -107,10 +123,7 @@ func verifyRecentRevision(conn net.Conn, contract contractHeader, hostVersion st | |
} else if lastRevision.NewRevisionNumber != ourRev.NewRevisionNumber { | ||
return &recentRevisionError{ourRev.NewRevisionNumber, lastRevision.NewRevisionNumber} | ||
} | ||
// NOTE: we can fake the blockheight here because it doesn't affect | ||
// verification; it just needs to be above the fork height and below the | ||
// contract expiration (which was checked earlier). | ||
return modules.VerifyFileContractRevisionTransactionSignatures(lastRevision, hostSignatures, contract.EndHeight()-1) | ||
return nil | ||
} | ||
|
||
// negotiateRevision sends a revision and actions to the host for approval, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these numbers are kind of magic; better would be
SectorSize / crypto.HashSize
.