mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-24 15:56:42 +00:00

* Revert "[NOD-1500] Delete integration tests" This reverts commit fcb57a206690a884fa6afb69d5d493282954a8bf. * [NOD-1518] hashserialization -> consenusserialization * [NOD-1518] Fix add genesis to virtual * [NOD-1518] Fix a bug in SerializeCoinbasePayload. * [NOD-1518] Fix a loop error and make pastMedianTime behave correctly everywhere on genesis. * [NOD-1518] Fix another bug and an infinite loop. * [NOD-1518] Fix uninitialized slice. * [NOD-1518] Fix bad should-commit checks and another infinite loop. * [NOD-1518] Fix nil serialization. * [NOD-1518] Rename blockHash to currentBlockHash. * [NOD-1518] Move the check whether stagedVirtualUTXOSet != nil to the top of commitVirtualUTXODiff. * [NOD-1518] Simplify utxoDiffStore.Commit. * [NOD-1518] Unextract resolveBlockStatusAndCheckFinality. * [NOD-1518] Move no-transactions logic into CalculateIDMerkleRoot. * [NOD-1518] Remove redundant is-staged check. * [NOD-1518] Fix merge errors. * [NOD-1518] Don't write anything if utxoDiffChild is nil. * [NOD-1518] Stage virtualAcceptanceData and virtualMultiset. * [NOD-1518] Fix bugs in getBlockTemplate and submitBlock. * [NOD-1518] Fix bad validation order in validateHeaderInContext. * [NOD-1518] Fix bug in Next(). * [NOD-1518] Fix nil dereference of subnetworks in AddressCache. * [NOD-1518] Fix multisetStore.Get returning a pointer to a multiset that is changed in place. * [NOD-1518] Break on genesis in countSubtrees. * [NOD-1518] Fix createBlockLocator. * [NOD-1518] Fix MsgTxToDomainTransaction. * [NOD-1518] Set MaxTxVersion to 1. * [NOD-1518] Fix missing error handling, bug in MsgTxToDomainTransaction, and bad subnetwork equality check. * [NOD-1518] Fix bug in hasUTXOByOutpointFromStagedVirtualUTXODiff. * [NOD-1518] Remove irrelevant comments. * [NOD-1518] Generate transactions with sufficient fee in tx_relay_test. * [NOD-1518] Fix broken RPC handlers. * [NOD-1518] Fix merge errors. * [NOD-1518] Fix bad exists check in restorePastUTXO and missing genesis check in CalculatePastUTXOAndAcceptanceData. * [NOD-1518] Add a comment. * [NOD-1518] Use a regular mutex instead of a read-write mutex in consensus to avoid dealing with sneaky not-actually-read functions. * [NOD-1518] Fix a deadlock in GetVirtualSelectedParent. * [NOD-1518] Fix missing handler registration for CmdHeader. * [NOD-1518] Fix processHeader calling OnNewBlock and LogBlock. Also fix conversion errors in IBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad Command() in MsgIBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad SyncStateMissingUTXOSet logic in resolveSyncState. * [NOD-1518] Rename mode to syncState. * [NOD-1518] Fix headers-only blocks coming in after the consensus thinks it's synced. * [NOD-1518] Fix selectedChildIterator.Next not ignoring virtual, infinite loop in HashSet.Length(). * [NOD-1518] Fix not-properly wrapped IBD blocks. * [NOD-1518] Fix bad conversion in RequestIBDBlocks. * [NOD-1518] Fix bad string for CmdRequestHeaders. * [NOD-1518] Fix bad string for CmdDoneHeaders. * [NOD-1518] Fix bad Command() for MsgIBDRootNotFound. * [NOD-1518] Fix bad areHeaderTipsSyncedMaxTimeDifference value. * [NOD-1518] Add missing string for CmdRequestIBDBlocks. * [NOD-1518] Fix bad check for SyncStateMissingBlockBodies. * [NOD-1518] Fix bad timeout durations in tests. * [NOD-1518] Fix IBD blocks not calling OnNewBlock. * [NOD-1518] Change when IBD finishes. * [NOD-1518] Properly clone utxoDiffChild. * [NOD-1518] Fix merge errors. * [NOD-1518] Move call to LogBlock to into OnNewBlock. * [NOD-1518] Return "not implemented" in unimplemented RPC handlers. * [NOD-1518] Extract cloning of hashes to a method over DomainHash. * [NOD-1518] Use isHeaderOnlyBlock. * [NOD-1518] Use constants.TransactionVersion. * [NOD-1518] Break immediately if we reached the virtual in SelectedChildIterator. * [NOD-1518] Don't stage nil utxoDiffChild. * [NOD-1518] Properly check the genesis hash in CalculatePastUTXOAndAcceptanceData. * [NOD-1518] Explain why we break on current == nil in countSubtrees. * [NOD-1518] Add a comment explaining why we check against StatusValid in resolveSyncState. Co-authored-by: Mike Zak <feanorr@gmail.com> Co-authored-by: Ori Newman <orinewman1@gmail.com>
109 lines
3.6 KiB
Go
109 lines
3.6 KiB
Go
package merkle
|
|
|
|
import (
|
|
"math"
|
|
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// 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
|
|
// calculation of a merkle tree.
|
|
func nextPowerOfTwo(n int) int {
|
|
// Return the number if it's already a power of 2.
|
|
if n&(n-1) == 0 {
|
|
return n
|
|
}
|
|
|
|
// Figure out and return the next power of two.
|
|
exponent := uint(math.Log2(float64(n))) + 1
|
|
return 1 << exponent // 2^exponent
|
|
}
|
|
|
|
// hashMerkleBranches takes two hashes, treated as the left and right tree
|
|
// nodes, and returns the hash of their concatenation. This is a helper
|
|
// function used to aid in the generation of a merkle tree.
|
|
func hashMerkleBranches(left, right *externalapi.DomainHash) *externalapi.DomainHash {
|
|
// Concatenate the left and right nodes.
|
|
w := hashes.NewHashWriter()
|
|
|
|
_, err := w.Write(left[:])
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error"))
|
|
}
|
|
|
|
_, err = w.Write(right[:])
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error"))
|
|
}
|
|
|
|
return w.Finalize()
|
|
}
|
|
|
|
// CalculateHashMerkleRoot calculates the merkle root of a tree consisted of the given transaction hashes.
|
|
// See `merkleRoot` for more info.
|
|
func CalculateHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash {
|
|
txHashes := make([]*externalapi.DomainHash, len(transactions))
|
|
for i, tx := range transactions {
|
|
txHashes[i] = consensusserialization.TransactionHash(tx)
|
|
}
|
|
return merkleRoot(txHashes)
|
|
}
|
|
|
|
// CalculateIDMerkleRoot calculates the merkle root of a tree consisted of the given transaction IDs.
|
|
// See `merkleRoot` for more info.
|
|
func CalculateIDMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash {
|
|
if len(transactions) == 0 {
|
|
return &externalapi.DomainHash{}
|
|
}
|
|
|
|
txIDs := make([]*externalapi.DomainHash, len(transactions))
|
|
for i, tx := range transactions {
|
|
txIDs[i] = (*externalapi.DomainHash)(consensusserialization.TransactionID(tx))
|
|
}
|
|
return merkleRoot(txIDs)
|
|
}
|
|
|
|
// merkleRoot creates a merkle tree from a slice of hashes, and returns its root.
|
|
func merkleRoot(hashes []*externalapi.DomainHash) *externalapi.DomainHash {
|
|
// Calculate how many entries are required to hold the binary merkle
|
|
// tree as a linear array and create an array of that size.
|
|
nextPoT := nextPowerOfTwo(len(hashes))
|
|
arraySize := nextPoT*2 - 1
|
|
merkles := make([]*externalapi.DomainHash, arraySize)
|
|
|
|
// Create the base transaction hashes and populate the array with them.
|
|
for i, hash := range hashes {
|
|
merkles[i] = hash
|
|
}
|
|
|
|
// Start the array offset after the last transaction and adjusted to the
|
|
// next power of two.
|
|
offset := nextPoT
|
|
for i := 0; i < arraySize-1; i += 2 {
|
|
switch {
|
|
// When there is no left child node, the parent is nil too.
|
|
case merkles[i] == nil:
|
|
merkles[offset] = nil
|
|
|
|
// When there is no right child, the parent is generated by
|
|
// hashing the concatenation of the left child with itself.
|
|
case merkles[i+1] == nil:
|
|
newHash := hashMerkleBranches(merkles[i], merkles[i])
|
|
merkles[offset] = newHash
|
|
|
|
// The normal case sets the parent node to the double sha256
|
|
// of the concatentation of the left and right children.
|
|
default:
|
|
newHash := hashMerkleBranches(merkles[i], merkles[i+1])
|
|
merkles[offset] = newHash
|
|
}
|
|
offset++
|
|
}
|
|
|
|
return merkles[len(merkles)-1]
|
|
}
|