mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-17 19:46:40 +00:00
[NOD-216] Revert implicit fee transaction (#322)
* Revert "[NOD-214] Remove Fee transaction from addrindex (#321)" This reverts commit e4b2d869d49471021c56cb27cbc3001134b94dfd. * Revert "[NOD-195] Make fee tx implicit (#315)" This reverts commit ccca580a4b3ff8a44138041c0ce3bc0ce5847a4d.
This commit is contained in:
parent
6250342b86
commit
072c753323
@ -9,7 +9,6 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/daglabs/btcd/util"
|
|
||||||
"github.com/daglabs/btcd/util/daghash"
|
"github.com/daglabs/btcd/util/daghash"
|
||||||
"github.com/daglabs/btcd/wire"
|
"github.com/daglabs/btcd/wire"
|
||||||
)
|
)
|
||||||
@ -106,8 +105,6 @@ type blockNode struct {
|
|||||||
acceptedIDMerkleRoot *daghash.Hash
|
acceptedIDMerkleRoot *daghash.Hash
|
||||||
utxoCommitment *daghash.Hash
|
utxoCommitment *daghash.Hash
|
||||||
|
|
||||||
feeTransaction *util.Tx
|
|
||||||
|
|
||||||
// status is a bitfield representing the validation state of the block. The
|
// status is a bitfield representing the validation state of the block. The
|
||||||
// status field, unlike the other fields, may be written to and so should
|
// status field, unlike the other fields, may be written to and so should
|
||||||
// only be accessed using the concurrent-safe NodeStatus method on
|
// only be accessed using the concurrent-safe NodeStatus method on
|
||||||
|
@ -579,7 +579,7 @@ func (dag *BlockDAG) connectBlock(node *blockNode, block *util.Block, fastAdd bo
|
|||||||
return errors.New(newErrString)
|
return errors.New(newErrString)
|
||||||
}
|
}
|
||||||
|
|
||||||
node.feeTransaction, err = node.buildFeeTransaction(dag, txsAcceptanceData)
|
err = node.validateFeeTransaction(dag, block, txsAcceptanceData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -655,16 +655,7 @@ func (dag *BlockDAG) saveChangesFromBlock(node *blockNode, block *util.Block, vi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply the fee data into the database
|
// Apply the fee data into the database
|
||||||
err = dbStoreFeeData(dbTx, block.Hash(), feeData)
|
return dbStoreFeeData(dbTx, block.Hash(), feeData)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := dbPutFeeTx(dbTx, node.hash, node.feeTransaction); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -758,7 +749,7 @@ func (dag *BlockDAG) updateFinalityPoint() {
|
|||||||
// NextBlockFeeTransaction prepares the fee transaction for the next mined block
|
// NextBlockFeeTransaction prepares the fee transaction for the next mined block
|
||||||
//
|
//
|
||||||
// This function CAN'T be called with the DAG lock held.
|
// This function CAN'T be called with the DAG lock held.
|
||||||
func (dag *BlockDAG) NextBlockFeeTransaction() (*util.Tx, error) {
|
func (dag *BlockDAG) NextBlockFeeTransaction() (*wire.MsgTx, error) {
|
||||||
dag.dagLock.RLock()
|
dag.dagLock.RLock()
|
||||||
defer dag.dagLock.RUnlock()
|
defer dag.dagLock.RUnlock()
|
||||||
|
|
||||||
@ -768,7 +759,7 @@ func (dag *BlockDAG) NextBlockFeeTransaction() (*util.Tx, error) {
|
|||||||
// NextBlockFeeTransactionNoLock prepares the fee transaction for the next mined block
|
// NextBlockFeeTransactionNoLock prepares the fee transaction for the next mined block
|
||||||
//
|
//
|
||||||
// This function MUST be called with the DAG read-lock held
|
// This function MUST be called with the DAG read-lock held
|
||||||
func (dag *BlockDAG) NextBlockFeeTransactionNoLock() (*util.Tx, error) {
|
func (dag *BlockDAG) NextBlockFeeTransactionNoLock() (*wire.MsgTx, error) {
|
||||||
txsAcceptanceData, err := dag.TxsAcceptedByVirtual()
|
txsAcceptanceData, err := dag.TxsAcceptedByVirtual()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -971,18 +962,13 @@ func (node *blockNode) applyBlueBlocks(selectedParentUTXO UTXOSet, blueBlocks []
|
|||||||
pastUTXO UTXOSet, txsAcceptanceData MultiBlockTxsAcceptanceData, err error) {
|
pastUTXO UTXOSet, txsAcceptanceData MultiBlockTxsAcceptanceData, err error) {
|
||||||
|
|
||||||
pastUTXO = selectedParentUTXO
|
pastUTXO = selectedParentUTXO
|
||||||
txsAcceptanceData = make(MultiBlockTxsAcceptanceData, len(blueBlocks))
|
txsAcceptanceData = MultiBlockTxsAcceptanceData{}
|
||||||
|
|
||||||
for _, blueBlock := range blueBlocks {
|
for _, blueBlock := range blueBlocks {
|
||||||
transactions := blueBlock.Transactions()
|
transactions := blueBlock.Transactions()
|
||||||
numTransactions := len(transactions)
|
blockTxsAcceptanceData := make(BlockTxsAcceptanceData, len(transactions))
|
||||||
isSelectedParent := blueBlock.Hash().IsEqual(node.selectedParent.hash)
|
isSelectedParent := blueBlock.Hash().IsEqual(node.selectedParent.hash)
|
||||||
if isSelectedParent { // if this is selected parent - we will also add the fee tx to acceptance data
|
for i, tx := range blueBlock.Transactions() {
|
||||||
numTransactions++
|
|
||||||
}
|
|
||||||
|
|
||||||
blockTxsAcceptanceData := make(BlockTxsAcceptanceData, 0, numTransactions)
|
|
||||||
for _, tx := range blueBlock.Transactions() {
|
|
||||||
var isAccepted bool
|
var isAccepted bool
|
||||||
if isSelectedParent {
|
if isSelectedParent {
|
||||||
isAccepted = true
|
isAccepted = true
|
||||||
@ -992,13 +978,8 @@ func (node *blockNode) applyBlueBlocks(selectedParentUTXO UTXOSet, blueBlocks []
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blockTxsAcceptanceData = append(blockTxsAcceptanceData, TxAcceptanceData{Tx: tx, IsAccepted: isAccepted})
|
blockTxsAcceptanceData[i] = TxAcceptanceData{Tx: tx, IsAccepted: isAccepted}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add fee tx acceptance data for fee transaction
|
|
||||||
blockTxsAcceptanceData = append(blockTxsAcceptanceData,
|
|
||||||
TxAcceptanceData{Tx: node.selectedParent.feeTransaction, IsAccepted: isSelectedParent})
|
|
||||||
|
|
||||||
txsAcceptanceData[*blueBlock.Hash()] = blockTxsAcceptanceData
|
txsAcceptanceData[*blueBlock.Hash()] = blockTxsAcceptanceData
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1881,6 +1862,7 @@ func New(config *Config) (*BlockDAG, error) {
|
|||||||
SubnetworkStore: newSubnetworkStore(config.DB),
|
SubnetworkStore: newSubnetworkStore(config.DB),
|
||||||
subnetworkID: config.SubnetworkID,
|
subnetworkID: config.SubnetworkID,
|
||||||
}
|
}
|
||||||
|
|
||||||
dag.utxoDiffStore = newUTXODiffStore(&dag)
|
dag.utxoDiffStore = newUTXODiffStore(&dag)
|
||||||
|
|
||||||
// Initialize the chain state from the passed database. When the db
|
// Initialize the chain state from the passed database. When the db
|
||||||
|
@ -189,10 +189,10 @@ func TestHaveBlock(t *testing.T) {
|
|||||||
{hash: dagconfig.SimNetParams.GenesisHash.String(), want: true},
|
{hash: dagconfig.SimNetParams.GenesisHash.String(), want: true},
|
||||||
|
|
||||||
// Block 3b should be present (as a second child of Block 2).
|
// Block 3b should be present (as a second child of Block 2).
|
||||||
{hash: "7689c1facfa089e4afbdf9c7b75bd4375fd3fbf362d083e0d92abe799bde6d7a", want: true},
|
{hash: "4bb2e2f55fabd67e217126dbc41e7101d0d6058800368c428cd6e397c111ee47", want: true},
|
||||||
|
|
||||||
// Block 100000 should be present (as an orphan).
|
// Block 100000 should be present (as an orphan).
|
||||||
{hash: "6ea023a55d9b7c11a6bb22c17553efb5d045e3543a308208da0ef854d8ad2a0f", want: true},
|
{hash: "4e530ee9f967de3b2cd47ac5cd00109bb9ed7b0e30a60485c94badad29ecb4ce", want: true},
|
||||||
|
|
||||||
// Random hashes should not be available.
|
// Random hashes should not be available.
|
||||||
{hash: "123", want: false},
|
{hash: "123", want: false},
|
||||||
|
@ -60,10 +60,6 @@ var (
|
|||||||
// node's local subnetwork ID.
|
// node's local subnetwork ID.
|
||||||
localSubnetworkKeyName = []byte("localsubnetworkidkey")
|
localSubnetworkKeyName = []byte("localsubnetworkidkey")
|
||||||
|
|
||||||
// feeTxBucketName is the name of the db bucket used to house the
|
|
||||||
// fee transactions of blocks
|
|
||||||
feeTxBucketName = []byte("feetxs")
|
|
||||||
|
|
||||||
// byteOrder is the preferred byte order used for serializing numeric
|
// byteOrder is the preferred byte order used for serializing numeric
|
||||||
// fields for storage in the database.
|
// fields for storage in the database.
|
||||||
byteOrder = binary.LittleEndian
|
byteOrder = binary.LittleEndian
|
||||||
@ -339,13 +335,6 @@ func (dag *BlockDAG) createDAGState() error {
|
|||||||
if err := dbPutLocalSubnetworkID(dbTx, dag.subnetworkID); err != nil {
|
if err := dbPutLocalSubnetworkID(dbTx, dag.subnetworkID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the bucket that houses the fee transactions.
|
|
||||||
_, err = meta.CreateBucket(feeTxBucketName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -374,7 +363,7 @@ func (dag *BlockDAG) removeDAGState() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = meta.Delete(utxoSetVersionKeyName)
|
err = dbTx.Metadata().Delete(utxoSetVersionKeyName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -384,12 +373,7 @@ func (dag *BlockDAG) removeDAGState() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = meta.Delete(localSubnetworkKeyName)
|
err = dbTx.Metadata().Delete(localSubnetworkKeyName)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = meta.DeleteBucket(feeTxBucketName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -498,11 +482,6 @@ func (dag *BlockDAG) initDAGState() error {
|
|||||||
dag.blockCount++
|
dag.blockCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
node.feeTransaction, err = dbFetchFeeTx(dbTx, node.hash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
lastNode = node
|
lastNode = node
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
@ -193,9 +193,9 @@ const (
|
|||||||
// ErrBadFeeTransaction indicates that the block's fee transaction is not build as expected
|
// ErrBadFeeTransaction indicates that the block's fee transaction is not build as expected
|
||||||
ErrBadFeeTransaction
|
ErrBadFeeTransaction
|
||||||
|
|
||||||
// ErrExplicitFeeTransaction indicates a block contains an explicit
|
// ErrMultipleFeeTransactions indicates a block contains more than one
|
||||||
// fee transaction, while it should be omitted.
|
// fee transaction.
|
||||||
ErrExplicitFeeTransaction
|
ErrMultipleFeeTransactions
|
||||||
|
|
||||||
// ErrScriptMalformed indicates a transaction script is malformed in
|
// ErrScriptMalformed indicates a transaction script is malformed in
|
||||||
// some way. For example, it might be longer than the maximum allowed
|
// some way. For example, it might be longer than the maximum allowed
|
||||||
@ -285,7 +285,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
|||||||
ErrBadCoinbaseHeight: "ErrBadCoinbaseHeight",
|
ErrBadCoinbaseHeight: "ErrBadCoinbaseHeight",
|
||||||
ErrSecondTxNotFeeTransaction: "ErrSecondTxNotFeeTransaction",
|
ErrSecondTxNotFeeTransaction: "ErrSecondTxNotFeeTransaction",
|
||||||
ErrBadFeeTransaction: "ErrBadFeeTransaction",
|
ErrBadFeeTransaction: "ErrBadFeeTransaction",
|
||||||
ErrExplicitFeeTransaction: "ErrExplicitFeeTransaction",
|
ErrMultipleFeeTransactions: "ErrMultipleFeeTransactions",
|
||||||
ErrScriptMalformed: "ErrScriptMalformed",
|
ErrScriptMalformed: "ErrScriptMalformed",
|
||||||
ErrScriptValidation: "ErrScriptValidation",
|
ErrScriptValidation: "ErrScriptValidation",
|
||||||
ErrParentBlockUnknown: "ErrParentBlockUnknown",
|
ErrParentBlockUnknown: "ErrParentBlockUnknown",
|
||||||
|
@ -53,7 +53,7 @@ func TestErrorCodeStringer(t *testing.T) {
|
|||||||
{ErrBadCoinbaseHeight, "ErrBadCoinbaseHeight"},
|
{ErrBadCoinbaseHeight, "ErrBadCoinbaseHeight"},
|
||||||
{ErrSecondTxNotFeeTransaction, "ErrSecondTxNotFeeTransaction"},
|
{ErrSecondTxNotFeeTransaction, "ErrSecondTxNotFeeTransaction"},
|
||||||
{ErrBadFeeTransaction, "ErrBadFeeTransaction"},
|
{ErrBadFeeTransaction, "ErrBadFeeTransaction"},
|
||||||
{ErrExplicitFeeTransaction, "ErrExplicitFeeTransaction"},
|
{ErrMultipleFeeTransactions, "ErrMultipleFeeTransactions"},
|
||||||
{ErrScriptMalformed, "ErrScriptMalformed"},
|
{ErrScriptMalformed, "ErrScriptMalformed"},
|
||||||
{ErrScriptValidation, "ErrScriptValidation"},
|
{ErrScriptValidation, "ErrScriptValidation"},
|
||||||
{ErrParentBlockUnknown, "ErrParentBlockUnknown"},
|
{ErrParentBlockUnknown, "ErrParentBlockUnknown"},
|
||||||
|
@ -121,8 +121,24 @@ func dbFetchFeeData(dbTx database.Tx, blockHash *daghash.Hash) (compactFeeData,
|
|||||||
|
|
||||||
// The following functions deal with building and validating the fee transaction
|
// The following functions deal with building and validating the fee transaction
|
||||||
|
|
||||||
|
func (node *blockNode) validateFeeTransaction(dag *BlockDAG, block *util.Block, txsAcceptanceData MultiBlockTxsAcceptanceData) error {
|
||||||
|
if node.isGenesis() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
expectedFeeTransaction, err := node.buildFeeTransaction(dag, txsAcceptanceData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !expectedFeeTransaction.TxHash().IsEqual(block.FeeTransaction().Hash()) {
|
||||||
|
return ruleError(ErrBadFeeTransaction, "Fee transaction is not built as expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// buildFeeTransaction returns the expected fee transaction for the current block
|
// buildFeeTransaction returns the expected fee transaction for the current block
|
||||||
func (node *blockNode) buildFeeTransaction(dag *BlockDAG, txsAcceptanceData MultiBlockTxsAcceptanceData) (*util.Tx, error) {
|
func (node *blockNode) buildFeeTransaction(dag *BlockDAG, txsAcceptanceData MultiBlockTxsAcceptanceData) (*wire.MsgTx, error) {
|
||||||
bluesFeeData, err := node.getBluesFeeData(dag)
|
bluesFeeData, err := node.getBluesFeeData(dag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -142,7 +158,7 @@ func (node *blockNode) buildFeeTransaction(dag *BlockDAG, txsAcceptanceData Mult
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
feeTx := wire.NewNativeMsgTx(wire.TxVersion, txIns, txOuts)
|
feeTx := wire.NewNativeMsgTx(wire.TxVersion, txIns, txOuts)
|
||||||
return util.NewTx(txsort.Sort(feeTx)), nil
|
return txsort.Sort(feeTx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// feeInputAndOutputForBlueBlock calculates the input and output that should go into the fee transaction of blueBlock
|
// feeInputAndOutputForBlueBlock calculates the input and output that should go into the fee transaction of blueBlock
|
||||||
@ -201,34 +217,3 @@ func feeInputAndOutputForBlueBlock(blueBlock *blockNode, txsAcceptanceData Multi
|
|||||||
|
|
||||||
return txIn, txOut, nil
|
return txIn, txOut, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dbPutFeeTx(dbTx database.Tx, blockHash *daghash.Hash, feeTx *util.Tx) error {
|
|
||||||
w := &bytes.Buffer{}
|
|
||||||
|
|
||||||
if err := feeTx.MsgTx().Serialize(w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
serialized := w.Bytes()
|
|
||||||
|
|
||||||
feeTxBucket := dbTx.Metadata().Bucket(feeTxBucketName)
|
|
||||||
|
|
||||||
return feeTxBucket.Put(blockHash[:], serialized)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dbFetchFeeTx(dbTx database.Tx, blockHash *daghash.Hash) (*util.Tx, error) {
|
|
||||||
feeTxBucket := dbTx.Metadata().Bucket(feeTxBucketName)
|
|
||||||
serialized := feeTxBucket.Get(blockHash[:])
|
|
||||||
if serialized == nil {
|
|
||||||
return nil, fmt.Errorf("No feeTx found in database for block %s", blockHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := bytes.NewReader(serialized)
|
|
||||||
msgTx := &wire.MsgTx{}
|
|
||||||
err := msgTx.Deserialize(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.NewTx(msgTx), nil
|
|
||||||
}
|
|
||||||
|
@ -664,12 +664,10 @@ func (idx *AddrIndex) indexPkScript(data writeIndexData, pkScript []byte, txIdx
|
|||||||
// the passed map.
|
// the passed map.
|
||||||
func (idx *AddrIndex) indexBlock(data writeIndexData, block *util.Block, dag *blockdag.BlockDAG) {
|
func (idx *AddrIndex) indexBlock(data writeIndexData, block *util.Block, dag *blockdag.BlockDAG) {
|
||||||
for txIdx, tx := range block.Transactions() {
|
for txIdx, tx := range block.Transactions() {
|
||||||
// Coinbase does not reference any previous txs,
|
// Coinbases do not reference any inputs. Since the block is
|
||||||
// so skip scanning its inputs.
|
// required to have already gone through full validation, it has
|
||||||
//
|
// already been proven on the first transaction in the block is
|
||||||
// Since the block is required to have already gone through full
|
// a coinbase, and the second one is a fee transaction.
|
||||||
// validation, it has already been proven that the first tx in
|
|
||||||
// the block is a coinbase
|
|
||||||
if txIdx > 1 {
|
if txIdx > 1 {
|
||||||
for _, txIn := range tx.MsgTx().TxIn {
|
for _, txIn := range tx.MsgTx().TxIn {
|
||||||
// The UTXO should always have the input since
|
// The UTXO should always have the input since
|
||||||
@ -730,6 +728,28 @@ func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block *util.Block, dag *blo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisconnectBlock is invoked by the index manager when a block has been
|
||||||
|
// disconnected from the main chain. This indexer removes the address mappings
|
||||||
|
// each transaction in the block involve.
|
||||||
|
//
|
||||||
|
// This is part of the Indexer interface.
|
||||||
|
func (idx *AddrIndex) DisconnectBlock(dbTx database.Tx, block *util.Block, dag *blockdag.BlockDAG) error {
|
||||||
|
// Build all of the address to transaction mappings in a local map.
|
||||||
|
addrsToTxns := make(writeIndexData)
|
||||||
|
idx.indexBlock(addrsToTxns, block, dag)
|
||||||
|
|
||||||
|
// Remove all of the index entries for each address.
|
||||||
|
bucket := dbTx.Metadata().Bucket(addrIndexKey)
|
||||||
|
for addrKey, txIdxs := range addrsToTxns {
|
||||||
|
err := dbRemoveAddrIndexEntries(bucket, addrKey, len(txIdxs))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TxRegionsForAddress returns a slice of block regions which identify each
|
// TxRegionsForAddress returns a slice of block regions which identify each
|
||||||
// transaction that involves the passed address according to the specified
|
// transaction that involves the passed address according to the specified
|
||||||
// number to skip, number requested, and whether or not the results should be
|
// number to skip, number requested, and whether or not the results should be
|
||||||
|
@ -204,8 +204,8 @@ func storeFilter(dbTx database.Tx, block *util.Block, f *gcs.Filter,
|
|||||||
// ConnectBlock is invoked by the index manager when a new block has been
|
// ConnectBlock is invoked by the index manager when a new block has been
|
||||||
// connected to the main chain. This indexer adds a hash-to-cf mapping for
|
// connected to the main chain. This indexer adds a hash-to-cf mapping for
|
||||||
// every passed block. This is part of the Indexer interface.
|
// every passed block. This is part of the Indexer interface.
|
||||||
func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *util.Block, _ *blockdag.BlockDAG,
|
func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *util.Block,
|
||||||
_ blockdag.MultiBlockTxsAcceptanceData, _ blockdag.MultiBlockTxsAcceptanceData) error {
|
_ *blockdag.BlockDAG, _ blockdag.MultiBlockTxsAcceptanceData, _ blockdag.MultiBlockTxsAcceptanceData) error {
|
||||||
|
|
||||||
f, err := builder.BuildBasicFilter(block.MsgBlock())
|
f, err := builder.BuildBasicFilter(block.MsgBlock())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -225,6 +225,36 @@ func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *util.Block, _ *blockda
|
|||||||
return storeFilter(dbTx, block, f, wire.GCSFilterExtended)
|
return storeFilter(dbTx, block, f, wire.GCSFilterExtended)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisconnectBlock is invoked by the index manager when a block has been
|
||||||
|
// disconnected from the main chain. This indexer removes the hash-to-cf
|
||||||
|
// mapping for every passed block. This is part of the Indexer interface.
|
||||||
|
func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *util.Block,
|
||||||
|
_ *blockdag.BlockDAG) error {
|
||||||
|
|
||||||
|
for _, key := range cfIndexKeys {
|
||||||
|
err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range cfHeaderKeys {
|
||||||
|
err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range cfHashKeys {
|
||||||
|
err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// entryByBlockHash fetches a filter index entry of a particular type
|
// entryByBlockHash fetches a filter index entry of a particular type
|
||||||
// (eg. filter, filter header, etc) for a filter type and block hash.
|
// (eg. filter, filter header, etc) for a filter type and block hash.
|
||||||
func (idx *CfIndex) entryByBlockHash(filterTypeKeys [][]byte,
|
func (idx *CfIndex) entryByBlockHash(filterTypeKeys [][]byte,
|
||||||
|
@ -52,8 +52,7 @@ type Indexer interface {
|
|||||||
|
|
||||||
// ConnectBlock is invoked when the index manager is notified that a new
|
// ConnectBlock is invoked when the index manager is notified that a new
|
||||||
// block has been connected to the DAG.
|
// block has been connected to the DAG.
|
||||||
ConnectBlock(dbTx database.Tx, block *util.Block, dag *blockdag.BlockDAG,
|
ConnectBlock(dbTx database.Tx, block *util.Block, dag *blockdag.BlockDAG, _ blockdag.MultiBlockTxsAcceptanceData, _ blockdag.MultiBlockTxsAcceptanceData) error
|
||||||
acceptedTxsData blockdag.MultiBlockTxsAcceptanceData, virtualTxsAcceptanceData blockdag.MultiBlockTxsAcceptanceData) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertError identifies an error that indicates an internal code consistency
|
// AssertError identifies an error that indicates an internal code consistency
|
||||||
|
@ -6,7 +6,6 @@ package indexers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/daglabs/btcd/blockdag"
|
"github.com/daglabs/btcd/blockdag"
|
||||||
"github.com/daglabs/btcd/database"
|
"github.com/daglabs/btcd/database"
|
||||||
"github.com/daglabs/btcd/util"
|
"github.com/daglabs/btcd/util"
|
||||||
|
@ -5,9 +5,8 @@
|
|||||||
package blockdag
|
package blockdag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/daglabs/btcd/util/daghash"
|
"github.com/daglabs/btcd/util/daghash"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/daglabs/btcd/util"
|
"github.com/daglabs/btcd/util"
|
||||||
)
|
)
|
||||||
@ -26,7 +25,7 @@ func TestMerkle(t *testing.T) {
|
|||||||
|
|
||||||
idMerkleTree := BuildIDMerkleTreeStore(block.Transactions())
|
idMerkleTree := BuildIDMerkleTreeStore(block.Transactions())
|
||||||
calculatedIDMerkleRoot := idMerkleTree.Root()
|
calculatedIDMerkleRoot := idMerkleTree.Root()
|
||||||
wantIDMerkleRoot, err := daghash.NewHashFromStr("dba6ffd023a545ed2611653df48edfc20fe38526cf7a43c8c22f463bd8226e77")
|
wantIDMerkleRoot, err := daghash.NewHashFromStr("65308857c92c4e5dd3c5e61b73d6b78a87456b5f8f16b13c1e02c47768a0b881")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("BuildIDMerkleTreeStore: unexpected error: %s", err)
|
t.Errorf("BuildIDMerkleTreeStore: unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
BIN
blockdag/testdata/blk_0_to_4.dat
vendored
BIN
blockdag/testdata/blk_0_to_4.dat
vendored
Binary file not shown.
BIN
blockdag/testdata/blk_3A.dat
vendored
BIN
blockdag/testdata/blk_3A.dat
vendored
Binary file not shown.
BIN
blockdag/testdata/blk_3B.dat
vendored
BIN
blockdag/testdata/blk_3B.dat
vendored
Binary file not shown.
BIN
blockdag/testdata/blk_3C.dat
vendored
BIN
blockdag/testdata/blk_3C.dat
vendored
Binary file not shown.
BIN
blockdag/testdata/blk_3D.dat
vendored
BIN
blockdag/testdata/blk_3D.dat
vendored
Binary file not shown.
@ -153,7 +153,7 @@ func CalcBlockSubsidy(height uint64, dagParams *dagconfig.Params) uint64 {
|
|||||||
|
|
||||||
// CheckTransactionSanity performs some preliminary checks on a transaction to
|
// CheckTransactionSanity performs some preliminary checks on a transaction to
|
||||||
// ensure it is sane. These checks are context free.
|
// ensure it is sane. These checks are context free.
|
||||||
func CheckTransactionSanity(tx *util.Tx, subnetworkID *subnetworkid.SubnetworkID) error {
|
func CheckTransactionSanity(tx *util.Tx, subnetworkID *subnetworkid.SubnetworkID, isFeeTransaction bool) error {
|
||||||
// A transaction must have at least one input.
|
// A transaction must have at least one input.
|
||||||
msgTx := tx.MsgTx()
|
msgTx := tx.MsgTx()
|
||||||
if len(msgTx.TxIn) == 0 {
|
if len(msgTx.TxIn) == 0 {
|
||||||
@ -509,20 +509,29 @@ func (dag *BlockDAG) checkBlockSanity(block *util.Block, flags BehaviorFlags) er
|
|||||||
"block is not a coinbase")
|
"block is not a coinbase")
|
||||||
}
|
}
|
||||||
|
|
||||||
txOffset := 1
|
isGenesis := block.MsgBlock().Header.IsGenesis()
|
||||||
|
if !isGenesis && !IsFeeTransaction(transactions[1]) {
|
||||||
|
return ruleError(ErrSecondTxNotFeeTransaction, "second transaction in "+
|
||||||
|
"block is not a fee transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
txOffset := 2
|
||||||
|
if isGenesis {
|
||||||
|
txOffset = 1
|
||||||
|
}
|
||||||
|
|
||||||
// A block must not have more than one coinbase. And transactions must be
|
// A block must not have more than one coinbase. And transactions must be
|
||||||
// ordered by subnetwork
|
// ordered by subnetwork
|
||||||
for i, tx := range transactions[txOffset:] {
|
for i, tx := range transactions[txOffset:] {
|
||||||
if IsCoinBase(tx) {
|
if IsCoinBase(tx) {
|
||||||
str := fmt.Sprintf("block contains second coinbase at "+
|
str := fmt.Sprintf("block contains second coinbase at "+
|
||||||
"index %d", i+txOffset)
|
"index %d", i+2)
|
||||||
return ruleError(ErrMultipleCoinbases, str)
|
return ruleError(ErrMultipleCoinbases, str)
|
||||||
}
|
}
|
||||||
if IsFeeTransaction(tx) {
|
if IsFeeTransaction(tx) {
|
||||||
str := fmt.Sprintf("block contains an explicit fee transaction at "+
|
str := fmt.Sprintf("block contains second fee transaction at "+
|
||||||
"index %d", i+txOffset)
|
"index %d", i+2)
|
||||||
return ruleError(ErrExplicitFeeTransaction, str)
|
return ruleError(ErrMultipleFeeTransactions, str)
|
||||||
}
|
}
|
||||||
if subnetworkid.Less(&tx.MsgTx().SubnetworkID, &transactions[i].MsgTx().SubnetworkID) {
|
if subnetworkid.Less(&tx.MsgTx().SubnetworkID, &transactions[i].MsgTx().SubnetworkID) {
|
||||||
return ruleError(ErrTransactionsNotSorted, "transactions must be sorted by subnetwork")
|
return ruleError(ErrTransactionsNotSorted, "transactions must be sorted by subnetwork")
|
||||||
@ -531,8 +540,9 @@ func (dag *BlockDAG) checkBlockSanity(block *util.Block, flags BehaviorFlags) er
|
|||||||
|
|
||||||
// Do some preliminary checks on each transaction to ensure they are
|
// Do some preliminary checks on each transaction to ensure they are
|
||||||
// sane before continuing.
|
// sane before continuing.
|
||||||
for _, tx := range transactions {
|
for i, tx := range transactions {
|
||||||
err := CheckTransactionSanity(tx, dag.subnetworkID)
|
isFeeTransaction := i == util.FeeTransactionIndex
|
||||||
|
err := CheckTransactionSanity(tx, dag.subnetworkID, isFeeTransaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1035,10 +1045,6 @@ func (dag *BlockDAG) checkConnectToPastUTXO(block *blockNode, pastUTXO UTXOSet,
|
|||||||
return nil, fmt.Errorf("Error adding tx %s fee to compactFeeFactory: %s", tx.ID(), err)
|
return nil, fmt.Errorf("Error adding tx %s fee to compactFeeFactory: %s", tx.ID(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a 0 fee for implicit fee transaction
|
|
||||||
compactFeeFactory.add(0)
|
|
||||||
|
|
||||||
feeData, err := compactFeeFactory.data()
|
feeData, err := compactFeeFactory.data()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error getting bytes of fee data: %s", err)
|
return nil, fmt.Errorf("Error getting bytes of fee data: %s", err)
|
||||||
|
@ -730,7 +730,7 @@ func TestCheckTransactionSanity(t *testing.T) {
|
|||||||
test.extraModificationsFunc(tx)
|
test.extraModificationsFunc(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := CheckTransactionSanity(util.NewTx(tx), &test.nodeSubnetworkID)
|
err := CheckTransactionSanity(util.NewTx(tx), &test.nodeSubnetworkID, false)
|
||||||
if e := checkRuleError(err, test.expectedErr); e != nil {
|
if e := checkRuleError(err, test.expectedErr); e != nil {
|
||||||
t.Errorf("TestCheckTransactionSanity: '%s': %v", test.name, e)
|
t.Errorf("TestCheckTransactionSanity: '%s': %v", test.name, e)
|
||||||
continue
|
continue
|
||||||
@ -758,21 +758,21 @@ var Block100000 = wire.MsgBlock{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
HashMerkleRoot: &daghash.Hash{
|
HashMerkleRoot: &daghash.Hash{
|
||||||
0x07, 0x86, 0x69, 0xa4, 0x2c, 0x70, 0x6f, 0x67,
|
0x30, 0xed, 0xf5, 0xbd, 0xd1, 0x4f, 0x8f, 0xb2,
|
||||||
0xc3, 0xaa, 0xe5, 0x4c, 0x1b, 0x3e, 0x12, 0x92,
|
0x0b, 0x6c, 0x92, 0xac, 0xd2, 0x47, 0xb7, 0xd6,
|
||||||
0x5e, 0x90, 0x80, 0x48, 0x85, 0x88, 0x4b, 0x35,
|
0x6f, 0x22, 0xfa, 0x60, 0x36, 0x80, 0x99, 0xc3,
|
||||||
0xb4, 0x72, 0x53, 0x46, 0xbb, 0xa7, 0x38, 0xe8,
|
0x6e, 0x39, 0x14, 0x9b, 0xcc, 0x1f, 0x31, 0xa9,
|
||||||
},
|
},
|
||||||
AcceptedIDMerkleRoot: &daghash.Hash{
|
AcceptedIDMerkleRoot: &daghash.Hash{
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x5d, 0x4e, 0x2c, 0xc9, 0x57, 0x88, 0x30, 0x65,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x81, 0xb8, 0xa0, 0x68, 0x77, 0xc4, 0x02, 0x1e,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x3c, 0xb1, 0x16, 0x8f, 0x5f, 0x6b, 0x45, 0x87,
|
||||||
},
|
},
|
||||||
UTXOCommitment: &daghash.ZeroHash,
|
UTXOCommitment: &daghash.ZeroHash,
|
||||||
Timestamp: time.Unix(0x5cee92cc, 0),
|
Timestamp: time.Unix(0x5c404bc3, 0),
|
||||||
Bits: 0x207fffff,
|
Bits: 0x207fffff,
|
||||||
Nonce: 0x00000000,
|
Nonce: 0xdffffffffffffff9,
|
||||||
},
|
},
|
||||||
Transactions: []*wire.MsgTx{
|
Transactions: []*wire.MsgTx{
|
||||||
{
|
{
|
||||||
@ -784,7 +784,8 @@ var Block100000 = wire.MsgBlock{
|
|||||||
Index: 0xffffffff,
|
Index: 0xffffffff,
|
||||||
},
|
},
|
||||||
SignatureScript: []byte{
|
SignatureScript: []byte{
|
||||||
0x02, 0x10, 0x27, 0x51, 0x0b, 0x2f, 0x50, 0x32,
|
0x02, 0x10, 0x27, 0x08, 0x8f, 0x22, 0xfb, 0x88,
|
||||||
|
0x45, 0x7b, 0xee, 0xeb, 0x0b, 0x2f, 0x50, 0x32,
|
||||||
0x53, 0x48, 0x2f, 0x62, 0x74, 0x63, 0x64, 0x2f,
|
0x53, 0x48, 0x2f, 0x62, 0x74, 0x63, 0x64, 0x2f,
|
||||||
},
|
},
|
||||||
Sequence: math.MaxUint64,
|
Sequence: math.MaxUint64,
|
||||||
@ -794,15 +795,43 @@ var Block100000 = wire.MsgBlock{
|
|||||||
{
|
{
|
||||||
Value: 0x12a05f200, // 5000000000
|
Value: 0x12a05f200, // 5000000000
|
||||||
PkScript: []byte{
|
PkScript: []byte{
|
||||||
0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49,
|
0x51,
|
||||||
0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7,
|
|
||||||
0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
LockTime: 0,
|
LockTime: 0,
|
||||||
SubnetworkID: *subnetworkid.SubnetworkIDNative,
|
SubnetworkID: *subnetworkid.SubnetworkIDNative,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Version: 1,
|
||||||
|
TxIn: []*wire.TxIn{
|
||||||
|
{
|
||||||
|
PreviousOutPoint: wire.OutPoint{
|
||||||
|
TxID: daghash.TxID{
|
||||||
|
0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
|
||||||
|
0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
|
||||||
|
0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
|
||||||
|
0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
Index: 0xffffffff,
|
||||||
|
},
|
||||||
|
Sequence: math.MaxUint64,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PreviousOutPoint: wire.OutPoint{
|
||||||
|
TxID: daghash.TxID{
|
||||||
|
0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b,
|
||||||
|
0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87,
|
||||||
|
0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52,
|
||||||
|
0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
Index: 0xffffffff,
|
||||||
|
},
|
||||||
|
Sequence: math.MaxUint64,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SubnetworkID: *subnetworkid.SubnetworkIDNative,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
TxIn: []*wire.TxIn{
|
TxIn: []*wire.TxIn{
|
||||||
@ -1077,6 +1106,36 @@ var BlockWithWrongTxOrder = wire.MsgBlock{
|
|||||||
},
|
},
|
||||||
LockTime: 0,
|
LockTime: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Version: 1,
|
||||||
|
TxIn: []*wire.TxIn{
|
||||||
|
{
|
||||||
|
PreviousOutPoint: wire.OutPoint{
|
||||||
|
TxID: daghash.TxID{
|
||||||
|
0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
|
||||||
|
0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
|
||||||
|
0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
|
||||||
|
0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
Index: 0xffffffff,
|
||||||
|
},
|
||||||
|
Sequence: math.MaxUint64,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PreviousOutPoint: wire.OutPoint{
|
||||||
|
TxID: daghash.TxID{
|
||||||
|
0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b,
|
||||||
|
0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87,
|
||||||
|
0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52,
|
||||||
|
0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
Index: 0xffffffff,
|
||||||
|
},
|
||||||
|
Sequence: math.MaxUint64,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SubnetworkID: *subnetworkid.SubnetworkIDNative,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
TxIn: []*wire.TxIn{
|
TxIn: []*wire.TxIn{
|
||||||
|
@ -847,7 +847,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, isNew, rateLimit, rejectDu
|
|||||||
// Perform preliminary sanity checks on the transaction. This makes
|
// Perform preliminary sanity checks on the transaction. This makes
|
||||||
// use of blockDAG which contains the invariant rules for what
|
// use of blockDAG which contains the invariant rules for what
|
||||||
// transactions are allowed into blocks.
|
// transactions are allowed into blocks.
|
||||||
err := blockdag.CheckTransactionSanity(tx, subnetworkID)
|
err := blockdag.CheckTransactionSanity(tx, subnetworkID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if cerr, ok := err.(blockdag.RuleError); ok {
|
if cerr, ok := err.(blockdag.RuleError); ok {
|
||||||
return nil, nil, dagRuleError(cerr)
|
return nil, nil, dagRuleError(cerr)
|
||||||
@ -1436,12 +1436,12 @@ func (mp *TxPool) HandleNewBlock(block *util.Block, txChan chan NewBlockMsg) err
|
|||||||
// no longer an orphan. Transactions which depend on a confirmed
|
// no longer an orphan. Transactions which depend on a confirmed
|
||||||
// transaction are NOT removed recursively because they are still
|
// transaction are NOT removed recursively because they are still
|
||||||
// valid.
|
// valid.
|
||||||
err := mp.RemoveTransactions(block.Transactions()[util.CoinbaseTransactionIndex+1:])
|
err := mp.RemoveTransactions(block.Transactions()[util.FeeTransactionIndex:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mp.mpUTXOSet = oldUTXOSet
|
mp.mpUTXOSet = oldUTXOSet
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, tx := range block.Transactions()[util.CoinbaseTransactionIndex+1:] {
|
for _, tx := range block.Transactions()[util.FeeTransactionIndex:] {
|
||||||
mp.RemoveDoubleSpends(tx)
|
mp.RemoveDoubleSpends(tx)
|
||||||
mp.RemoveOrphan(tx)
|
mp.RemoveOrphan(tx)
|
||||||
acceptedTxs := mp.ProcessOrphans(tx)
|
acceptedTxs := mp.ProcessOrphans(tx)
|
||||||
|
@ -414,6 +414,13 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
|||||||
}
|
}
|
||||||
numCoinbaseSigOps := int64(blockdag.CountSigOps(coinbaseTx))
|
numCoinbaseSigOps := int64(blockdag.CountSigOps(coinbaseTx))
|
||||||
|
|
||||||
|
msgFeeTransaction, err := g.dag.NextBlockFeeTransactionNoLock()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
feeTransaction := util.NewTx(msgFeeTransaction)
|
||||||
|
feeTxSigOps := int64(blockdag.CountSigOps(feeTransaction))
|
||||||
|
|
||||||
// Get the current source transactions and create a priority queue to
|
// Get the current source transactions and create a priority queue to
|
||||||
// hold the transactions which are ready for inclusion into a block
|
// hold the transactions which are ready for inclusion into a block
|
||||||
// along with some priority related and fee metadata. Reserve the same
|
// along with some priority related and fee metadata. Reserve the same
|
||||||
@ -428,14 +435,14 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
|||||||
// generated block with reserved space. Also create a utxo view to
|
// generated block with reserved space. Also create a utxo view to
|
||||||
// house all of the input transactions so multiple lookups can be
|
// house all of the input transactions so multiple lookups can be
|
||||||
// avoided.
|
// avoided.
|
||||||
blockTxns := make([]*util.Tx, 0, len(sourceTxns)+1)
|
blockTxns := make([]*util.Tx, 0, len(sourceTxns)+2)
|
||||||
blockTxns = append(blockTxns, coinbaseTx)
|
blockTxns = append(blockTxns, coinbaseTx, feeTransaction)
|
||||||
|
|
||||||
// The starting block size is the size of the block header plus the max
|
// The starting block size is the size of the block header plus the max
|
||||||
// possible transaction count size, plus the size of the coinbase
|
// possible transaction count size, plus the size of the coinbase
|
||||||
// transaction.
|
// transaction.
|
||||||
blockSize := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())
|
blockSize := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())
|
||||||
blockSigOps := numCoinbaseSigOps
|
blockSigOps := numCoinbaseSigOps + feeTxSigOps
|
||||||
totalFees := uint64(0)
|
totalFees := uint64(0)
|
||||||
|
|
||||||
// Create slices to hold the fees and number of signature operations
|
// Create slices to hold the fees and number of signature operations
|
||||||
@ -444,10 +451,10 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
|||||||
// a transaction as it is selected for inclusion in the final block.
|
// a transaction as it is selected for inclusion in the final block.
|
||||||
// However, since the total fees aren't known yet, use a dummy value for
|
// However, since the total fees aren't known yet, use a dummy value for
|
||||||
// the coinbase fee which will be updated later.
|
// the coinbase fee which will be updated later.
|
||||||
txFees := make([]uint64, 0, len(sourceTxns)+1)
|
txFees := make([]uint64, 0, len(sourceTxns)+2)
|
||||||
txSigOpCounts := make([]int64, 0, len(sourceTxns)+1)
|
txSigOpCounts := make([]int64, 0, len(sourceTxns)+2)
|
||||||
txFees = append(txFees, 0, 0) // For coinbase and fee txs
|
txFees = append(txFees, 0, 0) // For coinbase and fee txs
|
||||||
txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)
|
txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps, feeTxSigOps)
|
||||||
|
|
||||||
log.Debugf("Considering %d transactions for inclusion to new block",
|
log.Debugf("Considering %d transactions for inclusion to new block",
|
||||||
len(sourceTxns))
|
len(sourceTxns))
|
||||||
|
@ -379,7 +379,7 @@ func TestNewBlockTemplate(t *testing.T) {
|
|||||||
*subnetworkTx1.TxID(): false,
|
*subnetworkTx1.TxID(): false,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tx := range template2.Block.Transactions[1:] {
|
for _, tx := range template2.Block.Transactions[2:] {
|
||||||
id := *tx.TxID()
|
id := *tx.TxID()
|
||||||
if _, ok := expectedTxs[id]; !ok {
|
if _, ok := expectedTxs[id]; !ok {
|
||||||
t.Errorf("Unexpected tx %v in template2's candidate block", id)
|
t.Errorf("Unexpected tx %v in template2's candidate block", id)
|
||||||
|
@ -26,6 +26,10 @@ const (
|
|||||||
|
|
||||||
// CoinbaseTransactionIndex is the index of the coinbase transaction in every block
|
// CoinbaseTransactionIndex is the index of the coinbase transaction in every block
|
||||||
CoinbaseTransactionIndex = 0
|
CoinbaseTransactionIndex = 0
|
||||||
|
|
||||||
|
// FeeTransactionIndex is the index of the fee transaction in every block (except genesis,
|
||||||
|
// which doesn't have a fee transaction)
|
||||||
|
FeeTransactionIndex = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error satisfies the error interface and prints human-readable errors.
|
// Error satisfies the error interface and prints human-readable errors.
|
||||||
@ -222,6 +226,16 @@ func (b *Block) CoinbaseTransaction() *Tx {
|
|||||||
return b.Transactions()[CoinbaseTransactionIndex]
|
return b.Transactions()[CoinbaseTransactionIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FeeTransaction returns this block's fee transaction
|
||||||
|
// If this block is a genesis block, it has no fee transaction, and therefore
|
||||||
|
// nil is returned.
|
||||||
|
func (b *Block) FeeTransaction() *Tx {
|
||||||
|
if b.IsGenesis() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b.Transactions()[FeeTransactionIndex]
|
||||||
|
}
|
||||||
|
|
||||||
// Timestamp returns this block's timestamp
|
// Timestamp returns this block's timestamp
|
||||||
func (b *Block) Timestamp() time.Time {
|
func (b *Block) Timestamp() time.Time {
|
||||||
return b.msgBlock.Header.Timestamp
|
return b.msgBlock.Header.Timestamp
|
||||||
|
@ -306,8 +306,8 @@ func (msg *MsgTx) IsCoinBase() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsFeeTransaction determines whether or not a transaction is a fee transaction. A fee
|
// IsFeeTransaction determines whether or not a transaction is a fee transaction. A fee
|
||||||
// transaction is a special transaction implicitly included in blocks that distributes fees to
|
// transaction is a special transaction created by miners that distributes fees to the
|
||||||
// the previous blocks' miners. Each input of the fee transaction should set index to maximum
|
// previous blocks' miners. Each input of the fee transaction should set index to maximum
|
||||||
// value and reference the relevant block id, instead of previous transaction id.
|
// value and reference the relevant block id, instead of previous transaction id.
|
||||||
func (msg *MsgTx) IsFeeTransaction() bool {
|
func (msg *MsgTx) IsFeeTransaction() bool {
|
||||||
for _, txIn := range msg.TxIn {
|
for _, txIn := range msg.TxIn {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user