當前位置: 首頁>>代碼示例>>Golang>>正文


Golang Transaction.ID方法代碼示例

本文整理匯總了Golang中github.com/NebulousLabs/Sia/types.Transaction.ID方法的典型用法代碼示例。如果您正苦於以下問題:Golang Transaction.ID方法的具體用法?Golang Transaction.ID怎麽用?Golang Transaction.ID使用的例子?那麽, 這裏精選的方法代碼示例或許可以為您提供幫助。您也可以進一步了解該方法所在github.com/NebulousLabs/Sia/types.Transaction的用法示例。


在下文中一共展示了Transaction.ID方法的8個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。

示例1: negotiateRevision

// negotiateRevision sends the revision and new piece data to the host.
func negotiateRevision(conn net.Conn, rev types.FileContractRevision, piece []byte, secretKey crypto.SecretKey) (types.Transaction, error) {
	conn.SetDeadline(time.Now().Add(5 * time.Minute)) // sufficient to transfer 4 MB over 100 kbps
	defer conn.SetDeadline(time.Time{})               // reset timeout after each revision

	// create transaction containing the revision
	signedTxn := types.Transaction{
		FileContractRevisions: []types.FileContractRevision{rev},
		TransactionSignatures: []types.TransactionSignature{{
			ParentID:       crypto.Hash(rev.ParentID),
			CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
			PublicKeyIndex: 0, // renter key is always first -- see negotiateContract
		}},
	}
	// sign the transaction
	encodedSig, _ := crypto.SignHash(signedTxn.SigHash(0), secretKey) // no error possible
	signedTxn.TransactionSignatures[0].Signature = encodedSig[:]

	// send the transaction
	if err := encoding.WriteObject(conn, signedTxn); err != nil {
		return types.Transaction{}, errors.New("couldn't send revision transaction: " + err.Error())
	}

	// host sends acceptance
	var response string
	if err := encoding.ReadObject(conn, &response, 128); err != nil {
		return types.Transaction{}, errors.New("couldn't read host acceptance: " + err.Error())
	}
	if response != modules.AcceptResponse {
		return types.Transaction{}, errors.New("host rejected revision: " + response)
	}

	// transfer piece
	if _, err := conn.Write(piece); err != nil {
		return types.Transaction{}, errors.New("couldn't transfer piece: " + err.Error())
	}

	// read txn signed by host
	var signedHostTxn types.Transaction
	if err := encoding.ReadObject(conn, &signedHostTxn, types.BlockSizeLimit); err != nil {
		return types.Transaction{}, errors.New("couldn't read signed revision transaction: " + err.Error())
	}

	if signedHostTxn.ID() != signedTxn.ID() {
		return types.Transaction{}, errors.New("host sent bad signed transaction")
	}

	return signedHostTxn, nil
}
開發者ID:zzmjohn,項目名稱:Sia,代碼行數:49,代碼來源:negotiate.go

示例2: managedRPCRevise

