github.com/NebulousLabs/Sia@v1.3.7/modules/consensus/applytransaction.go (about) 1 package consensus 2 3 // applytransaction.go handles applying a transaction to the consensus set. 4 // There is an assumption that the transaction has already been verified. 5 6 import ( 7 "github.com/NebulousLabs/Sia/build" 8 "github.com/NebulousLabs/Sia/modules" 9 "github.com/NebulousLabs/Sia/types" 10 11 "github.com/coreos/bbolt" 12 ) 13 14 // applySiacoinInputs takes all of the siacoin inputs in a transaction and 15 // applies them to the state, updating the diffs in the processed block. 16 func applySiacoinInputs(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 17 // Remove all siacoin inputs from the unspent siacoin outputs list. 18 for _, sci := range t.SiacoinInputs { 19 sco, err := getSiacoinOutput(tx, sci.ParentID) 20 if build.DEBUG && err != nil { 21 panic(err) 22 } 23 scod := modules.SiacoinOutputDiff{ 24 Direction: modules.DiffRevert, 25 ID: sci.ParentID, 26 SiacoinOutput: sco, 27 } 28 pb.SiacoinOutputDiffs = append(pb.SiacoinOutputDiffs, scod) 29 commitSiacoinOutputDiff(tx, scod, modules.DiffApply) 30 } 31 } 32 33 // applySiacoinOutputs takes all of the siacoin outputs in a transaction and 34 // applies them to the state, updating the diffs in the processed block. 35 func applySiacoinOutputs(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 36 // Add all siacoin outputs to the unspent siacoin outputs list. 37 for i, sco := range t.SiacoinOutputs { 38 scoid := t.SiacoinOutputID(uint64(i)) 39 scod := modules.SiacoinOutputDiff{ 40 Direction: modules.DiffApply, 41 ID: scoid, 42 SiacoinOutput: sco, 43 } 44 pb.SiacoinOutputDiffs = append(pb.SiacoinOutputDiffs, scod) 45 commitSiacoinOutputDiff(tx, scod, modules.DiffApply) 46 } 47 } 48 49 // applyFileContracts iterates through all of the file contracts in a 50 // transaction and applies them to the state, updating the diffs in the proccesed 51 // block. 52 func applyFileContracts(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 53 for i, fc := range t.FileContracts { 54 fcid := t.FileContractID(uint64(i)) 55 fcd := modules.FileContractDiff{ 56 Direction: modules.DiffApply, 57 ID: fcid, 58 FileContract: fc, 59 } 60 pb.FileContractDiffs = append(pb.FileContractDiffs, fcd) 61 commitFileContractDiff(tx, fcd, modules.DiffApply) 62 63 // Get the portion of the contract that goes into the siafund pool and 64 // add it to the siafund pool. 65 sfp := getSiafundPool(tx) 66 sfpd := modules.SiafundPoolDiff{ 67 Direction: modules.DiffApply, 68 Previous: sfp, 69 Adjusted: sfp.Add(types.Tax(blockHeight(tx), fc.Payout)), 70 } 71 pb.SiafundPoolDiffs = append(pb.SiafundPoolDiffs, sfpd) 72 commitSiafundPoolDiff(tx, sfpd, modules.DiffApply) 73 } 74 } 75 76 // applyTxFileContractRevisions iterates through all of the file contract 77 // revisions in a transaction and applies them to the state, updating the diffs 78 // in the processed block. 79 func applyFileContractRevisions(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 80 for _, fcr := range t.FileContractRevisions { 81 fc, err := getFileContract(tx, fcr.ParentID) 82 if build.DEBUG && err != nil { 83 panic(err) 84 } 85 86 // Add the diff to delete the old file contract. 87 fcd := modules.FileContractDiff{ 88 Direction: modules.DiffRevert, 89 ID: fcr.ParentID, 90 FileContract: fc, 91 } 92 pb.FileContractDiffs = append(pb.FileContractDiffs, fcd) 93 commitFileContractDiff(tx, fcd, modules.DiffApply) 94 95 // Add the diff to add the revised file contract. 96 newFC := types.FileContract{ 97 FileSize: fcr.NewFileSize, 98 FileMerkleRoot: fcr.NewFileMerkleRoot, 99 WindowStart: fcr.NewWindowStart, 100 WindowEnd: fcr.NewWindowEnd, 101 Payout: fc.Payout, 102 ValidProofOutputs: fcr.NewValidProofOutputs, 103 MissedProofOutputs: fcr.NewMissedProofOutputs, 104 UnlockHash: fcr.NewUnlockHash, 105 RevisionNumber: fcr.NewRevisionNumber, 106 } 107 fcd = modules.FileContractDiff{ 108 Direction: modules.DiffApply, 109 ID: fcr.ParentID, 110 FileContract: newFC, 111 } 112 pb.FileContractDiffs = append(pb.FileContractDiffs, fcd) 113 commitFileContractDiff(tx, fcd, modules.DiffApply) 114 } 115 } 116 117 // applyTxStorageProofs iterates through all of the storage proofs in a 118 // transaction and applies them to the state, updating the diffs in the processed 119 // block. 120 func applyStorageProofs(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 121 for _, sp := range t.StorageProofs { 122 fc, err := getFileContract(tx, sp.ParentID) 123 if build.DEBUG && err != nil { 124 panic(err) 125 } 126 127 // Add all of the outputs in the ValidProofOutputs of the contract. 128 for i, vpo := range fc.ValidProofOutputs { 129 spoid := sp.ParentID.StorageProofOutputID(types.ProofValid, uint64(i)) 130 dscod := modules.DelayedSiacoinOutputDiff{ 131 Direction: modules.DiffApply, 132 ID: spoid, 133 SiacoinOutput: vpo, 134 MaturityHeight: pb.Height + types.MaturityDelay, 135 } 136 pb.DelayedSiacoinOutputDiffs = append(pb.DelayedSiacoinOutputDiffs, dscod) 137 commitDelayedSiacoinOutputDiff(tx, dscod, modules.DiffApply) 138 } 139 140 fcd := modules.FileContractDiff{ 141 Direction: modules.DiffRevert, 142 ID: sp.ParentID, 143 FileContract: fc, 144 } 145 pb.FileContractDiffs = append(pb.FileContractDiffs, fcd) 146 commitFileContractDiff(tx, fcd, modules.DiffApply) 147 } 148 } 149 150 // applyTxSiafundInputs takes all of the siafund inputs in a transaction and 151 // applies them to the state, updating the diffs in the processed block. 152 func applySiafundInputs(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 153 for _, sfi := range t.SiafundInputs { 154 // Calculate the volume of siacoins to put in the claim output. 155 sfo, err := getSiafundOutput(tx, sfi.ParentID) 156 if build.DEBUG && err != nil { 157 panic(err) 158 } 159 claimPortion := getSiafundPool(tx).Sub(sfo.ClaimStart).Div(types.SiafundCount).Mul(sfo.Value) 160 161 // Add the claim output to the delayed set of outputs. 162 sco := types.SiacoinOutput{ 163 Value: claimPortion, 164 UnlockHash: sfi.ClaimUnlockHash, 165 } 166 sfoid := sfi.ParentID.SiaClaimOutputID() 167 dscod := modules.DelayedSiacoinOutputDiff{ 168 Direction: modules.DiffApply, 169 ID: sfoid, 170 SiacoinOutput: sco, 171 MaturityHeight: pb.Height + types.MaturityDelay, 172 } 173 pb.DelayedSiacoinOutputDiffs = append(pb.DelayedSiacoinOutputDiffs, dscod) 174 commitDelayedSiacoinOutputDiff(tx, dscod, modules.DiffApply) 175 176 // Create the siafund output diff and remove the output from the 177 // consensus set. 178 sfod := modules.SiafundOutputDiff{ 179 Direction: modules.DiffRevert, 180 ID: sfi.ParentID, 181 SiafundOutput: sfo, 182 } 183 pb.SiafundOutputDiffs = append(pb.SiafundOutputDiffs, sfod) 184 commitSiafundOutputDiff(tx, sfod, modules.DiffApply) 185 } 186 } 187 188 // applySiafundOutput applies a siafund output to the consensus set. 189 func applySiafundOutputs(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 190 for i, sfo := range t.SiafundOutputs { 191 sfoid := t.SiafundOutputID(uint64(i)) 192 sfo.ClaimStart = getSiafundPool(tx) 193 sfod := modules.SiafundOutputDiff{ 194 Direction: modules.DiffApply, 195 ID: sfoid, 196 SiafundOutput: sfo, 197 } 198 pb.SiafundOutputDiffs = append(pb.SiafundOutputDiffs, sfod) 199 commitSiafundOutputDiff(tx, sfod, modules.DiffApply) 200 } 201 } 202 203 // applyTransaction applies the contents of a transaction to the ConsensusSet. 204 // This produces a set of diffs, which are stored in the blockNode containing 205 // the transaction. No verification is done by this function. 206 func applyTransaction(tx *bolt.Tx, pb *processedBlock, t types.Transaction) { 207 applySiacoinInputs(tx, pb, t) 208 applySiacoinOutputs(tx, pb, t) 209 applyFileContracts(tx, pb, t) 210 applyFileContractRevisions(tx, pb, t) 211 applyStorageProofs(tx, pb, t) 212 applySiafundInputs(tx, pb, t) 213 applySiafundOutputs(tx, pb, t) 214 }