Skip to content

Commit

Permalink
Merge branch 'master' into #2106
Browse files Browse the repository at this point in the history
  • Loading branch information
theedtron committed Apr 16, 2024
2 parents e8d685c + 569155b commit 3b3b3b8
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 15 deletions.
36 changes: 36 additions & 0 deletions blockchain/blockindex.go
Expand Up @@ -135,6 +135,20 @@ func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode {
return &node
}

// Equals compares all the fields of the block node except for the parent and
// ancestor and returns true if they're equal.
func (node *blockNode) Equals(other *blockNode) bool {
return node.hash == other.hash &&
node.workSum.Cmp(other.workSum) == 0 &&
node.height == other.height &&
node.version == other.version &&
node.bits == other.bits &&
node.nonce == other.nonce &&
node.timestamp == other.timestamp &&
node.merkleRoot == other.merkleRoot &&
node.status == other.status
}

// Header constructs a block header from the node and returns it.
//
// This function is safe for concurrent access.
Expand Down Expand Up @@ -260,6 +274,28 @@ func (node *blockNode) RelativeAncestorCtx(distance int32) HeaderCtx {
return ancestor
}

// IsAncestor returns if the other node is an ancestor of this block node.
func (node *blockNode) IsAncestor(otherNode *blockNode) bool {
// Return early as false if the otherNode is nil.
if otherNode == nil {
return false
}

ancestor := node.Ancestor(otherNode.height)
if ancestor == nil {
return false
}

// If the otherNode has the same height as me, then the returned
// ancestor will be me. Return false since I'm not an ancestor of me.
if node.height == ancestor.height {
return false
}

// Return true if the fetched ancestor is other node.
return ancestor.Equals(otherNode)
}

// RelativeAncestor returns the ancestor block node a relative 'distance' blocks
// before this node. This is equivalent to calling Ancestor with the node's
// height minus provided distance.
Expand Down
156 changes: 156 additions & 0 deletions blockchain/chain_test.go
Expand Up @@ -1155,3 +1155,159 @@ func TestChainTips(t *testing.T) {
}
}
}

