func (sts *StateTransferState) Stop() {
outer:
	for {
		select {
		case sts.blockThreadExit <- struct{}{}:
		case sts.stateThreadExit <- struct{}{}:
		default:
			break outer
		}
	}
}
This will send a signal to any running threads to stop, regardless of whether they are stopped
It will never block, and if called before threads start, they will exit at startup
Attempting to start threads after this call may fail once
package statetransfer
import (
	"bytes"
	"fmt"
	"math/rand"
	"sort"
	"sync"
	"time"
	"github.com/op/go-logging"
	"github.com/openblockchain/obc-peer/openchain/consensus"
	"github.com/openblockchain/obc-peer/openchain/ledger/statemgmt"
	"github.com/openblockchain/obc-peer/protos"
	"github.com/spf13/viper"
)
var logger *logging.Logger  
func init() {
	logger = logging.MustGetLogger("consensus/statetransfer")
}
type Listener interface {
	Initiated()                                                    
	Errored(uint64, []byte, []*protos.PeerID, interface{}, error)  
	Completed(uint64, []byte, []*protos.PeerID, interface{})       
}
type ProtoListener struct {
	InitiatedImpl func()
	ErroredImpl   func(uint64, []byte, []*protos.PeerID, interface{}, error)
	CompletedImpl func(uint64, []byte, []*protos.PeerID, interface{})
}
func (pstl *ProtoListener) Initiated() {
	if nil != pstl.InitiatedImpl {
		pstl.InitiatedImpl()
	}
}
func (pstl *ProtoListener) Errored(bn uint64, bh []byte, pids []*protos.PeerID, m interface{}, e error) {
	if nil != pstl.ErroredImpl {
		pstl.ErroredImpl(bn, bh, pids, m, e)
	}
}
func (pstl *ProtoListener) Completed(bn uint64, bh []byte, pids []*protos.PeerID, m interface{}) {
	if nil != pstl.CompletedImpl {
		pstl.CompletedImpl(bn, bh, pids, m)
	}
}
type StateTransferState struct {
	ledger consensus.LedgerStack
	asynchronousTransferInProgress bool  
	id *protos.PeerID  
	stateValid bool  
	defaultPeerIDs []*protos.PeerID  
	blockVerifyChunkSize uint64         
	validBlockRanges     []*blockRange  
	RecoverDamage        bool           
	initiateStateSync chan *syncMark        
	blockHashReceiver chan *blockHashReply  
	blockSyncReq      chan *blockSyncReq    
	blockThreadExit chan struct{}  
	stateThreadExit chan struct{}  
	BlockRequestTimeout         time.Duration  
	StateDeltaRequestTimeout    time.Duration  
	StateSnapshotRequestTimeout time.Duration  
	stateTransferListeners     []Listener   
	stateTransferListenersLock *sync.Mutex  
}
func (sts *StateTransferState) BlockingAddTarget(blockNumber uint64, blockHash []byte, peerIDs []*protos.PeerID) error {
	result := make(chan error)
	listener := struct{ ProtoListener }{}
	listener.ErroredImpl = func(bn uint64, bh []byte, pids []*protos.PeerID, md interface{}, err error) {
		result <- err
	}
	listener.CompletedImpl = func(bn uint64, bh []byte, pids []*protos.PeerID, md interface{}) {
		result <- nil
	}
	sts.RegisterListener(&listener)
	defer sts.UnregisterListener(&listener)
	sts.AddTarget(blockNumber, blockHash, peerIDs, nil)
	return <-result
}
func (sts *StateTransferState) BlockingUntilSuccessAddTarget(blockNumber uint64, blockHash []byte, peerIDs []*protos.PeerID) {
	result := make(chan error)
	listener := struct{ ProtoListener }{}
	listener.CompletedImpl = func(bn uint64, bh []byte, pids []*protos.PeerID, md interface{}) {
		result <- nil
	}
	sts.RegisterListener(&listener)
	defer sts.UnregisterListener(&listener)
	sts.AddTarget(blockNumber, blockHash, peerIDs, nil)
	<-result
}
func (sts *StateTransferState) Initiate(peerIDs []*protos.PeerID) {
	select {
	case sts.initiateStateSync <- &syncMark{
		blockNumber: 0,
		peerIDs:     peerIDs,
	}:
	default:
	}
	sts.asynchronousTransferInProgress = true  
}
func (sts *StateTransferState) AddTarget(blockNumber uint64, blockHash []byte, peerIDs []*protos.PeerID, metadata interface{}) {
	logger.Debug("%v informed of a new block hash for block number %d with peers %v", sts.id, blockNumber, peerIDs)
	blockHashReply := &blockHashReply{
		syncMark: syncMark{
			blockNumber: blockNumber,
			peerIDs:     peerIDs,
		},
		blockHash: blockHash,
		metadata:  metadata,
	}
	for {
		select {
		case sts.blockHashReceiver <- blockHashReply:
			logger.Debug("%v block hash reply for block %d queued for state transfer", sts.id, blockNumber)
			return
		case lastHash := <-sts.blockHashReceiver:
			logger.Debug("%v block hash reply for block %d discarded", sts.id, lastHash.blockNumber)
		}
	}
}
func (sts *StateTransferState) RegisterListener(listener Listener) {
	sts.stateTransferListenersLock.Lock()
	defer func() {
		sts.stateTransferListenersLock.Unlock()
	}()
	sts.stateTransferListeners = append(sts.stateTransferListeners, listener)
}
func (sts *StateTransferState) UnregisterListener(listener Listener) {
	sts.stateTransferListenersLock.Lock()
	defer func() {
		sts.stateTransferListenersLock.Unlock()
	}()
	for i, l := range sts.stateTransferListeners {
		if listener == l {
			for j := i + 1; j < len(sts.stateTransferListeners); j++ {
				sts.stateTransferListeners[j-1] = sts.stateTransferListeners[j]
			}
			sts.stateTransferListeners = sts.stateTransferListeners[:len(sts.stateTransferListeners)-1]
			return
		}
	}
}
func (sts *StateTransferState) CompletionChannel() chan struct{} {
	complete := make(chan struct{}, 1)
	listener := struct{ ProtoListener }{}
	listener.CompletedImpl = func(bn uint64, bh []byte, pids []*protos.PeerID, md interface{}) {
		select {
		case complete <- struct{}{}:
		default:
		}
	}
	sts.RegisterListener(&listener)
	return complete
}
func (sts *StateTransferState) InProgress() bool {
	return sts.asynchronousTransferInProgress
}
func (sts *StateTransferState) InvalidateState() {
	sts.stateValid = false
}