func assertTxInBlock(r *rpctest.Harness, t *testing.T, blockHash *chainhash.Hash,
	txid *chainhash.Hash) {
	block, err := r.Node.GetBlock(blockHash)
	if err != nil {
		t.Fatalf("unable to get block: %v", err)
	}
	if len(block.Transactions) < 2 {
		t.Fatal("target transaction was not mined")
	}
	for _, txn := range block.Transactions {
		txHash := txn.TxHash()
		if txn.TxHash() == txHash {
			return
		}
	}
	_, _, line, _ := runtime.Caller(1)
	t.Fatalf("assertion failed at line %v: txid %v was not found in "+
		"block %v", line, txid, blockHash)
}
assertTxInBlock asserts a transaction with the specified txid is found
within the block with the passed block hash.
package integration
import (
	"bytes"
	"runtime"
	"strings"
	"testing"
	"time"
	"github.com/soteria-dag/soterd/blockdag"
	"github.com/soteria-dag/soterd/chaincfg"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/integration/rpctest"
	"github.com/soteria-dag/soterd/soterec"
	"github.com/soteria-dag/soterd/soterutil"
	"github.com/soteria-dag/soterd/txscript"
	"github.com/soteria-dag/soterd/wire"
)
const (
	csvKey = "csv"
)
func makeTestOutput(r *rpctest.Harness, t *testing.T,
	amt soterutil.Amount) (*soterec.PrivateKey, *wire.OutPoint, []byte, error) {
	key, err := soterec.NewPrivateKey(soterec.S256())
	if err != nil {
		return nil, nil, nil, err
	}
	a, err := soterutil.NewAddressPubKey(key.PubKey().SerializeCompressed(), r.ActiveNet)
	if err != nil {
		return nil, nil, nil, err
	}
	selfAddrScript, err := txscript.PayToAddrScript(a.AddressPubKeyHash())
	if err != nil {
		return nil, nil, nil, err
	}
	output := &wire.TxOut{PkScript: selfAddrScript, Value: soterutil.NanoSoterPerSoter}
	fundTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true)
	if err != nil {
		return nil, nil, nil, err
	}
	txHash, err := r.Node.SendRawTransaction(fundTx, true)
	if err != nil {
		return nil, nil, nil, err
	}
	blockHash, err := r.Node.Generate(1)
	if err != nil {
		return nil, nil, nil, err
	}
	assertTxInBlock(r, t, blockHash[0], txHash)
	var outputIndex uint32
	if bytes.Equal(fundTx.TxOut[0].PkScript, selfAddrScript) {
		outputIndex = 0
	} else {
		outputIndex = 1
	}
	utxo := &wire.OutPoint{
		Hash:  fundTx.TxHash(),
		Index: outputIndex,
	}
	return key, utxo, selfAddrScript, nil
}
func TestBIP0113Activation(t *testing.T) {
	t.Parallel()
	soterdCfg := []string{"--rejectnonstd"}
	r, err := rpctest.New(&chaincfg.SimNetParams, nil, soterdCfg, false)
	if err != nil {
		t.Fatal("unable to create primary harness: ", err)
	}
	if err := r.SetUp(true, 1); err != nil {
		t.Fatalf("unable to setup test chain: %v", err)
	}
	defer r.TearDown()
	const outputValue = soterutil.NanoSoterPerSoter
	outputKey, testOutput, testPkScript, err := makeTestOutput(r, t,
		outputValue)
	if err != nil {
		t.Fatalf("unable to create test output: %v", err)
	}
	addr, err := r.NewAddress()
	if err != nil {
		t.Fatalf("unable to generate address: %v", err)
	}
	addrScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		t.Fatalf("unable to generate addr script: %v", err)
	}
	tx := wire.NewMsgTx(1)
	tx.AddTxIn(&wire.TxIn{
		PreviousOutPoint: *testOutput,
	})
	tx.AddTxOut(&wire.TxOut{
		PkScript: addrScript,
		Value:    outputValue - 1000,
	})
	chainInfo, err := r.Node.GetBlockChainInfo()
	if err != nil {
		t.Fatalf("unable to query for chain info: %v", err)
	}
	tx.LockTime = uint32(chainInfo.MedianTime) + 1
	sigScript, err := txscript.SignatureScript(tx, 0, testPkScript,
		txscript.SigHashAll, outputKey, true)
	if err != nil {
		t.Fatalf("unable to generate sig: %v", err)
	}
	tx.TxIn[0].SignatureScript = sigScript
	_, err = r.Node.SendRawTransaction(tx, true)
	if err == nil {
		t.Fatalf("transaction accepted, but should be non-final")
	} else if !strings.Contains(err.Error(), "not finalized") {
		t.Fatalf("transaction should be rejected due to being "+
			"non-final, instead: %v", err)
	}
	txns := []*soterutil.Tx{soterutil.NewTx(tx)}
	block, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{})
	if err != nil {
		t.Fatalf("unable to submit block: %v", err)
	}
	txid := tx.TxHash()
	assertTxInBlock(r, t, block.Hash(), &txid)
	assertChainHeight(r, t, 103)
	numBlocks := (r.ActiveNet.MinerConfirmationWindow * 2) - 4
	if _, err := r.Node.Generate(numBlocks); err != nil {
		t.Fatalf("unable to generate blocks: %v", err)
	}
	assertChainHeight(r, t, 299)
	assertSoftForkStatus(r, t, csvKey, blockdag.ThresholdActive)
	timeLockDeltas := []int64{-1, 0, 1}
	for _, timeLockDelta := range timeLockDeltas {
		chainInfo, err = r.Node.GetBlockChainInfo()
		if err != nil {
			t.Fatalf("unable to query for chain info: %v", err)
		}
		medianTimePast := chainInfo.MedianTime
		outputKey, testOutput, testPkScript, err = makeTestOutput(r, t,
			outputValue)
		if err != nil {
			t.Fatalf("unable to create test output: %v", err)
		}
		tx = wire.NewMsgTx(1)
		tx.AddTxIn(&wire.TxIn{
			PreviousOutPoint: *testOutput,
		})
		tx.AddTxOut(&wire.TxOut{
			PkScript: addrScript,
			Value:    outputValue - 1000,
		})
		tx.LockTime = uint32(medianTimePast + timeLockDelta)
		sigScript, err = txscript.SignatureScript(tx, 0, testPkScript,
			txscript.SigHashAll, outputKey, true)
		if err != nil {
			t.Fatalf("unable to generate sig: %v", err)
		}
		tx.TxIn[0].SignatureScript = sigScript
		_, err = r.Node.SendRawTransaction(tx, true)
		if err == nil && timeLockDelta >= 0 {
			t.Fatal("transaction was accepted into the mempool " +
				"but should be rejected!")
		} else if err != nil && !strings.Contains(err.Error(), "not finalized") {
			t.Fatalf("transaction should be rejected from mempool "+
				"due to being  non-final, instead: %v", err)
		}
		txns = []*soterutil.Tx{soterutil.NewTx(tx)}
		_, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{})
		if err == nil && timeLockDelta >= 0 {
			t.Fatal("block should be rejected due to non-final " +
				"txn, but was accepted")
		} else if err != nil && !strings.Contains(err.Error(), "unfinalized") {
			t.Fatalf("block should be rejected due to non-final "+
				"tx, instead: %v", err)
		}
	}
}
func createCSVOutput(r *rpctest.Harness, t *testing.T,
	numNanoSoters soterutil.Amount, timeLock int32,
	isSeconds bool) ([]byte, *wire.OutPoint, *wire.MsgTx, error) {
	sequenceLock := blockdag.LockTimeToSequence(isSeconds,
		uint32(timeLock))
	b := txscript.NewScriptBuilder().
		AddInt64(int64(sequenceLock)).
		AddOp(txscript.OP_CHECKSEQUENCEVERIFY).
		AddOp(txscript.OP_DROP)
	csvScript, err := b.Script()
	if err != nil {
		return nil, nil, nil, err
	}
	p2shAddr, err := soterutil.NewAddressScriptHash(csvScript, r.ActiveNet)
	if err != nil {
		return nil, nil, nil, err
	}
	p2shScript, err := txscript.PayToAddrScript(p2shAddr)
	if err != nil {
		return nil, nil, nil, err
	}
	output := &wire.TxOut{
		PkScript: p2shScript,
		Value:    int64(numNanoSoters),
	}
	tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true)
	if err != nil {
		return nil, nil, nil, err
	}
	var outputIndex uint32
	if !bytes.Equal(tx.TxOut[0].PkScript, p2shScript) {
		outputIndex = 1
	}
	utxo := &wire.OutPoint{
		Hash:  tx.TxHash(),
		Index: outputIndex,
	}
	return csvScript, utxo, tx, nil
}
func spendCSVOutput(redeemScript []byte, csvUTXO *wire.OutPoint,
	sequence uint32, targetOutput *wire.TxOut,
	txVersion int32) (*wire.MsgTx, error) {
	tx := wire.NewMsgTx(txVersion)
	tx.AddTxIn(&wire.TxIn{
		PreviousOutPoint: *csvUTXO,
		Sequence:         sequence,
	})
	tx.AddTxOut(targetOutput)
	b := txscript.NewScriptBuilder().
		AddOp(txscript.OP_TRUE).
		AddData(redeemScript)
	sigScript, err := b.Script()
	if err != nil {
		return nil, err
	}
	tx.TxIn[0].SignatureScript = sigScript
	return tx, nil
}