kaspad/mining/test_utils.go
Ori Newman 7069d173c6 [NOD-180] Add validation of utxo commitments (#310)
* [NOD-172] Port EMCH from bchd

* [NOD-172] Fix hdkeychain.TestErrors and add btcec.TestRecoverCompact

* [NOD-172] Make ECMH immutable

* [NOD-172] Fix gofmt errors

* [NOD-172] Add TestMultiset_NewMultisetFromDataSlice and fix Point to be immutable

* [NOD-172] Fix gofmt errors

* [NOD-172] Add test for checking that the Union of a multiset and its inverse is zero

* [NOD-179] Add ECMH Point to all UTXO-structs

* [NOD-179] Fix utxo set tests

* [NOD-179] Fix mempool tests

* [NOD-179] Remove RemoveTxOuts

* [NOD-179] Move serializeBlockUTXODiffData to the top of the file

* [NOD-179] Fix serializeBlockUTXODiffData comment format

* [NOD-179] Fix AddTx comment and name return values

* [NOD-180] Validate utxo commitments

* [NOD-179] Fix TestAcceptingBlock and TestConfirmations to not use the block hash as phantom break even

* [NOD-180] Fix typo

* [NOD-180] move most of the logic in calcUTXOCommitment to UTXOSet.WithTransactions

* [NOD-180] Optionally return error when a transaction in WithTransactions is double spent

* [NOD-180] Rename allowDoubleSpends to ignoreDoubleSpends
2019-05-28 11:33:11 +03:00

137 lines
3.9 KiB
Go

package mining
// This file functions are not considered safe for regular use, and should be used for test purposes only.
import (
"fmt"
"time"
"github.com/daglabs/btcd/dagconfig"
"github.com/daglabs/btcd/blockdag"
"github.com/daglabs/btcd/txscript"
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/util/daghash"
"github.com/daglabs/btcd/wire"
)
// fakeTxSource is a simple implementation of TxSource interface
type fakeTxSource struct {
txDescs []*TxDesc
}
func (txs *fakeTxSource) LastUpdated() time.Time {
return time.Unix(0, 0)
}
func (txs *fakeTxSource) MiningDescs() []*TxDesc {
return txs.txDescs
}
func (txs *fakeTxSource) HaveTransaction(txID *daghash.TxID) bool {
for _, desc := range txs.txDescs {
if *desc.Tx.ID() == *txID {
return true
}
}
return false
}
// PrepareBlockForTest generates a block with the proper merkle roots, coinbase/fee transactions etc. This function is used for test purposes only
func PrepareBlockForTest(dag *blockdag.BlockDAG, params *dagconfig.Params, parentHashes []*daghash.Hash, transactions []*wire.MsgTx, forceTransactions bool, coinbaseOutputs uint64) (*wire.MsgBlock, error) {
newVirtual, err := blockdag.GetVirtualFromParentsForTest(dag, parentHashes)
if err != nil {
return nil, err
}
oldVirtual := blockdag.SetVirtualForTest(dag, newVirtual)
defer blockdag.SetVirtualForTest(dag, oldVirtual)
policy := Policy{
BlockMaxSize: 50000,
BlockPrioritySize: 750000,
TxMinFreeFee: util.Amount(0),
}
txSource := &fakeTxSource{
txDescs: make([]*TxDesc, len(transactions)),
}
for i, tx := range transactions {
txSource.txDescs[i] = &TxDesc{
Tx: util.NewTx(tx),
}
}
blockTemplateGenerator := NewBlkTmplGenerator(&policy,
params, txSource, dag, blockdag.NewMedianTime(), txscript.NewSigCache(100000))
template, err := blockTemplateGenerator.NewBlockTemplate(nil)
if err != nil {
return nil, err
}
// In order of creating deterministic coinbase tx ids.
err = blockTemplateGenerator.UpdateExtraNonce(template.Block, dag.Height()+1, GenerateDeterministicExtraNonceForTest())
if err != nil {
return nil, err
}
txsToAdd := make([]*wire.MsgTx, 0)
for _, tx := range transactions {
found := false
for _, blockTx := range template.Block.Transactions {
if blockTx.TxHash().IsEqual(tx.TxHash()) {
found = true
break
}
}
if !found {
if !forceTransactions {
return nil, fmt.Errorf("tx %s wasn't found in the block", tx.TxHash())
}
txsToAdd = append(txsToAdd, tx)
}
}
if coinbaseOutputs != 1 {
cb := template.Block.Transactions[0]
originalValue := cb.TxOut[0].Value
pkScript := cb.TxOut[0].PkScript
cb.TxOut = make([]*wire.TxOut, coinbaseOutputs)
if coinbaseOutputs != 0 {
newOutValue := originalValue / coinbaseOutputs
for i := uint64(0); i < coinbaseOutputs; i++ {
cb.TxOut[i] = &wire.TxOut{
Value: newOutValue,
PkScript: pkScript,
}
}
}
}
if forceTransactions && len(txsToAdd) > 0 {
for _, tx := range txsToAdd {
template.Block.Transactions = append(template.Block.Transactions, tx)
}
}
updateHeaderFields := coinbaseOutputs != 1 || (forceTransactions && len(txsToAdd) > 0)
if updateHeaderFields {
utilTxs := make([]*util.Tx, len(template.Block.Transactions))
for i, tx := range template.Block.Transactions {
utilTxs[i] = util.NewTx(tx)
}
template.Block.Header.HashMerkleRoot = blockdag.BuildHashMerkleTreeStore(utilTxs).Root()
template.Block.Header.UTXOCommitment, err = blockTemplateGenerator.buildUTXOCommitment(template.Block.Transactions, dag.Height()+1)
if err != nil {
return nil, err
}
}
return template.Block, nil
}
// GenerateDeterministicExtraNonceForTest returns a unique deterministic extra nonce for coinbase data, in order to create unique coinbase transactions.
func GenerateDeterministicExtraNonceForTest() uint64 {
extraNonceForTest++
return extraNonceForTest
}
var extraNonceForTest = uint64(0)