This makes the mining package an internal package such that it will no longer be an exported module. The only place its functionality is really needed is for the internal implementation of dcrd itself and thus having an unnecessary exported module significantly increases the maintenance burden. This is part of the overall effort to reduce the total number of modules and eventually get to the point it will be possible to follow semver for the root module. It is worth noting that there are a few constants, which will be listed below, that were exported from this module that callers might have previously relied upon. However, due to previous discussions about the goal of removing the module, a code search has revealed that there are no known callers that still rely on them. The aforementioned constants are: - UnminedHeight - MinHighPriority Overview of the major changes: - Move the following files from mining -> internal/mining: - README.md - cpuminer.go - doc.go - miningerror.go -> error.go - log.go - mining.go - mining_test.go - policy.go - policy_test.go - Remove mining/go.mod and mining/go.sum - Make the README.md and doc.go files match the new reality - Update all import paths in the repository accordingly - Remove the dependency from the root go.mod - Run go mod tidy on all modules
263 lines
8.0 KiB
Go
263 lines
8.0 KiB
Go
// Copyright (c) 2019 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package mining
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"testing"
|
|
|
|
"github.com/decred/dcrd/chaincfg/chainhash"
|
|
"github.com/decred/dcrd/wire"
|
|
)
|
|
|
|
// fromHex converts the passed hex string into a byte slice and will panic if
|
|
// there is an error. This is only provided for the hard-coded constants so
|
|
// errors in the source code can be detected. It will only (and must only) be
|
|
// called for initialization purposes.
|
|
func fromHex(s string) []byte {
|
|
r, err := hex.DecodeString(s)
|
|
if err != nil {
|
|
panic("invalid hex in source file: " + s)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// mockPrioInputSourceEntry houses a block height and amount for use when
|
|
// associating them to a given transaction output.
|
|
type mockPrioInputSourceEntry struct {
|
|
height int64
|
|
amount int64
|
|
}
|
|
|
|
// mockPrioInputSource provides a source of transaction output block heights and
|
|
// amounts for given outpoints and implements the PriorityInputser interface so
|
|
// it may be used in cases that require access to said information.
|
|
type mockPrioInputSource map[wire.OutPoint]mockPrioInputSourceEntry
|
|
|
|
// PriorityInput returns the block height and amount associated with the
|
|
// provided previous outpoint along with a bool that indicates whether or not
|
|
// the requested entry exists. This ensures the caller is able to distinguish
|
|
// missing entries from zero values.
|
|
func (m mockPrioInputSource) PriorityInput(prevOut *wire.OutPoint) (int64, int64, bool) {
|
|
entry, ok := m[*prevOut]
|
|
if !ok {
|
|
return 0, 0, false
|
|
}
|
|
|
|
return entry.height, entry.amount, true
|
|
}
|
|
|
|
// TestCheckTransactionStandard tests the checkTransactionStandard API.
|
|
func TestCalcPriority(t *testing.T) {
|
|
// Create some dummy, but otherwise standard, data for transactions.
|
|
prevOutHash, err := chainhash.NewHashFromStr("01")
|
|
if err != nil {
|
|
t.Fatalf("NewHashFromStr: unexpected error: %v", err)
|
|
}
|
|
dummyPrevOut := wire.OutPoint{Hash: *prevOutHash, Index: 1, Tree: 0}
|
|
dummySigScript := bytes.Repeat([]byte{0x00}, 107)
|
|
dummyTxIn := wire.TxIn{
|
|
PreviousOutPoint: dummyPrevOut,
|
|
Sequence: wire.MaxTxInSequenceNum,
|
|
ValueIn: 10000,
|
|
BlockHeight: 150000,
|
|
BlockIndex: 2,
|
|
SignatureScript: dummySigScript,
|
|
}
|
|
dummySigScriptP2SH := bytes.Repeat([]byte{0x00}, 145)
|
|
dummyPrevOutP2SH := wire.OutPoint{Hash: *prevOutHash, Index: 1, Tree: 0}
|
|
dummyPrevOutP2SH.Hash[0] = 0x02
|
|
dummyTxInP2SH := wire.TxIn{
|
|
PreviousOutPoint: dummyPrevOutP2SH,
|
|
Sequence: wire.MaxTxInSequenceNum,
|
|
ValueIn: 20000,
|
|
BlockHeight: 149950,
|
|
BlockIndex: 2,
|
|
SignatureScript: dummySigScriptP2SH,
|
|
}
|
|
dummyP2PKHScript := fromHex("76a914000000000000000000000000000000000000000088ac")
|
|
dummyTxOut := wire.TxOut{
|
|
Value: dummyTxIn.ValueIn - 3000, // Use 3000 atoms for dummy fee.
|
|
Version: 0,
|
|
PkScript: dummyP2PKHScript,
|
|
}
|
|
dummyTxOutP2SH := wire.TxOut{
|
|
Value: dummyTxInP2SH.ValueIn - 3000, // Use 3000 atoms for dummy fee.
|
|
Version: 0,
|
|
PkScript: dummyP2PKHScript,
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
tx wire.MsgTx
|
|
prioInputs mockPrioInputSource
|
|
nextHeight int64
|
|
wantSize int
|
|
want float64
|
|
}{{
|
|
name: "p2pkh spend (input age 100) with one output",
|
|
tx: wire.MsgTx{
|
|
SerType: wire.TxSerializeFull,
|
|
Version: 1,
|
|
TxIn: []*wire.TxIn{&dummyTxIn},
|
|
TxOut: []*wire.TxOut{&dummyTxOut},
|
|
LockTime: 0,
|
|
},
|
|
prioInputs: mockPrioInputSource{
|
|
dummyPrevOut: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxIn.BlockHeight),
|
|
amount: dummyTxIn.ValueIn,
|
|
}},
|
|
nextHeight: int64(dummyTxIn.BlockHeight) + 100,
|
|
wantSize: 216,
|
|
want: 19607.843137254902,
|
|
}, {
|
|
name: "p2pkh spend (input age 100) with two outputs",
|
|
tx: wire.MsgTx{
|
|
SerType: wire.TxSerializeFull,
|
|
Version: 1,
|
|
TxIn: []*wire.TxIn{&dummyTxIn},
|
|
TxOut: func() []*wire.TxOut {
|
|
dummyTxOut1 := dummyTxOut
|
|
dummyTxOut1.Value = dummyTxIn.ValueIn/2 - 1500
|
|
dummyTxOut2 := dummyTxOut
|
|
dummyTxOut2.Value = dummyTxIn.ValueIn/2 - 1500
|
|
return []*wire.TxOut{&dummyTxOut1, &dummyTxOut2}
|
|
}(),
|
|
LockTime: 0,
|
|
},
|
|
prioInputs: mockPrioInputSource{
|
|
dummyPrevOut: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxIn.BlockHeight),
|
|
amount: dummyTxIn.ValueIn,
|
|
}},
|
|
nextHeight: int64(dummyTxIn.BlockHeight) + 100,
|
|
wantSize: 252,
|
|
want: 11494.252873563218,
|
|
}, {
|
|
name: "p2pkh spend (input age 350) with one output",
|
|
tx: wire.MsgTx{
|
|
SerType: wire.TxSerializeFull,
|
|
Version: 1,
|
|
TxIn: []*wire.TxIn{&dummyTxIn},
|
|
TxOut: []*wire.TxOut{&dummyTxOut},
|
|
LockTime: 0,
|
|
},
|
|
prioInputs: mockPrioInputSource{
|
|
dummyPrevOut: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxIn.BlockHeight),
|
|
amount: dummyTxIn.ValueIn,
|
|
}},
|
|
nextHeight: int64(dummyTxIn.BlockHeight) + 350,
|
|
wantSize: 216,
|
|
want: 68627.45098039215,
|
|
}, {
|
|
name: "p2pkh spend (input age 350) with two outputs",
|
|
tx: wire.MsgTx{
|
|
SerType: wire.TxSerializeFull,
|
|
Version: 1,
|
|
TxIn: []*wire.TxIn{&dummyTxIn},
|
|
TxOut: func() []*wire.TxOut {
|
|
dummyTxOut1 := dummyTxOut
|
|
dummyTxOut1.Value = dummyTxIn.ValueIn/2 - 1500
|
|
dummyTxOut2 := dummyTxOut
|
|
dummyTxOut2.Value = dummyTxIn.ValueIn/2 - 1500
|
|
return []*wire.TxOut{&dummyTxOut1, &dummyTxOut2}
|
|
}(),
|
|
LockTime: 0,
|
|
},
|
|
prioInputs: mockPrioInputSource{
|
|
dummyPrevOut: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxIn.BlockHeight),
|
|
amount: dummyTxIn.ValueIn,
|
|
}},
|
|
nextHeight: int64(dummyTxIn.BlockHeight) + 350,
|
|
wantSize: 252,
|
|
want: 40229.88505747126,
|
|
}, {
|
|
name: "p2sh spend (input age 50) with one output",
|
|
tx: wire.MsgTx{
|
|
SerType: wire.TxSerializeFull,
|
|
Version: 1,
|
|
TxIn: []*wire.TxIn{&dummyTxInP2SH},
|
|
TxOut: []*wire.TxOut{&dummyTxOutP2SH},
|
|
LockTime: 0,
|
|
},
|
|
prioInputs: mockPrioInputSource{
|
|
dummyPrevOutP2SH: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxInP2SH.BlockHeight),
|
|
amount: dummyTxInP2SH.ValueIn,
|
|
}},
|
|
nextHeight: int64(dummyTxInP2SH.BlockHeight) + 50,
|
|
wantSize: 254,
|
|
want: 11627.906976744186,
|
|
}, {
|
|
name: "p2pkh and p2sh spends (input age 50 and 100) with one output",
|
|
tx: wire.MsgTx{
|
|
SerType: wire.TxSerializeFull,
|
|
Version: 1,
|
|
TxIn: func() []*wire.TxIn {
|
|
return []*wire.TxIn{&dummyTxIn, &dummyTxInP2SH}
|
|
}(),
|
|
TxOut: []*wire.TxOut{&dummyTxOutP2SH},
|
|
LockTime: 0,
|
|
},
|
|
prioInputs: mockPrioInputSource{
|
|
dummyPrevOut: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxIn.BlockHeight),
|
|
amount: dummyTxIn.ValueIn,
|
|
},
|
|
dummyPrevOutP2SH: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxInP2SH.BlockHeight),
|
|
amount: dummyTxInP2SH.ValueIn,
|
|
}},
|
|
nextHeight: int64(dummyTxIn.BlockHeight) + 50,
|
|
wantSize: 419,
|
|
want: 29069.767441860465,
|
|
}, {
|
|
name: "p2pkh and p2sh spends (input age 50 and 100) with one output",
|
|
tx: wire.MsgTx{
|
|
SerType: wire.TxSerializeFull,
|
|
Version: 1,
|
|
TxIn: func() []*wire.TxIn {
|
|
return []*wire.TxIn{&dummyTxIn, &dummyTxInP2SH}
|
|
}(),
|
|
TxOut: []*wire.TxOut{&dummyTxOutP2SH},
|
|
LockTime: 0,
|
|
},
|
|
prioInputs: mockPrioInputSource{
|
|
dummyPrevOut: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxIn.BlockHeight),
|
|
amount: dummyTxIn.ValueIn,
|
|
},
|
|
dummyPrevOutP2SH: mockPrioInputSourceEntry{
|
|
height: int64(dummyTxInP2SH.BlockHeight),
|
|
amount: dummyTxInP2SH.ValueIn,
|
|
}},
|
|
nextHeight: int64(dummyTxIn.BlockHeight) + 50,
|
|
wantSize: 419,
|
|
want: 29069.767441860465,
|
|
}}
|
|
|
|
for _, test := range tests {
|
|
// Ensure the serialized transaction size matches hardcoded values to
|
|
// help ensure the related overhead values are updated properly if the
|
|
// transaction serialization format changes.
|
|
gotSize := test.tx.SerializeSize()
|
|
if gotSize != test.wantSize {
|
|
t.Fatalf("%q: unexpected tx size -- got %d, want %d", test.name,
|
|
gotSize, test.wantSize)
|
|
}
|
|
|
|
// Ensure the calculate priority is the expected value.
|
|
got := CalcPriority(&test.tx, test.prioInputs, test.nextHeight)
|
|
if got != test.want {
|
|
t.Fatalf("%q: unexpected priority -- got %v, want %v", test.name,
|
|
got, test.want)
|
|
}
|
|
}
|
|
}
|