func (cw *ChainWatcher) ProcessConsensusChange(cc modules.ConsensusChange) {
	process := func(blocks []types.Block) (pcc ProcessedConsensusChange) {
		for _, block := range blocks {
			for _, txn := range block.Transactions {
				for j := range txn.FileContracts {
					pcc.Contracts = append(pcc.Contracts, txn.FileContractID(uint64(j)))
				}
				for _, fcr := range txn.FileContractRevisions {
					pcc.Revisions = append(pcc.Revisions, fcr.ParentID)
				}
				for _, sp := range txn.StorageProofs {
					pcc.Proofs = append(pcc.Proofs, sp.ParentID)
				}
			}
			pcc.BlockIDs = append(pcc.BlockIDs, block.ID())
		}
		return
	}
	reverted := process(cc.RevertedBlocks)
	applied := process(cc.AppliedBlocks)
	cw.contracts.ApplyConsensusChange(reverted, applied, cc.ID)
	select {
	case cw.watchChan <- struct{}{}:
	default:
	}
}
ProcessConsensusChange implements modules.ConsensusSetSubscriber.
package host
import (
	"crypto/ed25519"
	"encoding/binary"
	"errors"
	"math/bits"
	"strings"
	"go.sia.tech/siad/modules"
	"go.sia.tech/siad/types"
	"golang.org/x/crypto/blake2b"
	"lukechampine.com/us/merkle"
)
var (
	ErrMissingSiacoinOutput = errors.New("transaction spends a nonexisting siacoin output")
)
func ContractIsActionable(c Contract, currentHeight types.BlockHeight) bool {
	return c.FatalError == nil && (!c.FormationConfirmed ||
		(!c.FinalizationConfirmed && currentHeight >= c.FinalizationHeight && c.Revision.NewRevisionNumber > 1) ||
		(!c.ProofConfirmed && currentHeight >= c.ProofHeight && c.Revision.NewFileSize > 0))
}
func minFee(tp TransactionPool) types.Currency {
	_, max, err := tp.FeeEstimate()
	if err != nil {
		max = types.SiacoinPrecision.Div64(1e3)  
	}
	return max
}
type ChainWatcher struct {
	tpool     TransactionPool
	wallet    Wallet
	contracts ContractStore
	sectors   SectorStore
	watchChan chan struct{}
	stopChan  chan struct{}
}
type ProcessedConsensusChange struct {
	Contracts []types.FileContractID
	Revisions []types.FileContractID
	Proofs    []types.FileContractID
	BlockIDs  []types.BlockID
}