Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main, rpcclient, integration: add rpccalls for invalidate and reconsiderblock #2183

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
471 changes: 352 additions & 119 deletions blockchain/chain.go

Large diffs are not rendered by default.

537 changes: 537 additions & 0 deletions blockchain/chain_test.go

Large diffs are not rendered by default.

94 changes: 94 additions & 0 deletions blockchain/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"strings"
"time"

"github.com/btcsuite/btcd/blockchain/internal/testhelper"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
Expand Down Expand Up @@ -396,3 +397,96 @@ func newFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp t
}
return newBlockNode(header, parent)
}

// addBlock adds a block to the blockchain that succeeds the previous block.
// The blocks spends all the provided spendable outputs. The new block and
// the new spendable outputs created in the block are returned.
func addBlock(chain *BlockChain, prev *btcutil.Block, spends []*testhelper.SpendableOut) (
*btcutil.Block, []*testhelper.SpendableOut, error) {

block, outs, err := newBlock(chain, prev, spends)
if err != nil {
return nil, nil, err
}

_, _, err = chain.ProcessBlock(block, BFNone)
if err != nil {
return nil, nil, err
}

return block, outs, nil
}

// calcMerkleRoot creates a merkle tree from the slice of transactions and
// returns the root of the tree.
func calcMerkleRoot(txns []*wire.MsgTx) chainhash.Hash {
if len(txns) == 0 {
return chainhash.Hash{}
}

utilTxns := make([]*btcutil.Tx, 0, len(txns))
for _, tx := range txns {
utilTxns = append(utilTxns, btcutil.NewTx(tx))
}
return CalcMerkleRoot(utilTxns, false)
}

// newBlock creates a block to the blockchain that succeeds the previous block.
// The blocks spends all the provided spendable outputs. The new block and the
// newly spendable outputs created in the block are returned.
func newBlock(chain *BlockChain, prev *btcutil.Block,
spends []*testhelper.SpendableOut) (*btcutil.Block, []*testhelper.SpendableOut, error) {

blockHeight := prev.Height() + 1
txns := make([]*wire.MsgTx, 0, 1+len(spends))

// Create and add coinbase tx.
cb := testhelper.CreateCoinbaseTx(blockHeight, CalcBlockSubsidy(blockHeight, chain.chainParams))
txns = append(txns, cb)

// Spend all txs to be spent.
for _, spend := range spends {
cb.TxOut[0].Value += int64(testhelper.LowFee)

spendTx := testhelper.CreateSpendTx(spend, testhelper.LowFee)
txns = append(txns, spendTx)
}

// Use a timestamp that is one second after the previous block unless
// this is the first block in which case the current time is used.
var ts time.Time
if blockHeight == 1 {
ts = time.Unix(time.Now().Unix(), 0)
} else {
ts = prev.MsgBlock().Header.Timestamp.Add(time.Second)
}

// Create the block. The nonce will be solved in the below code in
// SolveBlock.
block := btcutil.NewBlock(&wire.MsgBlock{
Header: wire.BlockHeader{
Version: 1,
PrevBlock: *prev.Hash(),
MerkleRoot: calcMerkleRoot(txns),
Bits: chain.chainParams.PowLimitBits,
Timestamp: ts,
Nonce: 0, // To be solved.
},
Transactions: txns,
})
block.SetHeight(blockHeight)

// Solve the block.
if !testhelper.SolveBlock(&block.MsgBlock().Header) {
return nil, nil, fmt.Errorf("Unable to solve block at height %d", blockHeight)
}

// Create spendable outs to return.
outs := make([]*testhelper.SpendableOut, len(txns))
for i, tx := range txns {
out := testhelper.MakeSpendableOutForTx(tx, 0)
outs[i] = &out
}

return block, outs, nil
}
95 changes: 5 additions & 90 deletions blockchain/difficulty.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,14 @@ import (
"math/big"
"time"

"github.com/btcsuite/btcd/blockchain/internal/workmath"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)

var (
// bigOne is 1 represented as a big.Int. It is defined here to avoid
// the overhead of creating it multiple times.
bigOne = big.NewInt(1)

// oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid
// the overhead of creating it multiple times.
oneLsh256 = new(big.Int).Lsh(bigOne, 256)
)

