func (view *KeyViewpoint) ProcessAdminOuts(tx *provautil.Tx, blockHeight uint32) {
	threadInt, adminOutputs := txscript.GetAdminDetails(tx)
	if threadInt < 0 {
		return  
	}
	if provautil.ThreadID(threadInt) == provautil.IssueThread {
		isDestruction := len(tx.MsgTx().TxIn) > 1
		if isDestruction {
			for i := 0; i < len(adminOutputs); i++ {
				scriptType := txscript.TypeOfScript(adminOutputs[i])
				if scriptType == txscript.NullDataTy {
					view.totalSupply -= uint64(tx.MsgTx().TxOut[i+1].Value)
				}
			}
		} else {
			for i := 1; i < len(tx.MsgTx().TxOut); i++ {
				view.totalSupply += uint64(tx.MsgTx().TxOut[i].Value)
			}
		}
		view.threadTips[provautil.IssueThread] = wire.NewOutPoint(tx.Hash(), 0)
		return
	}
	for i := 0; i < len(adminOutputs); i++ {
		isAddOp, keySetType, pubKey,
			keyID := txscript.ExtractAdminOpData(adminOutputs[i])
		view.applyAdminOp(isAddOp, keySetType, pubKey, keyID)
	}
	threadId := provautil.ThreadID(threadInt)
	view.threadTips[threadId] = wire.NewOutPoint(tx.Hash(), 0)
}
ProcessAdminOuts finds admin transactions and executes all ops in it.
This function is called after the validity of the transaction has been
verified.
package blockchain
import (
	"bytes"
	"github.com/bitgo/prova/btcec"
	"github.com/bitgo/prova/provautil"
	"github.com/bitgo/prova/txscript"
	"github.com/bitgo/prova/wire"
)
type KeyViewpoint struct {
	threadTips   map[provautil.ThreadID]*wire.OutPoint
	lastKeyID    btcec.KeyID
	totalSupply  uint64
	adminKeySets map[btcec.KeySetType]btcec.PublicKeySet
	aspKeyIdMap  btcec.KeyIdMap
}
func (view *KeyViewpoint) ThreadTips() map[provautil.ThreadID]*wire.OutPoint {
	return view.threadTips
}
func (view *KeyViewpoint) SetThreadTips(
	threadTips map[provautil.ThreadID]*wire.OutPoint) {
	view.threadTips = provautil.CopyThreadTips(threadTips)
}
func (view *KeyViewpoint) LastKeyID() btcec.KeyID {
	return view.lastKeyID
}
func (view *KeyViewpoint) SetLastKeyID(lastKeyID btcec.KeyID) {
	view.lastKeyID = lastKeyID
}
func (view *KeyViewpoint) TotalSupply() uint64 {
	return view.totalSupply
}
func (view *KeyViewpoint) SetTotalSupply(totalSupply uint64) {
	view.totalSupply = totalSupply
}
func (view *KeyViewpoint) SetKeys(keys map[btcec.KeySetType]btcec.PublicKeySet) {
	if keys != nil {
		view.adminKeySets = btcec.DeepCopy(keys)
	}
}
func (view *KeyViewpoint) Keys() map[btcec.KeySetType]btcec.PublicKeySet {
	return view.adminKeySets
}
func (view *KeyViewpoint) GetAdminKeyHashes(threadID provautil.ThreadID) [][]byte {
	pubs := view.adminKeySets[btcec.KeySetType(threadID)]
	hashes := make([][]byte, len(pubs))
	for i, pubKey := range pubs {
		hashes[i] = provautil.Hash160(pubKey.SerializeCompressed())
	}
	return hashes
}
func (view *KeyViewpoint) SetKeyIDs(aspKeyIdMap btcec.KeyIdMap) {
	if aspKeyIdMap != nil {
		view.aspKeyIdMap = aspKeyIdMap.DeepCopy()
	}
}
func (view *KeyViewpoint) KeyIDs() btcec.KeyIdMap {
	return view.aspKeyIdMap
}
func (view *KeyViewpoint) LookupKeyIDs(keyIDs []btcec.KeyID) map[btcec.KeyID][]byte {
	keyIdMap := make(map[btcec.KeyID][]byte)
	for _, keyID := range keyIDs {
		pubKey := view.aspKeyIdMap[keyID]
		if pubKey != nil {
			keyIdMap[keyID] = provautil.Hash160(pubKey.SerializeCompressed())
		} else {
			keyIdMap[keyID] = bytes.Repeat([]byte{0x00}, 20)
		}
	}
	return keyIdMap
}