func TestIsAncestor(t *testing.T) {
// Construct a synthetic block chain with a block index consisting of
// the following structure.
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
tip := tstTip
chain := newFakeChain(&chaincfg.MainNetParams)
branch0Nodes := chainedNodes(chain.bestChain.Genesis(), 3)
for _, node := range branch0Nodes {
chain.index.SetStatusFlags(node, statusDataStored)
chain.index.SetStatusFlags(node, statusValid)
chain.index.AddNode(node)
}
chain.bestChain.SetTip(tip(branch0Nodes))

branch1Nodes := chainedNodes(chain.bestChain.Genesis(), 1)
for _, node := range branch1Nodes {
chain.index.SetStatusFlags(node, statusDataStored)
chain.index.SetStatusFlags(node, statusValid)
chain.index.AddNode(node)
}

branch2Nodes := chainedNodes(chain.bestChain.Genesis(), 1)
for _, node := range branch2Nodes {
chain.index.SetStatusFlags(node, statusDataStored)
chain.index.SetStatusFlags(node, statusValidateFailed)
chain.index.AddNode(node)
}

// Is 1 an ancestor of 3?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeTrue := branch0Nodes[2].IsAncestor(branch0Nodes[0])
if !shouldBeTrue {
t.Errorf("TestIsAncestor fail. Node %s is an ancestor of node %s but got false",
branch0Nodes[0].hash.String(), branch0Nodes[2].hash.String())
}

// Is 1 an ancestor of 2?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeTrue = branch0Nodes[1].IsAncestor(branch0Nodes[0])
if !shouldBeTrue {
t.Errorf("TestIsAncestor fail. Node %s is an ancestor of node %s but got false",
branch0Nodes[0].hash.String(), branch0Nodes[1].hash.String())
}

// Is the genesis an ancestor of 1?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeTrue = branch0Nodes[0].IsAncestor(chain.bestChain.Genesis())
if !shouldBeTrue {
t.Errorf("TestIsAncestor fail. The genesis block is an ancestor of all blocks "+
"but got false for node %s",
branch0Nodes[0].hash.String())
}

// Is the genesis an ancestor of 1a?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeTrue = branch1Nodes[0].IsAncestor(chain.bestChain.Genesis())
if !shouldBeTrue {
t.Errorf("TestIsAncestor fail. The genesis block is an ancestor of all blocks "+
"but got false for node %s",
branch1Nodes[0].hash.String())
}

// Is the genesis an ancestor of 1b?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeTrue = branch2Nodes[0].IsAncestor(chain.bestChain.Genesis())
if !shouldBeTrue {
t.Errorf("TestIsAncestor fail. The genesis block is an ancestor of all blocks "+
"but got false for node %s",
branch2Nodes[0].hash.String())
}

// Is 1 an ancestor of 1a?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeFalse := branch1Nodes[0].IsAncestor(branch0Nodes[0])
if shouldBeFalse {
t.Errorf("TestIsAncestor fail. Node %s is in a different branch than "+
"node %s but got true", branch1Nodes[0].hash.String(),
branch0Nodes[0].hash.String())
}

// Is 1 an ancestor of 1b?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeFalse = branch2Nodes[0].IsAncestor(branch0Nodes[0])
if shouldBeFalse {
t.Errorf("TestIsAncestor fail. Node %s is in a different branch than "+
"node %s but got true", branch2Nodes[0].hash.String(),
branch0Nodes[0].hash.String())
}

// Is 1a an ancestor of 1b?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeFalse = branch2Nodes[0].IsAncestor(branch1Nodes[0])
if shouldBeFalse {
t.Errorf("TestIsAncestor fail. Node %s is in a different branch than "+
"node %s but got true", branch2Nodes[0].hash.String(),
branch1Nodes[0].hash.String())
}

// Is 1 an ancestor of 1?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeFalse = branch0Nodes[0].IsAncestor(branch0Nodes[0])
if shouldBeFalse {
t.Errorf("TestIsAncestor fail. Node is not an ancestor of itself but got true for node %s",
branch0Nodes[0].hash.String())
}

// Is the geneis an ancestor of genesis?
//
// genesis -> 1 -> 2 -> 3 (active)
// \ -> 1a (valid-fork)
// \ -> 1b (invalid)
shouldBeFalse = chain.bestChain.Genesis().IsAncestor(chain.bestChain.Genesis())
if shouldBeFalse {
t.Errorf("TestIsAncestor fail. Node is not an ancestor of itself but got true for node %s",
chain.bestChain.Genesis().hash.String())
}

// Is a block from another chain an ancestor of 1b?
fakeChain := newFakeChain(&chaincfg.TestNet3Params)
shouldBeFalse = branch2Nodes[0].IsAncestor(fakeChain.bestChain.Genesis())
if shouldBeFalse {
t.Errorf("TestIsAncestor fail. Node %s is in a different chain than "+
"node %s but got true", fakeChain.bestChain.Genesis().hash.String(),
branch2Nodes[0].hash.String())
}
}
37 changes: 37 additions & 0 deletions btcec/pubkey.go
Expand Up @@ -10,6 +10,8 @@ import (

// These constants define the lengths of serialized public keys.
const (
// PubKeyBytesLenCompressed is the bytes length of a serialized compressed
// public key.
PubKeyBytesLenCompressed = 33
)

Expand Down Expand Up @@ -49,3 +51,38 @@ type PublicKey = secp.PublicKey
func NewPublicKey(x, y *FieldVal) *PublicKey {
return secp.NewPublicKey(x, y)
}

// SerializedKey is a type for representing a public key in its compressed
// serialized form.
//
// NOTE: This type is useful when using public keys as keys in maps.
type SerializedKey [PubKeyBytesLenCompressed]byte

// ToPubKey returns the public key parsed from the serialized key.
func (s SerializedKey) ToPubKey() (*PublicKey, error) {
return ParsePubKey(s[:])
}

// SchnorrSerialized returns the Schnorr serialized, x-only 32-byte
// representation of the serialized key.
func (s SerializedKey) SchnorrSerialized() [32]byte {
var serializedSchnorr [32]byte
copy(serializedSchnorr[:], s[1:])
return serializedSchnorr
}

// CopyBytes returns a copy of the underlying array as a byte slice.
func (s SerializedKey) CopyBytes() []byte {
c := make([]byte, PubKeyBytesLenCompressed)
copy(c, s[:])

return c
}

// ToSerialized serializes a public key into its compressed form.
func ToSerialized(pubKey *PublicKey) SerializedKey {
var serialized SerializedKey
copy(serialized[:], pubKey.SerializeCompressed())

return serialized
}
2 changes: 1 addition & 1 deletion btcutil/hdkeychain/README.md
Expand Up @@ -17,7 +17,7 @@ report.

- Full BIP0032 implementation
- Single type for private and public extended keys
- Convenient cryptograpically secure seed generation
- Convenient cryptographically secure seed generation
- Simple creation of master nodes
- Support for multi-layer derivation
- Easy serialization and deserialization for both private and public extended
Expand Down
2 changes: 1 addition & 1 deletion cmd/addblock/config.go
Expand Up @@ -45,7 +45,7 @@ type config struct {
TxIndex bool `long:"txindex" description:"Build a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"`
}

// filesExists reports whether the named file or directory exists.
// fileExists reports whether the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/gencerts/gencerts.go
Expand Up @@ -90,7 +90,7 @@ func cleanAndExpandPath(path string) string {
return filepath.Clean(os.ExpandEnv(path))
}

// filesExists reports whether the named file or directory exists.
// fileExists reports whether the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
Expand Down
4 changes: 2 additions & 2 deletions config.go
Expand Up @@ -101,7 +101,7 @@ type config struct {
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
AddrIndex bool `long:"addrindex" description:"Maintain a full address-based transaction index which makes the searchrawtransactions RPC available"`
AgentBlacklist []string `long:"agentblacklist" description:"A comma separated list of user-agent substrings which will cause btcd to reject any peers whose user-agent contains any of the blacklisted substrings."`
AgentWhitelist []string `long:"agentwhitelist" description:"A comma separated list of user-agent substrings which will cause btcd to require all peers' user-agents to contain one of the whitelisted substrings. The blacklist is applied before the blacklist, and an empty whitelist will allow all agents that do not fail the blacklist."`
AgentWhitelist []string `long:"agentwhitelist" description:"A comma separated list of user-agent substrings which will cause btcd to require all peers' user-agents to contain one of the whitelisted substrings. The blacklist is applied before the whitelist, and an empty whitelist will allow all agents that do not fail the blacklist."`
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"`
Expand Down Expand Up @@ -385,7 +385,7 @@ func parseCheckpoints(checkpointStrings []string) ([]chaincfg.Checkpoint, error)
return checkpoints, nil
}

// filesExists reports whether the named file or directory exists.
// fileExists reports whether the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
Expand Down
2 changes: 1 addition & 1 deletion database/ffldb/db.go
Expand Up @@ -2071,7 +2071,7 @@ func (db *db) Close() error {
return closeErr
}

// filesExists reports whether the named file or directory exists.
// fileExists reports whether the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
Expand Down
2 changes: 1 addition & 1 deletion docs/developer_resources.md
Expand Up @@ -28,7 +28,7 @@
* [mempool](https://github.com/btcsuite/btcd/tree/master/mempool) -
Package mempool provides a policy-enforced pool of unmined bitcoin
transactions.
* [btcutil](https://github.com/btcsuite/btcd/btcutil) - Provides Bitcoin-specific
* [btcutil](https://github.com/btcsuite/btcd/tree/master/btcutil) - Provides Bitcoin-specific
convenience functions and types
* [chainhash](https://github.com/btcsuite/btcd/tree/master/chaincfg/chainhash) -
Provides a generic hash type and associated functions that allows the
Expand Down
2 changes: 1 addition & 1 deletion mempool/README.md
Expand Up @@ -7,7 +7,7 @@ mempool

Package mempool provides a policy-enforced pool of unmined bitcoin transactions.

A key responsbility of the bitcoin network is mining user-generated transactions
A key responsibility of the bitcoin network is mining user-generated transactions
into blocks. In order to facilitate this, the mining process relies on having a
readily-available source of transactions to include in a block that is being
solved.
Expand Down
2 changes: 1 addition & 1 deletion txscript/doc.go
Expand Up @@ -17,7 +17,7 @@ bitcoin transaction scripts.
Bitcoin transaction scripts are written in a stack-base, FORTH-like language.
The bitcoin script language consists of a number of opcodes which fall into
several categories such pushing and popping data to and from the stack,
several categories such as pushing and popping data to and from the stack,
performing basic and bitwise arithmetic, conditional branching, comparing
hashes, and checking cryptographic signatures. Scripts are processed from left
to right and intentionally do not provide loops.
Expand Down
2 changes: 1 addition & 1 deletion txscript/engine.go
Expand Up @@ -605,7 +605,7 @@ func (vm *Engine) verifyWitnessProgram(witness wire.TxWitness) error {
return scriptError(ErrWitnessProgramWrongLength, errStr)
}

// We're attempting to to verify a taproot input, and the witness
// We're attempting to verify a taproot input, and the witness
// program data push is of the expected size, so we'll be looking for a
// normal key-path spend, or a merkle proof for a tapscript with
// execution afterwards.
Expand Down
2 changes: 1 addition & 1 deletion txscript/script.go
Expand Up @@ -178,7 +178,7 @@ func DisasmString(script []byte) (string, error) {
// removeOpcodeRaw will return the script after removing any opcodes that match
// `opcode`. If the opcode does not appear in script, the original script will
// be returned unmodified. Otherwise, a new script will be allocated to contain
// the filtered script. This metehod assumes that the script parses
// the filtered script. This method assumes that the script parses
// successfully.
//
// NOTE: This function is only valid for version 0 scripts. Since the function
Expand Down
2 changes: 1 addition & 1 deletion txscript/sigvalidate.go
Expand Up @@ -385,7 +385,7 @@ func (t *taprootSigVerifier) Verify() bool {
var _ signatureVerifier = (*taprootSigVerifier)(nil)

// baseTapscriptSigVerifier verifies a signature for an input spending a
// tapscript leaf from the prevoous output.
// tapscript leaf from the previous output.
type baseTapscriptSigVerifier struct {
*taprootSigVerifier

Expand Down
4 changes: 2 additions & 2 deletions txscript/standard.go
Expand Up @@ -153,7 +153,7 @@ func isPubKeyScript(script []byte) bool {
// is a standard pay-to-pubkey-hash script. It will return nil otherwise.
func extractPubKeyHash(script []byte) []byte {
// A pay-to-pubkey-hash script is of the form:
// OP_DUP OP_HASH160 <20-byte hash> OP_EQUALVERIFY OP_CHECKSIG
// OP_DUP OP_HASH160 OP_DATA_20 <20-byte hash> OP_EQUALVERIFY OP_CHECKSIG
if len(script) == 25 &&
script[0] == OP_DUP &&
script[1] == OP_HASH160 &&
Expand Down Expand Up @@ -181,7 +181,7 @@ func isPubKeyHashScript(script []byte) bool {
// versions.
func extractScriptHash(script []byte) []byte {
// A pay-to-script-hash script is of the form:
// OP_HASH160 <20-byte scripthash> OP_EQUAL
// OP_HASH160 OP_DATA_20 <20-byte scripthash> OP_EQUAL
if len(script) == 23 &&
script[0] == OP_HASH160 &&
script[1] == OP_DATA_20 &&
Expand Down
2 changes: 1 addition & 1 deletion txscript/taproot.go
Expand Up @@ -65,7 +65,7 @@ func VerifyTaprootKeySpend(witnessProgram []byte, rawSig []byte, tx *wire.MsgTx,
// program.
rawKey := witnessProgram

// Extract the annex if it exists, so we can compute the proper proper
// Extract the annex if it exists, so we can compute the proper
// sighash below.
var annex []byte
witness := tx.TxIn[inputIndex].Witness
Expand Down

0 comments on commit 3b3b3b8

Please sign in to comment.