mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-23 11:58:22 +00:00
Compare commits
7 Commits
patch1
...
optimize-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5f2495522 | ||
|
|
8588774837 | ||
|
|
94c3f4b80c | ||
|
|
a5a84e9215 | ||
|
|
1cec4c91cf | ||
|
|
3c0b74208a | ||
|
|
08d983b84a |
@@ -0,0 +1,52 @@
|
|||||||
|
package binaryserialization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
|
"github.com/kaspanet/kaspad/util/binaryserializer"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SerializeUTXOCollection serializes the given utxoCollection into the given writer
|
||||||
|
func SerializeUTXOCollection(writer io.Writer, utxoCollection model.UTXOCollection) error {
|
||||||
|
length := uint64(utxoCollection.Len())
|
||||||
|
err := binaryserializer.PutUint64(writer, length)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
utxoIterator := utxoCollection.Iterator()
|
||||||
|
for ok := utxoIterator.First(); ok; ok = utxoIterator.Next() {
|
||||||
|
outpoint, utxoEntry, err := utxoIterator.Get()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = utxo.SerializeUTXOIntoWriter(writer, utxoEntry, outpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeserializeUTXOCollection deserializes a utxoCollection out of the given reader
|
||||||
|
func DeserializeUTXOCollection(reader io.Reader) (model.UTXOCollection, error) {
|
||||||
|
length, err := binaryserializer.Uint64(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
utxoMap := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry, length)
|
||||||
|
for i := uint64(0); i < length; i++ {
|
||||||
|
utxoEntry, outpoint, err := utxo.DeserializeUTXOOutOfReader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
utxoMap[*outpoint] = utxoEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
utxoCollection := utxo.NewUTXOCollection(utxoMap)
|
||||||
|
return utxoCollection, nil
|
||||||
|
}
|
||||||
29
domain/consensus/database/binaryserialization/utxo_diff.go
Normal file
29
domain/consensus/database/binaryserialization/utxo_diff.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package binaryserialization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SerializeUTXODiff serializes the given utxoDiff into the given writer
|
||||||
|
func SerializeUTXODiff(writer io.Writer, utxoDiff model.UTXODiff) error {
|
||||||
|
err := SerializeUTXOCollection(writer, utxoDiff.ToAdd())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return SerializeUTXOCollection(writer, utxoDiff.ToRemove())
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeserializeUTXODiff deserializes a utxoDiff out of the given reader
|
||||||
|
func DeserializeUTXODiff(reader io.Reader) (model.UTXODiff, error) {
|
||||||
|
toAdd, err := DeserializeUTXOCollection(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
toRemove, err := DeserializeUTXOCollection(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return utxo.NewUTXODiffFromCollections(toAdd, toRemove)
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package utxodiffstore
|
package utxodiffstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/database"
|
"github.com/kaspanet/kaspad/domain/consensus/database"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/database/binaryserialization"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/database/serialization"
|
"github.com/kaspanet/kaspad/domain/consensus/database/serialization"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
@@ -188,27 +190,17 @@ func (uds *utxoDiffStore) utxoDiffChildHashAsKey(hash *externalapi.DomainHash) m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uds *utxoDiffStore) serializeUTXODiff(utxoDiff model.UTXODiff) ([]byte, error) {
|
func (uds *utxoDiffStore) serializeUTXODiff(utxoDiff model.UTXODiff) ([]byte, error) {
|
||||||
dbUtxoDiff, err := serialization.UTXODiffToDBUTXODiff(utxoDiff)
|
writer := &bytes.Buffer{}
|
||||||
|
err := binaryserialization.SerializeUTXODiff(writer, utxoDiff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return writer.Bytes(), nil
|
||||||
bytes, err := proto.Marshal(dbUtxoDiff)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uds *utxoDiffStore) deserializeUTXODiff(utxoDiffBytes []byte) (model.UTXODiff, error) {
|
func (uds *utxoDiffStore) deserializeUTXODiff(utxoDiffBytes []byte) (model.UTXODiff, error) {
|
||||||
dbUTXODiff := &serialization.DbUtxoDiff{}
|
reader := bytes.NewReader(utxoDiffBytes)
|
||||||
err := proto.Unmarshal(utxoDiffBytes, dbUTXODiff)
|
return binaryserialization.DeserializeUTXODiff(reader)
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return serialization.DBUTXODiffToUTXODiff(dbUTXODiff)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uds *utxoDiffStore) serializeUTXODiffChild(utxoDiffChild *externalapi.DomainHash) ([]byte, error) {
|
func (uds *utxoDiffStore) serializeUTXODiffChild(utxoDiffChild *externalapi.DomainHash) ([]byte, error) {
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package utxodiffstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUTXODiffSerializationAndDeserialization(t *testing.T) {
|
||||||
|
utxoDiffStore := New(0).(*utxoDiffStore)
|
||||||
|
|
||||||
|
testUTXODiff, err := buildTestUTXODiff()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not create UTXODiff from toAdd and toRemove collections: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedUTXODiff, err := utxoDiffStore.serializeUTXODiff(testUTXODiff)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not serialize UTXO diff: %s", err)
|
||||||
|
}
|
||||||
|
deserializedUTXODiff, err := utxoDiffStore.deserializeUTXODiff(serializedUTXODiff)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not deserialize UTXO diff: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testUTXODiff.ToAdd().Len() != deserializedUTXODiff.ToAdd().Len() {
|
||||||
|
t.Fatalf("Unexpected toAdd length in deserialized utxoDiff. Want: %d, got: %d",
|
||||||
|
testUTXODiff.ToAdd().Len(), deserializedUTXODiff.ToAdd().Len())
|
||||||
|
}
|
||||||
|
if testUTXODiff.ToRemove().Len() != deserializedUTXODiff.ToRemove().Len() {
|
||||||
|
t.Fatalf("Unexpected toRemove length in deserialized utxoDiff. Want: %d, got: %d",
|
||||||
|
testUTXODiff.ToRemove().Len(), deserializedUTXODiff.ToRemove().Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
testToAddIterator := testUTXODiff.ToAdd().Iterator()
|
||||||
|
for ok := testToAddIterator.First(); ok; ok = testToAddIterator.Next() {
|
||||||
|
testOutpoint, testUTXOEntry, err := testToAddIterator.Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not get an outpoint-utxoEntry pair out of the toAdd iterator: %s", err)
|
||||||
|
}
|
||||||
|
deserializedUTXOEntry, ok := deserializedUTXODiff.ToAdd().Get(testOutpoint)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Outpoint %s:%d not found in the deserialized toAdd collection",
|
||||||
|
testOutpoint.TransactionID, testOutpoint.Index)
|
||||||
|
}
|
||||||
|
if !testUTXOEntry.Equal(deserializedUTXOEntry) {
|
||||||
|
t.Fatalf("Deserialized UTXO entry is not equal to the original UTXO entry for outpoint %s:%d "+
|
||||||
|
"in the toAdd collection", testOutpoint.TransactionID, testOutpoint.Index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testToRemoveIterator := testUTXODiff.ToRemove().Iterator()
|
||||||
|
for ok := testToRemoveIterator.First(); ok; ok = testToRemoveIterator.Next() {
|
||||||
|
testOutpoint, testUTXOEntry, err := testToRemoveIterator.Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not get an outpoint-utxoEntry pair out of the toRemove iterator: %s", err)
|
||||||
|
}
|
||||||
|
deserializedUTXOEntry, ok := deserializedUTXODiff.ToRemove().Get(testOutpoint)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Outpoint %s:%d not found in the deserialized toRemove collection",
|
||||||
|
testOutpoint.TransactionID, testOutpoint.Index)
|
||||||
|
}
|
||||||
|
if !testUTXOEntry.Equal(deserializedUTXOEntry) {
|
||||||
|
t.Fatalf("Deserialized UTXO entry is not equal to the original UTXO entry for outpoint %s:%d "+
|
||||||
|
"in the toRemove collection", testOutpoint.TransactionID, testOutpoint.Index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUTXODiffSerialization(b *testing.B) {
|
||||||
|
utxoDiffStore := New(0).(*utxoDiffStore)
|
||||||
|
|
||||||
|
testUTXODiff, err := buildTestUTXODiff()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not create UTXODiff from toAdd and toRemove collections: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := utxoDiffStore.serializeUTXODiff(testUTXODiff)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not serialize UTXO diff: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUTXODiffDeserialization(b *testing.B) {
|
||||||
|
utxoDiffStore := New(0).(*utxoDiffStore)
|
||||||
|
|
||||||
|
testUTXODiff, err := buildTestUTXODiff()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not create UTXODiff from toAdd and toRemove collections: %s", err)
|
||||||
|
}
|
||||||
|
serializedUTXODiff, err := utxoDiffStore.serializeUTXODiff(testUTXODiff)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not serialize UTXO diff: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err = utxoDiffStore.deserializeUTXODiff(serializedUTXODiff)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not deserialize UTXO diff: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUTXODiffSerializationAndDeserialization(b *testing.B) {
|
||||||
|
utxoDiffStore := New(0).(*utxoDiffStore)
|
||||||
|
|
||||||
|
testUTXODiff, err := buildTestUTXODiff()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not create UTXODiff from toAdd and toRemove collections: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
serializedUTXODiff, err := utxoDiffStore.serializeUTXODiff(testUTXODiff)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not serialize UTXO diff: %s", err)
|
||||||
|
}
|
||||||
|
_, err = utxoDiffStore.deserializeUTXODiff(serializedUTXODiff)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Could not deserialize UTXO diff: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildTestUTXODiff() (model.UTXODiff, error) {
|
||||||
|
toAdd := buildTestUTXOCollection()
|
||||||
|
toRemove := buildTestUTXOCollection()
|
||||||
|
|
||||||
|
utxoDiff, err := utxo.NewUTXODiffFromCollections(toAdd, toRemove)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return utxoDiff, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildTestUTXOCollection() model.UTXOCollection {
|
||||||
|
utxoMap := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry)
|
||||||
|
|
||||||
|
for i := 0; i < 100_000; i++ {
|
||||||
|
var outpointTransactionIDBytes [32]byte
|
||||||
|
rand.Read(outpointTransactionIDBytes[:])
|
||||||
|
outpointTransactionID := externalapi.NewDomainTransactionIDFromByteArray(&outpointTransactionIDBytes)
|
||||||
|
outpointIndex := rand.Uint32()
|
||||||
|
outpoint := externalapi.NewDomainOutpoint(outpointTransactionID, outpointIndex)
|
||||||
|
|
||||||
|
utxoEntryAmount := rand.Uint64()
|
||||||
|
var utxoEntryScriptPublicKeyScript [256]byte
|
||||||
|
rand.Read(utxoEntryScriptPublicKeyScript[:])
|
||||||
|
utxoEntryScriptPublicKeyVersion := uint16(rand.Uint32())
|
||||||
|
utxoEntryScriptPublicKey := &externalapi.ScriptPublicKey{
|
||||||
|
Script: utxoEntryScriptPublicKeyScript[:],
|
||||||
|
Version: utxoEntryScriptPublicKeyVersion,
|
||||||
|
}
|
||||||
|
utxoEntryIsCoinbase := rand.Float32() > 0.5
|
||||||
|
utxoEntryBlockBlueScore := rand.Uint64()
|
||||||
|
utxoEntry := utxo.NewUTXOEntry(utxoEntryAmount, utxoEntryScriptPublicKey, utxoEntryIsCoinbase, utxoEntryBlockBlueScore)
|
||||||
|
|
||||||
|
utxoMap[*outpoint] = utxoEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
return utxo.NewUTXOCollection(utxoMap)
|
||||||
|
}
|
||||||
@@ -14,12 +14,7 @@ import (
|
|||||||
func SerializeUTXO(entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) ([]byte, error) {
|
func SerializeUTXO(entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) ([]byte, error) {
|
||||||
w := &bytes.Buffer{}
|
w := &bytes.Buffer{}
|
||||||
|
|
||||||
err := serializeOutpoint(w, outpoint)
|
err := SerializeUTXOIntoWriter(w, entry, outpoint)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = serializeUTXOEntry(w, entry)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -27,15 +22,30 @@ func SerializeUTXO(entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutp
|
|||||||
return w.Bytes(), nil
|
return w.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SerializeUTXOIntoWriter serializes the byte-slice representation for given UTXOEntry-outpoint pair into the given writer
|
||||||
|
func SerializeUTXOIntoWriter(writer io.Writer, entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error {
|
||||||
|
err := serializeOutpoint(writer, outpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return serializeUTXOEntry(writer, entry)
|
||||||
|
}
|
||||||
|
|
||||||
// DeserializeUTXO deserializes the given byte slice to UTXOEntry-outpoint pair
|
// DeserializeUTXO deserializes the given byte slice to UTXOEntry-outpoint pair
|
||||||
func DeserializeUTXO(utxoBytes []byte) (entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint, err error) {
|
func DeserializeUTXO(utxoBytes []byte) (entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint, err error) {
|
||||||
r := bytes.NewReader(utxoBytes)
|
r := bytes.NewReader(utxoBytes)
|
||||||
outpoint, err = deserializeOutpoint(r)
|
return DeserializeUTXOOutOfReader(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeserializeUTXOOutOfReader deserializes a UTXOEntry-outpoint pair out of the given reader
|
||||||
|
func DeserializeUTXOOutOfReader(reader io.Reader) (entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint, err error) {
|
||||||
|
outpoint, err = deserializeOutpoint(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
entry, err = deserializeUTXOEntry(r)
|
entry, err = deserializeUTXOEntry(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user