// managedRPCRevise is an RPC that allows a renter to revise a file contract. It will
// read new revisions in a loop until the renter sends a termination signal.
func (h *Host) managedRPCRevise(conn net.Conn) error {
	// read ID of contract to be revised
	var fcid types.FileContractID
	if err := encoding.ReadObject(conn, &fcid, crypto.HashSize); err != nil {
		return errors.New("couldn't read contract ID: " + err.Error())
	}

	// remove conn deadline while we wait for lock and rebuild the Merkle tree.
	err := conn.SetDeadline(time.Now().Add(15 * time.Minute))
	if err != nil {
		return err
	}

	h.mu.RLock()
	obligation, exists := h.obligationsByID[fcid]
	h.mu.RUnlock()
	if !exists {
		return errors.New("no record of that contract")
	}
	// need to protect against two simultaneous revisions to the same
	// contract; this can cause inconsistency and data loss, making storage
	// proofs impossible
	//
	// TODO: DOS vector - the host has locked the obligation even though the
	// renter has not proven themselves to be the owner of the file contract.
	obligation.mu.Lock()
	defer obligation.mu.Unlock()

	// open the file in append mode
	file, err := os.OpenFile(obligation.Path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
	if err != nil {
		return err
	}

	// rebuild current Merkle tree
	tree := crypto.NewTree()
	err = tree.ReadSegments(file)
	if err != nil {
		// Error does not need to be checked when closing the file, already
		// there have been issues related to the filesystem.
		_ = file.Close()
		return err
	}

	// accept new revisions in a loop. The final good transaction will be
	// submitted to the blockchain.
	revisionErr := func() error {
		for {
			// allow 5 minutes between revisions
			err := conn.SetDeadline(time.Now().Add(5 * time.Minute))
			if err != nil {
				return err
			}

			// read proposed revision
			var revTxn types.Transaction
			if err = encoding.ReadObject(conn, &revTxn, types.BlockSizeLimit); err != nil {
				return errors.New("couldn't read revision: " + err.Error())
			}
			// an empty transaction indicates completion
			if revTxn.ID() == (types.Transaction{}).ID() {
				return nil
			}

			// allow 5 minutes for each revision
			err = conn.SetDeadline(time.Now().Add(5 * time.Minute))
			if err != nil {
				return err
			}

			// check revision against original file contract
			h.mu.RLock()
			err = h.considerRevision(revTxn, obligation)
			h.mu.RUnlock()
			if err != nil {
				// There is nothing that can be done if there is an error while
				// writing to a connection.
				_ = encoding.WriteObject(conn, err.Error())
				return err
			}

			// indicate acceptance
			if err := encoding.WriteObject(conn, modules.AcceptResponse); err != nil {
				return errors.New("couldn't write acceptance: " + err.Error())
			}

			// read piece
			// TODO: simultaneously read into tree and file
			rev := revTxn.FileContractRevisions[0]
			piece := make([]byte, rev.NewFileSize-obligation.fileSize())
			_, err = io.ReadFull(conn, piece)
			if err != nil {
				return errors.New("couldn't read piece data: " + err.Error())
			}

			// verify Merkle root
			err = tree.ReadSegments(bytes.NewReader(piece))
			if err != nil {
//.........這裏部分代碼省略.........
開發者ID:cfromknecht,項目名稱:Sia,代碼行數:101,代碼來源:upload.go

示例3: buildExplorerTransaction

// buildExplorerTransaction takes a transaction and the height + id of the
// block it appears in an uses that to build an explorer transaction.
func (srv *Server) buildExplorerTransaction(height types.BlockHeight, parent types.BlockID, txn types.Transaction) (et ExplorerTransaction) {
	// Get the header information for the transaction.
	et.ID = txn.ID()
	et.Height = height
	et.Parent = parent
	et.RawTransaction = txn

	// Add the siacoin outputs that correspond with each siacoin input.
	for _, sci := range txn.SiacoinInputs {
		sco, exists := srv.explorer.SiacoinOutput(sci.ParentID)
		if build.DEBUG && !exists {
			panic("could not find corresponding siacoin output")
		}
		et.SiacoinInputOutputs = append(et.SiacoinInputOutputs, sco)
	}

	for i := range txn.SiacoinOutputs {
		et.SiacoinOutputIDs = append(et.SiacoinOutputIDs, txn.SiacoinOutputID(uint64(i)))
	}

	// Add all of the valid and missed proof ids as extra data to the file
	// contracts.
	for i, fc := range txn.FileContracts {
		fcid := txn.FileContractID(uint64(i))
		var fcvpoids []types.SiacoinOutputID
		var fcmpoids []types.SiacoinOutputID
		for j := range fc.ValidProofOutputs {
			fcvpoids = append(fcvpoids, fcid.StorageProofOutputID(types.ProofValid, uint64(j)))
		}
		for j := range fc.MissedProofOutputs {
			fcmpoids = append(fcmpoids, fcid.StorageProofOutputID(types.ProofMissed, uint64(j)))
		}
		et.FileContractIDs = append(et.FileContractIDs, fcid)
		et.FileContractValidProofOutputIDs = append(et.FileContractValidProofOutputIDs, fcvpoids)
		et.FileContractMissedProofOutputIDs = append(et.FileContractMissedProofOutputIDs, fcmpoids)
	}

	// Add all of the valid and missed proof ids as extra data to the file
	// contract revisions.
	for _, fcr := range txn.FileContractRevisions {
		var fcrvpoids []types.SiacoinOutputID
		var fcrmpoids []types.SiacoinOutputID
		for j := range fcr.NewValidProofOutputs {
			fcrvpoids = append(fcrvpoids, fcr.ParentID.StorageProofOutputID(types.ProofValid, uint64(j)))
		}
		for j := range fcr.NewMissedProofOutputs {
			fcrmpoids = append(fcrmpoids, fcr.ParentID.StorageProofOutputID(types.ProofMissed, uint64(j)))
		}
		et.FileContractValidProofOutputIDs = append(et.FileContractValidProofOutputIDs, fcrvpoids)
		et.FileContractMissedProofOutputIDs = append(et.FileContractMissedProofOutputIDs, fcrmpoids)
	}

	// Add all of the output ids and outputs corresponding with each storage
	// proof.
	for _, sp := range txn.StorageProofs {
		fileContract, fileContractRevisions, fileContractExists, _ := srv.explorer.FileContractHistory(sp.ParentID)
		if !fileContractExists && build.DEBUG {
			panic("could not find a file contract connected with a storage proof")
		}
		var storageProofOutputs []types.SiacoinOutput
		if len(fileContractRevisions) > 0 {
			storageProofOutputs = fileContractRevisions[len(fileContractRevisions)-1].NewValidProofOutputs
		} else {
			storageProofOutputs = fileContract.ValidProofOutputs
		}
		var storageProofOutputIDs []types.SiacoinOutputID
		for i := range storageProofOutputs {
			storageProofOutputIDs = append(storageProofOutputIDs, sp.ParentID.StorageProofOutputID(types.ProofValid, uint64(i)))
		}
		et.StorageProofOutputIDs = append(et.StorageProofOutputIDs, storageProofOutputIDs)
		et.StorageProofOutputs = append(et.StorageProofOutputs, storageProofOutputs)
	}

	// Add the siafund outputs that correspond to each siacoin input.
	for _, sci := range txn.SiafundInputs {
		sco, exists := srv.explorer.SiafundOutput(sci.ParentID)
		if build.DEBUG && !exists {
			panic("could not find corresponding siafund output")
		}
		et.SiafundInputOutputs = append(et.SiafundInputOutputs, sco)
	}

	for i := range txn.SiafundOutputs {
		et.SiafundOutputIDs = append(et.SiafundOutputIDs, txn.SiafundOutputID(uint64(i)))
	}

	for _, sfi := range txn.SiafundInputs {
		et.SiaClaimOutputIDs = append(et.SiaClaimOutputIDs, sfi.ParentID.SiaClaimOutputID())
	}
	return et
}
開發者ID:cfromknecht,項目名稱:Sia,代碼行數:93,代碼來源:explorer.go

示例4: revise

// revise revises fc to cover piece and uploads both the revision and the
// piece data to the host.
func (hu *hostUploader) revise(fc types.FileContract, piece []byte, height types.BlockHeight) error {
	hu.conn.SetDeadline(time.Now().Add(5 * time.Minute)) // sufficient to transfer 4 MB over 100 kbps
	defer hu.conn.SetDeadline(time.Time{})               // reset timeout after each revision

	// calculate new merkle root
	err := hu.tree.ReadSegments(bytes.NewReader(piece))
	if err != nil {
		return err
	}

	// create revision
	rev := types.FileContractRevision{
		ParentID:          hu.contract.ID,
		UnlockConditions:  hu.unlockConditions,
		NewRevisionNumber: fc.RevisionNumber + 1,

		NewFileSize:           fc.FileSize + uint64(len(piece)),
		NewFileMerkleRoot:     hu.tree.Root(),
		NewWindowStart:        fc.WindowStart,
		NewWindowEnd:          fc.WindowEnd,
		NewValidProofOutputs:  fc.ValidProofOutputs,
		NewMissedProofOutputs: fc.MissedProofOutputs,
		NewUnlockHash:         fc.UnlockHash,
	}
	// transfer value of piece from renter to host
	safeDuration := uint64(fc.WindowStart - height + 20) // buffer in case host is behind
	piecePrice := types.NewCurrency64(uint64(len(piece))).Mul(types.NewCurrency64(safeDuration)).Mul(hu.settings.Price)
	// prevent a negative currency panic
	if piecePrice.Cmp(fc.ValidProofOutputs[0].Value) > 0 {
		// probably not enough money, but the host might accept it anyway
		piecePrice = fc.ValidProofOutputs[0].Value
	}
	rev.NewValidProofOutputs[0].Value = rev.NewValidProofOutputs[0].Value.Sub(piecePrice)   // less returned to renter
	rev.NewValidProofOutputs[1].Value = rev.NewValidProofOutputs[1].Value.Add(piecePrice)   // more given to host
	rev.NewMissedProofOutputs[0].Value = rev.NewMissedProofOutputs[0].Value.Sub(piecePrice) // less returned to renter
	rev.NewMissedProofOutputs[1].Value = rev.NewMissedProofOutputs[1].Value.Add(piecePrice) // more given to void

	// create transaction containing the revision
	signedTxn := types.Transaction{
		FileContractRevisions: []types.FileContractRevision{rev},
		TransactionSignatures: []types.TransactionSignature{{
			ParentID:       crypto.Hash(hu.contract.ID),
			CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
			PublicKeyIndex: 0, // renter key is always first -- see negotiateContract
		}},
	}

	// sign the transaction
	encodedSig, err := crypto.SignHash(signedTxn.SigHash(0), hu.secretKey)
	if err != nil {
		return err
	}
	signedTxn.TransactionSignatures[0].Signature = encodedSig[:]

	// send the transaction
	if err := encoding.WriteObject(hu.conn, signedTxn); err != nil {
		return err
	}

	// host sends acceptance
	var response string
	if err := encoding.ReadObject(hu.conn, &response, 128); err != nil {
		return err
	}
	if response != modules.AcceptResponse {
		return errors.New("host rejected revision: " + response)
	}

	// transfer piece
	if _, err := hu.conn.Write(piece); err != nil {
		return err
	}

	// read txn signed by host
	var signedHostTxn types.Transaction
	if err := encoding.ReadObject(hu.conn, &signedHostTxn, types.BlockSizeLimit); err != nil {
		return err
	}

	if signedHostTxn.ID() != signedTxn.ID() {
		return errors.New("host sent bad signed transaction")
	} else if err = signedHostTxn.StandaloneValid(height); err != nil {
		return err
	}

	hu.lastTxn = signedHostTxn

	return nil
}
開發者ID:xmagicbox,項目名稱:Sia,代碼行數:91,代碼來源:negotiate.go

示例5: addTransaction

// addTransaction is called from addBlockDB, and delegates the adding
// of information to the database to the functions defined above
func (tx *boltTx) addTransaction(txn types.Transaction) {
	// Store this for quick lookup
	txid := txn.ID()

	// Append each input to the list of modifications
	for _, input := range txn.SiacoinInputs {
		tx.addAddress(input.UnlockConditions.UnlockHash(), txid)
		tx.addSiacoinInput(input.ParentID, txid)
	}

	// Handle all the transaction outputs
	for i, output := range txn.SiacoinOutputs {
		tx.addAddress(output.UnlockHash, txid)
		tx.addNewOutput(txn.SiacoinOutputID(uint64(i)), txid)
	}

	// Handle each file contract individually
	for i, contract := range txn.FileContracts {
		fcid := txn.FileContractID(uint64(i))
		tx.addNewHash("FileContracts", hashFilecontract, crypto.Hash(fcid), fcInfo{
			Contract: txid,
		})

		for j, output := range contract.ValidProofOutputs {
			tx.addAddress(output.UnlockHash, txid)
			tx.addNewOutput(fcid.StorageProofOutputID(true, uint64(j)), txid)
		}
		for j, output := range contract.MissedProofOutputs {
			tx.addAddress(output.UnlockHash, txid)
			tx.addNewOutput(fcid.StorageProofOutputID(false, uint64(j)), txid)
		}

		tx.addAddress(contract.UnlockHash, txid)
	}

	// Update the list of revisions
	for _, revision := range txn.FileContractRevisions {
		tx.addFcRevision(revision.ParentID, txid)

		// Note the old outputs will still be there in the
		// database. This is to provide information to the
		// people who may just need it.
		for i, output := range revision.NewValidProofOutputs {
			tx.addAddress(output.UnlockHash, txid)
			tx.addNewOutput(revision.ParentID.StorageProofOutputID(true, uint64(i)), txid)
		}
		for i, output := range revision.NewMissedProofOutputs {
			tx.addAddress(output.UnlockHash, txid)
			tx.addNewOutput(revision.ParentID.StorageProofOutputID(false, uint64(i)), txid)
		}

		tx.addAddress(revision.NewUnlockHash, txid)
	}

	// Update the list of storage proofs
	for _, proof := range txn.StorageProofs {
		tx.addFcProof(proof.ParentID, txid)
	}

	// Append all the siafund inputs to the modification list
	for _, input := range txn.SiafundInputs {
		tx.addSiafundInput(input.ParentID, txid)
	}

	// Handle all the siafund outputs
	for i, output := range txn.SiafundOutputs {
		tx.addAddress(output.UnlockHash, txid)
		tx.addNewSFOutput(txn.SiafundOutputID(uint64(i)), txid)

	}

	tx.putObject("Hashes", txid, hashTransaction)
}
開發者ID:zoutaiqi,項目名稱:Sia,代碼行數:75,代碼來源:addblock.go

示例6: rpcRevise

// rpcRevise is an RPC that allows a renter to revise a file contract. It will
// read new revisions in a loop until the renter sends a termination signal.
func (h *Host) rpcRevise(conn net.Conn) error {
	// read ID of contract to be revised
	var fcid types.FileContractID
	if err := encoding.ReadObject(conn, &fcid, crypto.HashSize); err != nil {
		return err
	}
	lockID := h.mu.RLock()
	obligation, exists := h.obligationsByID[fcid]
	h.mu.RUnlock(lockID)
	if !exists {
		return errors.New("no record of that contract")
	}

	// need to protect against two simultaneous revisions to the same
	// contract; this can cause inconsistency and data loss, making storage
	// proofs impossible
	obligation.mu.Lock()
	defer obligation.mu.Unlock()

	// open the file in append mode
	file, err := os.OpenFile(obligation.Path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
	if err != nil {
		return err
	}
	defer func() {
		// if a newly-created file was not updated, remove it
		if stat, _ := file.Stat(); stat.Size() == 0 {
			os.Remove(obligation.Path)
		}
		file.Close()
	}()

	// rebuild current Merkle tree
	tree := crypto.NewTree()
	buf := make([]byte, crypto.SegmentSize)
	for {
		_, err := io.ReadFull(file, buf)
		if err == io.EOF {
			break
		} else if err != nil && err != io.ErrUnexpectedEOF {
			return err
		}
		tree.Push(buf)
	}

	// accept new revisions in a loop. The final good transaction will be
	// submitted to the blockchain.
	var finalTxn types.Transaction
	defer func() {
		h.tpool.AcceptTransactionSet([]types.Transaction{finalTxn})
	}()
	for {
		// read proposed revision
		var revTxn types.Transaction
		if err := encoding.ReadObject(conn, &revTxn, types.BlockSizeLimit); err != nil {
			return err
		}
		// an empty transaction indicates completion
		if revTxn.ID() == (types.Transaction{}).ID() {
			break
		}

		// check revision against original file contract
		lockID = h.mu.RLock()
		err := h.considerRevision(revTxn, obligation)
		h.mu.RUnlock(lockID)
		if err != nil {
			encoding.WriteObject(conn, err.Error())
			continue // don't terminate loop; subsequent revisions may be okay
		}

		// indicate acceptance
		if err := encoding.WriteObject(conn, modules.AcceptResponse); err != nil {
			return err
		}

		// read piece
		// TODO: simultaneously read into tree?
		rev := revTxn.FileContractRevisions[0]
		piece := make([]byte, rev.NewFileSize-obligation.FileContract.FileSize)
		_, err = io.ReadFull(conn, piece)
		if err != nil {
			return err
		}

		// verify Merkle root
		r := bytes.NewReader(piece)
		for {
			_, err := io.ReadFull(r, buf)
			if err == io.EOF {
				break
			} else if err != nil && err != io.ErrUnexpectedEOF {
				return err
			}
			tree.Push(buf)
		}
		if tree.Root() != rev.NewFileMerkleRoot {
			return errors.New("revision has bad Merkle root")
//.........這裏部分代碼省略.........
開發者ID:kustomzone,項目名稱:Sia,代碼行數:101,代碼來源:negotiate.go

示例7: rpcContract

// rpcContract is an RPC that negotiates a file contract. If the
// negotiation is successful, the file is downloaded and the host begins
// submitting proofs of storage.
func (h *Host) rpcContract(conn net.Conn) (err error) {
	// Read the contract terms.
	var terms modules.ContractTerms
	err = encoding.ReadObject(conn, &terms, maxContractLen)
	if err != nil {
		return
	}

	// Consider the contract terms. If they are unacceptable, return an error
	// describing why.
	lockID := h.mu.RLock()
	err = h.considerTerms(terms)
	h.mu.RUnlock(lockID)
	if err != nil {
		err = encoding.WriteObject(conn, err.Error())
		return
	}

	// terms are acceptable; allocate space for file
	lockID = h.mu.Lock()
	file, path, err := h.allocate(terms.FileSize)
	h.mu.Unlock(lockID)
	if err != nil {
		return
	}
	defer file.Close()

	// rollback everything if something goes wrong
	defer func() {
		lockID := h.mu.Lock()
		defer h.mu.Unlock(lockID)
		if err != nil {
			h.deallocate(terms.FileSize, path)
		}
	}()

	// signal that we are ready to download file
	err = encoding.WriteObject(conn, modules.AcceptTermsResponse)
	if err != nil {
		return
	}

	// simultaneously download file and calculate its Merkle root.
	tee := io.TeeReader(
		// use a LimitedReader to ensure we don't read indefinitely
		io.LimitReader(conn, int64(terms.FileSize)),
		// each byte we read from tee will also be written to file
		file,
	)
	merkleRoot, err := crypto.ReaderMerkleRoot(tee)
	if err != nil {
		return
	}

	// Data has been sent, read in the unsigned transaction with the file
	// contract.
	var unsignedTxn types.Transaction
	err = encoding.ReadObject(conn, &unsignedTxn, maxContractLen)
	if err != nil {
		return
	}

	// Verify that the transaction matches the agreed upon terms, and that the
	// Merkle root in the file contract matches our independently calculated
	// Merkle root.
	err = verifyTransaction(unsignedTxn, terms, merkleRoot)
	if err != nil {
		err = errors.New("transaction does not satisfy terms: " + err.Error())
		return
	}

	// Add the collateral to the transaction, but do not sign the transaction.
	collateralTxn, txnBuilder, err := h.addCollateral(unsignedTxn, terms)
	if err != nil {
		return
	}
	err = encoding.WriteObject(conn, collateralTxn)
	if err != nil {
		return
	}

	// Read in the renter-signed transaction and check that it matches the
	// previously accepted transaction.
	var signedTxn types.Transaction
	err = encoding.ReadObject(conn, &signedTxn, maxContractLen)
	if err != nil {
		return
	}
	if collateralTxn.ID() != signedTxn.ID() {
		err = errors.New("signed transaction does not match the transaction with collateral")
		return
	}

	// Add the signatures from the renter signed transaction, and then sign the
	// transaction, then submit the transaction.
	for _, sig := range signedTxn.TransactionSignatures {
		txnBuilder.AddTransactionSignature(sig)
//.........這裏部分代碼省略.........
開發者ID:Butterfly-3Kisses,項目名稱:Sia,代碼行數:101,代碼來源:negotiate.go

示例8: rpcRevise

// rpcRevise is an RPC that allows a renter to revise a file contract. It will
// read new revisions in a loop until the renter sends a termination signal.
func (h *Host) rpcRevise(conn net.Conn) error {
	// read ID of contract to be revised
	var fcid types.FileContractID
	if err := encoding.ReadObject(conn, &fcid, crypto.HashSize); err != nil {
		return errors.New("couldn't read contract ID: " + err.Error())
	}

	// remove conn deadline while we wait for lock and rebuild the Merkle tree
	conn.SetDeadline(time.Time{})

	h.mu.RLock()
	obligation, exists := h.obligationsByID[fcid]
	h.mu.RUnlock()
	if !exists {
		return errors.New("no record of that contract")
	}

	// need to protect against two simultaneous revisions to the same
	// contract; this can cause inconsistency and data loss, making storage
	// proofs impossible
	obligation.mu.Lock()
	defer obligation.mu.Unlock()

	// open the file in append mode
	file, err := os.OpenFile(obligation.Path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
	if err != nil {
		return err
	}

	// rebuild current Merkle tree
	tree := crypto.NewTree()
	err = tree.ReadSegments(file)
	if err != nil {
		file.Close()
		return err
	}

	// accept new revisions in a loop. The final good transaction will be
	// submitted to the blockchain.
	revisionErr := func() error {
		for {
			// allow 2 minutes between revisions
			conn.SetDeadline(time.Now().Add(2 * time.Minute))

			// read proposed revision
			var revTxn types.Transaction
			if err := encoding.ReadObject(conn, &revTxn, types.BlockSizeLimit); err != nil {
				return errors.New("couldn't read revision: " + err.Error())
			}
			// an empty transaction indicates completion
			if revTxn.ID() == (types.Transaction{}).ID() {
				return nil
			}

			// allow 5 minutes for each revision
			conn.SetDeadline(time.Now().Add(5 * time.Minute))

			// check revision against original file contract
			h.mu.RLock()
			err := h.considerRevision(revTxn, *obligation)
			h.mu.RUnlock()
			if err != nil {
				encoding.WriteObject(conn, err.Error())
				continue // don't terminate loop; subsequent revisions may be okay
			}

			// indicate acceptance
			if err := encoding.WriteObject(conn, modules.AcceptResponse); err != nil {
				return errors.New("couldn't write acceptance: " + err.Error())
			}

			// read piece
			// TODO: simultaneously read into tree and file
			rev := revTxn.FileContractRevisions[0]
			last := obligation.LastRevisionTxn.FileContractRevisions[0]
			piece := make([]byte, rev.NewFileSize-last.NewFileSize)
			_, err = io.ReadFull(conn, piece)
			if err != nil {
				return errors.New("couldn't read piece data: " + err.Error())
			}

			// verify Merkle root
			err = tree.ReadSegments(bytes.NewReader(piece))
			if err != nil {
				return errors.New("couldn't verify Merkle root: " + err.Error())
			}
			if tree.Root() != rev.NewFileMerkleRoot {
				return errors.New("revision has bad Merkle root")
			}

			// manually sign the transaction
			revTxn.TransactionSignatures = append(revTxn.TransactionSignatures, types.TransactionSignature{
				ParentID:       crypto.Hash(fcid),
				CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
				PublicKeyIndex: 1, // host key is always second
			})
			encodedSig, err := crypto.SignHash(revTxn.SigHash(1), h.secretKey)
			if err != nil {
//.........這裏部分代碼省略.........
開發者ID:mantyr,項目名稱:Sia,代碼行數:101,代碼來源:negotiate.go


注:本文中的github.com/NebulousLabs/Sia/types.Transaction.ID方法示例由純淨天空整理自Github/MSDocs等開源代碼及文檔管理平台,相關代碼片段篩選自各路編程大神貢獻的開源項目,源碼版權歸原作者所有,傳播和使用請參考對應項目的License;未經允許,請勿轉載。