func (u updateUploadRevision) apply(data *journalPersist) {
	if len(u.NewRevisionTxn.FileContractRevisions) == 0 {
		build.Critical("updateUploadRevision is missing its FileContractRevision")
		return
	}
	rev := u.NewRevisionTxn.FileContractRevisions[0]
	c := data.Contracts[rev.ParentID.String()]
	c.LastRevisionTxn = u.NewRevisionTxn
	if u.NewSectorIndex == len(c.MerkleRoots) {
		c.MerkleRoots = append(c.MerkleRoots, u.NewSectorRoot)
	} else if u.NewSectorIndex < len(c.MerkleRoots) {
		c.MerkleRoots[u.NewSectorIndex] = u.NewSectorRoot
	} else {
	}
	c.UploadSpending = u.NewUploadSpending
	c.StorageSpending = u.NewStorageSpending
	data.Contracts[rev.ParentID.String()] = c
}
apply sets the LastRevision, LastRevisionTxn, UploadSpending, and
DownloadSpending fields of the contract being revised. It also adds the new
Merkle root to the contract's Merkle root set.
package contractor
import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/renter/proto"
	"github.com/NebulousLabs/Sia/persist"
	"github.com/NebulousLabs/Sia/types"
)
var journalMeta = persist.Metadata{
	Header:  "Contractor Journal",
	Version: "1.1.1",
}
type journalPersist struct {
	Allowance       modules.Allowance                   `json:"allowance"`
	BlockHeight     types.BlockHeight                   `json:"blockheight"`
	CachedRevisions map[string]proto.V130CachedRevision `json:"cachedrevisions"`
	Contracts       map[string]proto.V130Contract       `json:"contracts"`
	CurrentPeriod   types.BlockHeight                   `json:"currentperiod"`
	LastChange      modules.ConsensusChangeID           `json:"lastchange"`
	OldContracts    []proto.V130Contract                `json:"oldcontracts"`
	RenewedIDs      map[string]string                   `json:"renewedids"`
}
type journal struct {
	f        *os.File
	filename string
}
func (j *journal) update(us updateSet) error {
	if err := json.NewEncoder(j.f).Encode(us); err != nil {
		return err
	}
	return j.f.Sync()
}
func (j *journal) Close() error {
	return j.f.Close()
}
func openJournal(filename string, data *journalPersist) (*journal, error) {
	f, err := os.OpenFile(filename, os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}
	dec := json.NewDecoder(f)
	var meta persist.Metadata
	if err = dec.Decode(&meta); err != nil {
		return nil, err
	} else if meta.Header != journalMeta.Header {
		return nil, fmt.Errorf("expected header %q, got %q", journalMeta.Header, meta.Header)
	} else if meta.Version != journalMeta.Version {
		return nil, fmt.Errorf("journal version (%s) is incompatible with the current version (%s)", meta.Version, journalMeta.Version)
	}
	if err = dec.Decode(data); err != nil {
		return nil, err
	}
	if data.CachedRevisions == nil {
		data.CachedRevisions = map[string]proto.V130CachedRevision{}
	}
	if data.Contracts == nil {
		data.Contracts = map[string]proto.V130Contract{}
	}
	if data.RenewedIDs == nil {
		data.RenewedIDs = map[string]string{}
	}
	for {
		var set updateSet
		if err = dec.Decode(&set); err == io.EOF || err == io.ErrUnexpectedEOF {
			break
		} else if err != nil {
			continue
		}
		for _, u := range set {
			u.apply(data)
		}
	}
	return &journal{
		f:        f,
		filename: filename,
	}, nil
}
type journalUpdate interface {
	apply(*journalPersist)
}
type marshaledUpdate struct {
	Type     string          `json:"type"`
	Data     json.RawMessage `json:"data"`
	Checksum crypto.Hash     `json:"checksum"`
}
type updateSet []journalUpdate
func (set *updateSet) UnmarshalJSON(b []byte) error {
	var marshaledSet []marshaledUpdate
	if err := json.Unmarshal(b, &marshaledSet); err != nil {
		return err
	}
	for _, u := range marshaledSet {
		if crypto.HashBytes(u.Data) != u.Checksum {
			return errors.New("bad checksum")
		}
		var err error
		switch u.Type {
		case "uploadRevision":
			var ur updateUploadRevision
			err = json.Unmarshal(u.Data, &ur)
			*set = append(*set, ur)
		case "downloadRevision":
			var dr updateDownloadRevision
			err = json.Unmarshal(u.Data, &dr)
			*set = append(*set, dr)
		case "cachedUploadRevision":
			var cur updateCachedUploadRevision
			err = json.Unmarshal(u.Data, &cur)
			*set = append(*set, cur)
		case "cachedDownloadRevision":
			var cdr updateCachedDownloadRevision
			err = json.Unmarshal(u.Data, &cdr)
			*set = append(*set, cdr)
		}
		if err != nil {
			return err
		}
	}
	return nil
}
type updateUploadRevision struct {
	NewRevisionTxn     types.Transaction `json:"newrevisiontxn"`
	NewSectorRoot      crypto.Hash       `json:"newsectorroot"`
	NewSectorIndex     int               `json:"newsectorindex"`
	NewUploadSpending  types.Currency    `json:"newuploadspending"`
	NewStorageSpending types.Currency    `json:"newstoragespending"`
}