mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-10-14 00:59:33 +00:00
(#DEV-14) Removed segwit from blockchain package
This commit is contained in:
parent
ffdb76ecec
commit
cea07f3b98
@ -62,14 +62,13 @@ type BestState struct {
|
|||||||
Height int32 // The height of the block.
|
Height int32 // The height of the block.
|
||||||
Bits uint32 // The difficulty bits of the block.
|
Bits uint32 // The difficulty bits of the block.
|
||||||
BlockSize uint64 // The size of the block.
|
BlockSize uint64 // The size of the block.
|
||||||
BlockWeight uint64 // The weight of the block.
|
|
||||||
NumTxns uint64 // The number of txns in the block.
|
NumTxns uint64 // The number of txns in the block.
|
||||||
TotalTxns uint64 // The total number of txns in the chain.
|
TotalTxns uint64 // The total number of txns in the chain.
|
||||||
MedianTime time.Time // Median time as per CalcPastMedianTime.
|
MedianTime time.Time // Median time as per CalcPastMedianTime.
|
||||||
}
|
}
|
||||||
|
|
||||||
// newBestState returns a new best stats instance for the given parameters.
|
// newBestState returns a new best stats instance for the given parameters.
|
||||||
func newBestState(node *blockNode, blockSize, blockWeight, numTxns,
|
func newBestState(node *blockNode, blockSize, numTxns,
|
||||||
totalTxns uint64, medianTime time.Time) *BestState {
|
totalTxns uint64, medianTime time.Time) *BestState {
|
||||||
|
|
||||||
return &BestState{
|
return &BestState{
|
||||||
@ -77,7 +76,6 @@ func newBestState(node *blockNode, blockSize, blockWeight, numTxns,
|
|||||||
Height: node.height,
|
Height: node.height,
|
||||||
Bits: node.bits,
|
Bits: node.bits,
|
||||||
BlockSize: blockSize,
|
BlockSize: blockSize,
|
||||||
BlockWeight: blockWeight,
|
|
||||||
NumTxns: numTxns,
|
NumTxns: numTxns,
|
||||||
TotalTxns: totalTxns,
|
TotalTxns: totalTxns,
|
||||||
MedianTime: medianTime,
|
MedianTime: medianTime,
|
||||||
@ -99,7 +97,6 @@ type BlockChain struct {
|
|||||||
timeSource MedianTimeSource
|
timeSource MedianTimeSource
|
||||||
sigCache *txscript.SigCache
|
sigCache *txscript.SigCache
|
||||||
indexManager IndexManager
|
indexManager IndexManager
|
||||||
hashCache *txscript.HashCache
|
|
||||||
|
|
||||||
// The following fields are calculated based upon the provided chain
|
// The following fields are calculated based upon the provided chain
|
||||||
// parameters. They are also set when the instance is created and
|
// parameters. They are also set when the instance is created and
|
||||||
@ -600,8 +597,7 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, view *U
|
|||||||
b.stateLock.RUnlock()
|
b.stateLock.RUnlock()
|
||||||
numTxns := uint64(len(block.MsgBlock().Transactions))
|
numTxns := uint64(len(block.MsgBlock().Transactions))
|
||||||
blockSize := uint64(block.MsgBlock().SerializeSize())
|
blockSize := uint64(block.MsgBlock().SerializeSize())
|
||||||
blockWeight := uint64(GetBlockWeight(block))
|
state := newBestState(node, blockSize, numTxns,
|
||||||
state := newBestState(node, blockSize, blockWeight, numTxns,
|
|
||||||
curTotalTxns+numTxns, node.CalcPastMedianTime())
|
curTotalTxns+numTxns, node.CalcPastMedianTime())
|
||||||
|
|
||||||
// Atomically insert info into the database.
|
// Atomically insert info into the database.
|
||||||
@ -712,9 +708,8 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
|
|||||||
b.stateLock.RUnlock()
|
b.stateLock.RUnlock()
|
||||||
numTxns := uint64(len(prevBlock.MsgBlock().Transactions))
|
numTxns := uint64(len(prevBlock.MsgBlock().Transactions))
|
||||||
blockSize := uint64(prevBlock.MsgBlock().SerializeSize())
|
blockSize := uint64(prevBlock.MsgBlock().SerializeSize())
|
||||||
blockWeight := uint64(GetBlockWeight(prevBlock))
|
|
||||||
newTotalTxns := curTotalTxns - uint64(len(block.MsgBlock().Transactions))
|
newTotalTxns := curTotalTxns - uint64(len(block.MsgBlock().Transactions))
|
||||||
state := newBestState(prevNode, blockSize, blockWeight, numTxns,
|
state := newBestState(prevNode, blockSize, numTxns,
|
||||||
newTotalTxns, prevNode.CalcPastMedianTime())
|
newTotalTxns, prevNode.CalcPastMedianTime())
|
||||||
|
|
||||||
err = b.db.Update(func(dbTx database.Tx) error {
|
err = b.db.Update(func(dbTx database.Tx) error {
|
||||||
@ -1629,16 +1624,6 @@ type Config struct {
|
|||||||
// This field can be nil if the caller does not wish to make use of an
|
// This field can be nil if the caller does not wish to make use of an
|
||||||
// index manager.
|
// index manager.
|
||||||
IndexManager IndexManager
|
IndexManager IndexManager
|
||||||
|
|
||||||
// HashCache defines a transaction hash mid-state cache to use when
|
|
||||||
// validating transactions. This cache has the potential to greatly
|
|
||||||
// speed up transaction validation as re-using the pre-calculated
|
|
||||||
// mid-state eliminates the O(N^2) validation complexity due to the
|
|
||||||
// SigHashAll flag.
|
|
||||||
//
|
|
||||||
// This field can be nil if the caller is not interested in using a
|
|
||||||
// signature cache.
|
|
||||||
HashCache *txscript.HashCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a BlockChain instance using the provided configuration details.
|
// New returns a BlockChain instance using the provided configuration details.
|
||||||
@ -1688,7 +1673,6 @@ func New(config *Config) (*BlockChain, error) {
|
|||||||
maxRetargetTimespan: targetTimespan * adjustmentFactor,
|
maxRetargetTimespan: targetTimespan * adjustmentFactor,
|
||||||
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
|
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
|
||||||
index: newBlockIndex(config.DB, params),
|
index: newBlockIndex(config.DB, params),
|
||||||
hashCache: config.HashCache,
|
|
||||||
bestChain: newChainView(nil),
|
bestChain: newChainView(nil),
|
||||||
orphans: make(map[chainhash.Hash]*orphanBlock),
|
orphans: make(map[chainhash.Hash]*orphanBlock),
|
||||||
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
|
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
|
||||||
|
@ -987,8 +987,7 @@ func (b *BlockChain) createChainState() error {
|
|||||||
// genesis block, use its timestamp for the median time.
|
// genesis block, use its timestamp for the median time.
|
||||||
numTxns := uint64(len(genesisBlock.MsgBlock().Transactions))
|
numTxns := uint64(len(genesisBlock.MsgBlock().Transactions))
|
||||||
blockSize := uint64(genesisBlock.MsgBlock().SerializeSize())
|
blockSize := uint64(genesisBlock.MsgBlock().SerializeSize())
|
||||||
blockWeight := uint64(GetBlockWeight(genesisBlock))
|
b.stateSnapshot = newBestState(node, blockSize, numTxns,
|
||||||
b.stateSnapshot = newBestState(node, blockSize, blockWeight, numTxns,
|
|
||||||
numTxns, time.Unix(node.timestamp, 0))
|
numTxns, time.Unix(node.timestamp, 0))
|
||||||
|
|
||||||
// Create the initial the database chain state including creating the
|
// Create the initial the database chain state including creating the
|
||||||
@ -1192,10 +1191,8 @@ func (b *BlockChain) initChainState() error {
|
|||||||
|
|
||||||
// Initialize the state related to the best block.
|
// Initialize the state related to the best block.
|
||||||
blockSize := uint64(len(blockBytes))
|
blockSize := uint64(len(blockBytes))
|
||||||
blockWeight := uint64(GetBlockWeight(btcutil.NewBlock(&block)))
|
|
||||||
numTxns := uint64(len(block.Transactions))
|
numTxns := uint64(len(block.Transactions))
|
||||||
b.stateSnapshot = newBestState(tip, blockSize, blockWeight,
|
b.stateSnapshot = newBestState(tip, blockSize, numTxns, state.totalTxns, tip.CalcPastMedianTime())
|
||||||
numTxns, state.totalTxns, tip.CalcPastMedianTime())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -41,10 +41,6 @@ const (
|
|||||||
// maximum allowed size.
|
// maximum allowed size.
|
||||||
ErrBlockTooBig
|
ErrBlockTooBig
|
||||||
|
|
||||||
// ErrBlockWeightTooHigh indicates that the block's computed weight
|
|
||||||
// metric exceeds the maximum allowed value.
|
|
||||||
ErrBlockWeightTooHigh
|
|
||||||
|
|
||||||
// ErrBlockVersionTooOld indicates the block version is too old and is
|
// ErrBlockVersionTooOld indicates the block version is too old and is
|
||||||
// no longer accepted since the majority of the network has upgraded
|
// no longer accepted since the majority of the network has upgraded
|
||||||
// to a newer version.
|
// to a newer version.
|
||||||
@ -195,20 +191,6 @@ const (
|
|||||||
// the stack.
|
// the stack.
|
||||||
ErrScriptValidation
|
ErrScriptValidation
|
||||||
|
|
||||||
// ErrUnexpectedWitness indicates that a block includes transactions
|
|
||||||
// with witness data, but doesn't also have a witness commitment within
|
|
||||||
// the coinbase transaction.
|
|
||||||
ErrUnexpectedWitness
|
|
||||||
|
|
||||||
// ErrInvalidWitnessCommitment indicates that a block's witness
|
|
||||||
// commitment is not well formed.
|
|
||||||
ErrInvalidWitnessCommitment
|
|
||||||
|
|
||||||
// ErrWitnessCommitmentMismatch indicates that the witness commitment
|
|
||||||
// included in the block's coinbase transaction doesn't match the
|
|
||||||
// manually computed witness commitment.
|
|
||||||
ErrWitnessCommitmentMismatch
|
|
||||||
|
|
||||||
// ErrPreviousBlockUnknown indicates that the previous block is not known.
|
// ErrPreviousBlockUnknown indicates that the previous block is not known.
|
||||||
ErrPreviousBlockUnknown
|
ErrPreviousBlockUnknown
|
||||||
|
|
||||||
@ -227,7 +209,6 @@ var errorCodeStrings = map[ErrorCode]string{
|
|||||||
ErrDuplicateBlock: "ErrDuplicateBlock",
|
ErrDuplicateBlock: "ErrDuplicateBlock",
|
||||||
ErrBlockTooBig: "ErrBlockTooBig",
|
ErrBlockTooBig: "ErrBlockTooBig",
|
||||||
ErrBlockVersionTooOld: "ErrBlockVersionTooOld",
|
ErrBlockVersionTooOld: "ErrBlockVersionTooOld",
|
||||||
ErrBlockWeightTooHigh: "ErrBlockWeightTooHigh",
|
|
||||||
ErrInvalidTime: "ErrInvalidTime",
|
ErrInvalidTime: "ErrInvalidTime",
|
||||||
ErrTimeTooOld: "ErrTimeTooOld",
|
ErrTimeTooOld: "ErrTimeTooOld",
|
||||||
ErrTimeTooNew: "ErrTimeTooNew",
|
ErrTimeTooNew: "ErrTimeTooNew",
|
||||||
@ -261,9 +242,6 @@ var errorCodeStrings = map[ErrorCode]string{
|
|||||||
ErrBadCoinbaseHeight: "ErrBadCoinbaseHeight",
|
ErrBadCoinbaseHeight: "ErrBadCoinbaseHeight",
|
||||||
ErrScriptMalformed: "ErrScriptMalformed",
|
ErrScriptMalformed: "ErrScriptMalformed",
|
||||||
ErrScriptValidation: "ErrScriptValidation",
|
ErrScriptValidation: "ErrScriptValidation",
|
||||||
ErrUnexpectedWitness: "ErrUnexpectedWitness",
|
|
||||||
ErrInvalidWitnessCommitment: "ErrInvalidWitnessCommitment",
|
|
||||||
ErrWitnessCommitmentMismatch: "ErrWitnessCommitmentMismatch",
|
|
||||||
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
|
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
|
||||||
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
|
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
|
||||||
ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
|
ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
|
||||||
|
@ -16,7 +16,6 @@ func TestErrorCodeStringer(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{ErrDuplicateBlock, "ErrDuplicateBlock"},
|
{ErrDuplicateBlock, "ErrDuplicateBlock"},
|
||||||
{ErrBlockTooBig, "ErrBlockTooBig"},
|
{ErrBlockTooBig, "ErrBlockTooBig"},
|
||||||
{ErrBlockWeightTooHigh, "ErrBlockWeightTooHigh"},
|
|
||||||
{ErrBlockVersionTooOld, "ErrBlockVersionTooOld"},
|
{ErrBlockVersionTooOld, "ErrBlockVersionTooOld"},
|
||||||
{ErrInvalidTime, "ErrInvalidTime"},
|
{ErrInvalidTime, "ErrInvalidTime"},
|
||||||
{ErrTimeTooOld, "ErrTimeTooOld"},
|
{ErrTimeTooOld, "ErrTimeTooOld"},
|
||||||
@ -52,9 +51,6 @@ func TestErrorCodeStringer(t *testing.T) {
|
|||||||
{ErrBadCoinbaseHeight, "ErrBadCoinbaseHeight"},
|
{ErrBadCoinbaseHeight, "ErrBadCoinbaseHeight"},
|
||||||
{ErrScriptMalformed, "ErrScriptMalformed"},
|
{ErrScriptMalformed, "ErrScriptMalformed"},
|
||||||
{ErrScriptValidation, "ErrScriptValidation"},
|
{ErrScriptValidation, "ErrScriptValidation"},
|
||||||
{ErrUnexpectedWitness, "ErrUnexpectedWitness"},
|
|
||||||
{ErrInvalidWitnessCommitment, "ErrInvalidWitnessCommitment"},
|
|
||||||
{ErrWitnessCommitmentMismatch, "ErrWitnessCommitmentMismatch"},
|
|
||||||
{ErrPreviousBlockUnknown, "ErrPreviousBlockUnknown"},
|
{ErrPreviousBlockUnknown, "ErrPreviousBlockUnknown"},
|
||||||
{ErrInvalidAncestorBlock, "ErrInvalidAncestorBlock"},
|
{ErrInvalidAncestorBlock, "ErrInvalidAncestorBlock"},
|
||||||
{ErrPrevBlockNotBest, "ErrPrevBlockNotBest"},
|
{ErrPrevBlockNotBest, "ErrPrevBlockNotBest"},
|
||||||
|
@ -309,7 +309,7 @@ func calcMerkleRoot(txns []*wire.MsgTx) chainhash.Hash {
|
|||||||
for _, tx := range txns {
|
for _, tx := range txns {
|
||||||
utilTxns = append(utilTxns, btcutil.NewTx(tx))
|
utilTxns = append(utilTxns, btcutil.NewTx(tx))
|
||||||
}
|
}
|
||||||
merkles := blockchain.BuildMerkleTreeStore(utilTxns, false)
|
merkles := blockchain.BuildMerkleTreeStore(utilTxns)
|
||||||
return *merkles[len(merkles)-1]
|
return *merkles[len(merkles)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,18 +51,6 @@ const (
|
|||||||
// hash.
|
// hash.
|
||||||
addrKeyTypeScriptHash = 1
|
addrKeyTypeScriptHash = 1
|
||||||
|
|
||||||
// addrKeyTypePubKeyHash is the address type in an address key which
|
|
||||||
// represents a pay-to-witness-pubkey-hash address. This is required
|
|
||||||
// as the 20-byte data push of a p2wkh witness program may be the same
|
|
||||||
// data push used a p2pkh address.
|
|
||||||
addrKeyTypeWitnessPubKeyHash = 2
|
|
||||||
|
|
||||||
// addrKeyTypeScriptHash is the address type in an address key which
|
|
||||||
// represents a pay-to-witness-script-hash address. This is required,
|
|
||||||
// as p2wsh are distinct from p2sh addresses since they use a new
|
|
||||||
// script template, as well as a 32-byte data push.
|
|
||||||
addrKeyTypeWitnessScriptHash = 3
|
|
||||||
|
|
||||||
// Size of a transaction entry. It consists of 4 bytes block id + 4
|
// Size of a transaction entry. It consists of 4 bytes block id + 4
|
||||||
// bytes offset + 4 bytes length.
|
// bytes offset + 4 bytes length.
|
||||||
txEntrySize = 4 + 4 + 4
|
txEntrySize = 4 + 4 + 4
|
||||||
@ -546,24 +534,6 @@ func addrToKey(addr btcutil.Address) ([addrKeySize]byte, error) {
|
|||||||
result[0] = addrKeyTypePubKeyHash
|
result[0] = addrKeyTypePubKeyHash
|
||||||
copy(result[1:], addr.AddressPubKeyHash().Hash160()[:])
|
copy(result[1:], addr.AddressPubKeyHash().Hash160()[:])
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|
||||||
case *btcutil.AddressWitnessScriptHash:
|
|
||||||
var result [addrKeySize]byte
|
|
||||||
result[0] = addrKeyTypeWitnessScriptHash
|
|
||||||
|
|
||||||
// P2WSH outputs utilize a 32-byte data push created by hashing
|
|
||||||
// the script with sha256 instead of hash160. In order to keep
|
|
||||||
// all address entries within the database uniform and compact,
|
|
||||||
// we use a hash160 here to reduce the size of the salient data
|
|
||||||
// push to 20-bytes.
|
|
||||||
copy(result[1:], btcutil.Hash160(addr.ScriptAddress()))
|
|
||||||
return result, nil
|
|
||||||
|
|
||||||
case *btcutil.AddressWitnessPubKeyHash:
|
|
||||||
var result [addrKeySize]byte
|
|
||||||
result[0] = addrKeyTypeWitnessPubKeyHash
|
|
||||||
copy(result[1:], addr.Hash160()[:])
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [addrKeySize]byte{}, errUnsupportedAddressType
|
return [addrKeySize]byte{}, errUnsupportedAddressType
|
||||||
|
@ -5,42 +5,12 @@
|
|||||||
package blockchain
|
package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/daglabs/btcd/chaincfg/chainhash"
|
"github.com/daglabs/btcd/chaincfg/chainhash"
|
||||||
"github.com/daglabs/btcd/txscript"
|
|
||||||
"github.com/daglabs/btcutil"
|
"github.com/daglabs/btcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// CoinbaseWitnessDataLen is the required length of the only element within
|
|
||||||
// the coinbase's witness data if the coinbase transaction contains a
|
|
||||||
// witness commitment.
|
|
||||||
CoinbaseWitnessDataLen = 32
|
|
||||||
|
|
||||||
// CoinbaseWitnessPkScriptLength is the length of the public key script
|
|
||||||
// containing an OP_RETURN, the WitnessMagicBytes, and the witness
|
|
||||||
// commitment itself. In order to be a valid candidate for the output
|
|
||||||
// containing the witness commitment
|
|
||||||
CoinbaseWitnessPkScriptLength = 38
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// WitnessMagicBytes is the prefix marker within the public key script
|
|
||||||
// of a coinbase output to indicate that this output holds the witness
|
|
||||||
// commitment for a block.
|
|
||||||
WitnessMagicBytes = []byte{
|
|
||||||
txscript.OP_RETURN,
|
|
||||||
txscript.OP_DATA_36,
|
|
||||||
0xaa,
|
|
||||||
0x21,
|
|
||||||
0xa9,
|
|
||||||
0xed,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// nextPowerOfTwo returns the next highest power of two from a given number if
|
// nextPowerOfTwo returns the next highest power of two from a given number if
|
||||||
// it is not already a power of two. This is a helper function used during the
|
// it is not already a power of two. This is a helper function used during the
|
||||||
// calculation of a merkle tree.
|
// calculation of a merkle tree.
|
||||||
@ -96,12 +66,7 @@ func HashMerkleBranches(left *chainhash.Hash, right *chainhash.Hash) *chainhash.
|
|||||||
// are calculated by concatenating the left node with itself before hashing.
|
// are calculated by concatenating the left node with itself before hashing.
|
||||||
// Since this function uses nodes that are pointers to the hashes, empty nodes
|
// Since this function uses nodes that are pointers to the hashes, empty nodes
|
||||||
// will be nil.
|
// will be nil.
|
||||||
//
|
func BuildMerkleTreeStore(transactions []*btcutil.Tx) []*chainhash.Hash {
|
||||||
// The additional bool parameter indicates if we are generating the merkle tree
|
|
||||||
// using witness transaction id's rather than regular transaction id's. This
|
|
||||||
// also presents an additional case wherein the wtxid of the coinbase transaction
|
|
||||||
// is the zeroHash.
|
|
||||||
func BuildMerkleTreeStore(transactions []*btcutil.Tx, witness bool) []*chainhash.Hash {
|
|
||||||
// Calculate how many entries are required to hold the binary merkle
|
// Calculate how many entries are required to hold the binary merkle
|
||||||
// tree as a linear array and create an array of that size.
|
// tree as a linear array and create an array of that size.
|
||||||
nextPoT := nextPowerOfTwo(len(transactions))
|
nextPoT := nextPowerOfTwo(len(transactions))
|
||||||
@ -110,23 +75,9 @@ func BuildMerkleTreeStore(transactions []*btcutil.Tx, witness bool) []*chainhash
|
|||||||
|
|
||||||
// Create the base transaction hashes and populate the array with them.
|
// Create the base transaction hashes and populate the array with them.
|
||||||
for i, tx := range transactions {
|
for i, tx := range transactions {
|
||||||
// If we're computing a witness merkle root, instead of the
|
|
||||||
// regular txid, we use the modified wtxid which includes a
|
|
||||||
// transaction's witness data within the digest. Additionally,
|
|
||||||
// the coinbase's wtxid is all zeroes.
|
|
||||||
switch {
|
|
||||||
case witness && i == 0:
|
|
||||||
var zeroHash chainhash.Hash
|
|
||||||
merkles[i] = &zeroHash
|
|
||||||
case witness:
|
|
||||||
wSha := tx.MsgTx().WitnessHash()
|
|
||||||
merkles[i] = &wSha
|
|
||||||
default:
|
|
||||||
merkles[i] = tx.Hash()
|
merkles[i] = tx.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the array offset after the last transaction and adjusted to the
|
// Start the array offset after the last transaction and adjusted to the
|
||||||
// next power of two.
|
// next power of two.
|
||||||
offset := nextPoT
|
offset := nextPoT
|
||||||
@ -153,113 +104,3 @@ func BuildMerkleTreeStore(transactions []*btcutil.Tx, witness bool) []*chainhash
|
|||||||
|
|
||||||
return merkles
|
return merkles
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractWitnessCommitment attempts to locate, and return the witness
|
|
||||||
// commitment for a block. The witness commitment is of the form:
|
|
||||||
// SHA256(witness root || witness nonce). The function additionally returns a
|
|
||||||
// boolean indicating if the witness root was located within any of the txOut's
|
|
||||||
// in the passed transaction. The witness commitment is stored as the data push
|
|
||||||
// for an OP_RETURN with special magic bytes to aide in location.
|
|
||||||
func ExtractWitnessCommitment(tx *btcutil.Tx) ([]byte, bool) {
|
|
||||||
// The witness commitment *must* be located within one of the coinbase
|
|
||||||
// transaction's outputs.
|
|
||||||
if !IsCoinBase(tx) {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
msgTx := tx.MsgTx()
|
|
||||||
for i := len(msgTx.TxOut) - 1; i >= 0; i-- {
|
|
||||||
// The public key script that contains the witness commitment
|
|
||||||
// must shared a prefix with the WitnessMagicBytes, and be at
|
|
||||||
// least 38 bytes.
|
|
||||||
pkScript := msgTx.TxOut[i].PkScript
|
|
||||||
if len(pkScript) >= CoinbaseWitnessPkScriptLength &&
|
|
||||||
bytes.HasPrefix(pkScript, WitnessMagicBytes) {
|
|
||||||
|
|
||||||
// The witness commitment itself is a 32-byte hash
|
|
||||||
// directly after the WitnessMagicBytes. The remaining
|
|
||||||
// bytes beyond the 38th byte currently have no consensus
|
|
||||||
// meaning.
|
|
||||||
start := len(WitnessMagicBytes)
|
|
||||||
end := CoinbaseWitnessPkScriptLength
|
|
||||||
return msgTx.TxOut[i].PkScript[start:end], true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateWitnessCommitment validates the witness commitment (if any) found
|
|
||||||
// within the coinbase transaction of the passed block.
|
|
||||||
func ValidateWitnessCommitment(blk *btcutil.Block) error {
|
|
||||||
// If the block doesn't have any transactions at all, then we won't be
|
|
||||||
// able to extract a commitment from the non-existent coinbase
|
|
||||||
// transaction. So we exit early here.
|
|
||||||
if len(blk.Transactions()) == 0 {
|
|
||||||
str := "cannot validate witness commitment of block without " +
|
|
||||||
"transactions"
|
|
||||||
return ruleError(ErrNoTransactions, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
coinbaseTx := blk.Transactions()[0]
|
|
||||||
if len(coinbaseTx.MsgTx().TxIn) == 0 {
|
|
||||||
return ruleError(ErrNoTxInputs, "transaction has no inputs")
|
|
||||||
}
|
|
||||||
|
|
||||||
witnessCommitment, witnessFound := ExtractWitnessCommitment(coinbaseTx)
|
|
||||||
|
|
||||||
// If we can't find a witness commitment in any of the coinbase's
|
|
||||||
// outputs, then the block MUST NOT contain any transactions with
|
|
||||||
// witness data.
|
|
||||||
if !witnessFound {
|
|
||||||
for _, tx := range blk.Transactions() {
|
|
||||||
msgTx := tx.MsgTx()
|
|
||||||
if msgTx.HasWitness() {
|
|
||||||
str := fmt.Sprintf("block contains transaction with witness" +
|
|
||||||
" data, yet no witness commitment present")
|
|
||||||
return ruleError(ErrUnexpectedWitness, str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point the block contains a witness commitment, so the
|
|
||||||
// coinbase transaction MUST have exactly one witness element within
|
|
||||||
// its witness data and that element must be exactly
|
|
||||||
// CoinbaseWitnessDataLen bytes.
|
|
||||||
coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness
|
|
||||||
if len(coinbaseWitness) != 1 {
|
|
||||||
str := fmt.Sprintf("the coinbase transaction has %d items in "+
|
|
||||||
"its witness stack when only one is allowed",
|
|
||||||
len(coinbaseWitness))
|
|
||||||
return ruleError(ErrInvalidWitnessCommitment, str)
|
|
||||||
}
|
|
||||||
witnessNonce := coinbaseWitness[0]
|
|
||||||
if len(witnessNonce) != CoinbaseWitnessDataLen {
|
|
||||||
str := fmt.Sprintf("the coinbase transaction witness nonce "+
|
|
||||||
"has %d bytes when it must be %d bytes",
|
|
||||||
len(witnessNonce), CoinbaseWitnessDataLen)
|
|
||||||
return ruleError(ErrInvalidWitnessCommitment, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, with the preliminary checks out of the way, we can check if
|
|
||||||
// the extracted witnessCommitment is equal to:
|
|
||||||
// SHA256(witnessMerkleRoot || witnessNonce). Where witnessNonce is the
|
|
||||||
// coinbase transaction's only witness item.
|
|
||||||
witnessMerkleTree := BuildMerkleTreeStore(blk.Transactions(), true)
|
|
||||||
witnessMerkleRoot := witnessMerkleTree[len(witnessMerkleTree)-1]
|
|
||||||
|
|
||||||
var witnessPreimage [chainhash.HashSize * 2]byte
|
|
||||||
copy(witnessPreimage[:], witnessMerkleRoot[:])
|
|
||||||
copy(witnessPreimage[chainhash.HashSize:], witnessNonce)
|
|
||||||
|
|
||||||
computedCommitment := chainhash.DoubleHashB(witnessPreimage[:])
|
|
||||||
if !bytes.Equal(computedCommitment, witnessCommitment) {
|
|
||||||
str := fmt.Sprintf("witness commitment does not match: "+
|
|
||||||
"computed %v, coinbase includes %v", computedCommitment,
|
|
||||||
witnessCommitment)
|
|
||||||
return ruleError(ErrWitnessCommitmentMismatch, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
// TestMerkle tests the BuildMerkleTreeStore API.
|
// TestMerkle tests the BuildMerkleTreeStore API.
|
||||||
func TestMerkle(t *testing.T) {
|
func TestMerkle(t *testing.T) {
|
||||||
block := btcutil.NewBlock(&Block100000)
|
block := btcutil.NewBlock(&Block100000)
|
||||||
merkles := BuildMerkleTreeStore(block.Transactions(), false)
|
merkles := BuildMerkleTreeStore(block.Transactions())
|
||||||
calculatedMerkleRoot := merkles[len(merkles)-1]
|
calculatedMerkleRoot := merkles[len(merkles)-1]
|
||||||
wantMerkle := &Block100000.Header.MerkleRoot
|
wantMerkle := &Block100000.Header.MerkleRoot
|
||||||
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
|
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
|
||||||
|
@ -20,7 +20,6 @@ type txValidateItem struct {
|
|||||||
txInIndex int
|
txInIndex int
|
||||||
txIn *wire.TxIn
|
txIn *wire.TxIn
|
||||||
tx *btcutil.Tx
|
tx *btcutil.Tx
|
||||||
sigHashes *txscript.TxSigHashes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// txValidator provides a type which asynchronously validates transaction
|
// txValidator provides a type which asynchronously validates transaction
|
||||||
@ -33,7 +32,6 @@ type txValidator struct {
|
|||||||
utxoView *UtxoViewpoint
|
utxoView *UtxoViewpoint
|
||||||
flags txscript.ScriptFlags
|
flags txscript.ScriptFlags
|
||||||
sigCache *txscript.SigCache
|
sigCache *txscript.SigCache
|
||||||
hashCache *txscript.HashCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendResult sends the result of a script pair validation on the internal
|
// sendResult sends the result of a script pair validation on the internal
|
||||||
@ -71,20 +69,17 @@ out:
|
|||||||
|
|
||||||
// Create a new script engine for the script pair.
|
// Create a new script engine for the script pair.
|
||||||
sigScript := txIn.SignatureScript
|
sigScript := txIn.SignatureScript
|
||||||
witness := txIn.Witness
|
|
||||||
pkScript := utxo.PkScript()
|
pkScript := utxo.PkScript()
|
||||||
inputAmount := utxo.Amount()
|
|
||||||
vm, err := txscript.NewEngine(pkScript, txVI.tx.MsgTx(),
|
vm, err := txscript.NewEngine(pkScript, txVI.tx.MsgTx(),
|
||||||
txVI.txInIndex, v.flags, v.sigCache, txVI.sigHashes,
|
txVI.txInIndex, v.flags, v.sigCache, &txscript.TxSigHashes{},
|
||||||
inputAmount)
|
utxo.Amount())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
str := fmt.Sprintf("failed to parse input "+
|
str := fmt.Sprintf("failed to parse input "+
|
||||||
"%s:%d which references output %v - "+
|
"%s:%d which references output %v - "+
|
||||||
"%v (input witness %x, input script "+
|
"%v (input script bytes %x, prev "+
|
||||||
"bytes %x, prev output script bytes %x)",
|
"output script bytes %x)",
|
||||||
txVI.tx.Hash(), txVI.txInIndex,
|
txVI.tx.Hash(), txVI.txInIndex,
|
||||||
txIn.PreviousOutPoint, err, witness,
|
txIn.PreviousOutPoint, err, sigScript, pkScript)
|
||||||
sigScript, pkScript)
|
|
||||||
err := ruleError(ErrScriptMalformed, str)
|
err := ruleError(ErrScriptMalformed, str)
|
||||||
v.sendResult(err)
|
v.sendResult(err)
|
||||||
break out
|
break out
|
||||||
@ -94,11 +89,10 @@ out:
|
|||||||
if err := vm.Execute(); err != nil {
|
if err := vm.Execute(); err != nil {
|
||||||
str := fmt.Sprintf("failed to validate input "+
|
str := fmt.Sprintf("failed to validate input "+
|
||||||
"%s:%d which references output %v - "+
|
"%s:%d which references output %v - "+
|
||||||
"%v (input witness %x, input script "+
|
"%v (input script bytes %x, prev output "+
|
||||||
"bytes %x, prev output script bytes %x)",
|
"script bytes %x)",
|
||||||
txVI.tx.Hash(), txVI.txInIndex,
|
txVI.tx.Hash(), txVI.txInIndex,
|
||||||
txIn.PreviousOutPoint, err, witness,
|
txIn.PreviousOutPoint, err, sigScript, pkScript)
|
||||||
sigScript, pkScript)
|
|
||||||
err := ruleError(ErrScriptValidation, str)
|
err := ruleError(ErrScriptValidation, str)
|
||||||
v.sendResult(err)
|
v.sendResult(err)
|
||||||
break out
|
break out
|
||||||
@ -173,47 +167,20 @@ func (v *txValidator) Validate(items []*txValidateItem) error {
|
|||||||
|
|
||||||
// newTxValidator returns a new instance of txValidator to be used for
|
// newTxValidator returns a new instance of txValidator to be used for
|
||||||
// validating transaction scripts asynchronously.
|
// validating transaction scripts asynchronously.
|
||||||
func newTxValidator(utxoView *UtxoViewpoint, flags txscript.ScriptFlags,
|
func newTxValidator(utxoView *UtxoViewpoint, flags txscript.ScriptFlags, sigCache *txscript.SigCache) *txValidator {
|
||||||
sigCache *txscript.SigCache, hashCache *txscript.HashCache) *txValidator {
|
|
||||||
return &txValidator{
|
return &txValidator{
|
||||||
validateChan: make(chan *txValidateItem),
|
validateChan: make(chan *txValidateItem),
|
||||||
quitChan: make(chan struct{}),
|
quitChan: make(chan struct{}),
|
||||||
resultChan: make(chan error),
|
resultChan: make(chan error),
|
||||||
utxoView: utxoView,
|
utxoView: utxoView,
|
||||||
sigCache: sigCache,
|
sigCache: sigCache,
|
||||||
hashCache: hashCache,
|
|
||||||
flags: flags,
|
flags: flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateTransactionScripts validates the scripts for the passed transaction
|
// ValidateTransactionScripts validates the scripts for the passed transaction
|
||||||
// using multiple goroutines.
|
// using multiple goroutines.
|
||||||
func ValidateTransactionScripts(tx *btcutil.Tx, utxoView *UtxoViewpoint,
|
func ValidateTransactionScripts(tx *btcutil.Tx, utxoView *UtxoViewpoint, flags txscript.ScriptFlags, sigCache *txscript.SigCache) error {
|
||||||
flags txscript.ScriptFlags, sigCache *txscript.SigCache,
|
|
||||||
hashCache *txscript.HashCache) error {
|
|
||||||
|
|
||||||
// First determine if segwit is active according to the scriptFlags. If
|
|
||||||
// it isn't then we don't need to interact with the HashCache.
|
|
||||||
segwitActive := flags&txscript.ScriptVerifyWitness == txscript.ScriptVerifyWitness
|
|
||||||
|
|
||||||
// If the hashcache doesn't yet has the sighash midstate for this
|
|
||||||
// transaction, then we'll compute them now so we can re-use them
|
|
||||||
// amongst all worker validation goroutines.
|
|
||||||
if segwitActive && tx.MsgTx().HasWitness() &&
|
|
||||||
!hashCache.ContainsHashes(tx.Hash()) {
|
|
||||||
hashCache.AddSigHashes(tx.MsgTx())
|
|
||||||
}
|
|
||||||
|
|
||||||
var cachedHashes *txscript.TxSigHashes
|
|
||||||
if segwitActive && tx.MsgTx().HasWitness() {
|
|
||||||
// The same pointer to the transaction's sighash midstate will
|
|
||||||
// be re-used amongst all validation goroutines. By
|
|
||||||
// pre-computing the sighash here instead of during validation,
|
|
||||||
// we ensure the sighashes
|
|
||||||
// are only computed once.
|
|
||||||
cachedHashes, _ = hashCache.GetSigHashes(tx.Hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect all of the transaction inputs and required information for
|
// Collect all of the transaction inputs and required information for
|
||||||
// validation.
|
// validation.
|
||||||
txIns := tx.MsgTx().TxIn
|
txIns := tx.MsgTx().TxIn
|
||||||
@ -228,26 +195,18 @@ func ValidateTransactionScripts(tx *btcutil.Tx, utxoView *UtxoViewpoint,
|
|||||||
txInIndex: txInIdx,
|
txInIndex: txInIdx,
|
||||||
txIn: txIn,
|
txIn: txIn,
|
||||||
tx: tx,
|
tx: tx,
|
||||||
sigHashes: cachedHashes,
|
|
||||||
}
|
}
|
||||||
txValItems = append(txValItems, txVI)
|
txValItems = append(txValItems, txVI)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate all of the inputs.
|
// Validate all of the inputs.
|
||||||
validator := newTxValidator(utxoView, flags, sigCache, hashCache)
|
validator := newTxValidator(utxoView, flags, sigCache)
|
||||||
return validator.Validate(txValItems)
|
return validator.Validate(txValItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkBlockScripts executes and validates the scripts for all transactions in
|
// checkBlockScripts executes and validates the scripts for all transactions in
|
||||||
// the passed block using multiple goroutines.
|
// the passed block using multiple goroutines.
|
||||||
func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint,
|
func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint, scriptFlags txscript.ScriptFlags, sigCache *txscript.SigCache) error {
|
||||||
scriptFlags txscript.ScriptFlags, sigCache *txscript.SigCache,
|
|
||||||
hashCache *txscript.HashCache) error {
|
|
||||||
|
|
||||||
// First determine if segwit is active according to the scriptFlags. If
|
|
||||||
// it isn't then we don't need to interact with the HashCache.
|
|
||||||
segwitActive := scriptFlags&txscript.ScriptVerifyWitness == txscript.ScriptVerifyWitness
|
|
||||||
|
|
||||||
// Collect all of the transaction inputs and required information for
|
// Collect all of the transaction inputs and required information for
|
||||||
// validation for all transactions in the block into a single slice.
|
// validation for all transactions in the block into a single slice.
|
||||||
numInputs := 0
|
numInputs := 0
|
||||||
@ -256,28 +215,6 @@ func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint,
|
|||||||
}
|
}
|
||||||
txValItems := make([]*txValidateItem, 0, numInputs)
|
txValItems := make([]*txValidateItem, 0, numInputs)
|
||||||
for _, tx := range block.Transactions() {
|
for _, tx := range block.Transactions() {
|
||||||
hash := tx.Hash()
|
|
||||||
|
|
||||||
// If the HashCache is present, and it doesn't yet contain the
|
|
||||||
// partial sighashes for this transaction, then we add the
|
|
||||||
// sighashes for the transaction. This allows us to take
|
|
||||||
// advantage of the potential speed savings due to the new
|
|
||||||
// digest algorithm (BIP0143).
|
|
||||||
if segwitActive && tx.HasWitness() && hashCache != nil &&
|
|
||||||
!hashCache.ContainsHashes(hash) {
|
|
||||||
|
|
||||||
hashCache.AddSigHashes(tx.MsgTx())
|
|
||||||
}
|
|
||||||
|
|
||||||
var cachedHashes *txscript.TxSigHashes
|
|
||||||
if segwitActive && tx.HasWitness() {
|
|
||||||
if hashCache != nil {
|
|
||||||
cachedHashes, _ = hashCache.GetSigHashes(hash)
|
|
||||||
} else {
|
|
||||||
cachedHashes = txscript.NewTxSigHashes(tx.MsgTx())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for txInIdx, txIn := range tx.MsgTx().TxIn {
|
for txInIdx, txIn := range tx.MsgTx().TxIn {
|
||||||
// Skip coinbases.
|
// Skip coinbases.
|
||||||
if txIn.PreviousOutPoint.Index == math.MaxUint32 {
|
if txIn.PreviousOutPoint.Index == math.MaxUint32 {
|
||||||
@ -288,14 +225,13 @@ func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint,
|
|||||||
txInIndex: txInIdx,
|
txInIndex: txInIdx,
|
||||||
txIn: txIn,
|
txIn: txIn,
|
||||||
tx: tx,
|
tx: tx,
|
||||||
sigHashes: cachedHashes,
|
|
||||||
}
|
}
|
||||||
txValItems = append(txValItems, txVI)
|
txValItems = append(txValItems, txVI)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate all of the inputs.
|
// Validate all of the inputs.
|
||||||
validator := newTxValidator(utxoView, scriptFlags, sigCache, hashCache)
|
validator := newTxValidator(utxoView, scriptFlags, sigCache)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := validator.Validate(txValItems); err != nil {
|
if err := validator.Validate(txValItems); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -304,16 +240,5 @@ func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint,
|
|||||||
|
|
||||||
log.Tracef("block %v took %v to verify", block.Hash(), elapsed)
|
log.Tracef("block %v took %v to verify", block.Hash(), elapsed)
|
||||||
|
|
||||||
// If the HashCache is present, once we have validated the block, we no
|
|
||||||
// longer need the cached hashes for these transactions, so we purge
|
|
||||||
// them from the cache.
|
|
||||||
if segwitActive && hashCache != nil {
|
|
||||||
for _, tx := range block.Transactions() {
|
|
||||||
if tx.MsgTx().HasWitness() {
|
|
||||||
hashCache.PurgeSigHashes(tx.Hash())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ func TestCheckBlockScripts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scriptFlags := txscript.ScriptBip16
|
scriptFlags := txscript.ScriptBip16
|
||||||
err = checkBlockScripts(blocks[0], view, scriptFlags, nil, nil)
|
err = checkBlockScripts(blocks[0], view, scriptFlags, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Transaction script validation failed: %v\n", err)
|
t.Errorf("Transaction script validation failed: %v\n", err)
|
||||||
return
|
return
|
||||||
|
@ -45,6 +45,10 @@ const (
|
|||||||
// baseSubsidy is the starting subsidy amount for mined blocks. This
|
// baseSubsidy is the starting subsidy amount for mined blocks. This
|
||||||
// value is halved every SubsidyHalvingInterval blocks.
|
// value is halved every SubsidyHalvingInterval blocks.
|
||||||
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
|
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
|
||||||
|
|
||||||
|
// MaxOutputsPerBlock is the maximum number of transaction outputs there
|
||||||
|
// can be in a block of max size.
|
||||||
|
MaxOutputsPerBlock = wire.MaxBlockPayload / wire.MinTxOutPayload
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -220,10 +224,10 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
|
|||||||
|
|
||||||
// A transaction must not exceed the maximum allowed block payload when
|
// A transaction must not exceed the maximum allowed block payload when
|
||||||
// serialized.
|
// serialized.
|
||||||
serializedTxSize := tx.MsgTx().SerializeSizeStripped()
|
serializedTxSize := tx.MsgTx().SerializeSize()
|
||||||
if serializedTxSize > MaxBlockBaseSize {
|
if serializedTxSize > wire.MaxBlockPayload {
|
||||||
str := fmt.Sprintf("serialized transaction is too big - got "+
|
str := fmt.Sprintf("serialized transaction is too big - got "+
|
||||||
"%d, max %d", serializedTxSize, MaxBlockBaseSize)
|
"%d, max %d", serializedTxSize, wire.MaxBlockPayload)
|
||||||
return ruleError(ErrTxTooBig, str)
|
return ruleError(ErrTxTooBig, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,19 +488,19 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A block must not have more transactions than the max block payload or
|
// A block must not have more transactions than the max block payload or
|
||||||
// else it is certainly over the weight limit.
|
// else it is certainly over the block size limit.
|
||||||
if numTx > MaxBlockBaseSize {
|
if numTx > wire.MaxBlockPayload {
|
||||||
str := fmt.Sprintf("block contains too many transactions - "+
|
str := fmt.Sprintf("block contains too many transactions - "+
|
||||||
"got %d, max %d", numTx, MaxBlockBaseSize)
|
"got %d, max %d", numTx, wire.MaxBlockPayload)
|
||||||
return ruleError(ErrBlockTooBig, str)
|
return ruleError(ErrBlockTooBig, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A block must not exceed the maximum allowed block payload when
|
// A block must not exceed the maximum allowed block payload when
|
||||||
// serialized.
|
// serialized.
|
||||||
serializedSize := msgBlock.SerializeSizeStripped()
|
serializedSize := msgBlock.SerializeSize()
|
||||||
if serializedSize > MaxBlockBaseSize {
|
if serializedSize > wire.MaxBlockPayload {
|
||||||
str := fmt.Sprintf("serialized block is too big - got %d, "+
|
str := fmt.Sprintf("serialized block is too big - got %d, "+
|
||||||
"max %d", serializedSize, MaxBlockBaseSize)
|
"max %d", serializedSize, wire.MaxBlockPayload)
|
||||||
return ruleError(ErrBlockTooBig, str)
|
return ruleError(ErrBlockTooBig, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,7 +535,7 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
|
|||||||
// checks. Bitcoind builds the tree here and checks the merkle root
|
// checks. Bitcoind builds the tree here and checks the merkle root
|
||||||
// after the following checks, but there is no reason not to check the
|
// after the following checks, but there is no reason not to check the
|
||||||
// merkle root matches here.
|
// merkle root matches here.
|
||||||
merkles := BuildMerkleTreeStore(block.Transactions(), false)
|
merkles := BuildMerkleTreeStore(block.Transactions())
|
||||||
calculatedMerkleRoot := merkles[len(merkles)-1]
|
calculatedMerkleRoot := merkles[len(merkles)-1]
|
||||||
if !header.MerkleRoot.IsEqual(calculatedMerkleRoot) {
|
if !header.MerkleRoot.IsEqual(calculatedMerkleRoot) {
|
||||||
str := fmt.Sprintf("block merkle root is invalid - block "+
|
str := fmt.Sprintf("block merkle root is invalid - block "+
|
||||||
@ -561,11 +565,11 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
|
|||||||
// We could potentially overflow the accumulator so check for
|
// We could potentially overflow the accumulator so check for
|
||||||
// overflow.
|
// overflow.
|
||||||
lastSigOps := totalSigOps
|
lastSigOps := totalSigOps
|
||||||
totalSigOps += (CountSigOps(tx) * WitnessScaleFactor)
|
totalSigOps += CountSigOps(tx)
|
||||||
if totalSigOps < lastSigOps || totalSigOps > MaxBlockSigOpsCost {
|
if totalSigOps < lastSigOps || totalSigOps > MaxSigOpsPerBlock {
|
||||||
str := fmt.Sprintf("block contains too many signature "+
|
str := fmt.Sprintf("block contains too many signature "+
|
||||||
"operations - got %v, max %v", totalSigOps,
|
"operations - got %v, max %v", totalSigOps,
|
||||||
MaxBlockSigOpsCost)
|
MaxSigOpsPerBlock)
|
||||||
return ruleError(ErrTooManySigOps, str)
|
return ruleError(ErrTooManySigOps, str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -781,42 +785,6 @@ func (b *BlockChain) checkBlockContext(block *btcutil.Block, prevNode *blockNode
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query for the Version Bits state for the segwit soft-fork
|
|
||||||
// deployment. If segwit is active, we'll switch over to
|
|
||||||
// enforcing all the new rules.
|
|
||||||
segwitState, err := b.deploymentState(prevNode,
|
|
||||||
chaincfg.DeploymentSegwit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If segwit is active, then we'll need to fully validate the
|
|
||||||
// new witness commitment for adherence to the rules.
|
|
||||||
if segwitState == ThresholdActive {
|
|
||||||
// Validate the witness commitment (if any) within the
|
|
||||||
// block. This involves asserting that if the coinbase
|
|
||||||
// contains the special commitment output, then this
|
|
||||||
// merkle root matches a computed merkle root of all
|
|
||||||
// the wtxid's of the transactions within the block. In
|
|
||||||
// addition, various other checks against the
|
|
||||||
// coinbase's witness stack.
|
|
||||||
if err := ValidateWitnessCommitment(block); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Once the witness commitment, witness nonce, and sig
|
|
||||||
// op cost have been validated, we can finally assert
|
|
||||||
// that the block's weight doesn't exceed the current
|
|
||||||
// consensus parameter.
|
|
||||||
blockWeight := GetBlockWeight(block)
|
|
||||||
if blockWeight > MaxBlockWeight {
|
|
||||||
str := fmt.Sprintf("block's weight metric is "+
|
|
||||||
"too high - got %v, max %v",
|
|
||||||
blockWeight, MaxBlockWeight)
|
|
||||||
return ruleError(ErrBlockWeightTooHigh, str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -1051,15 +1019,6 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
|
|||||||
// https://en.bitcoin.it/wiki/BIP_0016 for more details.
|
// https://en.bitcoin.it/wiki/BIP_0016 for more details.
|
||||||
enforceBIP0016 := node.timestamp >= txscript.Bip16Activation.Unix()
|
enforceBIP0016 := node.timestamp >= txscript.Bip16Activation.Unix()
|
||||||
|
|
||||||
// Query for the Version Bits state for the segwit soft-fork
|
|
||||||
// deployment. If segwit is active, we'll switch over to enforcing all
|
|
||||||
// the new rules.
|
|
||||||
segwitState, err := b.deploymentState(node.parent, chaincfg.DeploymentSegwit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
enforceSegWit := segwitState == ThresholdActive
|
|
||||||
|
|
||||||
// The number of signature operations must be less than the maximum
|
// The number of signature operations must be less than the maximum
|
||||||
// allowed per block. Note that the preliminary sanity checks on a
|
// allowed per block. Note that the preliminary sanity checks on a
|
||||||
// block also include a check similar to this one, but this check
|
// block also include a check similar to this one, but this check
|
||||||
@ -1067,28 +1026,31 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
|
|||||||
// signature operations in each of the input transaction public key
|
// signature operations in each of the input transaction public key
|
||||||
// scripts.
|
// scripts.
|
||||||
transactions := block.Transactions()
|
transactions := block.Transactions()
|
||||||
totalSigOpCost := 0
|
totalSigOps := 0
|
||||||
for i, tx := range transactions {
|
for i, tx := range transactions {
|
||||||
|
numsigOps := CountSigOps(tx)
|
||||||
|
if enforceBIP0016 {
|
||||||
// Since the first (and only the first) transaction has
|
// Since the first (and only the first) transaction has
|
||||||
// already been verified to be a coinbase transaction,
|
// already been verified to be a coinbase transaction,
|
||||||
// use i == 0 as an optimization for the flag to
|
// use i == 0 as an optimization for the flag to
|
||||||
// countP2SHSigOps for whether or not the transaction is
|
// countP2SHSigOps for whether or not the transaction is
|
||||||
// a coinbase transaction rather than having to do a
|
// a coinbase transaction rather than having to do a
|
||||||
// full coinbase check again.
|
// full coinbase check again.
|
||||||
sigOpCost, err := GetSigOpCost(tx, i == 0, view, enforceBIP0016,
|
numP2SHSigOps, err := CountP2SHSigOps(tx, i == 0, view)
|
||||||
enforceSegWit)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
numsigOps += numP2SHSigOps
|
||||||
|
}
|
||||||
|
|
||||||
// Check for overflow or going over the limits. We have to do
|
// Check for overflow or going over the limits. We have to do
|
||||||
// this on every loop iteration to avoid overflow.
|
// this on every loop iteration to avoid overflow.
|
||||||
lastSigOpCost := totalSigOpCost
|
lastSigops := totalSigOps
|
||||||
totalSigOpCost += sigOpCost
|
totalSigOps += numsigOps
|
||||||
if totalSigOpCost < lastSigOpCost || totalSigOpCost > MaxBlockSigOpsCost {
|
if totalSigOps < lastSigops || totalSigOps > MaxSigOpsPerBlock {
|
||||||
str := fmt.Sprintf("block contains too many "+
|
str := fmt.Sprintf("block contains too many "+
|
||||||
"signature operations - got %v, max %v",
|
"signature operations - got %v, max %v",
|
||||||
totalSigOpCost, MaxBlockSigOpsCost)
|
totalSigOps, MaxSigOpsPerBlock)
|
||||||
return ruleError(ErrTooManySigOps, str)
|
return ruleError(ErrTooManySigOps, str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1216,20 +1178,12 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce the segwit soft-fork package once the soft-fork has shifted
|
|
||||||
// into the "active" version bits state.
|
|
||||||
if enforceSegWit {
|
|
||||||
scriptFlags |= txscript.ScriptVerifyWitness
|
|
||||||
scriptFlags |= txscript.ScriptStrictMultiSig
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that the inexpensive checks are done and have passed, verify the
|
// Now that the inexpensive checks are done and have passed, verify the
|
||||||
// transactions are actually allowed to spend the coins by running the
|
// transactions are actually allowed to spend the coins by running the
|
||||||
// expensive ECDSA signature check scripts. Doing this last helps
|
// expensive ECDSA signature check scripts. Doing this last helps
|
||||||
// prevent CPU exhaustion attacks.
|
// prevent CPU exhaustion attacks.
|
||||||
if runScripts {
|
if runScripts {
|
||||||
err := checkBlockScripts(block, view, scriptFlags, b.sigCache,
|
err := checkBlockScripts(block, view, scriptFlags, b.sigCache)
|
||||||
b.hashCache)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
// Copyright (c) 2013-2017 The btcsuite developers
|
|
||||||
// Use of this source code is governed by an ISC
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package blockchain
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/daglabs/btcd/txscript"
|
|
||||||
"github.com/daglabs/btcd/wire"
|
|
||||||
"github.com/daglabs/btcutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// MaxBlockWeight defines the maximum block weight, where "block
|
|
||||||
// weight" is interpreted as defined in BIP0141. A block's weight is
|
|
||||||
// calculated as the sum of the of bytes in the existing transactions
|
|
||||||
// and header, plus the weight of each byte within a transaction. The
|
|
||||||
// weight of a "base" byte is 4, while the weight of a witness byte is
|
|
||||||
// 1. As a result, for a block to be valid, the BlockWeight MUST be
|
|
||||||
// less than, or equal to MaxBlockWeight.
|
|
||||||
MaxBlockWeight = 4000000
|
|
||||||
|
|
||||||
// MaxBlockBaseSize is the maximum number of bytes within a block
|
|
||||||
// which can be allocated to non-witness data.
|
|
||||||
MaxBlockBaseSize = 1000000
|
|
||||||
|
|
||||||
// MaxBlockSigOpsCost is the maximum number of signature operations
|
|
||||||
// allowed for a block. It is calculated via a weighted algorithm which
|
|
||||||
// weights segregated witness sig ops lower than regular sig ops.
|
|
||||||
MaxBlockSigOpsCost = 80000
|
|
||||||
|
|
||||||
// WitnessScaleFactor determines the level of "discount" witness data
|
|
||||||
// receives compared to "base" data. A scale factor of 4, denotes that
|
|
||||||
// witness data is 1/4 as cheap as regular non-witness data.
|
|
||||||
WitnessScaleFactor = 4
|
|
||||||
|
|
||||||
// MinTxOutputWeight is the minimum possible weight for a transaction
|
|
||||||
// output.
|
|
||||||
MinTxOutputWeight = WitnessScaleFactor * wire.MinTxOutPayload
|
|
||||||
|
|
||||||
// MaxOutputsPerBlock is the maximum number of transaction outputs there
|
|
||||||
// can be in a block of max weight size.
|
|
||||||
MaxOutputsPerBlock = MaxBlockWeight / MinTxOutputWeight
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetBlockWeight computes the value of the weight metric for a given block.
|
|
||||||
// Currently the weight metric is simply the sum of the block's serialized size
|
|
||||||
// without any witness data scaled proportionally by the WitnessScaleFactor,
|
|
||||||
// and the block's serialized size including any witness data.
|
|
||||||
func GetBlockWeight(blk *btcutil.Block) int64 {
|
|
||||||
msgBlock := blk.MsgBlock()
|
|
||||||
|
|
||||||
baseSize := msgBlock.SerializeSizeStripped()
|
|
||||||
totalSize := msgBlock.SerializeSize()
|
|
||||||
|
|
||||||
// (baseSize * 3) + totalSize
|
|
||||||
return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTransactionWeight computes the value of the weight metric for a given
|
|
||||||
// transaction. Currently the weight metric is simply the sum of the
|
|
||||||
// transactions's serialized size without any witness data scaled
|
|
||||||
// proportionally by the WitnessScaleFactor, and the transaction's serialized
|
|
||||||
// size including any witness data.
|
|
||||||
func GetTransactionWeight(tx *btcutil.Tx) int64 {
|
|
||||||
msgTx := tx.MsgTx()
|
|
||||||
|
|
||||||
baseSize := msgTx.SerializeSizeStripped()
|
|
||||||
totalSize := msgTx.SerializeSize()
|
|
||||||
|
|
||||||
// (baseSize * 3) + totalSize
|
|
||||||
return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSigOpCost returns the unified sig op cost for the passed transaction
|
|
||||||
// respecting current active soft-forks which modified sig op cost counting.
|
|
||||||
// The unified sig op cost for a transaction is computed as the sum of: the
|
|
||||||
// legacy sig op count scaled according to the WitnessScaleFactor, the sig op
|
|
||||||
// count for all p2sh inputs scaled by the WitnessScaleFactor, and finally the
|
|
||||||
// unscaled sig op count for any inputs spending witness programs.
|
|
||||||
func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint, bip16, segWit bool) (int, error) {
|
|
||||||
numSigOps := CountSigOps(tx) * WitnessScaleFactor
|
|
||||||
if bip16 {
|
|
||||||
numP2SHSigOps, err := CountP2SHSigOps(tx, isCoinBaseTx, utxoView)
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
numSigOps += (numP2SHSigOps * WitnessScaleFactor)
|
|
||||||
}
|
|
||||||
|
|
||||||
if segWit && !isCoinBaseTx {
|
|
||||||
msgTx := tx.MsgTx()
|
|
||||||
for txInIndex, txIn := range msgTx.TxIn {
|
|
||||||
// Ensure the referenced output is available and hasn't
|
|
||||||
// already been spent.
|
|
||||||
utxo := utxoView.LookupEntry(txIn.PreviousOutPoint)
|
|
||||||
if utxo == nil || utxo.IsSpent() {
|
|
||||||
str := fmt.Sprintf("output %v referenced from "+
|
|
||||||
"transaction %s:%d either does not "+
|
|
||||||
"exist or has already been spent",
|
|
||||||
txIn.PreviousOutPoint, tx.Hash(),
|
|
||||||
txInIndex)
|
|
||||||
return 0, ruleError(ErrMissingTxOut, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
witness := txIn.Witness
|
|
||||||
sigScript := txIn.SignatureScript
|
|
||||||
pkScript := utxo.PkScript()
|
|
||||||
numSigOps += txscript.GetWitnessSigOpCount(sigScript, pkScript, witness)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return numSigOps, nil
|
|
||||||
}
|
|
@ -21,13 +21,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/go-socks/socks"
|
"github.com/btcsuite/go-socks/socks"
|
||||||
"github.com/daglabs/btcd/blockchain"
|
|
||||||
"github.com/daglabs/btcd/chaincfg"
|
"github.com/daglabs/btcd/chaincfg"
|
||||||
"github.com/daglabs/btcd/chaincfg/chainhash"
|
"github.com/daglabs/btcd/chaincfg/chainhash"
|
||||||
"github.com/daglabs/btcd/connmgr"
|
"github.com/daglabs/btcd/connmgr"
|
||||||
"github.com/daglabs/btcd/database"
|
"github.com/daglabs/btcd/database"
|
||||||
_ "github.com/daglabs/btcd/database/ffldb"
|
_ "github.com/daglabs/btcd/database/ffldb"
|
||||||
"github.com/daglabs/btcd/mempool"
|
"github.com/daglabs/btcd/mempool"
|
||||||
|
"github.com/daglabs/btcd/wire"
|
||||||
"github.com/daglabs/btcutil"
|
"github.com/daglabs/btcutil"
|
||||||
flags "github.com/jessevdk/go-flags"
|
flags "github.com/jessevdk/go-flags"
|
||||||
)
|
)
|
||||||
@ -50,7 +50,7 @@ const (
|
|||||||
defaultBlockMinSize = 0
|
defaultBlockMinSize = 0
|
||||||
defaultBlockMaxSize = 750000
|
defaultBlockMaxSize = 750000
|
||||||
blockMaxSizeMin = 1000
|
blockMaxSizeMin = 1000
|
||||||
blockMaxSizeMax = blockchain.MaxBlockBaseSize - 1000
|
blockMaxSizeMax = wire.MaxBlockPayload - 1000
|
||||||
defaultGenerate = false
|
defaultGenerate = false
|
||||||
defaultMaxOrphanTransactions = 100
|
defaultMaxOrphanTransactions = 100
|
||||||
defaultMaxOrphanTxSize = 100000
|
defaultMaxOrphanTxSize = 100000
|
||||||
|
@ -181,7 +181,7 @@ func CreateBlock(prevBlock *btcutil.Block, inclusionTxs []*btcutil.Tx,
|
|||||||
if inclusionTxs != nil {
|
if inclusionTxs != nil {
|
||||||
blockTxns = append(blockTxns, inclusionTxs...)
|
blockTxns = append(blockTxns, inclusionTxs...)
|
||||||
}
|
}
|
||||||
merkles := blockchain.BuildMerkleTreeStore(blockTxns, false)
|
merkles := blockchain.BuildMerkleTreeStore(blockTxns)
|
||||||
var block wire.MsgBlock
|
var block wire.MsgBlock
|
||||||
block.Header = wire.BlockHeader{
|
block.Header = wire.BlockHeader{
|
||||||
Version: blockVersion,
|
Version: blockVersion,
|
||||||
|
@ -82,9 +82,6 @@ type Config struct {
|
|||||||
// SigCache defines a signature cache to use.
|
// SigCache defines a signature cache to use.
|
||||||
SigCache *txscript.SigCache
|
SigCache *txscript.SigCache
|
||||||
|
|
||||||
// HashCache defines the transaction hash mid-state cache to use.
|
|
||||||
HashCache *txscript.HashCache
|
|
||||||
|
|
||||||
// AddrIndex defines the optional address index instance to use for
|
// AddrIndex defines the optional address index instance to use for
|
||||||
// indexing the unconfirmed transactions in the memory pool.
|
// indexing the unconfirmed transactions in the memory pool.
|
||||||
// This can be nil if the address index is not enabled.
|
// This can be nil if the address index is not enabled.
|
||||||
@ -125,10 +122,10 @@ type Policy struct {
|
|||||||
// of big orphans.
|
// of big orphans.
|
||||||
MaxOrphanTxSize int
|
MaxOrphanTxSize int
|
||||||
|
|
||||||
// MaxSigOpCostPerTx is the cumulative maximum cost of all the signature
|
// MaxSigOpsPerTx is the maximum number of signature operations
|
||||||
// operations in a single transaction we will relay or mine. It is a
|
// in a single transaction we will relay or mine. It is a fraction
|
||||||
// fraction of the max signature operations for a block.
|
// of the max signature operations for a block.
|
||||||
MaxSigOpCostPerTx int
|
MaxSigOpsPerTx int
|
||||||
|
|
||||||
// MinRelayTxFee defines the minimum transaction fee in BTC/kB to be
|
// MinRelayTxFee defines the minimum transaction fee in BTC/kB to be
|
||||||
// considered a non-zero fee.
|
// considered a non-zero fee.
|
||||||
@ -809,16 +806,16 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||||||
// the coinbase address itself can contain signature operations, the
|
// the coinbase address itself can contain signature operations, the
|
||||||
// maximum allowed signature operations per transaction is less than
|
// maximum allowed signature operations per transaction is less than
|
||||||
// the maximum allowed signature operations per block.
|
// the maximum allowed signature operations per block.
|
||||||
sigOpCost, err := blockchain.GetSigOpCost(tx, false, utxoView, true, false)
|
sigOpCount, err := blockchain.CountP2SHSigOps(tx, false, utxoView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||||
return nil, nil, chainRuleError(cerr)
|
return nil, nil, chainRuleError(cerr)
|
||||||
}
|
}
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if sigOpCost > mp.cfg.Policy.MaxSigOpCostPerTx {
|
if sigOpCount > mp.cfg.Policy.MaxSigOpsPerTx {
|
||||||
str := fmt.Sprintf("transaction %v sigop cost is too high: %d > %d",
|
str := fmt.Sprintf("transaction %v sigop count is too high: %d > %d",
|
||||||
txHash, sigOpCost, mp.cfg.Policy.MaxSigOpCostPerTx)
|
txHash, sigOpCount, mp.cfg.Policy.MaxSigOpsPerTx)
|
||||||
return nil, nil, txRuleError(wire.RejectNonstandard, str)
|
return nil, nil, txRuleError(wire.RejectNonstandard, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,8 +882,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||||||
// Verify crypto signatures for each input and reject the transaction if
|
// Verify crypto signatures for each input and reject the transaction if
|
||||||
// any don't verify.
|
// any don't verify.
|
||||||
err = blockchain.ValidateTransactionScripts(tx, utxoView,
|
err = blockchain.ValidateTransactionScripts(tx, utxoView,
|
||||||
txscript.StandardVerifyFlags, mp.cfg.SigCache,
|
txscript.StandardVerifyFlags, mp.cfg.SigCache)
|
||||||
mp.cfg.HashCache)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||||
return nil, nil, chainRuleError(cerr)
|
return nil, nil, chainRuleError(cerr)
|
||||||
|
@ -313,7 +313,7 @@ func newPoolHarness(chainParams *chaincfg.Params) (*poolHarness, []spendableOutp
|
|||||||
FreeTxRelayLimit: 15.0,
|
FreeTxRelayLimit: 15.0,
|
||||||
MaxOrphanTxs: 5,
|
MaxOrphanTxs: 5,
|
||||||
MaxOrphanTxSize: 1000,
|
MaxOrphanTxSize: 1000,
|
||||||
MaxSigOpCostPerTx: blockchain.MaxBlockSigOpsCost / 4,
|
MaxSigOpsPerTx: blockchain.MaxSigOpsPerBlock / 5,
|
||||||
MinRelayTxFee: 1000, // 1 Satoshi per byte
|
MinRelayTxFee: 1000, // 1 Satoshi per byte
|
||||||
MaxTxVersion: 1,
|
MaxTxVersion: 1,
|
||||||
},
|
},
|
||||||
|
@ -345,7 +345,6 @@ type BlkTmplGenerator struct {
|
|||||||
chain *blockchain.BlockChain
|
chain *blockchain.BlockChain
|
||||||
timeSource blockchain.MedianTimeSource
|
timeSource blockchain.MedianTimeSource
|
||||||
sigCache *txscript.SigCache
|
sigCache *txscript.SigCache
|
||||||
hashCache *txscript.HashCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlkTmplGenerator returns a new block template generator for the given
|
// NewBlkTmplGenerator returns a new block template generator for the given
|
||||||
@ -357,8 +356,7 @@ type BlkTmplGenerator struct {
|
|||||||
func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
|
func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
|
||||||
txSource TxSource, chain *blockchain.BlockChain,
|
txSource TxSource, chain *blockchain.BlockChain,
|
||||||
timeSource blockchain.MedianTimeSource,
|
timeSource blockchain.MedianTimeSource,
|
||||||
sigCache *txscript.SigCache,
|
sigCache *txscript.SigCache) *BlkTmplGenerator {
|
||||||
hashCache *txscript.HashCache) *BlkTmplGenerator {
|
|
||||||
|
|
||||||
return &BlkTmplGenerator{
|
return &BlkTmplGenerator{
|
||||||
policy: policy,
|
policy: policy,
|
||||||
@ -367,7 +365,6 @@ func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
|
|||||||
chain: chain,
|
chain: chain,
|
||||||
timeSource: timeSource,
|
timeSource: timeSource,
|
||||||
sigCache: sigCache,
|
sigCache: sigCache,
|
||||||
hashCache: hashCache,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,7 +633,7 @@ mempoolLoop:
|
|||||||
}
|
}
|
||||||
numSigOps += int64(numP2SHSigOps)
|
numSigOps += int64(numP2SHSigOps)
|
||||||
if blockSigOps+numSigOps < blockSigOps ||
|
if blockSigOps+numSigOps < blockSigOps ||
|
||||||
blockSigOps+numSigOps > blockchain.MaxBlockSigOpsCost {
|
blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {
|
||||||
log.Tracef("Skipping tx %s because it would "+
|
log.Tracef("Skipping tx %s because it would "+
|
||||||
"exceed the maximum sigops per block", tx.Hash())
|
"exceed the maximum sigops per block", tx.Hash())
|
||||||
logSkippedDeps(tx, deps)
|
logSkippedDeps(tx, deps)
|
||||||
@ -698,8 +695,7 @@ mempoolLoop:
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
|
err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
|
||||||
txscript.StandardVerifyFlags, g.sigCache,
|
txscript.StandardVerifyFlags, g.sigCache)
|
||||||
g.hashCache)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Tracef("Skipping tx %s due to error in "+
|
log.Tracef("Skipping tx %s due to error in "+
|
||||||
"ValidateTransactionScripts: %v", tx.Hash(), err)
|
"ValidateTransactionScripts: %v", tx.Hash(), err)
|
||||||
@ -764,7 +760,7 @@ mempoolLoop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new block ready to be solved.
|
// Create a new block ready to be solved.
|
||||||
merkles := blockchain.BuildMerkleTreeStore(blockTxns, false)
|
merkles := blockchain.BuildMerkleTreeStore(blockTxns)
|
||||||
var msgBlock wire.MsgBlock
|
var msgBlock wire.MsgBlock
|
||||||
msgBlock.Header = wire.BlockHeader{
|
msgBlock.Header = wire.BlockHeader{
|
||||||
Version: nextBlockVersion,
|
Version: nextBlockVersion,
|
||||||
@ -850,7 +846,7 @@ func (g *BlkTmplGenerator) UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight
|
|||||||
|
|
||||||
// Recalculate the merkle root with the updated extra nonce.
|
// Recalculate the merkle root with the updated extra nonce.
|
||||||
block := btcutil.NewBlock(msgBlock)
|
block := btcutil.NewBlock(msgBlock)
|
||||||
merkles := blockchain.BuildMerkleTreeStore(block.Transactions(), false)
|
merkles := blockchain.BuildMerkleTreeStore(block.Transactions())
|
||||||
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
|
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1603,7 +1603,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *rpcServer, useCoinbaseValue bo
|
|||||||
|
|
||||||
// Update the merkle root.
|
// Update the merkle root.
|
||||||
block := btcutil.NewBlock(template.Block)
|
block := btcutil.NewBlock(template.Block)
|
||||||
merkles := blockchain.BuildMerkleTreeStore(block.Transactions(), false)
|
merkles := blockchain.BuildMerkleTreeStore(block.Transactions())
|
||||||
template.Block.Header.MerkleRoot = *merkles[len(merkles)-1]
|
template.Block.Header.MerkleRoot = *merkles[len(merkles)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1711,7 +1711,7 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld
|
|||||||
CurTime: header.Timestamp.Unix(),
|
CurTime: header.Timestamp.Unix(),
|
||||||
Height: int64(template.Height),
|
Height: int64(template.Height),
|
||||||
PreviousHash: header.PrevBlock.String(),
|
PreviousHash: header.PrevBlock.String(),
|
||||||
SigOpLimit: blockchain.MaxBlockSigOpsCost,
|
SigOpLimit: blockchain.MaxSigOpsPerBlock,
|
||||||
SizeLimit: wire.MaxBlockPayload,
|
SizeLimit: wire.MaxBlockPayload,
|
||||||
Transactions: transactions,
|
Transactions: transactions,
|
||||||
Version: header.Version,
|
Version: header.Version,
|
||||||
|
@ -208,7 +208,6 @@ type server struct {
|
|||||||
addrManager *addrmgr.AddrManager
|
addrManager *addrmgr.AddrManager
|
||||||
connManager *connmgr.ConnManager
|
connManager *connmgr.ConnManager
|
||||||
sigCache *txscript.SigCache
|
sigCache *txscript.SigCache
|
||||||
hashCache *txscript.HashCache
|
|
||||||
rpcServer *rpcServer
|
rpcServer *rpcServer
|
||||||
syncManager *netsync.SyncManager
|
syncManager *netsync.SyncManager
|
||||||
chain *blockchain.BlockChain
|
chain *blockchain.BlockChain
|
||||||
@ -2436,7 +2435,6 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
|||||||
timeSource: blockchain.NewMedianTime(),
|
timeSource: blockchain.NewMedianTime(),
|
||||||
services: services,
|
services: services,
|
||||||
sigCache: txscript.NewSigCache(cfg.SigCacheMaxSize),
|
sigCache: txscript.NewSigCache(cfg.SigCacheMaxSize),
|
||||||
hashCache: txscript.NewHashCache(cfg.SigCacheMaxSize),
|
|
||||||
cfCheckptCaches: make(map[wire.FilterType][]cfHeaderKV),
|
cfCheckptCaches: make(map[wire.FilterType][]cfHeaderKV),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2494,7 +2492,6 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
|||||||
TimeSource: s.timeSource,
|
TimeSource: s.timeSource,
|
||||||
SigCache: s.sigCache,
|
SigCache: s.sigCache,
|
||||||
IndexManager: indexManager,
|
IndexManager: indexManager,
|
||||||
HashCache: s.hashCache,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -2537,7 +2534,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
|||||||
FreeTxRelayLimit: cfg.FreeTxRelayLimit,
|
FreeTxRelayLimit: cfg.FreeTxRelayLimit,
|
||||||
MaxOrphanTxs: cfg.MaxOrphanTxs,
|
MaxOrphanTxs: cfg.MaxOrphanTxs,
|
||||||
MaxOrphanTxSize: defaultMaxOrphanTxSize,
|
MaxOrphanTxSize: defaultMaxOrphanTxSize,
|
||||||
MaxSigOpCostPerTx: blockchain.MaxBlockSigOpsCost / 4,
|
MaxSigOpsPerTx: blockchain.MaxSigOpsPerBlock / 5,
|
||||||
MinRelayTxFee: cfg.minRelayTxFee,
|
MinRelayTxFee: cfg.minRelayTxFee,
|
||||||
MaxTxVersion: 2,
|
MaxTxVersion: 2,
|
||||||
},
|
},
|
||||||
@ -2550,7 +2547,6 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
|||||||
},
|
},
|
||||||
IsDeploymentActive: s.chain.IsDeploymentActive,
|
IsDeploymentActive: s.chain.IsDeploymentActive,
|
||||||
SigCache: s.sigCache,
|
SigCache: s.sigCache,
|
||||||
HashCache: s.hashCache,
|
|
||||||
AddrIndex: s.addrIndex,
|
AddrIndex: s.addrIndex,
|
||||||
FeeEstimator: s.feeEstimator,
|
FeeEstimator: s.feeEstimator,
|
||||||
}
|
}
|
||||||
@ -2581,8 +2577,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
|||||||
TxMinFreeFee: cfg.minRelayTxFee,
|
TxMinFreeFee: cfg.minRelayTxFee,
|
||||||
}
|
}
|
||||||
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
|
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
|
||||||
s.chainParams, s.txMemPool, s.chain, s.timeSource,
|
s.chainParams, s.txMemPool, s.chain, s.timeSource, s.sigCache)
|
||||||
s.sigCache, s.hashCache)
|
|
||||||
s.cpuMiner = cpuminer.New(&cpuminer.Config{
|
s.cpuMiner = cpuminer.New(&cpuminer.Config{
|
||||||
ChainParams: chainParams,
|
ChainParams: chainParams,
|
||||||
BlockTemplateGenerator: blockTemplateGenerator,
|
BlockTemplateGenerator: blockTemplateGenerator,
|
||||||
|
@ -23,8 +23,7 @@ const defaultTransactionAlloc = 2048
|
|||||||
const MaxBlocksPerMsg = 500
|
const MaxBlocksPerMsg = 500
|
||||||
|
|
||||||
// MaxBlockPayload is the maximum bytes a block message can be in bytes.
|
// MaxBlockPayload is the maximum bytes a block message can be in bytes.
|
||||||
// After Segregated Witness, the max block payload has been raised to 4MB.
|
const MaxBlockPayload = 1000000
|
||||||
const MaxBlockPayload = 4000000
|
|
||||||
|
|
||||||
// maxTxPerBlock is the maximum number of transactions that could
|
// maxTxPerBlock is the maximum number of transactions that could
|
||||||
// possibly fit into a block.
|
// possibly fit into a block.
|
||||||
|
@ -36,7 +36,7 @@ func TestBlock(t *testing.T) {
|
|||||||
|
|
||||||
// Ensure max payload is expected value for latest protocol version.
|
// Ensure max payload is expected value for latest protocol version.
|
||||||
// Num addresses (varInt) + max allowed addresses.
|
// Num addresses (varInt) + max allowed addresses.
|
||||||
wantPayload := uint32(4000000)
|
wantPayload := uint32(1000000)
|
||||||
maxPayload := msg.MaxPayloadLength(pver)
|
maxPayload := msg.MaxPayloadLength(pver)
|
||||||
if maxPayload != wantPayload {
|
if maxPayload != wantPayload {
|
||||||
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
||||||
|
@ -38,7 +38,7 @@ func TestMerkleBlock(t *testing.T) {
|
|||||||
|
|
||||||
// Ensure max payload is expected value for latest protocol version.
|
// Ensure max payload is expected value for latest protocol version.
|
||||||
// Num addresses (varInt) + max allowed addresses.
|
// Num addresses (varInt) + max allowed addresses.
|
||||||
wantPayload := uint32(4000000)
|
wantPayload := uint32(1000000)
|
||||||
maxPayload := msg.MaxPayloadLength(pver)
|
maxPayload := msg.MaxPayloadLength(pver)
|
||||||
if maxPayload != wantPayload {
|
if maxPayload != wantPayload {
|
||||||
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
||||||
|
@ -35,7 +35,7 @@ func TestTx(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure max payload is expected value for latest protocol version.
|
// Ensure max payload is expected value for latest protocol version.
|
||||||
wantPayload := uint32(1000 * 4000)
|
wantPayload := uint32(1000 * 1000)
|
||||||
maxPayload := msg.MaxPayloadLength(pver)
|
maxPayload := msg.MaxPayloadLength(pver)
|
||||||
if maxPayload != wantPayload {
|
if maxPayload != wantPayload {
|
||||||
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
||||||
|
Loading…
x
Reference in New Issue
Block a user