mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-25 00:06:49 +00:00

* [NOD-1500] Added Domain type and Constructor * [NOD-1500] Replaced dag+txpool with domain in flowContext * [NOD-1500] Replaced dag+txpool with domain in flowContext * [NOD-1500] Converters: domain objects from/to appmessage * [NOD-1500] Convert hashes to DomainHashes in appmessages * [NOD-1500] Remove references to daghash in dagconfig * [NOD-1500] Fixed all appmessage usages of hashes * [NOD-1500] Update all RPC to use domain * [NOD-1500] Big chunk of protocol flows re-wired to domain * [NOD-1500] Finished re-wiring all protocol flows to new Domain * [NOD-1500] Fix some mempool and kaspaminer compilation errors * [NOD-1500] Deleted util/{block,tx,daghash} and dbaccess * [NOD-1500] util.CoinbaseTransactionIndex -> transactionhelper.CoinbaseTransactionIndex * [NOD-1500] Fix txsigner * [NOD-1500] Removed all references to util/subnetworkid * [NOD-1500] Update RpcGetBlock related messages * [NOD-1500] Many more compilation fixes * [NOD-1500] Return full list of missing blocks for orphan resolution * [NOD-1500] Fixed handshake * [NOD-1500] Fixed flowcontext compilation * [NOD-1500] Update users of StartIBDIfRequired to handle error * [NOD-1500] Removed some more fields from RPC * [NOD-1500] Fix the getBlockTemplate flow * [NOD-1500] Fix HandleGetCurrentNetwork * [NOD-1500] Remove redundant code * [NOD-1500] Remove obsolete notifications * [NOD-1500] Split MiningManager and Consensus to separate fields in Domain * [NOD-1500] Update two wrong references to location of txscript * [NOD-1500] Added comments * [NOD-1500] Fix some tests * [NOD-1500] Removed serialization logic from appmessage * [NOD-1500] Rename database/serialization/messages.proto to dbobjects.proto * [NOD-1500] Delete integration tests * [NOD-1500] Remove txsort * [NOD-1500] Fix tiny bug * [NOD-1500] Remove rogue dependancy on bchd * [NOD-1500] Some stylistic fixes
105 lines
3.5 KiB
Go
105 lines
3.5 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 {
|
|
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]
|
|
}
|