// HashToBig converts a chainhash.Hash into a big.Int that can be used to
// perform math comparisons.
func HashToBig(hash *chainhash.Hash) *big.Int {
// A Hash is in little-endian, but the big package wants the bytes in
// big-endian, so reverse them.
buf := *hash
blen := len(buf)
for i := 0; i < blen/2; i++ {
buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
}

return new(big.Int).SetBytes(buf[:])
return workmath.HashToBig(hash)
}

// CompactToBig converts a compact representation of a whole number N to an
Expand Down Expand Up @@ -60,73 +43,15 @@ func HashToBig(hash *chainhash.Hash) *big.Int {
// which represent difficulty targets, thus there really is not a need for a
// sign bit, but it is implemented here to stay consistent with bitcoind.
func CompactToBig(compact uint32) *big.Int {
// Extract the mantissa, sign bit, and exponent.
mantissa := compact & 0x007fffff
isNegative := compact&0x00800000 != 0
exponent := uint(compact >> 24)

// Since the base for the exponent is 256, the exponent can be treated
// as the number of bytes to represent the full 256-bit number. So,
// treat the exponent as the number of bytes and shift the mantissa
// right or left accordingly. This is equivalent to:
// N = mantissa * 256^(exponent-3)
var bn *big.Int
if exponent <= 3 {
mantissa >>= 8 * (3 - exponent)
bn = big.NewInt(int64(mantissa))
} else {
bn = big.NewInt(int64(mantissa))
bn.Lsh(bn, 8*(exponent-3))
}

// Make it negative if the sign bit is set.
if isNegative {
bn = bn.Neg(bn)
}

return bn
return workmath.CompactToBig(compact)
}

// BigToCompact converts a whole number N to a compact representation using
// an unsigned 32-bit number. The compact representation only provides 23 bits
// of precision, so values larger than (2^23 - 1) only encode the most
// significant digits of the number. See CompactToBig for details.
func BigToCompact(n *big.Int) uint32 {
// No need to do any work if it's zero.
if n.Sign() == 0 {
return 0
}

// Since the base for the exponent is 256, the exponent can be treated
// as the number of bytes. So, shift the number right or left
// accordingly. This is equivalent to:
// mantissa = mantissa / 256^(exponent-3)
var mantissa uint32
exponent := uint(len(n.Bytes()))
if exponent <= 3 {
mantissa = uint32(n.Bits()[0])
mantissa <<= 8 * (3 - exponent)
} else {
// Use a copy to avoid modifying the caller's original number.
tn := new(big.Int).Set(n)
mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])
}

// When the mantissa already has the sign bit set, the number is too
// large to fit into the available 23-bits, so divide the number by 256
// and increment the exponent accordingly.
if mantissa&0x00800000 != 0 {
mantissa >>= 8
exponent++
}

// Pack the exponent, sign bit, and mantissa into an unsigned 32-bit
// int and return it.
compact := uint32(exponent<<24) | mantissa
if n.Sign() < 0 {
compact |= 0x00800000
}
return compact
return workmath.BigToCompact(n)
}

// CalcWork calculates a work value from difficulty bits. Bitcoin increases
Expand All @@ -140,17 +65,7 @@ func BigToCompact(n *big.Int) uint32 {
// potential division by zero and really small floating point numbers, the
// result adds 1 to the denominator and multiplies the numerator by 2^256.
func CalcWork(bits uint32) *big.Int {
// Return a work value of zero if the passed difficulty bits represent
// a negative number. Note this should not happen in practice with valid
// blocks, but an invalid block could trigger it.
difficultyNum := CompactToBig(bits)
if difficultyNum.Sign() <= 0 {
return big.NewInt(0)
}

// (1 << 256) / (difficultyNum + 1)
denominator := new(big.Int).Add(difficultyNum, bigOne)
return new(big.Int).Div(oneLsh256, denominator)
return workmath.CalcWork(bits)
}

// calcEasiestDifficulty calculates the easiest possible difficulty that a block
Expand Down