github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/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/NebulousLabs/bolt"
    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  }