mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* [NOD-855] Save ECMH for each block UTXO * [NOD-855] Remove UpdateExtraNonce method * [NOD-855] Remove multiset data from UTXO diffs * [NOD-855] Fix to fetch multiset of selected parent * [NOD-855] Don't remove coinbase inputs from multiset * [NOD-855] Create multisetBucketName on startup * [NOD-855] Remove multiset from UTXO diff tests * [NOD-855] clear new entries from multisetstore on saveChangesFromBlock * [NOD-855] Fix tests * [NOD-855] Use UnacceptedBlueScore when adding current block transactions to multiset * [NOD-855] Hash utxo before adding it to multiset * [NOD-855] Pass isCoinbase to NewUTXOEntry * [NOD-855] Do not use hash when adding entries to multiset * [NOD-855] When calculating multiset, replace the unaccepted blue score of selected parent transaction with the block blue score * [NOD-855] Manually add a chained transaction to a block in TestChainedTransactions * [NOD-855] Change name and comments * [NOD-855] Use FindAcceptanceData to find a specific block acceptance data * [NOD-855] Remove redundant copy of txIn.PreviousOutpoint * [NOD-855] Use fmt.Sprintf when creating internalRPCError
251 lines
6.1 KiB
Go
251 lines
6.1 KiB
Go
package blockdag
|
|
|
|
import (
|
|
"bytes"
|
|
"github.com/kaspanet/kaspad/util/binaryserializer"
|
|
"github.com/kaspanet/kaspad/util/daghash"
|
|
"github.com/kaspanet/kaspad/wire"
|
|
"github.com/pkg/errors"
|
|
"io"
|
|
)
|
|
|
|
// serializeBlockUTXODiffData serializes diff data in the following format:
|
|
// Name | Data type | Description
|
|
// ------------ | --------- | -----------
|
|
// hasDiffChild | Boolean | Indicates if a diff child exist
|
|
// diffChild | Hash | The diffChild's hash. Empty if hasDiffChild is true.
|
|
// diff | UTXODiff | The diff data's diff
|
|
func serializeBlockUTXODiffData(w io.Writer, diffData *blockUTXODiffData) error {
|
|
hasDiffChild := diffData.diffChild != nil
|
|
err := wire.WriteElement(w, hasDiffChild)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if hasDiffChild {
|
|
err := wire.WriteElement(w, diffData.diffChild.hash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = serializeUTXODiff(w, diffData.diff)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// utxoEntryHeaderCode returns the calculated header code to be used when
|
|
// serializing the provided utxo entry.
|
|
func utxoEntryHeaderCode(entry *UTXOEntry) uint64 {
|
|
// As described in the serialization format comments, the header code
|
|
// encodes the blue score shifted over one bit and the block reward flag
|
|
// in the lowest bit.
|
|
headerCode := uint64(entry.BlockBlueScore()) << 1
|
|
if entry.IsCoinbase() {
|
|
headerCode |= 0x01
|
|
}
|
|
|
|
return headerCode
|
|
}
|
|
|
|
func (diffStore *utxoDiffStore) deserializeBlockUTXODiffData(serializedDiffData []byte) (*blockUTXODiffData, error) {
|
|
diffData := &blockUTXODiffData{}
|
|
r := bytes.NewBuffer(serializedDiffData)
|
|
|
|
var hasDiffChild bool
|
|
err := wire.ReadElement(r, &hasDiffChild)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if hasDiffChild {
|
|
hash := &daghash.Hash{}
|
|
err := wire.ReadElement(r, hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
diffData.diffChild = diffStore.dag.index.LookupNode(hash)
|
|
}
|
|
|
|
diffData.diff, err = deserializeUTXODiff(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return diffData, nil
|
|
}
|
|
|
|
func deserializeUTXODiff(r io.Reader) (*UTXODiff, error) {
|
|
diff := &UTXODiff{}
|
|
|
|
var err error
|
|
diff.toAdd, err = deserializeUTXOCollection(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
diff.toRemove, err = deserializeUTXOCollection(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return diff, nil
|
|
}
|
|
|
|
func deserializeUTXOCollection(r io.Reader) (utxoCollection, error) {
|
|
count, err := wire.ReadVarInt(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
collection := utxoCollection{}
|
|
for i := uint64(0); i < count; i++ {
|
|
utxoEntry, outpoint, err := deserializeUTXO(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
collection.add(*outpoint, utxoEntry)
|
|
}
|
|
return collection, nil
|
|
}
|
|
|
|
func deserializeUTXO(r io.Reader) (*UTXOEntry, *wire.Outpoint, error) {
|
|
outpoint, err := deserializeOutpoint(r)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
utxoEntry, err := deserializeUTXOEntry(r)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return utxoEntry, outpoint, nil
|
|
}
|
|
|
|
// serializeUTXODiff serializes UTXODiff by serializing
|
|
// UTXODiff.toAdd, UTXODiff.toRemove and UTXODiff.Multiset one after the other.
|
|
func serializeUTXODiff(w io.Writer, diff *UTXODiff) error {
|
|
err := serializeUTXOCollection(w, diff.toAdd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = serializeUTXOCollection(w, diff.toRemove)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// serializeUTXOCollection serializes utxoCollection by iterating over
|
|
// the utxo entries and serializing them and their corresponding outpoint
|
|
// prefixed by a varint that indicates their size.
|
|
func serializeUTXOCollection(w io.Writer, collection utxoCollection) error {
|
|
err := wire.WriteVarInt(w, uint64(len(collection)))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for outpoint, utxoEntry := range collection {
|
|
err := serializeUTXO(w, utxoEntry, &outpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// serializeUTXO serializes a utxo entry-outpoint pair
|
|
func serializeUTXO(w io.Writer, entry *UTXOEntry, outpoint *wire.Outpoint) error {
|
|
err := serializeOutpoint(w, outpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = serializeUTXOEntry(w, entry)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// p2pkhUTXOEntrySerializeSize is the serialized size for a P2PKH UTXO entry.
|
|
// 8 bytes (header code) + 8 bytes (amount) + varint for script pub key length of 25 (for P2PKH) + 25 bytes for P2PKH script.
|
|
var p2pkhUTXOEntrySerializeSize = 8 + 8 + wire.VarIntSerializeSize(25) + 25
|
|
|
|
// serializeUTXOEntry encodes the entry to the given io.Writer and use compression if useCompression is true.
|
|
// The compression format is described in detail above.
|
|
func serializeUTXOEntry(w io.Writer, entry *UTXOEntry) error {
|
|
// Encode the header code.
|
|
headerCode := utxoEntryHeaderCode(entry)
|
|
|
|
err := binaryserializer.PutUint64(w, byteOrder, headerCode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = binaryserializer.PutUint64(w, byteOrder, entry.Amount())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = wire.WriteVarInt(w, uint64(len(entry.ScriptPubKey())))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = w.Write(entry.ScriptPubKey())
|
|
if err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// deserializeUTXOEntry decodes a UTXO entry from the passed reader
|
|
// into a new UTXOEntry. If isCompressed is used it will decompress
|
|
// the entry according to the format that is described in detail
|
|
// above.
|
|
func deserializeUTXOEntry(r io.Reader) (*UTXOEntry, error) {
|
|
// Deserialize the header code.
|
|
headerCode, err := binaryserializer.Uint64(r, byteOrder)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Decode the header code.
|
|
//
|
|
// Bit 0 indicates whether the containing transaction is a coinbase.
|
|
// Bits 1-x encode blue score of the containing transaction.
|
|
isCoinbase := headerCode&0x01 != 0
|
|
blockBlueScore := headerCode >> 1
|
|
|
|
entry := &UTXOEntry{
|
|
blockBlueScore: blockBlueScore,
|
|
packedFlags: 0,
|
|
}
|
|
|
|
if isCoinbase {
|
|
entry.packedFlags |= tfCoinbase
|
|
}
|
|
|
|
entry.amount, err = binaryserializer.Uint64(r, byteOrder)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scriptPubKeyLen, err := wire.ReadVarInt(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
entry.scriptPubKey = make([]byte, scriptPubKeyLen)
|
|
_, err = r.Read(entry.scriptPubKey)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return entry, nil
|
|
}
|