func createSpendTx(spend *spendableOut, fee provautil.Amount) *wire.MsgTx {
	spendTx := wire.NewMsgTx(1)
	spendTx.AddTxIn(&wire.TxIn{
		PreviousOutPoint: spend.prevOut,
		Sequence:         wire.MaxTxInSequenceNum,
		SignatureScript:  nil,
	})
	scriptPkScript, _ := txscript.PayToAddrScript(makeAddr(nil, nil))
	spendTx.AddTxOut(wire.NewTxOut(int64(spend.amount-fee), scriptPkScript))
	sigScript, _ := txscript.SignTxOutput(&chaincfg.RegressionNetParams, spendTx,
		0, int64(spend.amount), spend.pkScript, txscript.SigHashAll, txscript.KeyClosure(lookupKey), nil)
	spendTx.TxIn[0].SignatureScript = sigScript
	return spendTx
}
createSpendTx creates a transaction that spends from the provided spendable
output and includes an additional unique OP_RETURN output to ensure the
transaction ends up with a unique hash.  The script is a simple OP_TRUE
script which avoids the need to track addresses and signature scripts in the
tests.
package fullblocktests
import (
	"errors"
	"fmt"
	"github.com/bitgo/prova/blockchain"
	"github.com/bitgo/prova/btcec"
	"github.com/bitgo/prova/chaincfg"
	"github.com/bitgo/prova/chaincfg/chainhash"
	"github.com/bitgo/prova/provautil"
	"github.com/bitgo/prova/txscript"
	"github.com/bitgo/prova/wire"
	"math"
	"math/rand"
	"runtime"
	"time"
)
var (
	privKey1, _ = btcec.PrivKeyFromBytes(btcec.S256(), []byte{
		0x2b, 0x8c, 0x52, 0xb7, 0x7b, 0x32, 0x7c, 0x75,
		0x5b, 0x9b, 0x37, 0x55, 0x00, 0xd3, 0xf4, 0xb2,
		0xda, 0x9b, 0x0a, 0x1f, 0xf6, 0x5f, 0x68, 0x91,
		0xd3, 0x11, 0xfe, 0x94, 0x29, 0x5b, 0xc2, 0x6a,
	})
	pubKey1     = (*btcec.PublicKey)(&privKey1.PublicKey)
	privKey2, _ = btcec.PrivKeyFromBytes(btcec.S256(), []byte{
		0xea, 0xf0, 0x2c, 0xa3, 0x48, 0xc5, 0x24, 0xe6,
		0x39, 0x26, 0x55, 0xba, 0x4d, 0x29, 0x60, 0x3c,
		0xd1, 0xa7, 0x34, 0x7d, 0x9d, 0x65, 0xcf, 0xe9,
		0x3c, 0xe1, 0xeb, 0xff, 0xdc, 0xa2, 0x26, 0x94,
	})
	pubKey2     = (*btcec.PublicKey)(&privKey2.PublicKey)
	privKey3, _ = btcec.PrivKeyFromBytes(btcec.S256(), []byte{
		0x64, 0x89, 0xdd, 0x3e, 0x30, 0x88, 0xc2, 0xc4,
		0xd6, 0xbc, 0x44, 0x4e, 0x4c, 0x47, 0xf9, 0x2c,
		0x9b, 0xf2, 0x8d, 0x89, 0x65, 0x1a, 0x9e, 0x22,
		0x0d, 0xbc, 0x2c, 0x0d, 0x11, 0x81, 0xc5, 0xe4,
	})
	pubKey3 = (*btcec.PublicKey)(&privKey3.PublicKey)
	validatePrivKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), []byte{
		0x40, 0x15, 0x28, 0x9a, 0x22, 0x86, 0x58, 0x04, 0x75, 0x20,
		0xf0, 0xd0, 0xab, 0xe7, 0xad, 0x49, 0xab, 0xc7, 0x7f, 0x6b,
		0xe0, 0xbe, 0x63, 0xb3, 0x6b, 0x94, 0xb8, 0x3c, 0x2d, 0x1f,
		0xd9, 0x77,
	})
	keyId1 = btcec.KeyID(1)
	keyId2 = btcec.KeyID(2)
	lookupKey = func(a provautil.Address) ([]txscript.PrivateKey, error) {
		return []txscript.PrivateKey{
			txscript.PrivateKey{privKey1, true},
			txscript.PrivateKey{privKey2, true},
		}, nil
	}
)
type TestInstance interface {
	FullBlockTestInstance()
}
type AcceptedBlock struct {
	Name         string
	Block        *wire.MsgBlock
	Height       uint32
	IsMainChain  bool
	IsOrphan     bool
	ThreadTips   map[provautil.ThreadID]*wire.OutPoint
	TotalSupply  uint64
	AdminKeySets map[btcec.KeySetType]btcec.PublicKeySet
	ASPKeyIdMap  btcec.KeyIdMap
}
var _ TestInstance = AcceptedBlock{}
func (b AcceptedBlock) FullBlockTestInstance() {}
type RejectedBlock struct {
	Name       string
	Block      *wire.MsgBlock
	Height     uint32
	RejectCode blockchain.ErrorCode
}
var _ TestInstance = RejectedBlock{}
func (b RejectedBlock) FullBlockTestInstance() {}
type OrphanOrRejectedBlock struct {
	Name   string
	Block  *wire.MsgBlock
	Height uint32
}
var _ TestInstance = OrphanOrRejectedBlock{}
func (b OrphanOrRejectedBlock) FullBlockTestInstance() {}
type ExpectedTip struct {
	Name   string
	Block  *wire.MsgBlock
	Height uint32
}
var _ TestInstance = ExpectedTip{}
func (b ExpectedTip) FullBlockTestInstance() {}
type RejectedNonCanonicalBlock struct {
	Name     string
	RawBlock []byte
	Height   uint32
}
func (b RejectedNonCanonicalBlock) FullBlockTestInstance() {}
type spendableOut struct {
	prevOut  wire.OutPoint
	pkScript []byte
	amount   provautil.Amount
}
func makeSpendableOutForTx(tx *wire.MsgTx, txOutIndex uint32) spendableOut {
	return spendableOut{
		prevOut: wire.OutPoint{
			Hash:  tx.TxHash(),
			Index: txOutIndex,
		},
		pkScript: tx.TxOut[0].PkScript,
		amount:   provautil.Amount(tx.TxOut[txOutIndex].Value),
	}
}
func makeSpendableOut(block *wire.MsgBlock, txIndex, txOutIndex uint32) spendableOut {
	return makeSpendableOutForTx(block.Transactions[txIndex], txOutIndex)
}
type testGenerator struct {
	params       *chaincfg.Params
	tip          *wire.MsgBlock
	tipName      string
	tipHeight    uint32
	blocks       map[chainhash.Hash]*wire.MsgBlock
	blocksByName map[string]*wire.MsgBlock
	blockHeights map[string]uint32
	spendableOuts     []spendableOut
	prevCollectedHash chainhash.Hash
	privKey *btcec.PrivateKey
}
func makeTestGenerator(params *chaincfg.Params) (testGenerator, error) {
	genesis := params.GenesisBlock
	genesis.Header.Sign(validatePrivKey)
	genesisHash := genesis.Header.BlockHash()
	return testGenerator{
		params:       params,
		blocks:       map[chainhash.Hash]*wire.MsgBlock{genesisHash: genesis},
		blocksByName: map[string]*wire.MsgBlock{"genesis": genesis},
		blockHeights: map[string]uint32{"genesis": 0},
		tip:          genesis,
		tipName:      "genesis",
		tipHeight:    0,
		privKey:      privKey2,
	}, nil
}
func standardCoinbaseScript() ([]byte, error) {
	return txscript.NewScriptBuilder().AddData([]byte("/prova/")).
		Script()
}
func provaThreadScript(threadID provautil.ThreadID) []byte {
	builder := txscript.NewScriptBuilder()
	script, err := builder.
		AddInt64(int64(threadID)).
		AddOp(txscript.OP_CHECKTHREAD).Script()
	if err != nil {
		panic(err)
	}
	return script
}
func provaAdminScript(opcode byte, pubKey *btcec.PublicKey) []byte {
	data := make([]byte, 1+btcec.PubKeyBytesLenCompressed)
	data[0] = opcode
	copy(data[1:], pubKey.SerializeCompressed())
	builder := txscript.NewScriptBuilder()
	script, err := builder.
		AddOp(txscript.OP_RETURN).
		AddData(data).Script()
	if err != nil {
		panic(err)
	}
	return script
}
func provaAdminASPScript(opcode byte, pubKey *btcec.PublicKey, keyID btcec.KeyID) []byte {
	data := make([]byte, 1+btcec.PubKeyBytesLenCompressed+btcec.KeyIDSize)
	data[0] = opcode
	copy(data[1:], pubKey.SerializeCompressed())
	keyID.ToAddressFormat(data[1+btcec.PubKeyBytesLenCompressed:])
	builder := txscript.NewScriptBuilder()
	script, err := builder.
		AddOp(txscript.OP_RETURN).
		AddData(data).Script()
	if err != nil {
		panic(err)
	}
	return script
}
func opReturnScript() []byte {
	return []byte{txscript.OP_RETURN}
}
func (g *testGenerator) createCoinbaseTx(blockHeight uint32) *wire.MsgTx {
	coinbaseScript, err := standardCoinbaseScript()
	if err != nil {
		panic(err)
	}
	tx := wire.NewMsgTx(1)
	tx.AddTxIn(&wire.TxIn{
		PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
			wire.MaxPrevOutIndex),
		Sequence:        wire.MaxTxInSequenceNum,
		SignatureScript: coinbaseScript,
	})
	pkHash := make([]byte, 20)
	rand.Read(pkHash)
	addr, _ := provautil.NewAddressProva(pkHash, []btcec.KeyID{keyId1, keyId2}, &chaincfg.RegressionNetParams)
	scriptPkScript, _ := txscript.PayToAddrScript(addr)
	tx.AddTxOut(&wire.TxOut{
		Value:    blockchain.CalcBlockSubsidy(blockHeight, g.params),
		PkScript: scriptPkScript,
	})
	return tx
}
func calcMerkleRoot(txns []*wire.MsgTx) chainhash.Hash {
	if len(txns) == 0 {
		return chainhash.Hash{}
	}
	utilTxns := make([]*provautil.Tx, 0, len(txns))
	for _, tx := range txns {
		utilTxns = append(utilTxns, provautil.NewTx(tx))
	}
	merkles := blockchain.BuildMerkleTreeStore(utilTxns)
	return *merkles[len(merkles)-1]
}
func solveBlock(header *wire.BlockHeader) bool {
	type sbResult struct {
		found bool
		nonce uint32
	}
	targetDifficulty := blockchain.CompactToBig(header.Bits)
	quit := make(chan bool)
	results := make(chan sbResult)
	solver := func(hdr wire.BlockHeader, startNonce, stopNonce uint32) {
		for i := startNonce; i >= startNonce && i <= stopNonce; i++ {
			select {
			case <-quit:
				return
			default:
				hdr.Nonce = uint64(i)
				hash := hdr.BlockHash()
				if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
					results <- sbResult{true, i}
					return
				}
			}
		}
		results <- sbResult{false, 0}
	}
	startNonce := uint32(1)
	stopNonce := uint32(math.MaxUint32)
	numCores := uint32(runtime.NumCPU())
	noncesPerCore := (stopNonce - startNonce) / numCores
	for i := uint32(0); i < numCores; i++ {
		rangeStart := startNonce + (noncesPerCore * i)
		rangeStop := startNonce + (noncesPerCore * (i + 1)) - 1
		if i == numCores-1 {
			rangeStop = stopNonce
		}
		go solver(*header, rangeStart, rangeStop)
	}
	for i := uint32(0); i < numCores; i++ {
		result := <-results
		if result.found {
			close(quit)
			header.Nonce = uint64(result.nonce)
			return true
		}
	}
	return false
}
func additionalTx(tx *wire.MsgTx) func(*wire.MsgBlock) {
	return func(b *wire.MsgBlock) {
		b.AddTransaction(tx)
	}
}
func changeCoinbaseValue(delta int64) func(*wire.MsgBlock) {
	return func(b *wire.MsgBlock) {
		txns := b.Transactions
		coinbaseTx := txns[0]
		coinbaseTx.TxOut[0].Value += delta
	}
}
func makeAddr(priv *btcec.PrivateKey, kids *[2]uint) provautil.Address {
	pkHash := make([]byte, 20)
	rand.Read(pkHash)
	if priv != nil {
		pub := (*btcec.PublicKey)(&priv.PublicKey)
		pkHash = provautil.Hash160(pub.SerializeCompressed())
	}
	keyIDs := []btcec.KeyID{keyId1, keyId2}
	if kids != nil {
		keyIDs[0] = btcec.KeyID(kids[0])
		keyIDs[1] = btcec.KeyID(kids[1])
	}
	addr, _ := provautil.NewAddressProva(pkHash, keyIDs, &chaincfg.RegressionNetParams)
	return addr
}
type ProvaOut struct {
	amount provautil.Amount
	addr   string
}
func createProvaSpendTx(spend *spendableOut, outs []ProvaOut, priv *btcec.PrivateKey) *wire.MsgTx {
	spendTx := wire.NewMsgTx(1)
	spendTx.AddTxIn(&wire.TxIn{
		PreviousOutPoint: spend.prevOut,
		Sequence:         wire.MaxTxInSequenceNum,
		SignatureScript:  nil,
	})
	for _, out := range outs {
		addr, _ := provautil.DecodeAddress(out.addr, &chaincfg.RegressionNetParams)
		scriptPkScript, _ := txscript.PayToAddrScript(addr)
		spendTx.AddTxOut(wire.NewTxOut(int64(out.amount), scriptPkScript))
	}
	privKeys := []txscript.PrivateKey{
		txscript.PrivateKey{privKey1, true},
		txscript.PrivateKey{privKey2, true},
	}
	if priv != nil {
		privKeys[1] = txscript.PrivateKey{priv, true}
	}
	lookupKeyFunc := func(a provautil.Address) ([]txscript.PrivateKey, error) {
		return privKeys, nil
	}
	sigScript, _ := txscript.SignTxOutput(&chaincfg.RegressionNetParams, spendTx,
		0, int64(spend.amount), spend.pkScript, txscript.SigHashAll, txscript.KeyClosure(lookupKeyFunc), nil)
	spendTx.TxIn[0].SignatureScript = sigScript
	return spendTx
}