// GenerateRevocation generates a revocation (SSRtx), signs it, and // submits it by SendRawTransaction. It also stores a record of it // in the local database. func (s *StakeStore) generateRevocation(ns walletdb.ReadWriteBucket, waddrmgrNs walletdb.ReadBucket, blockHash *chainhash.Hash, height int64, sstxHash *chainhash.Hash, allowHighFees bool) (*StakeNotification, error) { // 1. Fetch the SStx, then calculate all the values we'll need later for // the generation of the SSRtx tx outputs. sstxRecord, err := s.getSStx(ns, sstxHash) if err != nil { return nil, err } sstx := sstxRecord.tx // Store the sstx pubkeyhashes and amounts as found in the transaction // outputs. // TODO Get information on the allowable fee range for the revocation // and check to make sure we don't overflow that. sstxPayTypes, sstxPkhs, sstxAmts, _, _, _ := stake.TxSStxStakeOutputInfo(sstx.MsgTx()) ssrtxCalcAmts := stake.CalculateRewards(sstxAmts, sstx.MsgTx().TxOut[0].Value, int64(0)) // Calculate the fee to use for this revocation based on the fee // per KB that is standard for mainnet. revocationSizeEst := estimateSSRtxTxSize(1, len(sstxPkhs)) revocationFee := txrules.FeeForSerializeSize(revocationFeePerKB, revocationSizeEst) // 2. Add the only input. msgTx := wire.NewMsgTx() // SStx tagged output as an OutPoint; reference this as // the only input. prevOut := wire.NewOutPoint(sstxHash, 0, // Index 0 1) // Tree stake txIn := wire.NewTxIn(prevOut, []byte{}) msgTx.AddTxIn(txIn) // 3. Add all the OP_SSRTX tagged outputs. // Add all the SSRtx-tagged transaction outputs to the transaction after // performing some validity checks. feeAdded := false for i, sstxPkh := range sstxPkhs { // Create a new script which pays to the provided address specified in // the original ticket tx. var ssrtxOutScript []byte switch sstxPayTypes[i] { case false: // P2PKH ssrtxOutScript, err = txscript.PayToSSRtxPKHDirect(sstxPkh) if err != nil { return nil, err } case true: // P2SH ssrtxOutScript, err = txscript.PayToSSRtxSHDirect(sstxPkh) if err != nil { return nil, err } } // Add a fee from an output that has enough. amt := ssrtxCalcAmts[i] if !feeAdded && ssrtxCalcAmts[i] >= int64(revocationFee) { amt -= int64(revocationFee) feeAdded = true } // Add the txout to our SSRtx tx. txOut := wire.NewTxOut(amt, ssrtxOutScript) msgTx.AddTxOut(txOut) } // Check to make sure our SSRtx was created correctly. _, err = stake.IsSSRtx(msgTx) if err != nil { return nil, err } // Sign the transaction. err = s.SignVRTransaction(waddrmgrNs, msgTx, sstx, false) if err != nil { return nil, err } // Store the information about the SSRtx. hash := msgTx.TxSha() err = s.insertSSRtx(ns, blockHash, height, &hash, sstx.Sha()) if err != nil { return nil, err } // Send the transaction. ssrtxSha, err := s.chainSvr.SendRawTransaction(msgTx, allowHighFees) if err != nil { return nil, err } log.Debugf("Generated SSRtx %v. The ticket used to "+ "generate the SSRtx was %v.", ssrtxSha, sstx.Sha()) // Generate a notification to return. ntfn := &StakeNotification{ TxType: int8(stake.TxTypeSSRtx), TxHash: *ssrtxSha, BlockHash: chainhash.Hash{}, Height: 0, Amount: 0, SStxIn: *sstx.Sha(), VoteBits: 0, } return ntfn, nil }
// GenerateRevocation generates a revocation (SSRtx), signs it, and // submits it by SendRawTransaction. It also stores a record of it // in the local database. func (s *StakeStore) generateRevocation(blockHash *chainhash.Hash, height int64, sstxHash *chainhash.Hash) (*StakeNotification, error) { var revocationFee int64 switch { case s.Params == &chaincfg.MainNetParams: revocationFee = revocationFeeMainNet case s.Params == &chaincfg.TestNetParams: revocationFee = revocationFeeTestNet default: revocationFee = revocationFeeTestNet } // 1. Fetch the SStx, then calculate all the values we'll need later for // the generation of the SSRtx tx outputs. sstxRecord, err := s.getSStx(sstxHash) if err != nil { return nil, err } sstx := sstxRecord.tx // Store the sstx pubkeyhashes and amounts as found in the transaction // outputs. // TODO Get information on the allowable fee range for the revocation // and check to make sure we don't overflow that. sstxPayTypes, sstxPkhs, sstxAmts, _, _, _ := stake.GetSStxStakeOutputInfo(sstx) ssrtxCalcAmts := stake.GetStakeRewards(sstxAmts, sstx.MsgTx().TxOut[0].Value, int64(0)) // 2. Add the only input. msgTx := wire.NewMsgTx() // SStx tagged output as an OutPoint; reference this as // the only input. prevOut := wire.NewOutPoint(sstxHash, 0, // Index 0 1) // Tree stake txIn := wire.NewTxIn(prevOut, []byte{}) msgTx.AddTxIn(txIn) // 3. Add all the OP_SSRTX tagged outputs. // Add all the SSRtx-tagged transaction outputs to the transaction after // performing some validity checks. feeAdded := false for i, sstxPkh := range sstxPkhs { // Create a new script which pays to the provided address specified in // the original ticket tx. var ssrtxOutScript []byte switch sstxPayTypes[i] { case false: // P2PKH ssrtxOutScript, err = txscript.PayToSSRtxPKHDirect(sstxPkh) if err != nil { return nil, err } case true: // P2SH ssrtxOutScript, err = txscript.PayToSSRtxSHDirect(sstxPkh) if err != nil { return nil, err } } // Add a fee from an output that has enough. amt := ssrtxCalcAmts[i] if !feeAdded && ssrtxCalcAmts[i] >= revocationFee { amt -= revocationFee feeAdded = true } // Add the txout to our SSRtx tx. txOut := wire.NewTxOut(amt, ssrtxOutScript) msgTx.AddTxOut(txOut) } // Check to make sure our SSRtx was created correctly. ssrtxTx := dcrutil.NewTx(msgTx) ssrtxTx.SetTree(dcrutil.TxTreeStake) _, err = stake.IsSSRtx(ssrtxTx) if err != nil { return nil, err } // Sign the transaction. err = s.SignVRTransaction(msgTx, sstx, false) if err != nil { return nil, err } // Send the transaction. ssrtxSha, err := s.chainSvr.SendRawTransaction(msgTx, false) if err != nil { return nil, err } // Store the information about the SSRtx. err = s.insertSSRtx(blockHash, height, ssrtxSha, sstx.Sha()) if err != nil { return nil, err } log.Debugf("Generated SSRtx %v. "+ "The ticket used to generate the SSRtx was %v.", ssrtxSha, sstx.Sha()) // Generate a notification to return. ntfn := &StakeNotification{ TxType: int8(stake.TxTypeSSRtx), TxHash: *ssrtxSha, BlockHash: chainhash.Hash{}, Height: 0, Amount: 0, SStxIn: *sstx.Sha(), VoteBits: 0, } return ntfn, nil }