本文整理匯總了Golang中github.com/NebulousLabs/Sia/types.Transaction.TransactionSignatures方法的典型用法代碼示例。如果您正苦於以下問題:Golang Transaction.TransactionSignatures方法的具體用法?Golang Transaction.TransactionSignatures怎麽用?Golang Transaction.TransactionSignatures使用的例子?那麽, 這裏精選的方法代碼示例或許可以為您提供幫助。您也可以進一步了解該方法所在類github.com/NebulousLabs/Sia/types.Transaction
的用法示例。
在下文中一共展示了Transaction.TransactionSignatures方法的11個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。
示例1: verifyKeysSiag_1_0
// verifyKeysSiag_1_0 is a copy-pasted version of the verifyKeys method
// from siag 1.0.
func verifyKeysSiag_1_0(uc types.UnlockConditions, folder string, keyname string) error {
keysRequired := uc.SignaturesRequired
totalKeys := uint64(len(uc.PublicKeys))
loadedKeys := make([]KeyPairSiag_1_0, totalKeys)
for i := 0; i < len(loadedKeys); i++ {
err := encoding.ReadFile(filepath.Join(folder, keyname+"_Key"+strconv.Itoa(i)+".siakey"), &loadedKeys[i])
if err != nil {
return err
}
}
for _, loadedKey := range loadedKeys {
if loadedKey.UnlockConditions.UnlockHash() != uc.UnlockHash() {
return errors.New("ErrCorruptedKey")
}
}
txn := types.Transaction{
SiafundInputs: []types.SiafundInput{
types.SiafundInput{
UnlockConditions: loadedKeys[0].UnlockConditions,
},
},
}
var i uint64
for i != totalKeys {
if i+keysRequired > totalKeys {
i = totalKeys - keysRequired
}
var j uint64
for j < keysRequired {
txn.TransactionSignatures = append(txn.TransactionSignatures, types.TransactionSignature{
PublicKeyIndex: i,
CoveredFields: types.CoveredFields{WholeTransaction: true},
})
sigHash := txn.SigHash(int(j))
sig, err := crypto.SignHash(sigHash, loadedKeys[i].SecretKey)
if err != nil {
return err
}
txn.TransactionSignatures[j].Signature = sig[:]
i++
j++
}
err := txn.StandaloneValid(0)
if err != nil {
return err
}
txn.TransactionSignatures = nil
}
return nil
}
示例2: negotiateRevision
// negotiateRevision sends a revision and actions to the host for approval,
// completing one iteration of the revision loop.
func negotiateRevision(conn net.Conn, rev types.FileContractRevision, secretKey crypto.SecretKey) (types.Transaction, error) {
// 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 formContract
}},
}
// sign the transaction
encodedSig, _ := crypto.SignHash(signedTxn.SigHash(0), secretKey) // no error possible
signedTxn.TransactionSignatures[0].Signature = encodedSig[:]
// send the revision
if err := encoding.WriteObject(conn, rev); err != nil {
return types.Transaction{}, errors.New("couldn't send revision: " + err.Error())
}
// read acceptance
if err := modules.ReadNegotiationAcceptance(conn); err != nil {
return types.Transaction{}, errors.New("host did not accept revision: " + err.Error())
}
// send the new transaction signature
if err := encoding.WriteObject(conn, signedTxn.TransactionSignatures[0]); err != nil {
return types.Transaction{}, errors.New("couldn't send transaction signature: " + err.Error())
}
// read the host's acceptance and transaction signature
// NOTE: if the host sends ErrStopResponse, we should continue processing
// the revision, but return the error anyway.
responseErr := modules.ReadNegotiationAcceptance(conn)
if responseErr != nil && responseErr != modules.ErrStopResponse {
return types.Transaction{}, errors.New("host did not accept transaction signature: " + responseErr.Error())
}
var hostSig types.TransactionSignature
if err := encoding.ReadObject(conn, &hostSig, 16e3); err != nil {
return types.Transaction{}, errors.New("couldn't read host's signature: " + err.Error())
}
// add the signature to the transaction and verify it
// 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).
verificationHeight := rev.NewWindowStart - 1
signedTxn.TransactionSignatures = append(signedTxn.TransactionSignatures, hostSig)
if err := signedTxn.StandaloneValid(verificationHeight); err != nil {
return types.Transaction{}, err
}
// if the host sent ErrStopResponse, return it
return signedTxn, responseErr
}
示例3: addSignatures
// addSignatures will sign a transaction using a spendable key, with support
// for multisig spendable keys. Because of the restricted input, the function
// is compatible with both siacoin inputs and siafund inputs.
func addSignatures(txn *types.Transaction, cf types.CoveredFields, uc types.UnlockConditions, parentID crypto.Hash, spendKey spendableKey) (newSigIndices []int, err error) {
// Try to find the matching secret key for each public key - some public
// keys may not have a match. Some secret keys may be used multiple times,
// which is why public keys are used as the outer loop.
totalSignatures := uint64(0)
for i, siaPubKey := range uc.PublicKeys {
// Search for the matching secret key to the public key.
for j := range spendKey.SecretKeys {
pubKey := spendKey.SecretKeys[j].PublicKey()
if bytes.Compare(siaPubKey.Key, pubKey[:]) != 0 {
continue
}
// Found the right secret key, add a signature.
sig := types.TransactionSignature{
ParentID: parentID,
CoveredFields: cf,
PublicKeyIndex: uint64(i),
}
newSigIndices = append(newSigIndices, len(txn.TransactionSignatures))
txn.TransactionSignatures = append(txn.TransactionSignatures, sig)
sigIndex := len(txn.TransactionSignatures) - 1
sigHash := txn.SigHash(sigIndex)
encodedSig, err := crypto.SignHash(sigHash, spendKey.SecretKeys[j])
if err != nil {
return nil, err
}
txn.TransactionSignatures[sigIndex].Signature = encodedSig[:]
// Count that the signature has been added, and break out of the
// secret key loop.
totalSignatures++
break
}
// If there are enough signatures to satisfy the unlock conditions,
// break out of the outer loop.
if totalSignatures == uc.SignaturesRequired {
break
}
}
return newSigIndices, nil
}
示例4: addSignatures
// addSignatures will sign a transaction using a spendable key, with support
// for multisig spendable keys. Because of the restricted input, the function
// is compatible with both siacoin inputs and siafund inputs.
func addSignatures(txn *types.Transaction, cf types.CoveredFields, uc types.UnlockConditions, parentID crypto.Hash, key spendableKey) error {
usedIndices := make(map[int]struct{})
for i := range key.secretKeys {
found := false
keyIndex := 0
pubKey := key.secretKeys[i].PublicKey()
for i, siaPublicKey := range uc.PublicKeys {
_, exists := usedIndices[i]
if !exists && bytes.Compare(pubKey[:], siaPublicKey.Key) == 0 {
found = true
keyIndex = i
break
}
}
if !found && build.DEBUG {
panic("transaction builder cannot sign an input that it added")
}
usedIndices[keyIndex] = struct{}{}
// Create the unsigned transaction signature.
sig := types.TransactionSignature{
ParentID: parentID,
CoveredFields: cf,
PublicKeyIndex: uint64(keyIndex),
}
txn.TransactionSignatures = append(txn.TransactionSignatures, sig)
// Get the signature.
sigIndex := len(txn.TransactionSignatures) - 1
sigHash := txn.SigHash(sigIndex)
encodedSig, err := crypto.SignHash(sigHash, key.secretKeys[i])
if err != nil {
return err
}
txn.TransactionSignatures[sigIndex].Signature = encodedSig[:]
}
return nil
}
示例5: managedRPCRevise
//.........這裏部分代碼省略.........
// 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 {
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 {
return err
}
revTxn.TransactionSignatures[1].Signature = encodedSig[:]
// append piece to file
if _, err := file.Write(piece); err != nil {
return errors.New("couldn't write new data to file: " + err.Error())
}
// save updated obligation to disk
h.mu.Lock()
h.reviseObligation(revTxn)
h.mu.Unlock()
// send the signed transaction - this must be the last thing that happens.
if err := encoding.WriteObject(conn, revTxn); err != nil {
return errors.New("couldn't write signed revision transaction: " + err.Error())
}
}
}()
err = file.Close()
if err != nil {
return err
}
err = h.tpool.AcceptTransactionSet([]types.Transaction{obligation.RevisionTransaction})
if err != nil {
h.log.Println("WARN: transaction pool rejected revision transaction: " + err.Error())
}
return revisionErr
}
示例6: Renew
//.........這裏部分代碼省略.........
// were added to the transaction
var newParents []types.Transaction
var newInputs []types.SiacoinInput
var newOutputs []types.SiacoinOutput
if err = encoding.ReadObject(conn, &newParents, types.BlockSizeLimit); err != nil {
return modules.RenterContract{}, errors.New("couldn't read the host's added parents: " + err.Error())
}
if err = encoding.ReadObject(conn, &newInputs, types.BlockSizeLimit); err != nil {
return modules.RenterContract{}, errors.New("couldn't read the host's added inputs: " + err.Error())
}
if err = encoding.ReadObject(conn, &newOutputs, types.BlockSizeLimit); err != nil {
return modules.RenterContract{}, errors.New("couldn't read the host's added outputs: " + err.Error())
}
// merge txnAdditions with txnSet
txnBuilder.AddParents(newParents)
for _, input := range newInputs {
txnBuilder.AddSiacoinInput(input)
}
for _, output := range newOutputs {
txnBuilder.AddSiacoinOutput(output)
}
// sign the txn
signedTxnSet, err := txnBuilder.Sign(true)
if err != nil {
return modules.RenterContract{}, modules.WriteNegotiationRejection(conn, errors.New("failed to sign transaction: "+err.Error()))
}
// calculate signatures added by the transaction builder
var addedSignatures []types.TransactionSignature
_, _, _, addedSignatureIndices := txnBuilder.ViewAdded()
for _, i := range addedSignatureIndices {
addedSignatures = append(addedSignatures, signedTxnSet[len(signedTxnSet)-1].TransactionSignatures[i])
}
// create initial (no-op) revision, transaction, and signature
initRevision := types.FileContractRevision{
ParentID: signedTxnSet[len(signedTxnSet)-1].FileContractID(0),
UnlockConditions: contract.LastRevision.UnlockConditions,
NewRevisionNumber: 1,
NewFileSize: fc.FileSize,
NewFileMerkleRoot: fc.FileMerkleRoot,
NewWindowStart: fc.WindowStart,
NewWindowEnd: fc.WindowEnd,
NewValidProofOutputs: fc.ValidProofOutputs,
NewMissedProofOutputs: fc.MissedProofOutputs,
NewUnlockHash: fc.UnlockHash,
}
renterRevisionSig := types.TransactionSignature{
ParentID: crypto.Hash(initRevision.ParentID),
PublicKeyIndex: 0,
CoveredFields: types.CoveredFields{
FileContractRevisions: []uint64{0},
},
}
revisionTxn := types.Transaction{
FileContractRevisions: []types.FileContractRevision{initRevision},
TransactionSignatures: []types.TransactionSignature{renterRevisionSig},
}
encodedSig, err := crypto.SignHash(revisionTxn.SigHash(0), ourSK)
if err != nil {
return modules.RenterContract{}, modules.WriteNegotiationRejection(conn, errors.New("failed to sign revision transaction: "+err.Error()))
}
revisionTxn.TransactionSignatures[0].Signature = encodedSig[:]
示例7: FundTransaction
// FundTransaction adds siacoins to a transaction that the wallet knows how to
// spend. The exact amount of coins are always added, and this is achieved by
// creating two transactions. The first transaciton, the parent, spends a set
// of outputs that add up to at least the desired amount, and then creates a
// single output of the exact amount and a second refund output.
func (w *Wallet) FundTransaction(id string, amount types.Currency) (t types.Transaction, err error) {
counter := w.mu.Lock()
defer w.mu.Unlock(counter)
// Create a parent transaction and supply it with enough inputs to cover
// 'amount'.
parentTxn := types.Transaction{}
fundingOutputs, fundingTotal, err := w.findOutputs(amount)
if err != nil {
return
}
for _, output := range fundingOutputs {
output.age = w.age
key := w.keys[output.output.UnlockHash]
newInput := types.SiacoinInput{
ParentID: output.id,
UnlockConditions: key.unlockConditions,
}
parentTxn.SiacoinInputs = append(parentTxn.SiacoinInputs, newInput)
}
// Create and add the output that will be used to fund the standard
// transaction.
parentDest, parentSpendConds, err := w.coinAddress(false) // false indicates that the address should not be visible to the user
exactOutput := types.SiacoinOutput{
Value: amount,
UnlockHash: parentDest,
}
parentTxn.SiacoinOutputs = append(parentTxn.SiacoinOutputs, exactOutput)
// Create a refund output if needed.
if amount.Cmp(fundingTotal) != 0 {
var refundDest types.UnlockHash
refundDest, _, err = w.coinAddress(false) // false indicates that the address should not be visible to the user
if err != nil {
return
}
refundOutput := types.SiacoinOutput{
Value: fundingTotal.Sub(amount),
UnlockHash: refundDest,
}
parentTxn.SiacoinOutputs = append(parentTxn.SiacoinOutputs, refundOutput)
}
// Sign all of the inputs to the parent trancstion.
coveredFields := types.CoveredFields{WholeTransaction: true}
for _, input := range parentTxn.SiacoinInputs {
sig := types.TransactionSignature{
ParentID: crypto.Hash(input.ParentID),
CoveredFields: coveredFields,
PublicKeyIndex: 0,
}
parentTxn.TransactionSignatures = append(parentTxn.TransactionSignatures, sig)
// Hash the transaction according to the covered fields.
coinAddress := input.UnlockConditions.UnlockHash()
sigIndex := len(parentTxn.TransactionSignatures) - 1
secKey := w.keys[coinAddress].secretKey
sigHash := parentTxn.SigHash(sigIndex)
// Get the signature.
var encodedSig crypto.Signature
encodedSig, err = crypto.SignHash(sigHash, secKey)
if err != nil {
return
}
parentTxn.TransactionSignatures[sigIndex].Signature = types.Signature(encodedSig[:])
}
// Add the exact output to the wallet's knowledgebase before releasing the
// lock, to prevent the wallet from using the exact output elsewhere.
key := w.keys[parentSpendConds.UnlockHash()]
key.outputs[parentTxn.SiacoinOutputID(0)] = &knownOutput{
id: parentTxn.SiacoinOutputID(0),
output: exactOutput,
spendable: true,
age: w.age,
}
// Send the transaction to the transaction pool.
err = w.tpool.AcceptTransaction(parentTxn)
if err != nil {
return
}
// Get the transaction that was originally meant to be funded.
openTxn, exists := w.transactions[id]
if !exists {
err = ErrInvalidID
return
}
txn := openTxn.transaction
// Add the exact output.
//.........這裏部分代碼省略.........
示例8: rpcRevise
//.........這裏部分代碼省略.........
}
// 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")
}
// 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 {
return err
}
revTxn.TransactionSignatures[1].Signature = encodedSig[:]
// send the signed transaction
if err := encoding.WriteObject(conn, revTxn); err != nil {
return err
}
// append piece to file
if _, err := file.Write(piece); err != nil {
return err
}
// save updated obligation to disk
lockID = h.mu.Lock()
h.spaceRemaining -= int64(len(piece))
obligation.FileContract.RevisionNumber = rev.NewRevisionNumber
obligation.FileContract.FileSize = rev.NewFileSize
obligation.FileContract.FileMerkleRoot = rev.NewFileMerkleRoot
h.obligationsByID[obligation.ID] = obligation
heightObligations := h.obligationsByHeight[obligation.FileContract.WindowStart+StorageProofReorgDepth]
for i := range heightObligations {
if heightObligations[i].ID == obligation.ID {
heightObligations[i] = obligation
}
}
h.save()
h.mu.Unlock(lockID)
finalTxn = revTxn
}
return nil
}
示例9: verifyKeys
// verifyKeys checks a set of keys on disk to see that they can spend funds
// sent to their address.
func verifyKeys(uc types.UnlockConditions, folder string, keyname string) error {
keysRequired := uc.SignaturesRequired
totalKeys := uint64(len(uc.PublicKeys))
// Load the keys from disk back into memory, then verify that the keys on
// disk are able to sign outputs in transactions.
loadedKeys := make([]KeyPair, totalKeys)
for i := 0; i < len(loadedKeys); i++ {
err := encoding.ReadFile(filepath.Join(folder, keyname+"_Key"+strconv.Itoa(i)+FileExtension), &loadedKeys[i])
if err != nil {
return err
}
if loadedKeys[i].Header != FileHeader {
return ErrUnknownHeader
}
if loadedKeys[i].Version != FileVersion {
return ErrUnknownVersion
}
}
// Check that the keys can be used to spend transactions.
for _, loadedKey := range loadedKeys {
if loadedKey.UnlockConditions.UnlockHash() != uc.UnlockHash() {
return ErrCorruptedKey
}
}
// Create a transaction for the keys to sign.
txn := types.Transaction{
SiafundInputs: []types.SiafundInput{
types.SiafundInput{
UnlockConditions: loadedKeys[0].UnlockConditions,
},
},
}
// Loop through and sign the transaction multiple times. All keys will be
// used at least once by the time the loop terminates.
var i uint64
for i != totalKeys {
// i tracks which key is next to be used. If i + RequiredKeys results
// in going out-of-bounds, reduce i so that the last key will be used
// for the final signature.
if i+keysRequired > totalKeys {
i = totalKeys - keysRequired
}
var j uint64
for j < keysRequired {
txn.TransactionSignatures = append(txn.TransactionSignatures, types.TransactionSignature{
PublicKeyIndex: i,
CoveredFields: types.CoveredFields{WholeTransaction: true},
})
sigHash := txn.SigHash(int(j))
sig, err := crypto.SignHash(sigHash, loadedKeys[i].SecretKey)
if err != nil {
return err
}
txn.TransactionSignatures[j].Signature = sig[:]
i++
j++
}
// Check that the signature is valid.
err := txn.StandaloneValid(0)
if err != nil {
return err
}
// Delete all of the signatures for the next iteration.
txn.TransactionSignatures = nil
}
return nil
}
示例10: FormContract
//.........這裏部分代碼省略.........
// were added to the transaction
var newParents []types.Transaction
var newInputs []types.SiacoinInput
var newOutputs []types.SiacoinOutput
if err = encoding.ReadObject(conn, &newParents, types.BlockSizeLimit); err != nil {
return modules.RenterContract{}, errors.New("couldn't read the host's added parents: " + err.Error())
}
if err = encoding.ReadObject(conn, &newInputs, types.BlockSizeLimit); err != nil {
return modules.RenterContract{}, errors.New("couldn't read the host's added inputs: " + err.Error())
}
if err = encoding.ReadObject(conn, &newOutputs, types.BlockSizeLimit); err != nil {
return modules.RenterContract{}, errors.New("couldn't read the host's added outputs: " + err.Error())
}
// merge txnAdditions with txnSet
txnBuilder.AddParents(newParents)
for _, input := range newInputs {
txnBuilder.AddSiacoinInput(input)
}
for _, output := range newOutputs {
txnBuilder.AddSiacoinOutput(output)
}
// sign the txn
signedTxnSet, err := txnBuilder.Sign(true)
if err != nil {
return modules.RenterContract{}, modules.WriteNegotiationRejection(conn, errors.New("failed to sign transaction: "+err.Error()))
}
// calculate signatures added by the transaction builder
var addedSignatures []types.TransactionSignature
_, _, _, addedSignatureIndices := txnBuilder.ViewAdded()
for _, i := range addedSignatureIndices {
addedSignatures = append(addedSignatures, signedTxnSet[len(signedTxnSet)-1].TransactionSignatures[i])
}
// create initial (no-op) revision, transaction, and signature
initRevision := types.FileContractRevision{
ParentID: signedTxnSet[len(signedTxnSet)-1].FileContractID(0),
UnlockConditions: uc,
NewRevisionNumber: 1,
NewFileSize: fc.FileSize,
NewFileMerkleRoot: fc.FileMerkleRoot,
NewWindowStart: fc.WindowStart,
NewWindowEnd: fc.WindowEnd,
NewValidProofOutputs: fc.ValidProofOutputs,
NewMissedProofOutputs: fc.MissedProofOutputs,
NewUnlockHash: fc.UnlockHash,
}
renterRevisionSig := types.TransactionSignature{
ParentID: crypto.Hash(initRevision.ParentID),
PublicKeyIndex: 0,
CoveredFields: types.CoveredFields{
FileContractRevisions: []uint64{0},
},
}
revisionTxn := types.Transaction{
FileContractRevisions: []types.FileContractRevision{initRevision},
TransactionSignatures: []types.TransactionSignature{renterRevisionSig},
}
encodedSig, err := crypto.SignHash(revisionTxn.SigHash(0), ourSK)
if err != nil {
return modules.RenterContract{}, modules.WriteNegotiationRejection(conn, errors.New("failed to sign revision transaction: "+err.Error()))
}
revisionTxn.TransactionSignatures[0].Signature = encodedSig[:]
示例11: 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 {
//.........這裏部分代碼省略.........