// SignTransaction signs the transaction, then deletes the transaction from the // wallet's internal memory, then returns the transaction. func (w *Wallet) SignTransaction(id string, wholeTransaction bool) (txn types.Transaction, err error) { counter := w.mu.Lock() defer w.mu.Unlock(counter) // Fetch the transaction. openTxn, exists := w.transactions[id] if !exists { err = ErrInvalidID return } txn = *openTxn.transaction // Get the coveredfields struct. var coveredFields types.CoveredFields if wholeTransaction { coveredFields = types.CoveredFields{WholeTransaction: true} } else { for i := range txn.MinerFees { coveredFields.MinerFees = append(coveredFields.MinerFees, uint64(i)) } for i := range txn.SiacoinInputs { coveredFields.SiacoinInputs = append(coveredFields.SiacoinInputs, uint64(i)) } for i := range txn.SiacoinOutputs { coveredFields.SiacoinOutputs = append(coveredFields.SiacoinOutputs, uint64(i)) } for i := range txn.FileContracts { coveredFields.FileContracts = append(coveredFields.FileContracts, uint64(i)) } for i := range txn.StorageProofs { coveredFields.StorageProofs = append(coveredFields.StorageProofs, uint64(i)) } for i := range txn.ArbitraryData { coveredFields.ArbitraryData = append(coveredFields.ArbitraryData, uint64(i)) } for i := range txn.TransactionSignatures { coveredFields.TransactionSignatures = append(coveredFields.TransactionSignatures, uint64(i)) } } // For each input in the transaction that we added, provide a signature. for _, inputIndex := range openTxn.inputs { input := txn.SiacoinInputs[inputIndex] sig := types.TransactionSignature{ ParentID: crypto.Hash(input.ParentID), CoveredFields: coveredFields, PublicKeyIndex: 0, } txn.TransactionSignatures = append(txn.TransactionSignatures, sig) // Hash the transaction according to the covered fields. coinAddress := input.UnlockConditions.UnlockHash() sigIndex := len(txn.TransactionSignatures) - 1 secKey := w.keys[coinAddress].secretKey sigHash := txn.SigHash(sigIndex) // Get the signature. var encodedSig crypto.Signature encodedSig, err = crypto.SignHash(sigHash, secKey) if err != nil { return } txn.TransactionSignatures[sigIndex].Signature = types.Signature(encodedSig[:]) } // Delete the open transaction. delete(w.transactions, id) return }
// Sign will sign any inputs added by 'FundSiacoins' or 'FundSiafunds' and // return a transaction set that contains all parents prepended to the // transaction. If more fields need to be added, a new transaction builder will // need to be created. // // If the whole transaction flag is set to true, then the whole transaction // flag will be set in the covered fields object. If the whole transaction flag // is set to false, then the covered fields object will cover all fields that // have already been added to the transaction, but will also leave room for // more fields to be added. // // Sign should not be called more than once. If, for some reason, there is an // error while calling Sign, the builder should be dropped. func (tb *transactionBuilder) Sign(wholeTransaction bool) ([]types.Transaction, error) { if tb.signed { return nil, errBuilderAlreadySigned } // Create the coveredfields struct. var coveredFields types.CoveredFields if wholeTransaction { coveredFields = types.CoveredFields{WholeTransaction: true} } else { for i := range tb.transaction.MinerFees { coveredFields.MinerFees = append(coveredFields.MinerFees, uint64(i)) } for i := range tb.transaction.SiacoinInputs { coveredFields.SiacoinInputs = append(coveredFields.SiacoinInputs, uint64(i)) } for i := range tb.transaction.SiacoinOutputs { coveredFields.SiacoinOutputs = append(coveredFields.SiacoinOutputs, uint64(i)) } for i := range tb.transaction.FileContracts { coveredFields.FileContracts = append(coveredFields.FileContracts, uint64(i)) } for i := range tb.transaction.FileContractRevisions { coveredFields.FileContractRevisions = append(coveredFields.FileContractRevisions, uint64(i)) } for i := range tb.transaction.StorageProofs { coveredFields.StorageProofs = append(coveredFields.StorageProofs, uint64(i)) } for i := range tb.transaction.SiafundInputs { coveredFields.SiafundInputs = append(coveredFields.SiafundInputs, uint64(i)) } for i := range tb.transaction.SiafundOutputs { coveredFields.SiafundOutputs = append(coveredFields.SiafundOutputs, uint64(i)) } for i := range tb.transaction.ArbitraryData { coveredFields.ArbitraryData = append(coveredFields.ArbitraryData, uint64(i)) } } // TransactionSignatures don't get covered by the 'WholeTransaction' flag, // and must be covered manually. for i := range tb.transaction.TransactionSignatures { coveredFields.TransactionSignatures = append(coveredFields.TransactionSignatures, uint64(i)) } // For each siacoin input in the transaction that we added, provide a // signature. tb.wallet.mu.Lock() defer tb.wallet.mu.Unlock() for _, inputIndex := range tb.siacoinInputs { input := tb.transaction.SiacoinInputs[inputIndex] key := tb.wallet.keys[input.UnlockConditions.UnlockHash()] newSigIndices, err := addSignatures(&tb.transaction, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key) if err != nil { return nil, err } tb.transactionSignatures = append(tb.transactionSignatures, newSigIndices...) tb.signed = true // Signed is set to true after one successful signature to indicate that future signings can cause issues. } for _, inputIndex := range tb.siafundInputs { input := tb.transaction.SiafundInputs[inputIndex] key := tb.wallet.keys[input.UnlockConditions.UnlockHash()] newSigIndices, err := addSignatures(&tb.transaction, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key) if err != nil { return nil, err } tb.transactionSignatures = append(tb.transactionSignatures, newSigIndices...) tb.signed = true // Signed is set to true after one successful signature to indicate that future signings can cause issues. } // Get the transaction set and delete the transaction from the registry. txnSet := append(tb.parents, tb.transaction) return txnSet, nil }
// Sign will sign any inputs added by 'FundSiacoins' or 'FundSiafunds' and // return a transaction set that contains all parents prepended to the // transaction. If more fields need to be added, a new transaction builder will // need to be created. // // If the whole transaction flag is set to true, then the whole transaction // flag will be set in the covered fields object. If the whole transaction flag // is set to false, then the covered fields object will cover all fields that // have already been added to the transaction, but will also leave room for // more fields to be added. func (tb *transactionBuilder) Sign(wholeTransaction bool) ([]types.Transaction, error) { // Create the coveredfields struct. txn := tb.transaction var coveredFields types.CoveredFields if wholeTransaction { coveredFields = types.CoveredFields{WholeTransaction: true} } else { for i := range txn.MinerFees { coveredFields.MinerFees = append(coveredFields.MinerFees, uint64(i)) } for i := range txn.SiacoinInputs { coveredFields.SiacoinInputs = append(coveredFields.SiacoinInputs, uint64(i)) } for i := range txn.SiacoinOutputs { coveredFields.SiacoinOutputs = append(coveredFields.SiacoinOutputs, uint64(i)) } for i := range txn.FileContracts { coveredFields.FileContracts = append(coveredFields.FileContracts, uint64(i)) } for i := range txn.FileContractRevisions { coveredFields.FileContractRevisions = append(coveredFields.FileContractRevisions, uint64(i)) } for i := range txn.StorageProofs { coveredFields.StorageProofs = append(coveredFields.StorageProofs, uint64(i)) } for i := range txn.SiafundInputs { coveredFields.SiafundInputs = append(coveredFields.SiafundInputs, uint64(i)) } for i := range txn.SiafundOutputs { coveredFields.SiafundOutputs = append(coveredFields.SiafundOutputs, uint64(i)) } for i := range txn.ArbitraryData { coveredFields.ArbitraryData = append(coveredFields.ArbitraryData, uint64(i)) } } // TransactionSignatures don't get covered by the 'WholeTransaction' flag, // and must be covered manually. for i := range txn.TransactionSignatures { coveredFields.TransactionSignatures = append(coveredFields.TransactionSignatures, uint64(i)) } // For each siacoin input in the transaction that we added, provide a // signature. lockID := tb.wallet.mu.Lock() defer tb.wallet.mu.Unlock(lockID) for _, inputIndex := range tb.siacoinInputs { input := txn.SiacoinInputs[inputIndex] key := tb.wallet.keys[input.UnlockConditions.UnlockHash()] err := addSignatures(&txn, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key) if err != nil { return nil, err } } for _, inputIndex := range tb.siafundInputs { input := txn.SiafundInputs[inputIndex] key := tb.wallet.keys[input.UnlockConditions.UnlockHash()] err := addSignatures(&txn, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key) if err != nil { return nil, err } } // Get the transaction set and delete the transaction from the registry. txnSet := append(tb.parents, txn) return txnSet, nil }