Compare commits

..

2 Commits

Author SHA1 Message Date
Elichai Turkel
ac006ffcaa Add a github action deploy script to build and publish releases 2021-03-08 18:16:26 +02:00
Mike Zak
37654156a6 Update changelog for v0.9.0 2021-03-04 10:53:00 +02:00
283 changed files with 3046 additions and 7427 deletions

View File

@@ -37,33 +37,24 @@ jobs:
# `-extldflags=-static` - means static link everything, `-tags netgo,osusergo` means use pure go replacements for "os/user" and "net"
# `-s -w` strips the binary to produce smaller size binaries
run: |
go build -v -ldflags="-s -w -extldflags=-static" -tags netgo,osusergo -o ./bin/ ./...
archive="bin/kaspad-${{ github.event.release.tag_name }}-linux.zip"
asset_name="kaspad-${{ github.event.release.tag_name }}-linux.zip"
zip -r "${archive}" ./bin/*
echo "archive=${archive}" >> $GITHUB_ENV
echo "asset_name=${asset_name}" >> $GITHUB_ENV
binary="kaspad-${{ github.event.release.tag_name }}-linux"
echo "binary=${binary}" >> $GITHUB_ENV
go build -v -ldflags="-s -w -extldflags=-static" -tags netgo,osusergo -o "${binary}"
- name: Build on Windows
if: runner.os == 'Windows'
shell: bash
run: |
go build -v -ldflags="-s -w" -o bin/ ./...
archive="bin/kaspad-${{ github.event.release.tag_name }}-win64.zip"
asset_name="kaspad-${{ github.event.release.tag_name }}-win64.zip"
powershell "Compress-Archive bin/* \"${archive}\""
echo "archive=${archive}" >> $GITHUB_ENV
echo "asset_name=${asset_name}" >> $GITHUB_ENV
binary="kaspad-${{ github.event.release.tag_name }}-win64.exe"
echo "binary=${binary}" >> $GITHUB_ENV
go build -v -ldflags="-s -w" -o "${binary}"
- name: Build on MacOS
if: runner.os == 'macOS'
run: |
go build -v -ldflags="-s -w" -o ./bin/ ./...
archive="bin/kaspad-${{ github.event.release.tag_name }}-osx.zip"
asset_name="kaspad-${{ github.event.release.tag_name }}-osx.zip"
zip -r "${archive}" ./bin/*
echo "archive=${archive}" >> $GITHUB_ENV
echo "asset_name=${asset_name}" >> $GITHUB_ENV
binary="kaspad-${{ github.event.release.tag_name }}-osx"
echo "binary=${binary}" >> $GITHUB_ENV
go build -v -ldflags="-s -w" -o "${binary}"
- name: Upload Release Asset
@@ -72,6 +63,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: "./${{ env.archive }}"
asset_name: "${{ env.asset_name }}"
asset_path: "./${{ env.binary }}"
asset_name: "${{ env.binary }}"
asset_content_type: application/zip

View File

@@ -63,9 +63,6 @@ jobs:
with:
go-version: 1.16
- name: Delete the stability tests from coverage
run: rm -r stability-tests
- name: Create coverage file
run: go test -v -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./...

View File

@@ -56,7 +56,7 @@ $ kaspad
```
## Discord
Join our discord server using the following link: https://discord.gg/YNYnNN5Pf2
Join our discord server using the following link: https://discord.gg/WmGhhzk
## Issue Tracker

View File

@@ -171,7 +171,7 @@ func doUpgrades() error {
// dbPath returns the path to the block database given a database type.
func databasePath(cfg *config.Config) string {
return filepath.Join(cfg.AppDir, "data")
return filepath.Join(cfg.DataDir, "db")
}
func removeDatabase(cfg *config.Config) error {

View File

@@ -83,6 +83,7 @@ func DomainTransactionToMsgTx(domainTransaction *externalapi.DomainTransaction)
LockTime: domainTransaction.LockTime,
SubnetworkID: domainTransaction.SubnetworkID,
Gas: domainTransaction.Gas,
PayloadHash: domainTransaction.PayloadHash,
Payload: domainTransaction.Payload,
}
}
@@ -132,6 +133,7 @@ func MsgTxToDomainTransaction(msgTx *MsgTx) *externalapi.DomainTransaction {
LockTime: msgTx.LockTime,
SubnetworkID: msgTx.SubnetworkID,
Gas: msgTx.Gas,
PayloadHash: msgTx.PayloadHash,
Payload: payload,
}
}
@@ -196,6 +198,10 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa
if err != nil {
return nil, err
}
payloadHash, err := externalapi.NewDomainHashFromString(rpcTransaction.PayloadHash)
if err != nil {
return nil, err
}
payload, err := hex.DecodeString(rpcTransaction.Payload)
if err != nil {
return nil, err
@@ -208,6 +214,7 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa
LockTime: rpcTransaction.LockTime,
SubnetworkID: *subnetworkID,
Gas: rpcTransaction.LockTime,
PayloadHash: *payloadHash,
Payload: payload,
}, nil
}
@@ -237,6 +244,7 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio
}
}
subnetworkID := transaction.SubnetworkID.String()
payloadHash := transaction.PayloadHash.String()
payload := hex.EncodeToString(transaction.Payload)
return &RPCTransaction{
Version: transaction.Version,
@@ -245,6 +253,7 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio
LockTime: transaction.LockTime,
SubnetworkID: subnetworkID,
Gas: transaction.LockTime,
PayloadHash: payloadHash,
Payload: payload,
}
}
@@ -265,7 +274,7 @@ func OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs(
outpointAndUTXOEntryPair.UTXOEntry.Amount,
outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey,
outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase,
outpointAndUTXOEntryPair.UTXOEntry.BlockDAAScore,
outpointAndUTXOEntryPair.UTXOEntry.BlockBlueScore,
),
}
}
@@ -288,7 +297,7 @@ func DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(
Amount: outpointAndUTXOEntryPair.UTXOEntry.Amount(),
ScriptPublicKey: outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey(),
IsCoinbase: outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase(),
BlockDAAScore: outpointAndUTXOEntryPair.UTXOEntry.BlockDAAScore(),
BlockBlueScore: outpointAndUTXOEntryPair.UTXOEntry.BlockBlueScore(),
},
}
}

View File

@@ -15,6 +15,19 @@ import (
// backing array multiple times.
const defaultTransactionAlloc = 2048
// MaxMassAcceptedByBlock is the maximum total transaction mass a block may accept.
const MaxMassAcceptedByBlock = 10000000
// MaxMassPerTx is the maximum total mass a transaction may have.
const MaxMassPerTx = MaxMassAcceptedByBlock / 2
// MaxTxPerBlock is the maximum number of transactions that could
// possibly fit into a block.
const MaxTxPerBlock = (MaxMassAcceptedByBlock / minTxPayload) + 1
// MaxBlockParents is the maximum allowed number of parents for block.
const MaxBlockParents = 10
// TxLoc holds locator data for the offset and length of where a transaction is
// located within a MsgBlock data buffer.
type TxLoc struct {

View File

@@ -31,6 +31,6 @@ type OutpointAndUTXOEntryPair struct {
type UTXOEntry struct {
Amount uint64
ScriptPublicKey *externalapi.ScriptPublicKey
BlockDAAScore uint64
BlockBlueScore uint64
IsCoinbase bool
}

View File

@@ -6,6 +6,7 @@ package appmessage
import (
"encoding/binary"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"strconv"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
@@ -132,6 +133,7 @@ type MsgTx struct {
LockTime uint64
SubnetworkID externalapi.DomainSubnetworkID
Gas uint64
PayloadHash externalapi.DomainHash
Payload []byte
}
@@ -177,6 +179,7 @@ func (msg *MsgTx) Copy() *MsgTx {
LockTime: msg.LockTime,
SubnetworkID: msg.SubnetworkID,
Gas: msg.Gas,
PayloadHash: msg.PayloadHash,
}
if msg.Payload != nil {
@@ -277,12 +280,18 @@ func newMsgTx(version uint16, txIn []*TxIn, txOut []*TxOut, subnetworkID *extern
txOut = make([]*TxOut, 0, defaultTxInOutAlloc)
}
var payloadHash externalapi.DomainHash
if *subnetworkID != subnetworks.SubnetworkIDNative {
payloadHash = *hashes.PayloadHash(payload)
}
return &MsgTx{
Version: version,
TxIn: txIn,
TxOut: txOut,
SubnetworkID: *subnetworkID,
Gas: gas,
PayloadHash: payloadHash,
Payload: payload,
LockTime: lockTime,
}

View File

@@ -133,8 +133,8 @@ func TestTx(t *testing.T) {
// TestTxHash tests the ability to generate the hash of a transaction accurately.
func TestTxHashAndID(t *testing.T) {
txHash1Str := "93663e597f6c968d32d229002f76408edf30d6a0151ff679fc729812d8cb2acc"
txID1Str := "24079c6d2bdf602fc389cc307349054937744a9c8dc0f07c023e6af0e949a4e7"
txHash1Str := "4bee9ee495bd93a755de428376bd582a2bb6ec37c041753b711c0606d5745c13"
txID1Str := "f868bd20e816256b80eac976821be4589d24d21141bd1cec6e8005d0c16c6881"
wantTxID1, err := transactionid.FromString(txID1Str)
if err != nil {
t.Fatalf("NewTxIDFromStr: %v", err)
@@ -185,14 +185,14 @@ func TestTxHashAndID(t *testing.T) {
spew.Sprint(tx1ID), spew.Sprint(wantTxID1))
}
hash2Str := "8dafd1bec24527d8e3b443ceb0a3b92fffc0d60026317f890b2faf5e9afc177a"
hash2Str := "cb1bdb4a83d4885535fb3cceb5c96597b7df903db83f0ffcd779d703affd8efd"
wantHash2, err := externalapi.NewDomainHashFromString(hash2Str)
if err != nil {
t.Errorf("NewTxIDFromStr: %v", err)
return
}
id2Str := "89ffb49474637502d9059af38b8a95fc2f0d3baef5c801d7a9b9c8830671b711"
id2Str := "ca080073d4ddf5b84443a0964af633f3c70a5b290fd3bc35a7e6f93fd33f9330"
wantID2, err := transactionid.FromString(id2Str)
if err != nil {
t.Errorf("NewTxIDFromStr: %v", err)

View File

@@ -19,7 +19,7 @@ func TestVersion(t *testing.T) {
// Create version message data.
tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 16111}
me := NewNetAddress(tcpAddrMe)
me := NewNetAddress(tcpAddrMe, SFNodeNetwork)
generatedID, err := id.GenerateID()
if err != nil {
t.Fatalf("id.GenerateID: %s", err)

View File

@@ -15,6 +15,9 @@ type NetAddress struct {
// Last time the address was seen.
Timestamp mstime.Time
// Bitfield which identifies the services supported by the address.
Services ServiceFlag
// IP address of the peer.
IP net.IP
@@ -23,6 +26,17 @@ type NetAddress struct {
Port uint16
}
// HasService returns whether the specified service is supported by the address.
func (na *NetAddress) HasService(service ServiceFlag) bool {
return na.Services&service == service
}
// AddService adds service as a supported service by the peer generating the
// message.
func (na *NetAddress) AddService(service ServiceFlag) {
na.Services |= service
}
// TCPAddress converts the NetAddress to *net.TCPAddr
func (na *NetAddress) TCPAddress() *net.TCPAddr {
return &net.TCPAddr{
@@ -33,19 +47,20 @@ func (na *NetAddress) TCPAddress() *net.TCPAddr {
// NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
// supported services with defaults for the remaining fields.
func NewNetAddressIPPort(ip net.IP, port uint16) *NetAddress {
return NewNetAddressTimestamp(mstime.Now(), ip, port)
func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
return NewNetAddressTimestamp(mstime.Now(), services, ip, port)
}
// NewNetAddressTimestamp returns a new NetAddress using the provided
// timestamp, IP, port, and supported services. The timestamp is rounded to
// single millisecond precision.
func NewNetAddressTimestamp(
timestamp mstime.Time, ip net.IP, port uint16) *NetAddress {
timestamp mstime.Time, services ServiceFlag, ip net.IP, port uint16) *NetAddress {
// Limit the timestamp to one millisecond precision since the protocol
// doesn't support better.
na := NetAddress{
Timestamp: timestamp,
Services: services,
IP: ip,
Port: port,
}
@@ -54,6 +69,6 @@ func NewNetAddressTimestamp(
// NewNetAddress returns a new NetAddress using the provided TCP address and
// supported services with defaults for the remaining fields.
func NewNetAddress(addr *net.TCPAddr) *NetAddress {
return NewNetAddressIPPort(addr.IP, uint16(addr.Port))
func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress {
return NewNetAddressIPPort(addr.IP, uint16(addr.Port), services)
}

View File

@@ -15,7 +15,7 @@ func TestNetAddress(t *testing.T) {
port := 16111
// Test NewNetAddress.
na := NewNetAddress(&net.TCPAddr{IP: ip, Port: port})
na := NewNetAddress(&net.TCPAddr{IP: ip, Port: port}, 0)
// Ensure we get the same ip, port, and services back out.
if !na.IP.Equal(ip) {
@@ -25,4 +25,21 @@ func TestNetAddress(t *testing.T) {
t.Errorf("NetNetAddress: wrong port - got %v, want %v", na.Port,
port)
}
if na.Services != 0 {
t.Errorf("NetNetAddress: wrong services - got %v, want %v",
na.Services, 0)
}
if na.HasService(SFNodeNetwork) {
t.Errorf("HasService: SFNodeNetwork service is set")
}
// Ensure adding the full service node flag works.
na.AddService(SFNodeNetwork)
if na.Services != SFNodeNetwork {
t.Errorf("AddService: wrong services - got %v, want %v",
na.Services, SFNodeNetwork)
}
if !na.HasService(SFNodeNetwork) {
t.Errorf("HasService: SFNodeNetwork service not set")
}
}

View File

@@ -70,6 +70,7 @@ type TransactionVerboseData struct {
LockTime uint64
SubnetworkID string
Gas uint64
PayloadHash string
Payload string
TransactionVerboseInputs []*TransactionVerboseInput
TransactionVerboseOutputs []*TransactionVerboseOutput

View File

@@ -20,8 +20,7 @@ func NewGeInfoRequestMessage() *GetInfoRequestMessage {
// its respective RPC message
type GetInfoResponseMessage struct {
baseMessage
P2PID string
MempoolSize uint64
P2PID string
Error *RPCError
}
@@ -32,9 +31,8 @@ func (msg *GetInfoResponseMessage) Command() MessageCommand {
}
// NewGetInfoResponseMessage returns a instance of the message
func NewGetInfoResponseMessage(p2pID string, mempoolSize uint64) *GetInfoResponseMessage {
func NewGetInfoResponseMessage(p2pID string) *GetInfoResponseMessage {
return &GetInfoResponseMessage{
P2PID: p2pID,
MempoolSize: mempoolSize,
P2PID: p2pID,
}
}

View File

@@ -49,6 +49,7 @@ type RPCTransaction struct {
LockTime uint64
SubnetworkID string
Gas uint64
PayloadHash string
Payload string
}
@@ -85,6 +86,6 @@ type RPCOutpoint struct {
type RPCUTXOEntry struct {
Amount uint64
ScriptPublicKey *RPCScriptPublicKey
BlockDAAScore uint64
BlockBlueScore uint64
IsCoinbase bool
}

View File

@@ -72,8 +72,6 @@ func (a *ComponentManager) Stop() {
log.Errorf("Error stopping the net adapter: %+v", err)
}
a.protocolManager.Close()
return
}
@@ -157,7 +155,7 @@ func setupRPC(
func (a *ComponentManager) maybeSeedFromDNS() {
if !a.cfg.DisableDNSSeed {
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, false, nil,
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, appmessage.SFNodeNetwork, false, nil,
a.cfg.Lookup, func(addresses []*appmessage.NetAddress) {
// Kaspad uses a lookup of the dns seeder here. Since seeder returns
// IPs of nodes and not its own IP, we can not know real IP of
@@ -165,7 +163,7 @@ func (a *ComponentManager) maybeSeedFromDNS() {
a.addressManager.AddAddresses(addresses...)
})
dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, false, nil,
dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, appmessage.SFNodeNetwork, false, nil,
func(addresses []*appmessage.NetAddress) {
a.addressManager.AddAddresses(addresses...)
})

View File

@@ -61,8 +61,6 @@ type FlowContext struct {
orphans map[externalapi.DomainHash]*externalapi.DomainBlock
orphansMutex sync.RWMutex
shutdownChan chan struct{}
}
// New returns a new instance of FlowContext.
@@ -81,21 +79,9 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage
transactionsToRebroadcast: make(map[externalapi.DomainTransactionID]*externalapi.DomainTransaction),
orphans: make(map[externalapi.DomainHash]*externalapi.DomainBlock),
timeStarted: mstime.Now().UnixMilliseconds(),
shutdownChan: make(chan struct{}),
}
}
// Close signals to all flows the the protocol manager is closed.
func (f *FlowContext) Close() {
close(f.shutdownChan)
}
// ShutdownChan is a chan where flows can subscribe to shutdown
// event.
func (f *FlowContext) ShutdownChan() <-chan struct{} {
return f.shutdownChan
}
// SetOnBlockAddedToDAGHandler sets the onBlockAddedToDAG handler
func (f *FlowContext) SetOnBlockAddedToDAGHandler(onBlockAddedToDAGHandler OnBlockAddedToDAGHandler) {
f.onBlockAddedToDAGHandler = onBlockAddedToDAGHandler

View File

@@ -50,7 +50,7 @@ func (flow *handleRequestHeadersFlow) start() error {
// GetHashesBetween is a relatively heavy operation so we limit it
// in order to avoid locking the consensus for too long
const maxBlueScoreDifference = 1 << 10
blockHashes, _, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference)
blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference)
if err != nil {
return err
}

View File

@@ -13,7 +13,6 @@ import (
// SendPingsContext is the interface for the context needed for the SendPings flow.
type SendPingsContext interface {
ShutdownChan() <-chan struct{}
}
type sendPingsFlow struct {
@@ -40,13 +39,7 @@ func (flow *sendPingsFlow) start() error {
ticker := time.NewTicker(pingInterval)
defer ticker.Stop()
for {
select {
case <-flow.ShutdownChan():
return nil
case <-ticker.C:
}
for range ticker.C {
nonce, err := random.Uint64()
if err != nil {
return err
@@ -69,4 +62,5 @@ func (flow *sendPingsFlow) start() error {
}
flow.peer.SetPingIdle()
}
return nil
}

View File

@@ -181,7 +181,7 @@ func (f *fakeRelayInvsContext) GetBlockAcceptanceData(blockHash *externalapi.Dom
panic(errors.Errorf("called unimplemented function from test '%s'", f.testName))
}
func (f *fakeRelayInvsContext) GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) (hashes []*externalapi.DomainHash, actualHighHash *externalapi.DomainHash, err error) {
func (f *fakeRelayInvsContext) GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) {
panic(errors.Errorf("called unimplemented function from test '%s'", f.testName))
}

View File

@@ -2,9 +2,6 @@ package protocol
import (
"fmt"
"github.com/pkg/errors"
"sync"
"sync/atomic"
"github.com/kaspanet/kaspad/domain"
@@ -20,9 +17,7 @@ import (
// Manager manages the p2p protocol
type Manager struct {
context *flowcontext.FlowContext
routersWaitGroup sync.WaitGroup
isClosed uint32
context *flowcontext.FlowContext
}
// NewManager creates a new instance of the p2p protocol manager
@@ -37,18 +32,6 @@ func NewManager(cfg *config.Config, domain domain.Domain, netAdapter *netadapter
return &manager, nil
}
// Close closes the protocol manager and waits until all p2p flows
// finish.
func (m *Manager) Close() {
if !atomic.CompareAndSwapUint32(&m.isClosed, 0, 1) {
panic(errors.New("The protocol manager was already closed"))
}
atomic.StoreUint32(&m.isClosed, 1)
m.context.Close()
m.routersWaitGroup.Wait()
}
// Peers returns the currently active peers
func (m *Manager) Peers() []*peerpkg.Peer {
return m.context.Peers()
@@ -70,13 +53,11 @@ func (m *Manager) AddBlock(block *externalapi.DomainBlock) error {
return m.context.AddBlock(block)
}
func (m *Manager) runFlows(flows []*flow, peer *peerpkg.Peer, errChan <-chan error, flowsWaitGroup *sync.WaitGroup) error {
flowsWaitGroup.Add(len(flows))
func (m *Manager) runFlows(flows []*flow, peer *peerpkg.Peer, errChan <-chan error) error {
for _, flow := range flows {
executeFunc := flow.executeFunc // extract to new variable so that it's not overwritten
spawn(fmt.Sprintf("flow-%s", flow.name), func() {
executeFunc(peer)
flowsWaitGroup.Done()
})
}

View File

@@ -1,10 +1,10 @@
package protocol
import (
"sync/atomic"
"github.com/kaspanet/kaspad/app/protocol/flows/rejects"
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
"sync"
"sync/atomic"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/app/protocol/flows/addressexchange"
@@ -41,13 +41,6 @@ func (m *Manager) routerInitializer(router *routerpkg.Router, netConnection *net
// After flows were registered - spawn a new thread that will wait for connection to finish initializing
// and start receiving messages
spawn("routerInitializer-runFlows", func() {
m.routersWaitGroup.Add(1)
defer m.routersWaitGroup.Done()
if atomic.LoadUint32(&m.isClosed) == 1 {
panic(errors.Errorf("tried to initialize router when the protocol manager is closed"))
}
isBanned, err := m.context.ConnectionManager().IsBanned(netConnection)
if err != nil && !errors.Is(err, addressmanager.ErrAddressNotFound) {
panic(err)
@@ -86,17 +79,11 @@ func (m *Manager) routerInitializer(router *routerpkg.Router, netConnection *net
removeHandshakeRoutes(router)
flowsWaitGroup := &sync.WaitGroup{}
err = m.runFlows(flows, peer, errChan, flowsWaitGroup)
err = m.runFlows(flows, peer, errChan)
if err != nil {
m.handleError(err, netConnection, router.OutgoingRoute())
// We call `flowsWaitGroup.Wait()` in two places instead of deferring, because
// we already defer `m.routersWaitGroup.Done()`, so we try to avoid error prone
// and confusing use of multiple dependent defers.
flowsWaitGroup.Wait()
return
}
flowsWaitGroup.Wait()
})
}
@@ -251,7 +238,7 @@ func (m *Manager) registerTransactionRelayFlow(router *routerpkg.Router, isStopp
outgoingRoute := router.OutgoingRoute()
return []*flow{
m.registerFlowWithCapacity("HandleRelayedTransactions", 10_000, router,
m.registerFlow("HandleRelayedTransactions", router,
[]appmessage.MessageCommand{appmessage.CmdInvTransaction, appmessage.CmdTx, appmessage.CmdTransactionNotFound}, isStopping, errChan,
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
return transactionrelay.HandleRelayedTransactions(m.context, incomingRoute, outgoingRoute)
@@ -287,24 +274,6 @@ func (m *Manager) registerFlow(name string, router *routerpkg.Router, messageTyp
panic(err)
}
return m.registerFlowForRoute(route, name, isStopping, errChan, initializeFunc)
}
func (m *Manager) registerFlowWithCapacity(name string, capacity int, router *routerpkg.Router,
messageTypes []appmessage.MessageCommand, isStopping *uint32,
errChan chan error, initializeFunc flowInitializeFunc) *flow {
route, err := router.AddIncomingRouteWithCapacity(capacity, messageTypes)
if err != nil {
panic(err)
}
return m.registerFlowForRoute(route, name, isStopping, errChan, initializeFunc)
}
func (m *Manager) registerFlowForRoute(route *routerpkg.Route, name string, isStopping *uint32,
errChan chan error, initializeFunc flowInitializeFunc) *flow {
return &flow{
name: name,
executeFunc: func(peer *peerpkg.Peer) {

View File

@@ -24,7 +24,7 @@ func ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(address string, pair
UTXOEntry: &appmessage.RPCUTXOEntry{
Amount: utxoEntry.Amount(),
ScriptPublicKey: &appmessage.RPCScriptPublicKey{Script: hex.EncodeToString(utxoEntry.ScriptPublicKey().Script), Version: utxoEntry.ScriptPublicKey().Version},
BlockDAAScore: utxoEntry.BlockDAAScore(),
BlockBlueScore: utxoEntry.BlockBlueScore(),
IsCoinbase: utxoEntry.IsCoinbase(),
},
})

View File

@@ -17,6 +17,8 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
@@ -126,6 +128,11 @@ func (ctx *Context) BuildTransactionVerboseData(tx *externalapi.DomainTransactio
onEnd := logger.LogAndMeasureExecutionTime(log, "BuildTransactionVerboseData")
defer onEnd()
var payloadHash string
if tx.SubnetworkID != subnetworks.SubnetworkIDNative {
payloadHash = tx.PayloadHash.String()
}
txReply := &appmessage.TransactionVerboseData{
TxID: txID,
Hash: consensushashing.TransactionHash(tx).String(),
@@ -136,6 +143,7 @@ func (ctx *Context) BuildTransactionVerboseData(tx *externalapi.DomainTransactio
LockTime: tx.LockTime,
SubnetworkID: tx.SubnetworkID.String(),
Gas: tx.Gas,
PayloadHash: payloadHash,
Payload: hex.EncodeToString(tx.Payload),
}

View File

@@ -55,7 +55,7 @@ func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appm
if err != nil {
return nil, err
}
blockHashes, highHash, err := context.Domain.Consensus().GetHashesBetween(
blockHashes, err := context.Domain.Consensus().GetHashesBetween(
lowHash, virtualSelectedParent, maxBlocksInGetBlocksResponse)
if err != nil {
return nil, err
@@ -64,10 +64,9 @@ func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appm
// prepend low hash to make it inclusive
blockHashes = append([]*externalapi.DomainHash{lowHash}, blockHashes...)
// If the high hash is equal to virtualSelectedParent it means GetHashesBetween didn't skip any hashes, and
// there's space to add the virtualSelectedParent's anticone, otherwise you can't add the anticone because
// there's no guarantee that all of the anticone root ancestors will be present.
if highHash.Equal(virtualSelectedParent) {
// If there are no maxBlocksInGetBlocksResponse between lowHash and virtualSelectedParent -
// add virtualSelectedParent's anticone
if len(blockHashes) < maxBlocksInGetBlocksResponse {
virtualSelectedParentAnticone, err := context.Domain.Consensus().Anticone(virtualSelectedParent)
if err != nil {
return nil, err

View File

@@ -8,10 +8,6 @@ import (
// HandleGetInfo handles the respectively named RPC command
func HandleGetInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
response := appmessage.NewGetInfoResponseMessage(
context.NetAdapter.ID().String(),
uint64(context.Domain.MiningManager().TransactionCount()),
)
response := appmessage.NewGetInfoResponseMessage(context.NetAdapter.ID().String())
return response, nil
}

View File

@@ -16,7 +16,7 @@ func HandleUnban(context *rpccontext.Context, _ *router.Router, request appmessa
errorMessage.Error = appmessage.RPCErrorf("Could not parse IP %s", unbanRequest.IP)
return errorMessage, nil
}
err := context.AddressManager.Unban(appmessage.NewNetAddressIPPort(ip, 0))
err := context.AddressManager.Unban(appmessage.NewNetAddressIPPort(ip, 0, 0))
if err != nil {
errorMessage := &appmessage.UnbanResponseMessage{}
errorMessage.Error = appmessage.RPCErrorf("Could not unban IP: %s", err)

View File

@@ -1,11 +1,31 @@
Kaspad v0.9.0 - 2021-03-04
===========================
* Merge big subdags in pick virtual parents (#1574)
* Write in the reject message the tx rejection reason (#1573)
* Add nil checks for protowire (#1570)
* Increase getBlocks limit to 1000 (#1572)
* Return RPC error if getBlock's lowHash doesn't exist (#1569)
* Add default dns-seeder to testnet (#1568)
* Fix utxoindex deserialization (#1566)
* Add pruning point hash to GetBlockDagInfo response (#1565)
* Use EmitUnpopulated so that kaspactl prints all fields, even the default ones (#1561)
* Stop logging an error whenever an RPC/P2P connection is canceled (#1562)
* Cleanup the logger and make it asynchronous (#1524)
* Close all iterators (#1542)
* Add childrenHashes to GetBlock/s RPC commands (#1560)
* Add ScriptPublicKey.Version to RPC (#1559)
* Fix the target block rate to create less bursty mining (#1554)
Kaspad v0.8.10 - 2021-02-25
===========================
[*] Fix bug where invalid mempool transactions were not removed (#1551)
[*] Add RPC reconnection to the miner (#1552)
[*] Remove virtual diff parents - only selectedTip is virtualDiffParent now (#1550)
[*] Fix UTXO index (#1548)
[*] Prevent fast failing (#1545)
[*] Increase the sleep time in kaspaminer when the node is not synced (#1544)
[*] Disallow header only blocks on RPC, relay and when requesting IBD full blocks (#1537)
[*] Make templateManager hold a DomainBlock and isSynced bool instead of a GetBlockTemplateResponseMessage (#1538)
* Fix bug where invalid mempool transactions were not removed (#1551)
* Add RPC reconnection to the miner (#1552)
* Remove virtual diff parents - only selectedTip is virtualDiffParent now (#1550)
* Fix UTXO index (#1548)
* Prevent fast failing (#1545)
* Increase the sleep time in kaspaminer when the node is not synced (#1544)
* Disallow header only blocks on RPC, relay and when requesting IBD full blocks (#1537)
* Make templateManager hold a DomainBlock and isSynced bool instead of a GetBlockTemplateResponseMessage (#1538)

View File

@@ -24,9 +24,9 @@ const (
var (
// Default configuration options
defaultAppDir = util.AppDir("kaspaminer", false)
defaultLogFile = filepath.Join(defaultAppDir, defaultLogFilename)
defaultErrLogFile = filepath.Join(defaultAppDir, defaultErrLogFilename)
defaultHomeDir = util.AppDataDir("kaspaminer", false)
defaultLogFile = filepath.Join(defaultHomeDir, defaultLogFilename)
defaultErrLogFile = filepath.Join(defaultHomeDir, defaultErrLogFilename)
defaultRPCServer = "localhost"
)

View File

@@ -44,32 +44,34 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, targetBlocksPerSecond
spawn("blocksLoop", func() {
const windowSize = 10
var expectedDurationForWindow time.Duration
var windowExpectedEndTime time.Time
hasBlockRateTarget := targetBlocksPerSecond != 0
var windowTicker, blockTicker *time.Ticker
// We use tickers to limit the block rate:
// 1. windowTicker -> makes sure that the last windowSize blocks take at least windowSize*targetBlocksPerSecond.
// 2. blockTicker -> makes sure that each block takes at least targetBlocksPerSecond/windowSize.
// that way we both allow for fluctuation in block rate but also make sure they're not too big (by an order of magnitude)
if hasBlockRateTarget {
windowRate := time.Duration(float64(time.Second) / (targetBlocksPerSecond / windowSize))
blockRate := time.Duration(float64(time.Second) / (targetBlocksPerSecond * windowSize))
log.Infof("Minimum average time per %d blocks: %s, smaller minimum time per block: %s", windowSize, windowRate, blockRate)
windowTicker = time.NewTicker(windowRate)
blockTicker = time.NewTicker(blockRate)
defer windowTicker.Stop()
defer blockTicker.Stop()
expectedDurationForWindow = time.Duration(float64(windowSize)/targetBlocksPerSecond) * time.Second
windowExpectedEndTime = time.Now().Add(expectedDurationForWindow)
}
windowStart := time.Now()
for blockIndex := 1; ; blockIndex++ {
blockInWindowIndex := 0
sleepTime := 0 * time.Second
for {
foundBlockChan <- mineNextBlock(mineWhenNotSynced)
if hasBlockRateTarget {
<-blockTicker.C
if (blockIndex % windowSize) == 0 {
tickerStart := time.Now()
<-windowTicker.C
log.Infof("Finished mining %d blocks in: %s. slept for: %s", windowSize, time.Since(windowStart), time.Since(tickerStart))
windowStart = time.Now()
blockInWindowIndex++
if blockInWindowIndex == windowSize-1 {
deviation := windowExpectedEndTime.Sub(time.Now())
if deviation > 0 {
sleepTime = deviation / windowSize
log.Infof("Finished to mine %d blocks %s earlier than expected. Setting the miner "+
"to sleep %s between blocks to compensate",
windowSize, deviation, sleepTime)
}
blockInWindowIndex = 0
windowExpectedEndTime = time.Now().Add(expectedDurationForWindow)
}
time.Sleep(sleepTime)
}
}
})

View File

@@ -10,8 +10,7 @@ func isUTXOSpendable(entry *appmessage.UTXOsByAddressesEntry, virtualSelectedPar
if !entry.UTXOEntry.IsCoinbase {
return true
}
blockBlueScore := entry.UTXOEntry.BlockDAAScore
// TODO: Check for a better alternative than virtualSelectedParentBlueScore
blockBlueScore := entry.UTXOEntry.BlockBlueScore
return blockBlueScore+coinbaseMaturity < virtualSelectedParentBlueScore
}

View File

@@ -3,11 +3,9 @@ package main
import (
"encoding/hex"
"fmt"
"github.com/kaspanet/go-secp256k1"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
@@ -179,12 +177,11 @@ func generateTransaction(keyPair *secp256k1.SchnorrKeyPair, selectedUTXOs []*app
SubnetworkID: subnetworks.SubnetworkIDNative,
Gas: 0,
Payload: nil,
PayloadHash: externalapi.DomainHash{},
}
sighashReusedValues := &consensushashing.SighashReusedValues{}
for i, input := range domainTransaction.Inputs {
signatureScript, err := txscript.SignatureScript(
domainTransaction, i, consensushashing.SigHashAll, keyPair, sighashReusedValues)
signatureScript, err := txscript.SignatureScript(domainTransaction, i, fromScript, txscript.SigHashAll, keyPair)
if err != nil {
return nil, err
}

View File

@@ -46,7 +46,6 @@ type consensus struct {
utxoDiffStore model.UTXODiffStore
finalityStore model.FinalityStore
headersSelectedChainStore model.HeadersSelectedChainStore
daaBlocksStore model.DAABlocksStore
}
// BuildBlock builds a block over the current state, with the transactions
@@ -159,8 +158,6 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
}
func (s *consensus) GetBlockChildren(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
s.lock.Lock()
defer s.lock.Unlock()
blockRelation, err := s.blockRelationStore.BlockRelation(s.databaseContext, blockHash)
if err != nil {
return nil, err
@@ -182,18 +179,18 @@ func (s *consensus) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (e
}
func (s *consensus) GetHashesBetween(lowHash, highHash *externalapi.DomainHash,
maxBlueScoreDifference uint64) (hashes []*externalapi.DomainHash, actualHighHash *externalapi.DomainHash, err error) {
maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) {
s.lock.Lock()
defer s.lock.Unlock()
err = s.validateBlockHashExists(lowHash)
err := s.validateBlockHashExists(lowHash)
if err != nil {
return nil, nil, err
return nil, err
}
err = s.validateBlockHashExists(highHash)
if err != nil {
return nil, nil, err
return nil, err
}
return s.syncManager.GetHashesBetween(lowHash, highHash, maxBlueScoreDifference)

View File

@@ -13,9 +13,9 @@ type GHOSTDAGManagerConstructor func(model.DBReader, model.DAGTopologyManager,
// DifficultyManagerConstructor is the function signature for a constructor of a type implementing model.DifficultyManager
type DifficultyManagerConstructor func(model.DBReader, model.GHOSTDAGManager, model.GHOSTDAGDataStore,
model.BlockHeaderStore, model.DAABlocksStore, model.DAGTopologyManager, model.DAGTraversalManager, *big.Int, int, bool, time.Duration,
model.BlockHeaderStore, model.DAGTopologyManager, model.DAGTraversalManager, *big.Int, int, bool, time.Duration,
*externalapi.DomainHash) model.DifficultyManager
// PastMedianTimeManagerConstructor is the function signature for a constructor of a type implementing model.PastMedianTimeManager
type PastMedianTimeManagerConstructor func(int, model.DBReader, model.DAGTraversalManager, model.BlockHeaderStore,
model.GHOSTDAGDataStore, *externalapi.DomainHash) model.PastMedianTimeManager
model.GHOSTDAGDataStore) model.PastMedianTimeManager

View File

@@ -1,24 +0,0 @@
package binaryserialization
import (
"encoding/binary"
"github.com/pkg/errors"
)
const uint64Length = 8
// SerializeUint64 serializes a uint64
func SerializeUint64(value uint64) []byte {
var keyBytes [uint64Length]byte
binary.LittleEndian.PutUint64(keyBytes[:], value)
return keyBytes[:]
}
// DeserializeUint64 deserializes bytes to uint64
func DeserializeUint64(valueBytes []byte) (uint64, error) {
if len(valueBytes) != uint64Length {
return 0, errors.Errorf("the given value is %d bytes so it cannot be deserialized into uint64",
len(valueBytes))
}
return binary.LittleEndian.Uint64(valueBytes), nil
}

View File

@@ -1,47 +1,13 @@
package binaryserialization
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/pkg/errors"
)
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// SerializeHash serializes hash to a slice of bytes
func SerializeHash(hash *externalapi.DomainHash) []byte {
return hash.ByteSlice()
}
// DeserializeHash deserializes a slice of bytes to a hash
// DeserializeHash a slice of bytes to a hash
func DeserializeHash(hashBytes []byte) (*externalapi.DomainHash, error) {
return externalapi.NewDomainHashFromByteSlice(hashBytes)
}
// SerializeHashes serializes a slice of hashes to a slice of bytes
func SerializeHashes(hashes []*externalapi.DomainHash) []byte {
buff := make([]byte, len(hashes)*externalapi.DomainHashSize)
for i, hash := range hashes {
copy(buff[externalapi.DomainHashSize*i:], hash.ByteSlice())
}
return buff
}
// DeserializeHashes deserializes a slice of bytes to a slice of hashes
func DeserializeHashes(hashesBytes []byte) ([]*externalapi.DomainHash, error) {
if len(hashesBytes)%externalapi.DomainHashSize != 0 {
return nil, errors.Errorf("The length of hashBytes is not divisible by externalapi.DomainHashSize (%d)",
externalapi.DomainHashSize)
}
numHashes := len(hashesBytes) / externalapi.DomainHashSize
hashes := make([]*externalapi.DomainHash, numHashes)
for i := 0; i < numHashes; i++ {
var err error
start := i * externalapi.DomainHashSize
end := i*externalapi.DomainHashSize + externalapi.DomainHashSize
hashes[i], err = externalapi.NewDomainHashFromByteSlice(hashesBytes[start:end])
if err != nil {
return nil, err
}
}
return hashes, nil
}

View File

@@ -0,0 +1,15 @@
package binaryserialization
import "encoding/binary"
// SerializeChainBlockIndex serializes chain block index
func SerializeChainBlockIndex(index uint64) []byte {
var keyBytes [8]byte
binary.LittleEndian.PutUint64(keyBytes[:], index)
return keyBytes[:]
}
// DeserializeChainBlockIndex deserializes chain block index to uint64
func DeserializeChainBlockIndex(indexBytes []byte) uint64 {
return binary.LittleEndian.Uint64(indexBytes)
}

View File

@@ -241,6 +241,7 @@ type DbTransaction struct {
LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"`
SubnetworkID *DbSubnetworkId `protobuf:"bytes,5,opt,name=subnetworkID,proto3" json:"subnetworkID,omitempty"`
Gas uint64 `protobuf:"varint,6,opt,name=gas,proto3" json:"gas,omitempty"`
PayloadHash *DbHash `protobuf:"bytes,7,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"`
Payload []byte `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"`
}
@@ -318,6 +319,13 @@ func (x *DbTransaction) GetGas() uint64 {
return 0
}
func (x *DbTransaction) GetPayloadHash() *DbHash {
if x != nil {
return x.PayloadHash
}
return nil
}
func (x *DbTransaction) GetPayload() []byte {
if x != nil {
return x.Payload
@@ -1220,7 +1228,7 @@ type DbUtxoEntry struct {
Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"`
ScriptPublicKey *DbScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"`
BlockDaaScore uint64 `protobuf:"varint,3,opt,name=blockDaaScore,proto3" json:"blockDaaScore,omitempty"`
BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"`
IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"`
}
@@ -1270,9 +1278,9 @@ func (x *DbUtxoEntry) GetScriptPublicKey() *DbScriptPublicKey {
return nil
}
func (x *DbUtxoEntry) GetBlockDaaScore() uint64 {
func (x *DbUtxoEntry) GetBlockBlueScore() uint64 {
if x != nil {
return x.BlockDaaScore
return x.BlockBlueScore
}
return 0
}
@@ -1645,7 +1653,7 @@ var file_dbobjects_proto_rawDesc = []byte{
0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63,
0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c,
0x0a, 0x06, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0xad, 0x02, 0x0a,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0xe6, 0x02, 0x0a,
0x0d, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18,
0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75,
@@ -1663,184 +1671,188 @@ var file_dbobjects_proto_rawDesc = []byte{
0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44,
0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67,
0x61, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xa1, 0x01, 0x0a,
0x12, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e,
0x70, 0x75, 0x74, 0x12, 0x45, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f,
0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62,
0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f,
0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69,
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63,
0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
0x22, 0x68, 0x0a, 0x0a, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x44,
0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a,
0x61, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73,
0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b,
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70,
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xa1, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x45, 0x0a, 0x10,
0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69,
0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e,
0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65,
0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69,
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a,
0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x68, 0x0a, 0x0a, 0x44, 0x62, 0x4f,
0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x44, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e,
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44,
0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a,
0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x22, 0x37, 0x0a, 0x0f, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x77, 0x0a, 0x13,
0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74,
0x70, 0x75, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x34, 0x0a, 0x0e, 0x44, 0x62, 0x53, 0x75, 0x62, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73,
0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x6a, 0x0a, 0x10, 0x44,
0x62, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12,
0x56, 0x0a, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e,
0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61,
0x74, 0x61, 0x52, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xb6, 0x01, 0x0a, 0x15, 0x44, 0x62, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74,
0x61, 0x12, 0x68, 0x0a, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61,
0x52, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63,
0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x09, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15,
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44,
0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68,
0x22, 0xed, 0x01, 0x0a, 0x1b, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61,
0x12, 0x3e, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x37, 0x0a, 0x0f, 0x44, 0x62,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x24, 0x0a,
0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x49, 0x64, 0x22, 0x77, 0x0a, 0x13, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x12, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x53, 0x63, 0x72, 0x69,
0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x34, 0x0a, 0x0e,
0x44, 0x62, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x22,
0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x49, 0x64, 0x22, 0x6a, 0x0a, 0x10, 0x44, 0x62, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e,
0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x56, 0x0a, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41,
0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70,
0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xb6,
0x01, 0x0a, 0x15, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,
0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x68, 0x0a, 0x19, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63,
0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61,
0x74, 0x61, 0x12, 0x33, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0xed, 0x01, 0x0a, 0x1b, 0x44, 0x62, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x41,
0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69,
0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x1b, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78,
0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44,
0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x1b, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f,
0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x76, 0x0a, 0x10, 0x44, 0x62, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70,
0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48,
0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x08,
0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15,
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44,
0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22,
0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, 0x73, 0x74, 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61,
0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1a,
0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65,
0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63,
0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72,
0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65,
0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53,
0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48,
0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64,
0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f,
0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e,
0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62,
0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a,
0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e,
0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, 0x6d, 0x0a, 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65,
0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31,
0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73,
0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e,
0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, 0x0a, 0x0a, 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22,
0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05,
0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74,
0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d,
0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74,
0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d,
0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f,
0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72,
0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78,
0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x22, 0x45, 0x0a, 0x11, 0x44, 0x62, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x18,
0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xb7, 0x01, 0x0a, 0x0b, 0x44, 0x62, 0x55,
0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x53, 0x63, 0x72, 0x69,
0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x04, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f,
0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65,
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61,
0x73, 0x65, 0x22, 0xfe, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62,
0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69,
0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65,
0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66,
0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64,
0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,
0x65, 0x64, 0x12, 0x5c, 0x0a, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x49, 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73,
0x22, 0x76, 0x0a, 0x10, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61,
0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65,
0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08,
0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x22, 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f,
0x73, 0x74, 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75,
0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c,
0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57,
0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57,
0x6f, 0x72, 0x6b, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50,
0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61,
0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06,
0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48,
0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e,
0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62,
0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x43,
0x0a, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x53, 0x65, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x73, 0x68, 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65,
0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c,
0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68,
0x52, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x53, 0x65, 0x74, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62,
0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a,
0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74,
0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f,
0x44, 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12,
0x3f, 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
0x22, 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69,
0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52,
0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44,
0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e,
0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b,
0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x52, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12,
0x39, 0x0a, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18,
0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65,
0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c,
0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73,
0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69,
0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e,
0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75,
0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22,
0x6d, 0x0a, 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f,
0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48,
0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68,
0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e,
0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28,
0x0a, 0x0a, 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08,
0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08,
0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74,
0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
0x22, 0x87, 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74,
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75,
0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x12, 0x38, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x45, 0x0a, 0x11, 0x44, 0x62,
0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12,
0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x22, 0xb9, 0x01, 0x0a, 0x0b, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c,
0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a,
0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0xfe, 0x01,
0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79,
0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69,
0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63,
0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06,
0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68,
0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52,
0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x43, 0x0a, 0x11, 0x66, 0x75, 0x74,
0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x18, 0x04,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x11, 0x66, 0x75, 0x74,
0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x22, 0x40,
0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79,
0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10,
0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x65, 0x6e, 0x64,
0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x44, 0x69, 0x66, 0x66, 0x12,
0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23,
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44,
0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, 0x3f, 0x0a, 0x08, 0x74, 0x6f,
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55,
0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65,
0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x33, 0x0a, 0x06, 0x44,
0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73,
0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64,
0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1895,37 +1907,38 @@ var file_dbobjects_proto_depIdxs = []int32{
4, // 6: serialization.DbTransaction.inputs:type_name -> serialization.DbTransactionInput
7, // 7: serialization.DbTransaction.outputs:type_name -> serialization.DbTransactionOutput
8, // 8: serialization.DbTransaction.subnetworkID:type_name -> serialization.DbSubnetworkId
5, // 9: serialization.DbTransactionInput.previousOutpoint:type_name -> serialization.DbOutpoint
6, // 10: serialization.DbOutpoint.transactionID:type_name -> serialization.DbTransactionId
19, // 11: serialization.DbTransactionOutput.scriptPublicKey:type_name -> serialization.DbScriptPublicKey
10, // 12: serialization.DbAcceptanceData.blockAcceptanceData:type_name -> serialization.DbBlockAcceptanceData
11, // 13: serialization.DbBlockAcceptanceData.transactionAcceptanceData:type_name -> serialization.DbTransactionAcceptanceData
2, // 14: serialization.DbBlockAcceptanceData.blockHash:type_name -> serialization.DbHash
3, // 15: serialization.DbTransactionAcceptanceData.transaction:type_name -> serialization.DbTransaction
20, // 16: serialization.DbTransactionAcceptanceData.transactionInputUtxoEntries:type_name -> serialization.DbUtxoEntry
2, // 17: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash
2, // 18: serialization.DbBlockRelations.children:type_name -> serialization.DbHash
2, // 19: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash
2, // 20: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash
2, // 21: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash
15, // 22: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes
2, // 23: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash
18, // 24: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem
5, // 25: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint
20, // 26: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry
19, // 27: serialization.DbUtxoEntry.scriptPublicKey:type_name -> serialization.DbScriptPublicKey
2, // 28: serialization.DbReachabilityData.children:type_name -> serialization.DbHash
2, // 29: serialization.DbReachabilityData.parent:type_name -> serialization.DbHash
22, // 30: serialization.DbReachabilityData.interval:type_name -> serialization.DbReachabilityInterval
2, // 31: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash
18, // 32: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem
18, // 33: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem
2, // 34: serialization.DbTips.tips:type_name -> serialization.DbHash
35, // [35:35] is the sub-list for method output_type
35, // [35:35] is the sub-list for method input_type
35, // [35:35] is the sub-list for extension type_name
35, // [35:35] is the sub-list for extension extendee
0, // [0:35] is the sub-list for field type_name
2, // 9: serialization.DbTransaction.payloadHash:type_name -> serialization.DbHash
5, // 10: serialization.DbTransactionInput.previousOutpoint:type_name -> serialization.DbOutpoint
6, // 11: serialization.DbOutpoint.transactionID:type_name -> serialization.DbTransactionId
19, // 12: serialization.DbTransactionOutput.scriptPublicKey:type_name -> serialization.DbScriptPublicKey
10, // 13: serialization.DbAcceptanceData.blockAcceptanceData:type_name -> serialization.DbBlockAcceptanceData
11, // 14: serialization.DbBlockAcceptanceData.transactionAcceptanceData:type_name -> serialization.DbTransactionAcceptanceData
2, // 15: serialization.DbBlockAcceptanceData.blockHash:type_name -> serialization.DbHash
3, // 16: serialization.DbTransactionAcceptanceData.transaction:type_name -> serialization.DbTransaction
20, // 17: serialization.DbTransactionAcceptanceData.transactionInputUtxoEntries:type_name -> serialization.DbUtxoEntry
2, // 18: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash
2, // 19: serialization.DbBlockRelations.children:type_name -> serialization.DbHash
2, // 20: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash
2, // 21: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash
2, // 22: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash
15, // 23: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes
2, // 24: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash
18, // 25: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem
5, // 26: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint
20, // 27: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry
19, // 28: serialization.DbUtxoEntry.scriptPublicKey:type_name -> serialization.DbScriptPublicKey
2, // 29: serialization.DbReachabilityData.children:type_name -> serialization.DbHash
2, // 30: serialization.DbReachabilityData.parent:type_name -> serialization.DbHash
22, // 31: serialization.DbReachabilityData.interval:type_name -> serialization.DbReachabilityInterval
2, // 32: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash
18, // 33: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem
18, // 34: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem
2, // 35: serialization.DbTips.tips:type_name -> serialization.DbHash
36, // [36:36] is the sub-list for method output_type
36, // [36:36] is the sub-list for method input_type
36, // [36:36] is the sub-list for extension type_name
36, // [36:36] is the sub-list for extension extendee
0, // [0:36] is the sub-list for field type_name
}
func init() { file_dbobjects_proto_init() }

View File

@@ -30,6 +30,7 @@ message DbTransaction {
uint64 lockTime = 4;
DbSubnetworkId subnetworkID = 5;
uint64 gas = 6;
DbHash payloadHash = 7;
bytes payload = 8;
}
@@ -117,7 +118,7 @@ message DbScriptPublicKey {
message DbUtxoEntry {
uint64 amount = 1;
DbScriptPublicKey scriptPublicKey = 2;
uint64 blockDaaScore = 3;
uint64 blockBlueScore = 3;
bool isCoinbase = 4;
}

View File

@@ -33,6 +33,7 @@ func DomainTransactionToDbTransaction(domainTransaction *externalapi.DomainTrans
LockTime: domainTransaction.LockTime,
SubnetworkID: DomainSubnetworkIDToDbSubnetworkID(&domainTransaction.SubnetworkID),
Gas: domainTransaction.Gas,
PayloadHash: DomainHashToDbHash(&domainTransaction.PayloadHash),
Payload: domainTransaction.Payload,
}
}
@@ -43,6 +44,10 @@ func DbTransactionToDomainTransaction(dbTransaction *DbTransaction) (*externalap
if err != nil {
return nil, err
}
domainPayloadHash, err := DbHashToDomainHash(dbTransaction.PayloadHash)
if err != nil {
return nil, err
}
domainInputs := make([]*externalapi.DomainTransactionInput, len(dbTransaction.Inputs))
for i, dbTransactionInput := range dbTransaction.Inputs {
@@ -79,6 +84,7 @@ func DbTransactionToDomainTransaction(dbTransaction *DbTransaction) (*externalap
LockTime: dbTransaction.LockTime,
SubnetworkID: *domainSubnetworkID,
Gas: dbTransaction.Gas,
PayloadHash: *domainPayloadHash,
Payload: dbTransaction.Payload,
}, nil
}

View File

@@ -26,7 +26,7 @@ func UTXOEntryToDBUTXOEntry(utxoEntry externalapi.UTXOEntry) *DbUtxoEntry {
return &DbUtxoEntry{
Amount: utxoEntry.Amount(),
ScriptPublicKey: dbScriptPublicKey,
BlockDaaScore: utxoEntry.BlockDAAScore(),
BlockBlueScore: utxoEntry.BlockBlueScore(),
IsCoinbase: utxoEntry.IsCoinbase(),
}
}
@@ -37,5 +37,5 @@ func DBUTXOEntryToUTXOEntry(dbUtxoEntry *DbUtxoEntry) (externalapi.UTXOEntry, er
if err != nil {
return nil, err
}
return utxo.NewUTXOEntry(dbUtxoEntry.Amount, scriptPublicKey, dbUtxoEntry.IsCoinbase, dbUtxoEntry.BlockDaaScore), nil
return utxo.NewUTXOEntry(dbUtxoEntry.Amount, scriptPublicKey, dbUtxoEntry.IsCoinbase, dbUtxoEntry.BlockBlueScore), nil
}

View File

@@ -1,160 +0,0 @@
package daablocksstore
import (
"github.com/kaspanet/kaspad/domain/consensus/database"
"github.com/kaspanet/kaspad/domain/consensus/database/binaryserialization"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
)
var daaScoreBucket = database.MakeBucket([]byte("daa-score"))
var daaAddedBlocksBucket = database.MakeBucket([]byte("daa-added-blocks"))
// daaBlocksStore represents a store of DAABlocksStore
type daaBlocksStore struct {
daaScoreStaging map[externalapi.DomainHash]uint64
daaAddedBlocksStaging map[externalapi.DomainHash][]*externalapi.DomainHash
daaScoreToDelete map[externalapi.DomainHash]struct{}
daaAddedBlocksToDelete map[externalapi.DomainHash]struct{}
daaScoreLRUCache *lrucache.LRUCache
daaAddedBlocksLRUCache *lrucache.LRUCache
}
// New instantiates a new DAABlocksStore
func New(daaScoreCacheSize int, daaAddedBlocksCacheSize int, preallocate bool) model.DAABlocksStore {
return &daaBlocksStore{
daaScoreStaging: make(map[externalapi.DomainHash]uint64),
daaAddedBlocksStaging: make(map[externalapi.DomainHash][]*externalapi.DomainHash),
daaScoreLRUCache: lrucache.New(daaScoreCacheSize, preallocate),
daaAddedBlocksLRUCache: lrucache.New(daaAddedBlocksCacheSize, preallocate),
}
}
func (daas *daaBlocksStore) StageDAAScore(blockHash *externalapi.DomainHash, daaScore uint64) {
daas.daaScoreStaging[*blockHash] = daaScore
}
func (daas *daaBlocksStore) StageBlockDAAAddedBlocks(blockHash *externalapi.DomainHash,
addedBlocks []*externalapi.DomainHash) {
daas.daaAddedBlocksStaging[*blockHash] = externalapi.CloneHashes(addedBlocks)
}
func (daas *daaBlocksStore) IsAnythingStaged() bool {
return len(daas.daaScoreStaging) != 0 ||
len(daas.daaAddedBlocksStaging) != 0 ||
len(daas.daaScoreToDelete) != 0 ||
len(daas.daaAddedBlocksToDelete) != 0
}
func (daas *daaBlocksStore) Discard() {
daas.daaScoreStaging = make(map[externalapi.DomainHash]uint64)
daas.daaAddedBlocksStaging = make(map[externalapi.DomainHash][]*externalapi.DomainHash)
daas.daaScoreToDelete = make(map[externalapi.DomainHash]struct{})
daas.daaAddedBlocksToDelete = make(map[externalapi.DomainHash]struct{})
}
func (daas *daaBlocksStore) Commit(dbTx model.DBTransaction) error {
for hash, daaScore := range daas.daaScoreStaging {
daaScoreBytes := binaryserialization.SerializeUint64(daaScore)
err := dbTx.Put(daas.daaScoreHashAsKey(&hash), daaScoreBytes)
if err != nil {
return err
}
daas.daaScoreLRUCache.Add(&hash, daaScore)
}
for hash, addedBlocks := range daas.daaAddedBlocksStaging {
addedBlocksBytes := binaryserialization.SerializeHashes(addedBlocks)
err := dbTx.Put(daas.daaAddedBlocksHashAsKey(&hash), addedBlocksBytes)
if err != nil {
return err
}
daas.daaAddedBlocksLRUCache.Add(&hash, addedBlocks)
}
for hash := range daas.daaScoreToDelete {
err := dbTx.Delete(daas.daaScoreHashAsKey(&hash))
if err != nil {
return err
}
daas.daaScoreLRUCache.Remove(&hash)
}
for hash := range daas.daaAddedBlocksToDelete {
err := dbTx.Delete(daas.daaAddedBlocksHashAsKey(&hash))
if err != nil {
return err
}
daas.daaAddedBlocksLRUCache.Remove(&hash)
}
daas.Discard()
return nil
}
func (daas *daaBlocksStore) DAAScore(dbContext model.DBReader, blockHash *externalapi.DomainHash) (uint64, error) {
if daaScore, ok := daas.daaScoreStaging[*blockHash]; ok {
return daaScore, nil
}
if daaScore, ok := daas.daaScoreLRUCache.Get(blockHash); ok {
return daaScore.(uint64), nil
}
daaScoreBytes, err := dbContext.Get(daas.daaScoreHashAsKey(blockHash))
if err != nil {
return 0, err
}
daaScore, err := binaryserialization.DeserializeUint64(daaScoreBytes)
if err != nil {
return 0, err
}
daas.daaScoreLRUCache.Add(blockHash, daaScore)
return daaScore, nil
}
func (daas *daaBlocksStore) DAAAddedBlocks(dbContext model.DBReader, blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
if addedBlocks, ok := daas.daaAddedBlocksStaging[*blockHash]; ok {
return externalapi.CloneHashes(addedBlocks), nil
}
if addedBlocks, ok := daas.daaAddedBlocksLRUCache.Get(blockHash); ok {
return externalapi.CloneHashes(addedBlocks.([]*externalapi.DomainHash)), nil
}
addedBlocksBytes, err := dbContext.Get(daas.daaAddedBlocksHashAsKey(blockHash))
if err != nil {
return nil, err
}
addedBlocks, err := binaryserialization.DeserializeHashes(addedBlocksBytes)
if err != nil {
return nil, err
}
daas.daaAddedBlocksLRUCache.Add(blockHash, addedBlocks)
return externalapi.CloneHashes(addedBlocks), nil
}
func (daas *daaBlocksStore) daaScoreHashAsKey(hash *externalapi.DomainHash) model.DBKey {
return daaScoreBucket.Key(hash.ByteSlice())
}
func (daas *daaBlocksStore) daaAddedBlocksHashAsKey(hash *externalapi.DomainHash) model.DBKey {
return daaAddedBlocksBucket.Key(hash.ByteSlice())
}
func (daas *daaBlocksStore) Delete(blockHash *externalapi.DomainHash) {
if _, ok := daas.daaScoreStaging[*blockHash]; ok {
delete(daas.daaScoreStaging, *blockHash)
} else {
daas.daaAddedBlocksToDelete[*blockHash] = struct{}{}
}
if _, ok := daas.daaAddedBlocksStaging[*blockHash]; ok {
delete(daas.daaAddedBlocksStaging, *blockHash)
} else {
daas.daaAddedBlocksToDelete[*blockHash] = struct{}{}
}
}

View File

@@ -161,11 +161,7 @@ func (hscs *headersSelectedChainStore) GetIndexByHash(dbContext model.DBReader,
return 0, err
}
index, err := hscs.deserializeIndex(indexBytes)
if err != nil {
return 0, err
}
index := hscs.deserializeIndex(indexBytes)
hscs.cacheByHash.Add(blockHash, index)
return index, nil
}
@@ -197,11 +193,11 @@ func (hscs *headersSelectedChainStore) GetHashByIndex(dbContext model.DBReader,
}
func (hscs *headersSelectedChainStore) serializeIndex(index uint64) []byte {
return binaryserialization.SerializeUint64(index)
return binaryserialization.SerializeChainBlockIndex(index)
}
func (hscs *headersSelectedChainStore) deserializeIndex(indexBytes []byte) (uint64, error) {
return binaryserialization.DeserializeUint64(indexBytes)
func (hscs *headersSelectedChainStore) deserializeIndex(indexBytes []byte) uint64 {
return binaryserialization.DeserializeChainBlockIndex(indexBytes)
}
func (hscs *headersSelectedChainStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey {
@@ -227,11 +223,7 @@ func (hscs *headersSelectedChainStore) highestChainBlockIndex(dbContext model.DB
return 0, false, err
}
index, err := hscs.deserializeIndex(indexBytes)
if err != nil {
return 0, false, err
}
index := hscs.deserializeIndex(indexBytes)
hscs.cacheHighestChainBlockIndex = index
return index, true, nil
}

View File

@@ -1,7 +1,6 @@
package consensus
import (
daablocksstore "github.com/kaspanet/kaspad/domain/consensus/datastructures/daablocksstore"
"io/ioutil"
"os"
"sync"
@@ -127,7 +126,6 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
headersSelectedTipStore := headersselectedtipstore.New()
finalityStore := finalitystore.New(200, preallocateCaches)
headersSelectedChainStore := headersselectedchainstore.New(pruningWindowSizeForCaches, preallocateCaches)
daaBlocksStore := daablocksstore.New(pruningWindowSizeForCaches, int(dagParams.FinalityDepth()), preallocateCaches)
// Processes
reachabilityManager := reachabilitymanager.New(
@@ -151,15 +149,13 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
ghostdagDataStore,
reachabilityDataStore,
ghostdagManager,
consensusStateStore,
dagParams.GenesisHash)
consensusStateStore)
pastMedianTimeManager := f.pastMedianTimeConsructor(
dagParams.TimestampDeviationTolerance,
dbManager,
dagTraversalManager,
blockHeaderStore,
ghostdagDataStore,
dagParams.GenesisHash)
ghostdagDataStore)
transactionValidator := transactionvalidator.New(dagParams.BlockCoinbaseMaturity,
dagParams.EnableNonNativeSubnetworks,
dagParams.MassPerTxByte,
@@ -168,14 +164,12 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
dagParams.MaxCoinbasePayloadLength,
dbManager,
pastMedianTimeManager,
ghostdagDataStore,
daaBlocksStore)
ghostdagDataStore)
difficultyManager := f.difficultyConstructor(
dbManager,
ghostdagManager,
ghostdagDataStore,
blockHeaderStore,
daaBlocksStore,
dagTopologyManager,
dagTraversalManager,
dagParams.PowMax,
@@ -189,8 +183,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
dagParams.BaseSubsidy,
dagParams.CoinbasePayloadScriptPublicKeyMaxLength,
ghostdagDataStore,
acceptanceDataStore,
daaBlocksStore)
acceptanceDataStore)
headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, dagTraversalManager,
ghostdagManager, headersSelectedTipStore, headersSelectedChainStore)
genesisHash := dagParams.GenesisHash
@@ -255,7 +248,6 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
coinbaseManager,
mergeDepthManager,
finalityManager,
difficultyManager,
blockStatusStore,
ghostdagDataStore,
@@ -267,8 +259,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
acceptanceDataStore,
blockHeaderStore,
headersSelectedTipStore,
pruningStore,
daaBlocksStore)
pruningStore)
if err != nil {
return nil, err
}
@@ -288,7 +279,6 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
blockStore,
blockHeaderStore,
utxoDiffStore,
daaBlocksStore,
isArchivalNode,
genesisHash,
dagParams.FinalityDepth(),
@@ -353,8 +343,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
blockHeaderStore,
headersSelectedTipStore,
finalityStore,
headersSelectedChainStore,
daaBlocksStore)
headersSelectedChainStore)
c := &consensus{
lock: &sync.Mutex{},
@@ -392,7 +381,6 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
utxoDiffStore: utxoDiffStore,
finalityStore: finalityStore,
headersSelectedChainStore: headersSelectedChainStore,
daaBlocksStore: daaBlocksStore,
}
genesisInfo, err := c.GetBlockInfo(genesisHash)

View File

@@ -26,9 +26,14 @@ func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAccep
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -70,9 +75,14 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -99,9 +109,14 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -127,9 +142,14 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -155,9 +175,14 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -184,9 +209,14 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -214,9 +244,14 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -319,6 +354,11 @@ func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -366,6 +406,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -398,6 +443,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -430,6 +480,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -462,6 +517,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -495,6 +555,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -598,6 +663,11 @@ func initTestAcceptanceDataForClone() []externalapi.AcceptanceData {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -647,6 +717,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -679,6 +754,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -711,6 +791,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -743,6 +828,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,

View File

@@ -26,9 +26,14 @@ func initTestBaseTransactions() []*externalapi.DomainTransaction {
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -47,9 +52,14 @@ func initTestAnotherTransactions() []*externalapi.DomainTransaction {
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x02},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -68,9 +78,14 @@ func initTestTwoTransactions() []*externalapi.DomainTransaction {
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -83,9 +98,14 @@ func initTestTwoTransactions() []*externalapi.DomainTransaction {
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View File

@@ -12,7 +12,7 @@ type Consensus interface {
GetBlockChildren(blockHash *DomainHash) ([]*DomainHash, error)
GetBlockAcceptanceData(blockHash *DomainHash) (AcceptanceData, error)
GetHashesBetween(lowHash, highHash *DomainHash, maxBlueScoreDifference uint64) (hashes []*DomainHash, actualHighHash *DomainHash, err error)
GetHashesBetween(lowHash, highHash *DomainHash, maxBlueScoreDifference uint64) ([]*DomainHash, error)
GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error)
GetPruningPointUTXOs(expectedPruningPointHash *DomainHash, fromOutpoint *DomainOutpoint, limit int) ([]*OutpointAndUTXOEntryPair, error)
GetVirtualUTXOs(expectedVirtualParents []*DomainHash, fromOutpoint *DomainOutpoint, limit int) ([]*OutpointAndUTXOEntryPair, error)

View File

@@ -15,11 +15,6 @@ type DomainHash struct {
hashArray [DomainHashSize]byte
}
// NewZeroHash returns a DomainHash that represents the zero value (0x000000...000)
func NewZeroHash() *DomainHash {
return &DomainHash{hashArray: [32]byte{}}
}
// NewDomainHashFromByteArray constructs a new DomainHash out of a byte array
func NewDomainHashFromByteArray(hashBytes *[DomainHashSize]byte) *DomainHash {
return &DomainHash{

View File

@@ -15,6 +15,7 @@ type DomainTransaction struct {
LockTime uint64
SubnetworkID DomainSubnetworkID
Gas uint64
PayloadHash DomainHash
Payload []byte
Fee uint64
@@ -52,6 +53,7 @@ func (tx *DomainTransaction) Clone() *DomainTransaction {
LockTime: tx.LockTime,
SubnetworkID: *tx.SubnetworkID.Clone(),
Gas: tx.Gas,
PayloadHash: tx.PayloadHash,
Payload: payloadClone,
Fee: tx.Fee,
Mass: tx.Mass,
@@ -62,7 +64,7 @@ func (tx *DomainTransaction) Clone() *DomainTransaction {
// If this doesn't compile, it means the type definition has been changed, so it's
// an indication to update Equal and Clone accordingly.
var _ = DomainTransaction{0, []*DomainTransactionInput{}, []*DomainTransactionOutput{}, 0,
DomainSubnetworkID{}, 0, []byte{}, 0, 0,
DomainSubnetworkID{}, 0, DomainHash{}, []byte{}, 0, 0,
&DomainTransactionID{}}
// Equal returns whether tx equals to other
@@ -107,6 +109,10 @@ func (tx *DomainTransaction) Equal(other *DomainTransaction) bool {
return false
}
if !tx.PayloadHash.Equal(&other.PayloadHash) {
return false
}
if !bytes.Equal(tx.Payload, other.Payload) {
return false
}

View File

@@ -79,6 +79,10 @@ func initTestBaseTransaction() *externalapi.DomainTransaction {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -93,6 +97,34 @@ func initTestBaseTransaction() *externalapi.DomainTransaction {
func initTestTransactionToCompare() []*transactionToCompare {
testTx := []*transactionToCompare{{
tx: &externalapi.DomainTransaction{
1,
[]*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{
*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF},
[]byte{1, 2, 3},
uint64(0xFFFFFFFF),
utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}},
[]*externalapi.DomainTransactionOutput{{uint64(0xFFFF),
&externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}},
{uint64(0xFFFF),
&externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}},
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), //Changed
[]byte{0x01},
0,
1,
externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}),
},
expectedResult: false,
}, {
tx: &externalapi.DomainTransaction{
1,
[]*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{
@@ -107,6 +139,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -131,6 +167,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01, 0x02}, //Changed
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -155,6 +195,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01, 0x02}, //Changed
0,
1,
@@ -178,6 +222,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -204,6 +252,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -229,6 +281,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
1000000000, //Changed
1,
@@ -252,6 +308,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -275,6 +335,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
2, //Changed
@@ -298,6 +362,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
2, //Changed
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -326,6 +394,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -350,6 +422,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -373,6 +449,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -393,6 +473,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -418,6 +502,10 @@ func initTestTransactionToCompare() []*transactionToCompare {
1,
externalapi.DomainSubnetworkID{0x01},
2, // Changed
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
@@ -449,9 +537,13 @@ func initTestDomainTransactionForClone() []*externalapi.DomainTransaction {
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 5555555555,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
Payload: []byte{0x01},
Fee: 5555555555,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -463,10 +555,14 @@ func initTestDomainTransactionForClone() []*externalapi.DomainTransaction {
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{}),
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{}),
},
}
return tests
@@ -482,6 +578,27 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct {
{
baseTx: nil,
transactionToCompareTo: []*transactionToCompare{{
tx: &externalapi.DomainTransaction{
1,
[]*externalapi.DomainTransactionInput{},
[]*externalapi.DomainTransactionOutput{},
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
0,
1,
externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}),
},
expectedResult: false,
}, {
tx: nil,
expectedResult: true}},
}, {
@@ -492,6 +609,10 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
1,
1,
@@ -511,6 +632,10 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct {
1,
externalapi.DomainSubnetworkID{0x01},
0,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
1,
1,
@@ -525,6 +650,10 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
1,
1,
@@ -539,6 +668,10 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct {
1,
externalapi.DomainSubnetworkID{0x01},
1,
*externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
[]byte{0x01},
2, // Changed fee
1,

View File

@@ -27,5 +27,5 @@ type MutableUTXODiff interface {
ToRemove() UTXOCollection
WithDiffInPlace(other UTXODiff) error
AddTransaction(transaction *DomainTransaction, blockDAAScore uint64) error
AddTransaction(transaction *DomainTransaction, blockBlueScore uint64) error
}

View File

@@ -7,7 +7,7 @@ package externalapi
type UTXOEntry interface {
Amount() uint64
ScriptPublicKey() *ScriptPublicKey // The public key script for the output.
BlockDAAScore() uint64 // Blue score of the block accepting the tx.
BlockBlueScore() uint64 // Blue score of the block accepting the tx.
IsCoinbase() bool
Equal(other UTXOEntry) bool
}

View File

@@ -1,14 +0,0 @@
package model
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// DAABlocksStore represents a store of ???
type DAABlocksStore interface {
Store
StageDAAScore(blockHash *externalapi.DomainHash, daaScore uint64)
StageBlockDAAAddedBlocks(blockHash *externalapi.DomainHash, addedBlocks []*externalapi.DomainHash)
IsAnythingStaged() bool
DAAAddedBlocks(dbContext DBReader, blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
DAAScore(dbContext DBReader, blockHash *externalapi.DomainHash) (uint64, error)
Delete(blockHash *externalapi.DomainHash)
}

View File

@@ -5,6 +5,5 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// DifficultyManager provides a method to resolve the
// difficulty value of a block
type DifficultyManager interface {
StageDAADataAndReturnRequiredDifficulty(blockHash *externalapi.DomainHash) (uint32, error)
RequiredDifficulty(blockHash *externalapi.DomainHash) (uint32, error)
}

View File

@@ -4,8 +4,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// SyncManager exposes functions to support sync between kaspad nodes
type SyncManager interface {
GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) (
hashes []*externalapi.DomainHash, actualHighHash *externalapi.DomainHash, err error)
GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error)
GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error)
CreateHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error)

View File

@@ -66,7 +66,6 @@ type TestConsensus interface {
ReachabilityDataStore() model.ReachabilityDataStore
UTXODiffStore() model.UTXODiffStore
HeadersSelectedChainStore() model.HeadersSelectedChainStore
DAABlocksStore() model.DAABlocksStore
BlockBuilder() TestBlockBuilder
BlockProcessor() model.BlockProcessor

View File

@@ -71,6 +71,7 @@ func TestBuildBlockErrorCases(t *testing.T) {
LockTime: 0,
SubnetworkID: subnetworks.SubnetworkIDNative,
Gas: 0,
PayloadHash: externalapi.DomainHash{},
Payload: []byte{0},
},
{
@@ -85,6 +86,7 @@ func TestBuildBlockErrorCases(t *testing.T) {
LockTime: 0,
SubnetworkID: subnetworks.SubnetworkIDNative,
Gas: 0,
PayloadHash: externalapi.DomainHash{},
Payload: []byte{1},
},
},

View File

@@ -62,13 +62,18 @@ func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.Do
}
func (bb *testBlockBuilder) buildUTXOInvalidHeader(parentHashes []*externalapi.DomainHash,
bits uint32, transactions []*externalapi.DomainTransaction) (externalapi.BlockHeader, error) {
transactions []*externalapi.DomainTransaction) (externalapi.BlockHeader, error) {
timeInMilliseconds, err := bb.minBlockTime(tempBlockHash)
if err != nil {
return nil, err
}
bits, err := bb.difficultyManager.RequiredDifficulty(tempBlockHash)
if err != nil {
return nil, err
}
hashMerkleRoot := bb.newBlockHashMerkleRoot(transactions)
bb.nonceCounter++
@@ -84,11 +89,11 @@ func (bb *testBlockBuilder) buildUTXOInvalidHeader(parentHashes []*externalapi.D
), nil
}
func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, bits uint32,
func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash,
transactions []*externalapi.DomainTransaction, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) (
externalapi.BlockHeader, error) {
header, err := bb.buildUTXOInvalidHeader(parentHashes, bits, transactions)
header, err := bb.buildUTXOInvalidHeader(parentHashes, transactions)
if err != nil {
return nil, err
}
@@ -131,11 +136,6 @@ func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.Do
return nil, nil, err
}
bits, err := bb.difficultyManager.StageDAADataAndReturnRequiredDifficulty(tempBlockHash)
if err != nil {
return nil, nil, err
}
ghostdagData, err := bb.ghostdagDataStore.Get(bb.databaseContext, tempBlockHash)
if err != nil {
return nil, nil, err
@@ -163,7 +163,7 @@ func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.Do
}
transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...)
header, err := bb.buildHeaderWithParents(parentHashes, bits, transactionsWithCoinbase, acceptanceData, multiset)
header, err := bb.buildHeaderWithParents(parentHashes, transactionsWithCoinbase, acceptanceData, multiset)
if err != nil {
return nil, nil, err
}
@@ -199,13 +199,7 @@ func (bb *testBlockBuilder) BuildUTXOInvalidBlock(parentHashes []*externalapi.Do
// We use genesis transactions so we'll have something to build merkle root and coinbase with
genesisTransactions := bb.testConsensus.DAGParams().GenesisBlock.Transactions
bits, err := bb.difficultyManager.RequiredDifficulty(tempBlockHash)
if err != nil {
return nil, err
}
header, err := bb.buildUTXOInvalidHeader(parentHashes, bits, genesisTransactions)
header, err := bb.buildUTXOInvalidHeader(parentHashes, genesisTransactions)
if err != nil {
return nil, err
}

View File

@@ -42,7 +42,6 @@ type blockProcessor struct {
headersSelectedTipStore model.HeaderSelectedTipStore
finalityStore model.FinalityStore
headersSelectedChainStore model.HeadersSelectedChainStore
daaBlocksStore model.DAABlocksStore
stores []model.Store
}
@@ -79,7 +78,6 @@ func New(
headersSelectedTipStore model.HeaderSelectedTipStore,
finalityStore model.FinalityStore,
headersSelectedChainStore model.HeadersSelectedChainStore,
daaBlocksStore model.DAABlocksStore,
) model.BlockProcessor {
return &blockProcessor{
@@ -113,7 +111,6 @@ func New(
headersSelectedTipStore: headersSelectedTipStore,
finalityStore: finalityStore,
headersSelectedChainStore: headersSelectedChainStore,
daaBlocksStore: daaBlocksStore,
stores: []model.Store{
consensusStateStore,
@@ -131,7 +128,6 @@ func New(
headersSelectedTipStore,
finalityStore,
headersSelectedChainStore,
daaBlocksStore,
},
}
}

View File

@@ -199,9 +199,13 @@ func initData(params *dagconfig.Params) (*externalapi.DomainHash, externalapi.Do
LockTime: 1,
SubnetworkID: externalapi.DomainSubnetworkID{0x01},
Gas: 1,
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
Fee: 0,
Mass: 1,
ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View File

@@ -440,11 +440,11 @@ func TestGetPruningPointUTXOs(t *testing.T) {
Version: 0,
},
}
blockAboveGenesis, err := testConsensus.BuildBlock(emptyCoinbase, nil)
blockAboveGeneis, err := testConsensus.BuildBlock(emptyCoinbase, nil)
if err != nil {
t.Fatalf("Error building block above genesis: %+v", err)
}
_, err = testConsensus.ValidateAndInsertBlock(blockAboveGenesis)
_, err = testConsensus.ValidateAndInsertBlock(blockAboveGeneis)
if err != nil {
t.Fatalf("Error validating and inserting block above genesis: %+v", err)
}
@@ -476,7 +476,7 @@ func TestGetPruningPointUTXOs(t *testing.T) {
Sequence: constants.MaxTxInSequenceNum,
}
outputs := make([]*externalapi.DomainTransactionOutput, 900)
outputs := make([]*externalapi.DomainTransactionOutput, 1125)
for i := 0; i < len(outputs); i++ {
outputs[i] = &externalapi.DomainTransactionOutput{
ScriptPublicKey: scriptPublicKey,
@@ -524,15 +524,6 @@ func TestGetPruningPointUTXOs(t *testing.T) {
t.Fatalf("Error getting the pruning point: %+v", err)
}
pruningRelations, err := testConsensus.BlockRelationStore().BlockRelation(testConsensus.DatabaseContext(), pruningPoint)
if err != nil {
t.Fatalf("BlockRelation(): %+v", err)
}
if len(pruningRelations.Parents) != 1 && pruningRelations.Parents[0] != consensushashing.BlockHash(includingBlock) {
t.Fatalf("includingBlock should be pruning point's only parent")
}
// Get pruning point UTXOs in a loop
var allOutpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair
step := 100
@@ -550,9 +541,8 @@ func TestGetPruningPointUTXOs(t *testing.T) {
}
}
// Make sure the length of the UTXOs is exactly spendingTransaction.Outputs + 1 coinbase
// output (includingBlock's coinbase)
if len(allOutpointAndUTXOEntryPairs) != len(outputs)+1 {
// Make sure the length of the UTXOs is exactly spendingTransaction.Outputs + 2 coinbase outputs
if len(allOutpointAndUTXOEntryPairs) != len(outputs)+2 {
t.Fatalf("Returned an unexpected amount of UTXOs. "+
"Want: %d, got: %d", len(outputs)+2, len(allOutpointAndUTXOEntryPairs))
}
@@ -619,7 +609,7 @@ func BenchmarkGetPruningPointUTXOs(b *testing.B) {
SignatureScript: signatureScript,
Sequence: constants.MaxTxInSequenceNum,
}
outputs := make([]*externalapi.DomainTransactionOutput, 900)
outputs := make([]*externalapi.DomainTransactionOutput, 1125)
for i := 0; i < len(outputs); i++ {
outputs[i] = &externalapi.DomainTransactionOutput{
ScriptPublicKey: scriptPublicKey,

View File

@@ -120,14 +120,19 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi.
return err
}
blockTime := block.Header.TimeInMilliseconds()
ghostdagData, err := v.ghostdagDataStore.Get(v.databaseContext, blockHash)
if err != nil {
return err
}
blockTime, err := v.pastMedianTimeManager.PastMedianTime(blockHash)
if err != nil {
return err
// If it's not genesis
if len(block.Header.ParentHashes()) != 0 {
blockTime, err = v.pastMedianTimeManager.PastMedianTime(blockHash)
if err != nil {
return err
}
}
// Ensure all transactions in the block are finalized.

View File

@@ -2,6 +2,7 @@ package blockvalidator_test
import (
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
@@ -153,47 +154,18 @@ func TestIsFinalizedTransaction(t *testing.T) {
}
defer teardown(false)
// Build a small DAG
outerParents := []*externalapi.DomainHash{params.GenesisHash}
for i := 0; i < 5; i++ {
var innerParents []*externalapi.DomainHash
for i := 0; i < 4; i++ {
blockHash, _, err := tc.AddBlock(outerParents, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
innerParents = append(innerParents, blockHash)
}
outerParents = []*externalapi.DomainHash{}
for i := 0; i < 3; i++ {
blockHash, _, err := tc.AddBlock(innerParents, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
outerParents = append(outerParents, blockHash)
}
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
block, err := tc.BuildBlock(&externalapi.DomainCoinbaseData{&externalapi.ScriptPublicKey{}, nil}, nil)
if err != nil {
t.Fatalf("Error getting block: %+v", err)
}
_, err = tc.ValidateAndInsertBlock(block)
if err != nil {
t.Fatalf("Error Inserting block: %+v", err)
}
blockGhostDAG, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), consensushashing.BlockHash(block))
if err != nil {
t.Fatalf("Error getting GhostDAG Data: %+v", err)
}
blockParents := block.Header.ParentHashes()
parentToSpend, err := tc.GetBlock(blockParents[0])
block1, err := tc.GetBlock(block1Hash)
if err != nil {
t.Fatalf("Error getting block1: %+v", err)
}
checkForLockTimeAndSequence := func(lockTime, sequence uint64, shouldPass bool) {
tx, err := testutils.CreateTransaction(parentToSpend.Transactions[0])
tx, err := testutils.CreateTransaction(block1.Transactions[0])
if err != nil {
t.Fatalf("Error creating tx: %+v", err)
}
@@ -201,22 +173,23 @@ func TestIsFinalizedTransaction(t *testing.T) {
tx.LockTime = lockTime
tx.Inputs[0].Sequence = sequence
_, _, err = tc.AddBlock(blockParents, nil, []*externalapi.DomainTransaction{tx})
_, _, err = tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil, []*externalapi.DomainTransaction{tx})
if (shouldPass && err != nil) || (!shouldPass && !errors.Is(err, ruleerrors.ErrUnfinalizedTx)) {
t.Fatalf("shouldPass: %t Unexpected error: %+v", shouldPass, err)
t.Fatalf("Unexpected error: %+v", err)
}
}
// Check that the same blueScore or higher fails, but lower passes.
checkForLockTimeAndSequence(blockGhostDAG.BlueScore()+1, 0, false)
checkForLockTimeAndSequence(blockGhostDAG.BlueScore(), 0, false)
checkForLockTimeAndSequence(blockGhostDAG.BlueScore()-1, 0, true)
// The next block blue score is 2, so we check if we see the expected
// behaviour when the lock time blue score is higher, lower or equal
// to it.
checkForLockTimeAndSequence(3, 0, false)
checkForLockTimeAndSequence(2, 0, false)
checkForLockTimeAndSequence(1, 0, true)
pastMedianTime, err := tc.PastMedianTimeManager().PastMedianTime(consensushashing.BlockHash(block))
pastMedianTime, err := tc.PastMedianTimeManager().PastMedianTime(model.VirtualBlockHash)
if err != nil {
t.Fatalf("PastMedianTime: %+v", err)
}
// Check that the same pastMedianTime or higher fails, but lower passes.
checkForLockTimeAndSequence(uint64(pastMedianTime)+1, 0, false)
checkForLockTimeAndSequence(uint64(pastMedianTime), 0, false)
checkForLockTimeAndSequence(uint64(pastMedianTime)-1, 0, true)

View File

@@ -33,12 +33,7 @@ func TestChainedTransactions(t *testing.T) {
}
defer teardown(false)
fundingBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil, nil)
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -148,10 +143,10 @@ var unOrderedParentsBlock = externalapi.DomainBlock{
}),
},
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x09, 0xaf, 0x3b, 0x09, 0xa8, 0x8f, 0xfc, 0x7e,
0x7d, 0xc6, 0x06, 0x78, 0x04, 0x2b, 0x1c, 0x8a,
0xbe, 0x37, 0x0d, 0x55, 0x41, 0xb0, 0xb8, 0x15,
0xb1, 0x08, 0xd4, 0x01, 0x2a, 0xf0, 0xfd, 0x29,
0x33, 0x77, 0x88, 0xd7, 0x8a, 0xd7, 0x49, 0xbf,
0xce, 0x97, 0x58, 0x4f, 0x05, 0x4c, 0xbb, 0x18,
0xb4, 0xe4, 0x73, 0x6e, 0x1f, 0xcd, 0x57, 0x5d,
0x6b, 0xe4, 0xb1, 0x01, 0xea, 0x7f, 0x01, 0xd7,
}),
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95,
@@ -197,6 +192,12 @@ var unOrderedParentsBlock = externalapi.DomainBlock{
LockTime: 0,
SubnetworkID: subnetworks.SubnetworkIDCoinbase,
Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x2e, 0xb5, 0xe8, 0x1c, 0xe2, 0xa7, 0x67, 0x84,
0xd1, 0x1a, 0x42, 0x66, 0xcf, 0x12, 0x7f, 0x10,
0x9b, 0x6f, 0x84, 0x63, 0xf5, 0x65, 0x5a, 0x65,
0xec, 0xed, 0x60, 0xc6, 0x32, 0x7a, 0x9d, 0x08,
}),
},
{
Version: 0,
@@ -416,10 +417,10 @@ var exampleValidBlock = externalapi.DomainBlock{
}),
},
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x6e, 0xa3, 0x1a, 0xd6, 0xb8, 0xd9, 0xc1, 0xb2,
0xab, 0x18, 0xcc, 0x59, 0x6d, 0x03, 0x6b, 0x8d,
0x86, 0x59, 0x8f, 0x0e, 0x42, 0x07, 0x81, 0xa9,
0x59, 0x16, 0x95, 0x97, 0x8c, 0x9b, 0x0a, 0x19,
0x8f, 0x2e, 0x67, 0x13, 0x86, 0xf9, 0x4c, 0x2a,
0x1d, 0x1a, 0xc1, 0xf0, 0x30, 0x88, 0xfd, 0x48,
0x20, 0xf3, 0x50, 0xd1, 0xfb, 0x6d, 0x06, 0x39,
0x72, 0xaa, 0x6f, 0x78, 0x22, 0x64, 0x83, 0x19,
}),
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3,
@@ -463,6 +464,12 @@ var exampleValidBlock = externalapi.DomainBlock{
LockTime: 0,
SubnetworkID: subnetworks.SubnetworkIDCoinbase,
Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x2e, 0xb5, 0xe8, 0x1c, 0xe2, 0xa7, 0x67, 0x84,
0xd1, 0x1a, 0x42, 0x66, 0xcf, 0x12, 0x7f, 0x10,
0x9b, 0x6f, 0x84, 0x63, 0xf5, 0x65, 0x5a, 0x65,
0xec, 0xed, 0x60, 0xc6, 0x32, 0x7a, 0x9d, 0x08,
}),
},
{
Version: 0,
@@ -712,10 +719,10 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{
}),
},
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0xfc, 0x03, 0xa8, 0x09, 0x03, 0xf6, 0x64, 0xd9,
0xba, 0xab, 0x6d, 0x50, 0x1c, 0x67, 0xcb, 0xff,
0x2e, 0x53, 0x76, 0x6b, 0x02, 0xa9, 0xd4, 0x78,
0x2b, 0x49, 0xe8, 0x90, 0x33, 0x90, 0xdd, 0xdf,
0xaf, 0xba, 0x3c, 0x18, 0x9e, 0x44, 0xac, 0x7c,
0xb7, 0xcc, 0x90, 0x0b, 0x75, 0x88, 0x6b, 0x9c,
0x3e, 0xc9, 0xea, 0xf1, 0x5c, 0xaf, 0x28, 0x30,
0x34, 0x23, 0xf5, 0xeb, 0x18, 0xdf, 0xd1, 0x75,
}),
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3,
@@ -764,6 +771,12 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{
LockTime: 0,
SubnetworkID: subnetworks.SubnetworkIDCoinbase,
Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x2e, 0xb5, 0xe8, 0x1c, 0xe2, 0xa7, 0x67, 0x84,
0xd1, 0x1a, 0x42, 0x66, 0xcf, 0x12, 0x7f, 0x10,
0x9b, 0x6f, 0x84, 0x63, 0xf5, 0x65, 0x5a, 0x65,
0xec, 0xed, 0x60, 0xc6, 0x32, 0x7a, 0x9d, 0x08,
}),
},
{
@@ -866,6 +879,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{
LockTime: 0,
SubnetworkID: externalapi.DomainSubnetworkID{11},
Payload: []byte{},
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0xFF, 0xFF}),
},
{
Version: 0,
@@ -1077,6 +1091,10 @@ func initBlockWithInvalidBlockSize(params *dagconfig.Params, tc testapi.TestCons
Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF),
&externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF),
&externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}},
PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
Payload: []byte{0x01},
}

View File

@@ -27,6 +27,11 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa
}
if !hasValidatedHeader {
err = v.ghostdagManager.GHOSTDAG(blockHash)
if err != nil {
return err
}
var logErr error
log.Debug(logger.NewLogClosure(func() string {
var ghostdagData *model.BlockGHOSTDAGData

View File

@@ -54,16 +54,10 @@ func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficult
}
func (v *blockValidator) validateDifficulty(blockHash *externalapi.DomainHash) error {
// We need to calculate GHOSTDAG for the block in order to check its difficulty
err := v.ghostdagManager.GHOSTDAG(blockHash)
if err != nil {
return err
}
// Ensure the difficulty specified in the block header matches
// the calculated difficulty based on the previous block and
// difficulty retarget rules.
expectedBits, err := v.difficultyManager.StageDAADataAndReturnRequiredDifficulty(blockHash)
expectedBits, err := v.difficultyManager.RequiredDifficulty(blockHash)
if err != nil {
return err
}

View File

@@ -246,19 +246,16 @@ func TestCheckPruningPointViolation(t *testing.T) {
// TestValidateDifficulty verifies that in case of a block with an unexpected difficulty,
// an appropriate error message (ErrUnexpectedDifficulty) will be returned on the
// function ValidatePruningPointViolationAndProofOfWorkAndDifficulty. The required difficulty is
// "calculated" by the mocDifficultyManager, where mocDifficultyManager is special implementation
// of the type DifficultyManager for this test (defined below).
// "calculated" by the function (dm *mocDifficultyManager) RequiredDifficulty ,
// where mocDifficultyManager is special implementation of the type DifficultyManager for this test (defined below).
func TestValidateDifficulty(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
factory := consensus.NewFactory()
mocDifficulty := &mocDifficultyManager{}
factory.SetTestDifficultyManager(func(_ model.DBReader, _ model.GHOSTDAGManager, _ model.GHOSTDAGDataStore,
_ model.BlockHeaderStore, daaBlocksStore model.DAABlocksStore, _ model.DAGTopologyManager,
_ model.DAGTraversalManager, _ *big.Int, _ int, _ bool, _ time.Duration,
_ *externalapi.DomainHash) model.DifficultyManager {
mocDifficulty.daaBlocksStore = daaBlocksStore
factory.SetTestDifficultyManager(func(model.DBReader, model.GHOSTDAGManager, model.GHOSTDAGDataStore,
model.BlockHeaderStore, model.DAGTopologyManager, model.DAGTraversalManager, *big.Int, int, bool, time.Duration,
*externalapi.DomainHash) model.DifficultyManager {
return mocDifficulty
})
genesisDifficulty := params.GenesisBlock.Header.Bits()
@@ -296,19 +293,9 @@ func TestValidateDifficulty(t *testing.T) {
type mocDifficultyManager struct {
testDifficulty uint32
testGenesisBits uint32
daaBlocksStore model.DAABlocksStore
}
// RequiredDifficulty returns the difficulty required for the test
func (dm *mocDifficultyManager) RequiredDifficulty(*externalapi.DomainHash) (uint32, error) {
return dm.testDifficulty, nil
}
// StageDAADataAndReturnRequiredDifficulty returns the difficulty required for the test
func (dm *mocDifficultyManager) StageDAADataAndReturnRequiredDifficulty(blockHash *externalapi.DomainHash) (uint32, error) {
// Populate daaBlocksStore with fake values
dm.daaBlocksStore.StageDAAScore(blockHash, 0)
dm.daaBlocksStore.StageBlockDAAAddedBlocks(blockHash, nil)
return dm.testDifficulty, nil
}

View File

@@ -4,9 +4,8 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"github.com/pkg/errors"
)
type coinbaseManager struct {
@@ -17,7 +16,6 @@ type coinbaseManager struct {
databaseContext model.DBReader
ghostdagDataStore model.GHOSTDAGDataStore
acceptanceDataStore model.AcceptanceDataStore
daaBlocksStore model.DAABlocksStore
}
func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.DomainHash,
@@ -33,14 +31,9 @@ func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Dom
return nil, err
}
daaAddedBlocksSet, err := c.daaAddedBlocksSet(blockHash)
if err != nil {
return nil, err
}
txOuts := make([]*externalapi.DomainTransactionOutput, 0, len(ghostdagData.MergeSetBlues()))
for i, blue := range ghostdagData.MergeSetBlues() {
txOut, hasReward, err := c.coinbaseOutputForBlueBlock(blue, acceptanceData[i], daaAddedBlocksSet)
txOut, hasReward, err := c.coinbaseOutputForBlueBlock(blue, acceptanceData[i])
if err != nil {
return nil, err
}
@@ -50,20 +43,13 @@ func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Dom
}
}
txOut, hasReward, err := c.coinbaseOutputForRewardFromRedBlocks(ghostdagData, acceptanceData, daaAddedBlocksSet, coinbaseData)
if err != nil {
return nil, err
}
if hasReward {
txOuts = append(txOuts, txOut)
}
payload, err := c.serializeCoinbasePayload(ghostdagData.BlueScore(), coinbaseData)
if err != nil {
return nil, err
}
payloadHash := hashes.PayloadHash(payload)
return &externalapi.DomainTransaction{
Version: constants.MaxTransactionVersion,
Inputs: []*externalapi.DomainTransactionInput{},
@@ -71,30 +57,30 @@ func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Dom
LockTime: 0,
SubnetworkID: subnetworks.SubnetworkIDCoinbase,
Gas: 0,
PayloadHash: *payloadHash,
Payload: payload,
}, nil
}
func (c *coinbaseManager) daaAddedBlocksSet(blockHash *externalapi.DomainHash) (hashset.HashSet, error) {
daaAddedBlocks, err := c.daaBlocksStore.DAAAddedBlocks(c.databaseContext, blockHash)
if err != nil {
return nil, err
}
return hashset.NewFromSlice(daaAddedBlocks...), nil
}
// coinbaseOutputForBlueBlock calculates the output that should go into the coinbase transaction of blueBlock
// If blueBlock gets no fee - returns nil for txOut
func (c *coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.DomainHash,
blockAcceptanceData *externalapi.BlockAcceptanceData,
mergingBlockDAAAddedBlocksSet hashset.HashSet) (*externalapi.DomainTransactionOutput, bool, error) {
blockAcceptanceData *externalapi.BlockAcceptanceData) (*externalapi.DomainTransactionOutput, bool, error) {
totalReward, err := c.calcMergedBlockReward(blueBlock, blockAcceptanceData, mergingBlockDAAAddedBlocksSet)
totalFees := uint64(0)
for _, txAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
if txAcceptanceData.IsAccepted {
totalFees += txAcceptanceData.Fee
}
}
subsidy, err := c.calcBlockSubsidy(blueBlock)
if err != nil {
return nil, false, err
}
totalReward := subsidy + totalFees
if totalReward == 0 {
return nil, false, nil
}
@@ -113,31 +99,6 @@ func (c *coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.Doma
return txOut, true, nil
}
func (c *coinbaseManager) coinbaseOutputForRewardFromRedBlocks(ghostdagData *model.BlockGHOSTDAGData,
acceptanceData externalapi.AcceptanceData, daaAddedBlocksSet hashset.HashSet,
coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransactionOutput, bool, error) {
totalReward := uint64(0)
mergeSetBluesCount := len(ghostdagData.MergeSetBlues())
for i, red := range ghostdagData.MergeSetReds() {
reward, err := c.calcMergedBlockReward(red, acceptanceData[mergeSetBluesCount+i], daaAddedBlocksSet)
if err != nil {
return nil, false, err
}
totalReward += reward
}
if totalReward == 0 {
return nil, false, nil
}
return &externalapi.DomainTransactionOutput{
Value: totalReward,
ScriptPublicKey: coinbaseData.ScriptPublicKey,
}, true, nil
}
// calcBlockSubsidy returns the subsidy amount a block at the provided blue score
// should have. This is mainly used for determining how much the coinbase for
// newly generated blocks awards as well as validating the coinbase for blocks
@@ -153,40 +114,13 @@ func (c *coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (u
return c.baseSubsidy, nil
}
daaScore, err := c.daaBlocksStore.DAAScore(c.databaseContext, blockHash)
ghostdagData, err := c.ghostdagDataStore.Get(c.databaseContext, blockHash)
if err != nil {
return 0, err
}
// Equivalent to: baseSubsidy / 2^(daaScore/subsidyHalvingInterval)
return c.baseSubsidy >> uint(daaScore/c.subsidyReductionInterval), nil
}
func (c *coinbaseManager) calcMergedBlockReward(blockHash *externalapi.DomainHash,
blockAcceptanceData *externalapi.BlockAcceptanceData, mergingBlockDAAAddedBlocksSet hashset.HashSet) (uint64, error) {
if !blockHash.Equal(blockAcceptanceData.BlockHash) {
return 0, errors.Errorf("blockAcceptanceData.BlockHash is expected to be %s but got %s",
blockHash, blockAcceptanceData.BlockHash)
}
if !mergingBlockDAAAddedBlocksSet.Contains(blockHash) {
return 0, nil
}
totalFees := uint64(0)
for _, txAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
if txAcceptanceData.IsAccepted {
totalFees += txAcceptanceData.Fee
}
}
subsidy, err := c.calcBlockSubsidy(blockHash)
if err != nil {
return 0, err
}
return subsidy + totalFees, nil
// Equivalent to: baseSubsidy / 2^(blueScore/subsidyHalvingInterval)
return c.baseSubsidy >> uint(ghostdagData.BlueScore()/c.subsidyReductionInterval), nil
}
// New instantiates a new CoinbaseManager
@@ -198,8 +132,7 @@ func New(
coinbasePayloadScriptPublicKeyMaxLength uint8,
ghostdagDataStore model.GHOSTDAGDataStore,
acceptanceDataStore model.AcceptanceDataStore,
daaBlocksStore model.DAABlocksStore) model.CoinbaseManager {
acceptanceDataStore model.AcceptanceDataStore) model.CoinbaseManager {
return &coinbaseManager{
databaseContext: databaseContext,
@@ -210,6 +143,5 @@ func New(
ghostdagDataStore: ghostdagDataStore,
acceptanceDataStore: acceptanceDataStore,
daaBlocksStore: daaBlocksStore,
}
}

View File

@@ -21,32 +21,17 @@ func TestVirtualDiff(t *testing.T) {
defer teardown(false)
// Add block A over the genesis
blockAHash, blockInsertionResult, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
blockHash, blockInsertionResult, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("Error adding block A: %+v", err)
}
virtualUTXODiff := blockInsertionResult.VirtualUTXODiff
if virtualUTXODiff.ToRemove().Len() != 0 {
t.Fatalf("Unexpected length %d for virtualUTXODiff.ToRemove()", virtualUTXODiff.ToRemove().Len())
}
// Because the genesis is not in block A's DAA window, block A's coinbase doesn't pay to it, so it has no outputs.
if virtualUTXODiff.ToAdd().Len() != 0 {
t.Fatalf("Unexpected length %d for virtualUTXODiff.ToAdd()", virtualUTXODiff.ToAdd().Len())
}
blockBHash, blockInsertionResult, err := tc.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, nil)
if err != nil {
t.Fatalf("Error adding block A: %+v", err)
}
blockB, err := tc.BlockStore().Block(tc.DatabaseContext(), blockBHash)
block, err := tc.BlockStore().Block(tc.DatabaseContext(), blockHash)
if err != nil {
t.Fatalf("Block: %+v", err)
}
virtualUTXODiff = blockInsertionResult.VirtualUTXODiff
virtualUTXODiff := blockInsertionResult.VirtualUTXODiff
if virtualUTXODiff.ToRemove().Len() != 0 {
t.Fatalf("Unexpected length %d for virtualUTXODiff.ToRemove()", virtualUTXODiff.ToRemove().Len())
}
@@ -64,17 +49,17 @@ func TestVirtualDiff(t *testing.T) {
}
if !outpoint.Equal(&externalapi.DomainOutpoint{
TransactionID: *consensushashing.TransactionID(blockB.Transactions[0]),
TransactionID: *consensushashing.TransactionID(block.Transactions[0]),
Index: 0,
}) {
t.Fatalf("Unexpected outpoint %s", outpoint)
}
if !entry.Equal(utxo.NewUTXOEntry(
blockB.Transactions[0].Outputs[0].Value,
blockB.Transactions[0].Outputs[0].ScriptPublicKey,
block.Transactions[0].Outputs[0].Value,
block.Transactions[0].Outputs[0].ScriptPublicKey,
true,
2, //Expected virtual DAA score
2, //Expected virtual blue score
)) {
t.Fatalf("Unexpected entry %s", entry)
}

View File

@@ -38,24 +38,18 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *
if err != nil {
return nil, nil, nil, err
}
daaScore, err := csm.daaBlocksStore.DAAScore(csm.databaseContext, blockHash)
if err != nil {
return nil, nil, nil, err
}
log.Debugf("Restored the past UTXO of block %s with selectedParent %s. "+
"Diff toAdd length: %d, toRemove length: %d", blockHash, blockGHOSTDAGData.SelectedParent(),
selectedParentPastUTXO.ToAdd().Len(), selectedParentPastUTXO.ToRemove().Len())
log.Debugf("Applying blue blocks to the selected parent past UTXO of block %s", blockHash)
acceptanceData, utxoDiff, err := csm.applyMergeSetBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData, daaScore)
acceptanceData, utxoDiff, err := csm.applyMergeSetBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData)
if err != nil {
return nil, nil, nil, err
}
log.Debugf("Calculating the multiset of %s", blockHash)
multiset, err := csm.calculateMultiset(acceptanceData, blockGHOSTDAGData, daaScore)
multiset, err := csm.calculateMultiset(acceptanceData, blockGHOSTDAGData)
if err != nil {
return nil, nil, nil, err
}
@@ -121,7 +115,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH
}
func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.DomainHash,
selectedParentPastUTXODiff externalapi.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData, daaScore uint64) (
selectedParentPastUTXODiff externalapi.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData) (
externalapi.AcceptanceData, externalapi.MutableUTXODiff, error) {
log.Debugf("applyMergeSetBlocks start for block %s", blockHash)
@@ -162,7 +156,7 @@ func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.Dom
transactionID, mergeSetBlockHash)
isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent,
accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, daaScore)
accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore())
if err != nil {
return nil, nil, err
}
@@ -192,7 +186,7 @@ func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.Dom
func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalapi.DomainTransaction,
blockHash *externalapi.DomainHash, isSelectedParent bool, accumulatedUTXODiff externalapi.MutableUTXODiff,
accumulatedMassBefore uint64, selectedParentPastMedianTime int64, blockDAAScore uint64) (
accumulatedMassBefore uint64, selectedParentPastMedianTime int64, blockBlueScore uint64) (
isAccepted bool, accumulatedMassAfter uint64, err error) {
transactionID := consensushashing.TransactionID(transaction)
@@ -243,7 +237,7 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap
}
log.Tracef("Adding transaction %s in block %s to the accumulated diff", transactionID, blockHash)
err = accumulatedUTXODiff.AddTransaction(transaction, blockDAAScore)
err = accumulatedUTXODiff.AddTransaction(transaction, blockBlueScore)
if err != nil {
return false, 0, err
}

View File

@@ -24,7 +24,6 @@ type consensusStateManager struct {
coinbaseManager model.CoinbaseManager
mergeDepthManager model.MergeDepthManager
finalityManager model.FinalityManager
difficultyManager model.DifficultyManager
headersSelectedTipStore model.HeaderSelectedTipStore
blockStatusStore model.BlockStatusStore
@@ -37,7 +36,6 @@ type consensusStateManager struct {
acceptanceDataStore model.AcceptanceDataStore
blockHeaderStore model.BlockHeaderStore
pruningStore model.PruningStore
daaBlocksStore model.DAABlocksStore
stores []model.Store
}
@@ -61,7 +59,6 @@ func New(
coinbaseManager model.CoinbaseManager,
mergeDepthManager model.MergeDepthManager,
finalityManager model.FinalityManager,
difficultyManager model.DifficultyManager,
blockStatusStore model.BlockStatusStore,
ghostdagDataStore model.GHOSTDAGDataStore,
@@ -73,8 +70,7 @@ func New(
acceptanceDataStore model.AcceptanceDataStore,
blockHeaderStore model.BlockHeaderStore,
headersSelectedTipStore model.HeaderSelectedTipStore,
pruningStore model.PruningStore,
daaBlocksStore model.DAABlocksStore) (model.ConsensusStateManager, error) {
pruningStore model.PruningStore) (model.ConsensusStateManager, error) {
csm := &consensusStateManager{
pruningDepth: pruningDepth,
@@ -94,7 +90,6 @@ func New(
coinbaseManager: coinbaseManager,
mergeDepthManager: mergeDepthManager,
finalityManager: finalityManager,
difficultyManager: difficultyManager,
multisetStore: multisetStore,
blockStore: blockStore,
@@ -107,7 +102,6 @@ func New(
blockHeaderStore: blockHeaderStore,
headersSelectedTipStore: headersSelectedTipStore,
pruningStore: pruningStore,
daaBlocksStore: daaBlocksStore,
stores: []model.Store{
consensusStateStore,

View File

@@ -9,7 +9,7 @@ import (
)
func (csm *consensusStateManager) calculateMultiset(
acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData, daaScore uint64) (model.Multiset, error) {
acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) {
log.Debugf("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent())
defer log.Debugf("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent())
@@ -38,7 +38,7 @@ func (csm *consensusStateManager) calculateMultiset(
isCoinbase := i == 0
log.Tracef("Is transaction %s a coinbase transaction: %t", transactionID, isCoinbase)
err := addTransactionToMultiset(ms, transaction, daaScore, isCoinbase)
err := addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore(), isCoinbase)
if err != nil {
return nil, err
}
@@ -50,7 +50,7 @@ func (csm *consensusStateManager) calculateMultiset(
}
func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.DomainTransaction,
blockDAAScore uint64, isCoinbase bool) error {
blockBlueScore uint64, isCoinbase bool) error {
transactionID := consensushashing.TransactionID(transaction)
log.Tracef("addTransactionToMultiset start for transaction %s", transactionID)
@@ -70,7 +70,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.
TransactionID: *transactionID,
Index: uint32(i),
}
utxoEntry := utxo.NewUTXOEntry(output.Value, output.ScriptPublicKey, isCoinbase, blockDAAScore)
utxoEntry := utxo.NewUTXOEntry(output.Value, output.ScriptPublicKey, isCoinbase, blockBlueScore)
log.Tracef("Adding input %s at index %d from the multiset", transactionID, i)
err := addUTXOToMultiset(multiset, utxoEntry, outpoint)

View File

@@ -261,12 +261,7 @@ func TestTransactionAcceptance(t *testing.T) {
t.Fatalf("Error creating tip: %+v", err)
}
finalTipScriptPublicKey := &externalapi.ScriptPublicKey{Script: []byte{4}, Version: 0}
finalTipHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{finalTipSelectedParentHash, redHash, blueHash},
&externalapi.DomainCoinbaseData{
ScriptPublicKey: finalTipScriptPublicKey,
ExtraData: nil,
},
finalTipHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{finalTipSelectedParentHash, redHash, blueHash}, nil,
nil)
if err != nil {
t.Fatalf("Error creating finalTip: %+v", err)
@@ -359,7 +354,7 @@ func TestTransactionAcceptance(t *testing.T) {
}
// We expect the coinbase transaction to pay reward for the selected parent, the
// blue block, and bestow the red block reward to the merging block.
// blue block, and not for the red block.
expectedCoinbase := &externalapi.DomainTransaction{
Version: constants.MaxTransactionVersion,
Inputs: nil,
@@ -372,14 +367,11 @@ func TestTransactionAcceptance(t *testing.T) {
Value: 50*constants.SompiPerKaspa + 1, // testutils.CreateTransaction pays a fee of 1 sompi
ScriptPublicKey: blueScriptPublicKey,
},
{
Value: 50*constants.SompiPerKaspa + 1,
ScriptPublicKey: finalTipScriptPublicKey,
},
},
LockTime: 0,
SubnetworkID: subnetworks.SubnetworkIDCoinbase,
Gas: 0,
PayloadHash: finalTip.Transactions[0].PayloadHash,
Payload: finalTip.Transactions[0].Payload,
}
if !finalTip.Transactions[transactionhelper.CoinbaseTransactionIndex].Equal(expectedCoinbase) {

View File

@@ -42,12 +42,6 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain
return nil, nil, err
}
// This is needed for `csm.CalculatePastUTXOAndAcceptanceData`
_, err = csm.difficultyManager.StageDAADataAndReturnRequiredDifficulty(model.VirtualBlockHash)
if err != nil {
return nil, nil, err
}
log.Debugf("Calculating past UTXO, acceptance data, and multiset for the new virtual block")
virtualUTXODiff, virtualAcceptanceData, virtualMultiset, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash)
if err != nil {

View File

@@ -16,7 +16,6 @@ type dagTraversalManager struct {
ghostdagDataStore model.GHOSTDAGDataStore
reachabilityDataStore model.ReachabilityDataStore
consensusStateStore model.ConsensusStateStore
genesisHash *externalapi.DomainHash
}
// New instantiates a new DAGTraversalManager
@@ -26,8 +25,7 @@ func New(
ghostdagDataStore model.GHOSTDAGDataStore,
reachabilityDataStore model.ReachabilityDataStore,
ghostdagManager model.GHOSTDAGManager,
conssensusStateStore model.ConsensusStateStore,
genesisHash *externalapi.DomainHash) model.DAGTraversalManager {
conssensusStateStore model.ConsensusStateStore) model.DAGTraversalManager {
return &dagTraversalManager{
databaseContext: databaseContext,
dagTopologyManager: dagTopologyManager,
@@ -35,7 +33,6 @@ func New(
reachabilityDataStore: reachabilityDataStore,
ghostdagManager: ghostdagManager,
consensusStateStore: conssensusStateStore,
genesisHash: genesisHash,
}
}

View File

@@ -9,14 +9,15 @@ import (
// If the number of blocks in the past of startingNode is less then windowSize,
// the window will be padded by genesis blocks to achieve a size of windowSize.
func (dtm *dagTraversalManager) BlockWindow(startingBlock *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) {
currentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, startingBlock)
currentHash := startingBlock
currentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash)
if err != nil {
return nil, err
}
windowHeap := dtm.newSizedUpHeap(windowSize)
for windowHeap.len() <= windowSize && currentGHOSTDAGData.SelectedParent() != nil && !currentGHOSTDAGData.SelectedParent().Equal(dtm.genesisHash) {
for windowHeap.len() <= windowSize && currentGHOSTDAGData.SelectedParent() != nil {
selectedParentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentGHOSTDAGData.SelectedParent())
if err != nil {
return nil, err
@@ -57,12 +58,21 @@ func (dtm *dagTraversalManager) BlockWindow(startingBlock *externalapi.DomainHas
break
}
}
currentHash = currentGHOSTDAGData.SelectedParent()
currentGHOSTDAGData = selectedParentGHOSTDAGData
}
window := make([]*externalapi.DomainHash, 0, len(windowHeap.impl.slice))
window := make([]*externalapi.DomainHash, 0, windowSize)
for _, b := range windowHeap.impl.slice {
window = append(window, b.hash)
}
if len(window) < windowSize {
genesis := currentHash
for len(window) < windowSize {
window = append(window, genesis)
}
}
return window, nil
}

View File

@@ -15,296 +15,296 @@ import (
func TestBlockWindow(t *testing.T) {
tests := map[string][]*struct {
parents []string
id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash
expectedWindow []string
parents []string
id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash
expectedWindowWithGenesisPadding []string
}{
dagconfig.MainnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
parents: []string{"A"},
id: "B",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "C",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "D",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"C", "D"},
id: "E",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"C", "D"},
id: "E",
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"C", "D"},
id: "F",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"C", "D"},
id: "F",
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
parents: []string{"A"},
id: "G",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
parents: []string{"G"},
id: "H",
expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "D", "H", "C", "B", "G"},
parents: []string{"H", "F"},
id: "I",
expectedWindowWithGenesisPadding: []string{"F", "C", "D", "H", "G", "B", "A", "A", "A", "A"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "D", "H", "C", "B", "G"},
parents: []string{"I"},
id: "J",
expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "H", "G", "B", "A", "A", "A"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "D", "H", "C", "B", "G"},
parents: []string{"J"},
id: "K",
expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "H", "G", "B", "A", "A"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G"},
parents: []string{"K"},
id: "L",
expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "H", "G", "B", "A"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"},
parents: []string{"L"},
id: "M",
expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "H", "G", "B"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"},
parents: []string{"M"},
id: "N",
expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "G"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"},
parents: []string{"N"},
id: "O",
expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"},
},
},
dagconfig.TestnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
parents: []string{"A"},
id: "B",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "C",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "D",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"C", "D"},
id: "E",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"C", "D"},
id: "E",
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"C", "D"},
id: "F",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"C", "D"},
id: "F",
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
parents: []string{"A"},
id: "G",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
parents: []string{"G"},
id: "H",
expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "D", "H", "C", "G", "B"},
parents: []string{"H", "F"},
id: "I",
expectedWindowWithGenesisPadding: []string{"F", "H", "C", "D", "B", "G", "A", "A", "A", "A"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "D", "H", "C", "G", "B"},
parents: []string{"I"},
id: "J",
expectedWindowWithGenesisPadding: []string{"I", "F", "H", "C", "D", "B", "G", "A", "A", "A"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "D", "H", "C", "G", "B"},
parents: []string{"J"},
id: "K",
expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "C", "D", "B", "G", "A", "A"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B"},
parents: []string{"K"},
id: "L",
expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "C", "D", "B", "G", "A"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"},
parents: []string{"L"},
id: "M",
expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "C", "D", "B", "G"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"},
parents: []string{"M"},
id: "N",
expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "B"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"},
parents: []string{"N"},
id: "O",
expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"},
},
},
dagconfig.DevnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
parents: []string{"A"},
id: "B",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "C",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "D",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"C", "D"},
id: "E",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"C", "D"},
id: "E",
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"C", "D"},
id: "F",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"C", "D"},
id: "F",
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
parents: []string{"A"},
id: "G",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
parents: []string{"G"},
id: "H",
expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "H", "D", "C", "G", "B"},
parents: []string{"H", "F"},
id: "I",
expectedWindowWithGenesisPadding: []string{"F", "H", "C", "D", "B", "G", "A", "A", "A", "A"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "H", "D", "C", "G", "B"},
parents: []string{"I"},
id: "J",
expectedWindowWithGenesisPadding: []string{"I", "F", "H", "C", "D", "B", "G", "A", "A", "A"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "H", "D", "C", "G", "B"},
parents: []string{"J"},
id: "K",
expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "C", "D", "B", "G", "A", "A"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "H", "D", "C", "G", "B"},
parents: []string{"K"},
id: "L",
expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "C", "D", "B", "G", "A"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "H", "D", "C", "G", "B"},
parents: []string{"L"},
id: "M",
expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "C", "D", "B", "G"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "H", "D", "C", "G"},
parents: []string{"M"},
id: "N",
expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "B"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "H", "D", "C"},
parents: []string{"N"},
id: "O",
expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"},
},
},
dagconfig.SimnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
parents: []string{"A"},
id: "B",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "C",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
parents: []string{"B"},
id: "D",
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"D", "C"},
id: "E",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"D", "C"},
id: "E",
expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"D", "C"},
id: "F",
expectedWindow: []string{"D", "C", "B"},
parents: []string{"D", "C"},
id: "F",
expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
parents: []string{"A"},
id: "G",
expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
parents: []string{"G"},
id: "H",
expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "H", "D", "C", "B", "G"},
parents: []string{"H", "F"},
id: "I",
expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "H", "D", "C", "B", "G"},
parents: []string{"I"},
id: "J",
expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "H", "D", "C", "B", "G"},
parents: []string{"J"},
id: "K",
expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "H", "D", "C", "B", "G"},
parents: []string{"K"},
id: "L",
expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "H", "D", "C", "B", "G"},
parents: []string{"L"},
id: "M",
expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "H", "D", "C", "B"},
parents: []string{"M"},
id: "N",
expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "H", "D", "C"},
parents: []string{"N"},
id: "O",
expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"},
},
},
}
@@ -345,7 +345,7 @@ func TestBlockWindow(t *testing.T) {
t.Fatalf("BlockWindow: %s", err)
}
sort.Sort(testutils.NewTestGhostDAGSorter(window, tc, t))
if err := checkWindowIDs(window, blockData.expectedWindow, idByBlockMap); err != nil {
if err := checkWindowIDs(window, blockData.expectedWindowWithGenesisPadding, idByBlockMap); err != nil {
t.Errorf("Unexpected values for window for block %s: %s", blockData.id, err)
}
}

View File

@@ -1,10 +1,13 @@
package difficultymanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/util/difficulty"
"math"
"math/big"
"sort"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/util/difficulty"
"github.com/pkg/errors"
)
type difficultyBlock struct {
@@ -29,23 +32,21 @@ func (dm *difficultyManager) getDifficultyBlock(blockHash *externalapi.DomainHas
// blocks in the past of startindNode, the sorting is unspecified.
// If the number of blocks in the past of startingNode is less then windowSize,
// the window will be padded by genesis blocks to achieve a size of windowSize.
func (dm *difficultyManager) blockWindow(startingNode *externalapi.DomainHash, windowSize int) (blockWindow,
[]*externalapi.DomainHash, error) {
func (dm *difficultyManager) blockWindow(startingNode *externalapi.DomainHash, windowSize int) (blockWindow, error) {
window := make(blockWindow, 0, windowSize)
windowHashes, err := dm.dagTraversalManager.BlockWindow(startingNode, windowSize)
if err != nil {
return nil, nil, err
return nil, err
}
for _, hash := range windowHashes {
block, err := dm.getDifficultyBlock(hash)
if err != nil {
return nil, nil, err
return nil, err
}
window = append(window, block)
}
return window, windowHashes, nil
return window, nil
}
func (window blockWindow) minMaxTimestamps() (min, max int64, minIndex, maxIndex int) {
@@ -80,3 +81,15 @@ func (window blockWindow) averageTarget() *big.Int {
}
return averageTarget.Div(averageTarget, big.NewInt(int64(len(window))))
}
func (window blockWindow) medianTimestamp() (int64, error) {
if len(window) == 0 {
return 0, errors.New("Cannot calculate median timestamp for an empty block window")
}
timestamps := make([]int64, len(window))
for i, node := range window {
timestamps[i] = node.timeInMilliseconds
}
sort.Sort(timeSorter(timestamps))
return timestamps[len(timestamps)/2], nil
}

View File

@@ -1,8 +1,6 @@
package difficultymanager
import (
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util/math"
"math/big"
"time"
@@ -19,7 +17,6 @@ type difficultyManager struct {
ghostdagManager model.GHOSTDAGManager
ghostdagStore model.GHOSTDAGDataStore
headerStore model.BlockHeaderStore
daaBlocksStore model.DAABlocksStore
dagTopologyManager model.DAGTopologyManager
dagTraversalManager model.DAGTraversalManager
genesisHash *externalapi.DomainHash
@@ -34,7 +31,6 @@ func New(databaseContext model.DBReader,
ghostdagManager model.GHOSTDAGManager,
ghostdagStore model.GHOSTDAGDataStore,
headerStore model.BlockHeaderStore,
daaBlocksStore model.DAABlocksStore,
dagTopologyManager model.DAGTopologyManager,
dagTraversalManager model.DAGTraversalManager,
powMax *big.Int,
@@ -47,7 +43,6 @@ func New(databaseContext model.DBReader,
ghostdagManager: ghostdagManager,
ghostdagStore: ghostdagStore,
headerStore: headerStore,
daaBlocksStore: daaBlocksStore,
dagTopologyManager: dagTopologyManager,
dagTraversalManager: dagTraversalManager,
powMax: powMax,
@@ -67,51 +62,39 @@ func (dm *difficultyManager) genesisBits() (uint32, error) {
return header.Bits(), nil
}
// StageDAADataAndReturnRequiredDifficulty calculates the DAA window, stages the DAA score and DAA added
// blocks, and returns the required difficulty for the given block.
// The reason this function both stages DAA data and returns the difficulty is because in order to calculate
// both of them we need to calculate the DAA window, which is a relatively heavy operation, so we reuse the
// block window instead of recalculating it for the two purposes.
// For cases where no staging should happen and the caller only needs to know the difficulty he should
// use RequiredDifficulty.
func (dm *difficultyManager) StageDAADataAndReturnRequiredDifficulty(blockHash *externalapi.DomainHash) (uint32, error) {
// Fetch window of dag.difficultyAdjustmentWindowSize + 1 so we can have dag.difficultyAdjustmentWindowSize block intervals
targetsWindow, windowHashes, err := dm.blockWindow(blockHash, dm.difficultyAdjustmentWindowSize+1)
if err != nil {
return 0, err
}
err = dm.stageDAAScoreAndAddedBlocks(blockHash, windowHashes)
if err != nil {
return 0, err
}
return dm.requiredDifficultyFromTargetsWindow(targetsWindow)
}
// RequiredDifficulty returns the difficulty required for some block
func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHash) (uint32, error) {
// Fetch window of dag.difficultyAdjustmentWindowSize + 1 so we can have dag.difficultyAdjustmentWindowSize block intervals
targetsWindow, _, err := dm.blockWindow(blockHash, dm.difficultyAdjustmentWindowSize+1)
parents, err := dm.dagTopologyManager.Parents(blockHash)
if err != nil {
return 0, err
}
// Genesis block or network that doesn't have difficulty adjustment (such as simnet)
if len(parents) == 0 || dm.disableDifficultyAdjustment {
return dm.genesisBits()
}
// find bluestParent
bluestParent, err := dm.ghostdagManager.ChooseSelectedParent(parents...)
if err != nil {
return 0, err
}
bluestGhostDAG, err := dm.ghostdagStore.Get(dm.databaseContext, bluestParent)
if err != nil {
return 0, err
}
return dm.requiredDifficultyFromTargetsWindow(targetsWindow)
}
func (dm *difficultyManager) requiredDifficultyFromTargetsWindow(targetsWindow blockWindow) (uint32, error) {
if dm.disableDifficultyAdjustment {
// Not enough blocks for building a difficulty window.
if bluestGhostDAG.BlueScore() < uint64(dm.difficultyAdjustmentWindowSize)+1 {
return dm.genesisBits()
}
// We need at least 2 blocks to get a timestamp interval
// We could instead clamp the timestamp difference to `targetTimePerBlock`,
// but then everything will cancel out and we'll get the target from the last block, which will be the same as genesis.
if len(targetsWindow) < 2 {
return dm.genesisBits()
// Fetch window of dag.difficultyAdjustmentWindowSize + 1 so we can have dag.difficultyAdjustmentWindowSize block intervals
targetsWindow, err := dm.blockWindow(bluestParent, dm.difficultyAdjustmentWindowSize+1)
if err != nil {
return 0, err
}
windowMinTimestamp, windowMaxTimeStamp, windowsMinIndex, _ := targetsWindow.minMaxTimestamps()
// Remove the last block from the window so to calculate the average target of dag.difficultyAdjustmentWindowSize blocks
targetsWindow.remove(windowsMinIndex)
@@ -122,66 +105,12 @@ func (dm *difficultyManager) requiredDifficultyFromTargetsWindow(targetsWindow b
div := new(big.Int)
newTarget := targetsWindow.averageTarget()
newTarget.
// We need to clamp the timestamp difference to 1 so that we'll never get a 0 target.
Mul(newTarget, div.SetInt64(math.MaxInt64(windowMaxTimeStamp-windowMinTimestamp, 1))).
Mul(newTarget, div.SetInt64(windowMaxTimeStamp-windowMinTimestamp)).
Div(newTarget, div.SetInt64(dm.targetTimePerBlock.Milliseconds())).
Div(newTarget, div.SetUint64(uint64(len(targetsWindow))))
Div(newTarget, div.SetUint64(uint64(dm.difficultyAdjustmentWindowSize)))
if newTarget.Cmp(dm.powMax) > 0 {
return difficulty.BigToCompact(dm.powMax), nil
}
newTargetBits := difficulty.BigToCompact(newTarget)
return newTargetBits, nil
}
func (dm *difficultyManager) stageDAAScoreAndAddedBlocks(blockHash *externalapi.DomainHash,
windowHashes []*externalapi.DomainHash) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "stageDAAScoreAndAddedBlocks")
defer onEnd()
daaScore, addedBlocks, err := dm.calculateDaaScoreAndAddedBlocks(blockHash, windowHashes)
if err != nil {
return err
}
dm.daaBlocksStore.StageDAAScore(blockHash, daaScore)
dm.daaBlocksStore.StageBlockDAAAddedBlocks(blockHash, addedBlocks)
return nil
}
func (dm *difficultyManager) calculateDaaScoreAndAddedBlocks(blockHash *externalapi.DomainHash,
windowHashes []*externalapi.DomainHash) (uint64, []*externalapi.DomainHash, error) {
if blockHash.Equal(dm.genesisHash) {
return 0, nil, nil
}
ghostdagData, err := dm.ghostdagStore.Get(dm.databaseContext, blockHash)
if err != nil {
return 0, nil, err
}
mergeSet := make(map[externalapi.DomainHash]struct{}, len(ghostdagData.MergeSet()))
for _, hash := range ghostdagData.MergeSet() {
mergeSet[*hash] = struct{}{}
}
// TODO: Consider optimizing by breaking the loop once you arrive to the
// window block with blue work higher than all non-added merge set blocks.
daaAddedBlocks := make([]*externalapi.DomainHash, 0, len(mergeSet))
for _, hash := range windowHashes {
if _, exists := mergeSet[*hash]; exists {
daaAddedBlocks = append(daaAddedBlocks, hash)
if len(daaAddedBlocks) == len(mergeSet) {
break
}
}
}
selectedParentDAAScore, err := dm.daaBlocksStore.DAAScore(dm.databaseContext, ghostdagData.SelectedParent())
if err != nil {
return 0, nil, err
}
return selectedParentDAAScore + uint64(len(daaAddedBlocks)), daaAddedBlocks, nil
}

View File

@@ -103,7 +103,7 @@ func TestDifficulty(t *testing.T) {
for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ {
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits() != params.GenesisBlock.Header.Bits() {
t.Fatalf("As long as the block blue score is less then the difficulty adjustment " +
t.Fatalf("As long as the bluest parent's blue score is less then the difficulty adjustment " +
"window size, the difficulty should be the same as genesis'")
}
}
@@ -116,10 +116,15 @@ func TestDifficulty(t *testing.T) {
blockInThePast, tipHash := addBlockWithMinimumTime(tipHash)
if blockInThePast.Header.Bits() != tip.Header.Bits() {
t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block")
t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent")
}
tip = blockInThePast
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits() != blockInThePast.Header.Bits() {
t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent")
}
tip, tipHash = addBlock(0, tipHash)
if compareBits(tip.Header.Bits(), blockInThePast.Header.Bits()) >= 0 {
t.Fatalf("tip.bits should be smaller than blockInThePast.bits because blockInThePast increased the " +
@@ -173,175 +178,37 @@ func TestDifficulty(t *testing.T) {
slowBlockTime := tip.Header.TimeInMilliseconds() + params.TargetTimePerBlock.Milliseconds() + 1000
slowBlock, tipHash := addBlock(slowBlockTime, tipHash)
if slowBlock.Header.Bits() != tip.Header.Bits() {
t.Fatalf("The difficulty should only change when slowBlock is in the past of a block")
t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent")
}
tip = slowBlock
tip, tipHash = addBlock(0, tipHash)
if tip.Header.Bits() != slowBlock.Header.Bits() {
t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent")
}
tip, tipHash = addBlock(0, tipHash)
if compareBits(tip.Header.Bits(), slowBlock.Header.Bits()) <= 0 {
t.Fatalf("tip.bits should be smaller than slowBlock.bits because slowBlock decreased the block" +
" rate, so the difficulty should decrease as well")
}
// Here we create two chains: a chain of blue blocks, and a chain of red blocks with
// very low timestamps. Because the red blocks should be part of the difficulty
// window, their low timestamps should lower the difficulty, and we check it by
// comparing the bits of two blocks with the same blue score, one with the red
// blocks in its past and one without.
_, tipHash = addBlock(0, tipHash)
splitBlockHash := tipHash
blueTipHash := splitBlockHash
for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ {
_, blueTipHash = addBlock(0, blueTipHash)
for i := 0; i < 100; i++ {
_, tipHash = addBlock(0, tipHash)
}
blueTipHash := tipHash
redChainTipHash := splitBlockHash
const redChainLength = 10
for i := 0; i < redChainLength; i++ {
for i := 0; i < 10; i++ {
_, redChainTipHash = addBlockWithMinimumTime(redChainTipHash)
}
tipWithRedPast, _ := addBlock(0, redChainTipHash, blueTipHash)
tipWithoutRedPast, _ := addBlock(0, blueTipHash)
if tipWithRedPast.Header.Bits() <= tipWithoutRedPast.Header.Bits() {
t.Fatalf("tipWithRedPast.bits should be greater than tipWithoutRedPast.bits because the red blocks" +
" blocks have very low timestamp and should lower the difficulty")
}
// We repeat the test, but now we make the blue chain longer in order to filter
// out the red blocks from the window, and check that the red blocks don't
// affect the difficulty.
blueTipHash = splitBlockHash
for i := 0; i < params.DifficultyAdjustmentWindowSize+redChainLength+1; i++ {
_, blueTipHash = addBlock(0, blueTipHash)
}
redChainTipHash = splitBlockHash
for i := 0; i < redChainLength; i++ {
_, redChainTipHash = addBlockWithMinimumTime(redChainTipHash)
}
tipWithRedPast, _ = addBlock(0, redChainTipHash, blueTipHash)
tipWithoutRedPast, _ = addBlock(0, blueTipHash)
if tipWithRedPast.Header.Bits() != tipWithoutRedPast.Header.Bits() {
t.Fatalf("tipWithoutRedPast.bits should be the same as tipWithRedPast.bits because the red blocks" +
" are not part of the difficulty window")
}
})
}
func TestDAAScore(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
params.DifficultyAdjustmentWindowSize = 264
factory := consensus.NewFactory()
tc, teardown, err := factory.NewTestConsensus(params, false, "TestDifficulty")
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown(false)
// We create a small DAG in order to skip from block with blue score of 1 directly to 3
split1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
block, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
blockBlueScore3, _, err := tc.AddBlock([]*externalapi.DomainHash{split1Hash, block}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
tipHash := blockBlueScore3
blockBlueScore3DAAScore, err := tc.DAABlocksStore().DAAScore(tc.DatabaseContext(), tipHash)
if err != nil {
t.Fatalf("DAAScore: %+v", err)
}
blockBlueScore3ExpectedDAAScore := uint64(2)
if blockBlueScore3DAAScore != blockBlueScore3ExpectedDAAScore {
t.Fatalf("DAA score is expected to be %d but got %d", blockBlueScore3ExpectedDAAScore, blockBlueScore3ExpectedDAAScore)
}
tipDAAScore := blockBlueScore3ExpectedDAAScore
for i := uint64(0); i < 10; i++ {
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
tipDAAScore, err = tc.DAABlocksStore().DAAScore(tc.DatabaseContext(), tipHash)
if err != nil {
t.Fatalf("DAAScore: %+v", err)
}
expectedDAAScore := blockBlueScore3ExpectedDAAScore + i + 1
if tipDAAScore != expectedDAAScore {
t.Fatalf("DAA score is expected to be %d but got %d", expectedDAAScore, tipDAAScore)
}
}
split2Hash := tipHash
split2DAAScore := tipDAAScore
for i := uint64(0); i < uint64(params.DifficultyAdjustmentWindowSize)-1; i++ {
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
tipDAAScore, err = tc.DAABlocksStore().DAAScore(tc.DatabaseContext(), tipHash)
if err != nil {
t.Fatalf("DAAScore: %+v", err)
}
expectedDAAScore := split2DAAScore + i + 1
if tipDAAScore != expectedDAAScore {
t.Fatalf("DAA score is expected to be %d but got %d", expectedDAAScore, split2DAAScore)
}
}
// This block should have blue score of 2 so it shouldn't be added to the DAA window of a merging block
blockAboveSplit1, _, err := tc.AddBlock([]*externalapi.DomainHash{split1Hash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
// This block is in the anticone of params.DifficultyAdjustmentWindowSize-1 blocks, so it must be part
// of the DAA window of a merging block
blockAboveSplit2, _, err := tc.AddBlock([]*externalapi.DomainHash{split2Hash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
currentSelectedTipDAAScore := tipDAAScore
currentSelectedTip := tipHash
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{blockAboveSplit1, blockAboveSplit2, tipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
tipDAAScore, err = tc.DAABlocksStore().DAAScore(tc.DatabaseContext(), tipHash)
if err != nil {
t.Fatalf("DAAScore: %+v", err)
}
// The DAA score should be increased only by 2, because 1 of the 3 merged blocks
// is not in the DAA window
expectedDAAScore := currentSelectedTipDAAScore + 2
if tipDAAScore != expectedDAAScore {
t.Fatalf("DAA score is expected to be %d but got %d", expectedDAAScore, tipDAAScore)
}
tipDAAAddedBlocks, err := tc.DAABlocksStore().DAAAddedBlocks(tc.DatabaseContext(), tipHash)
if err != nil {
t.Fatalf("DAAScore: %+v", err)
}
// blockAboveSplit2 should be excluded from the DAA added blocks because it's not in the tip's
// DAA window.
expectedDAABlocks := []*externalapi.DomainHash{blockAboveSplit2, currentSelectedTip}
if !externalapi.HashesEqual(tipDAAAddedBlocks, expectedDAABlocks) {
t.Fatalf("DAA added blocks are expected to be %s but got %s", expectedDAABlocks, tipDAAAddedBlocks)
if tipWithoutRedPast.Header.Bits() != tipWithRedPast.Header.Bits() {
t.Fatalf("tipWithoutRedPast.bits should be the same as tipWithRedPast.bits because red blocks" +
" shouldn't affect the difficulty")
}
})
}

View File

@@ -1,7 +0,0 @@
package difficultymanager
import (
"github.com/kaspanet/kaspad/infrastructure/logger"
)
var log = logger.RegisterSubSystem("DAA")

View File

@@ -2,31 +2,26 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package sorters
package difficultymanager
import "sort"
// Int64Slice implements sort.Interface to allow a slice of timestamps to
// timeSorter implements sort.Interface to allow a slice of timestamps to
// be sorted.
type Int64Slice []int64
type timeSorter []int64
// Len returns the number of timestamps in the slice. It is part of the
// sort.Interface implementation.
func (s Int64Slice) Len() int {
func (s timeSorter) Len() int {
return len(s)
}
// Swap swaps the timestamps at the passed indices. It is part of the
// sort.Interface implementation.
func (s Int64Slice) Swap(i, j int) {
func (s timeSorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// Less returns whether the timstamp with index i should sort before the
// timestamp with index j. It is part of the sort.Interface implementation.
func (s Int64Slice) Less(i, j int) bool {
func (s timeSorter) Less(i, j int) bool {
return s[i] < s[j]
}
// Sort is a convenience method: s.Sort() calls sort.Sort(s).
func (s Int64Slice) Sort() { sort.Sort(s) }

View File

@@ -1,7 +1,6 @@
package pastmediantimemanager
import (
"github.com/kaspanet/kaspad/domain/consensus/utils/sorters"
"sort"
"github.com/kaspanet/kaspad/domain/consensus/model"
@@ -20,8 +19,6 @@ type pastMedianTimeManager struct {
blockHeaderStore model.BlockHeaderStore
ghostdagDataStore model.GHOSTDAGDataStore
genesisHash *externalapi.DomainHash
}
// New instantiates a new PastMedianTimeManager
@@ -29,8 +26,7 @@ func New(timestampDeviationTolerance int,
databaseContext model.DBReader,
dagTraversalManager model.DAGTraversalManager,
blockHeaderStore model.BlockHeaderStore,
ghostdagDataStore model.GHOSTDAGDataStore,
genesisHash *externalapi.DomainHash) model.PastMedianTimeManager {
ghostdagDataStore model.GHOSTDAGDataStore) model.PastMedianTimeManager {
return &pastMedianTimeManager{
timestampDeviationTolerance: timestampDeviationTolerance,
@@ -40,24 +36,32 @@ func New(timestampDeviationTolerance int,
blockHeaderStore: blockHeaderStore,
ghostdagDataStore: ghostdagDataStore,
genesisHash: genesisHash,
}
}
// PastMedianTime returns the past median time for some block
func (pmtm *pastMedianTimeManager) PastMedianTime(blockHash *externalapi.DomainHash) (int64, error) {
window, err := pmtm.dagTraversalManager.BlockWindow(blockHash, 2*pmtm.timestampDeviationTolerance-1)
blockGHOSTDAGData, err := pmtm.ghostdagDataStore.Get(pmtm.databaseContext, blockHash)
if err != nil {
return 0, err
}
if len(window) == 0 {
header, err := pmtm.blockHeaderStore.BlockHeader(pmtm.databaseContext, pmtm.genesisHash)
selectedParentHash := blockGHOSTDAGData.SelectedParent()
// Genesis block
if selectedParentHash == nil {
header, err := pmtm.blockHeaderStore.BlockHeader(pmtm.databaseContext, blockHash)
if err != nil {
return 0, err
}
return header.TimeInMilliseconds(), nil
}
window, err := pmtm.dagTraversalManager.BlockWindow(selectedParentHash, 2*pmtm.timestampDeviationTolerance-1)
if err != nil {
return 0, err
}
return pmtm.windowMedianTimestamp(window)
}
@@ -75,7 +79,9 @@ func (pmtm *pastMedianTimeManager) windowMedianTimestamp(window []*externalapi.D
timestamps[i] = blockHeader.TimeInMilliseconds()
}
sort.Sort(sorters.Int64Slice(timestamps))
sort.Slice(timestamps, func(i, j int) bool {
return timestamps[i] < timestamps[j]
})
return timestamps[len(timestamps)/2], nil
}

View File

@@ -47,19 +47,19 @@ func TestPastMedianTime(t *testing.T) {
}{
{
blockNumber: 263,
expectedMillisecondsSinceGenesis: 132000,
expectedMillisecondsSinceGenesis: 130000,
},
{
blockNumber: 271,
expectedMillisecondsSinceGenesis: 139000,
expectedMillisecondsSinceGenesis: 138000,
},
{
blockNumber: 241,
expectedMillisecondsSinceGenesis: 121000,
expectedMillisecondsSinceGenesis: 108000,
},
{
blockNumber: 5,
expectedMillisecondsSinceGenesis: 3000,
expectedMillisecondsSinceGenesis: 0,
},
}

View File

@@ -34,7 +34,7 @@ func TestPruning(t *testing.T) {
},
"dag-for-test-pruning.json": {
dagconfig.MainnetParams.Name: "503",
dagconfig.TestnetParams.Name: "502",
dagconfig.TestnetParams.Name: "503",
dagconfig.DevnetParams.Name: "503",
dagconfig.SimnetParams.Name: "502",
},

View File

@@ -28,7 +28,6 @@ type pruningManager struct {
blocksStore model.BlockStore
blockHeaderStore model.BlockHeaderStore
utxoDiffStore model.UTXODiffStore
daaBlocksStore model.DAABlocksStore
isArchivalNode bool
genesisHash *externalapi.DomainHash
@@ -43,18 +42,17 @@ func New(
dagTraversalManager model.DAGTraversalManager,
dagTopologyManager model.DAGTopologyManager,
consensusStateManager model.ConsensusStateManager,
consensusStateStore model.ConsensusStateStore,
ghostdagDataStore model.GHOSTDAGDataStore,
pruningStore model.PruningStore,
blockStatusStore model.BlockStatusStore,
headerSelectedTipStore model.HeaderSelectedTipStore,
multiSetStore model.MultisetStore,
acceptanceDataStore model.AcceptanceDataStore,
blocksStore model.BlockStore,
blockHeaderStore model.BlockHeaderStore,
utxoDiffStore model.UTXODiffStore,
daaBlocksStore model.DAABlocksStore,
isArchivalNode bool,
genesisHash *externalapi.DomainHash,
@@ -77,7 +75,6 @@ func New(
blockHeaderStore: blockHeaderStore,
utxoDiffStore: utxoDiffStore,
headerSelectedTipStore: headerSelectedTipStore,
daaBlocksStore: daaBlocksStore,
isArchivalNode: isArchivalNode,
genesisHash: genesisHash,
pruningDepth: pruningDepth,
@@ -351,7 +348,6 @@ func (pm *pruningManager) deleteBlock(blockHash *externalapi.DomainHash) (alread
pm.acceptanceDataStore.Delete(blockHash)
pm.blocksStore.Delete(blockHash)
pm.utxoDiffStore.Delete(blockHash)
pm.daaBlocksStore.Delete(blockHash)
return false, nil
}

View File

@@ -1,109 +0,0 @@
package reachabilitymanager_test
import (
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"github.com/kaspanet/kaspad/domain/dagconfig"
"testing"
)
func TestReachabilityIsDAGAncestorOf(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
factory := consensus.NewFactory()
tc, teardown, err := factory.NewTestConsensus(params, false, "TestReachabilityIsDAGAncestorOf")
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown(false)
// A <- B - - - -
// / \ \
// genesis \ \ sharedBlock
// \ \ /
// C <- D - - - - /
genesisHash := params.GenesisHash
blockHashA, _, err := tc.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %v", err)
}
blockHashB, _, err := tc.AddBlock([]*externalapi.DomainHash{blockHashA}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %v", err)
}
blockHashC, _, err := tc.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %v", err)
}
blockHashD, _, err := tc.AddBlock([]*externalapi.DomainHash{blockHashA, blockHashC}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %v", err)
}
sharedBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{blockHashB, blockHashD}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %v", err)
}
tests := []struct {
firstBlockHash *externalapi.DomainHash
secondBlockHash *externalapi.DomainHash
expectedResult bool
}{
{
firstBlockHash: blockHashA,
secondBlockHash: blockHashA,
expectedResult: true,
},
{
firstBlockHash: genesisHash,
secondBlockHash: blockHashA,
expectedResult: true,
},
{
firstBlockHash: genesisHash,
secondBlockHash: sharedBlockHash,
expectedResult: true,
},
{
firstBlockHash: blockHashC,
secondBlockHash: blockHashD,
expectedResult: true,
},
{
firstBlockHash: blockHashA,
secondBlockHash: blockHashD,
expectedResult: true,
},
{
firstBlockHash: blockHashC,
secondBlockHash: blockHashB,
expectedResult: false,
},
{
firstBlockHash: blockHashB,
secondBlockHash: blockHashD,
expectedResult: false,
},
{
firstBlockHash: blockHashB,
secondBlockHash: blockHashA,
expectedResult: false,
},
}
for _, test := range tests {
isDAGAncestorOf, err := tc.ReachabilityManager().IsDAGAncestorOf(test.firstBlockHash, test.secondBlockHash)
if err != nil {
t.Fatalf("IsDAGAncestorOf: %v", err)
}
if isDAGAncestorOf != test.expectedResult {
t.Fatalf("IsDAGAncestorOf: should returns %v but got %v", test.expectedResult, isDAGAncestorOf)
}
}
})
}

View File

@@ -11,28 +11,29 @@ import (
// `maxBlueScoreDifference`, if non-zero.
// The result excludes lowHash and includes highHash. If lowHash == highHash, returns nothing.
func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.DomainHash,
maxBlueScoreDifference uint64) (hashes []*externalapi.DomainHash, actualHighHash *externalapi.DomainHash, err error) {
maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) {
// If lowHash is not in the selectedParentChain of highHash - SelectedChildIterator will fail.
// Therefore, we traverse down lowHash's selectedParentChain until we reach a block that is in
// highHash's selectedParentChain.
// We keep originalLowHash to filter out blocks in it's past later down the road
originalLowHash := lowHash
var err error
lowHash, err = sm.findLowHashInHighHashSelectedParentChain(lowHash, highHash)
if err != nil {
return nil, nil, err
return nil, err
}
lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash)
if err != nil {
return nil, nil, err
return nil, err
}
highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash)
if err != nil {
return nil, nil, err
return nil, err
}
if lowBlockGHOSTDAGData.BlueScore() > highBlockGHOSTDAGData.BlueScore() {
return nil, nil, errors.Errorf("low hash blueScore > high hash blueScore (%d > %d)",
return nil, errors.Errorf("low hash blueScore > high hash blueScore (%d > %d)",
lowBlockGHOSTDAGData.BlueScore(), highBlockGHOSTDAGData.BlueScore())
}
@@ -48,7 +49,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
// blue.
highHash, err = sm.findHighHashAccordingToMaxBlueScoreDifference(lowHash, highHash, maxBlueScoreDifference, highBlockGHOSTDAGData, lowBlockGHOSTDAGData)
if err != nil {
return nil, nil, err
return nil, err
}
}
@@ -56,13 +57,13 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
blockHashes := []*externalapi.DomainHash{}
iterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, lowHash)
if err != nil {
return nil, nil, err
return nil, err
}
defer iterator.Close()
for ok := iterator.First(); ok; ok = iterator.Next() {
current, err := iterator.Get()
if err != nil {
return nil, nil, err
return nil, err
}
// Both blue and red merge sets are topologically sorted, but not the concatenation of the two.
// We require the blocks to be topologically sorted. In addition, for optimal performance,
@@ -72,14 +73,14 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
// Therefore we first append the selectedParent, then the rest of blocks in ghostdag order.
sortedMergeSet, err := sm.getSortedMergeSet(current)
if err != nil {
return nil, nil, err
return nil, err
}
// append to blockHashes all blocks in sortedMergeSet which are not in the past of originalLowHash
for _, blockHash := range sortedMergeSet {
isInPastOfOriginalLowHash, err := sm.dagTopologyManager.IsAncestorOf(blockHash, originalLowHash)
if err != nil {
return nil, nil, err
return nil, err
}
if isInPastOfOriginalLowHash {
continue
@@ -93,7 +94,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
blockHashes = append(blockHashes, highHash)
}
return blockHashes, highHash, nil
return blockHashes, nil
}
func (sm *syncManager) getSortedMergeSet(current *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
@@ -225,7 +226,7 @@ func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash)
lowHash, highHash)
}
hashesBetween, _, err := sm.antiPastHashesBetween(lowHash, highHash, 0)
hashesBetween, err := sm.antiPastHashesBetween(lowHash, highHash, 0)
if err != nil {
return nil, err
}

View File

@@ -58,7 +58,7 @@ func New(
}
func (sm *syncManager) GetHashesBetween(lowHash, highHash *externalapi.DomainHash,
maxBlueScoreDifference uint64) (hashes []*externalapi.DomainHash, actualHighHash *externalapi.DomainHash, err error) {
maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "GetHashesBetween")
defer onEnd()

View File

@@ -55,7 +55,7 @@ func TestSyncManager_GetHashesBetween(t *testing.T) {
}
for i, blockHash := range expectedOrder {
empty, _, err := tc.SyncManager().GetHashesBetween(blockHash, blockHash, math.MaxUint64)
empty, err := tc.SyncManager().GetHashesBetween(blockHash, blockHash, math.MaxUint64)
if err != nil {
t.Fatalf("TestSyncManager_GetHashesBetween failed returning 0 hashes on the %d'th block: %v", i, err)
}
@@ -64,7 +64,7 @@ func TestSyncManager_GetHashesBetween(t *testing.T) {
}
}
actualOrder, _, err := tc.SyncManager().GetHashesBetween(params.GenesisHash, expectedOrder[len(expectedOrder)-1], math.MaxUint64)
actualOrder, err := tc.SyncManager().GetHashesBetween(params.GenesisHash, expectedOrder[len(expectedOrder)-1], math.MaxUint64)
if err != nil {
t.Fatalf("TestSyncManager_GetHashesBetween failed returning actualOrder: %v", err)
}

View File

@@ -3,7 +3,6 @@ package transactionvalidator
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
@@ -55,25 +54,26 @@ func (v *transactionValidator) ValidateTransactionInContextAndPopulateMassAndFee
func (v *transactionValidator) checkTransactionCoinbaseMaturity(
povBlockHash *externalapi.DomainHash, tx *externalapi.DomainTransaction) error {
povDAAScore, err := v.daaBlocksStore.DAAScore(v.databaseContext, povBlockHash)
ghostdagData, err := v.ghostdagDataStore.Get(v.databaseContext, povBlockHash)
if err != nil {
return err
}
txBlueScore := ghostdagData.BlueScore()
var missingOutpoints []*externalapi.DomainOutpoint
for _, input := range tx.Inputs {
utxoEntry := input.UTXOEntry
if utxoEntry == nil {
missingOutpoints = append(missingOutpoints, &input.PreviousOutpoint)
} else if utxoEntry.IsCoinbase() {
originDAAScore := utxoEntry.BlockDAAScore()
daaScoreSincePrev := povDAAScore - originDAAScore
if daaScoreSincePrev < v.blockCoinbaseMaturity {
originBlueScore := utxoEntry.BlockBlueScore()
blueScoreSincePrev := txBlueScore - originBlueScore
if blueScoreSincePrev < v.blockCoinbaseMaturity {
return errors.Wrapf(ruleerrors.ErrImmatureSpend, "tried to spend coinbase "+
"transaction output %s from DAA score %d "+
"to DAA score %d before required maturity "+
"transaction output %s from blue score %d "+
"to blue score %d before required maturity "+
"of %d", input.PreviousOutpoint,
originDAAScore, povDAAScore,
originBlueScore, txBlueScore,
v.blockCoinbaseMaturity)
}
}
@@ -161,12 +161,12 @@ func (v *transactionValidator) checkTransactionSequenceLock(povBlockHash *extern
return err
}
daaScore, err := v.daaBlocksStore.DAAScore(v.databaseContext, povBlockHash)
ghostdagData, err := v.ghostdagDataStore.Get(v.databaseContext, povBlockHash)
if err != nil {
return err
}
if !v.sequenceLockActive(sequenceLock, daaScore, medianTime) {
if !v.sequenceLockActive(sequenceLock, ghostdagData.BlueScore(), medianTime) {
return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains "+
"transaction whose input sequence "+
"locks are not met")
@@ -178,8 +178,6 @@ func (v *transactionValidator) checkTransactionSequenceLock(povBlockHash *extern
func (v *transactionValidator) validateTransactionScripts(tx *externalapi.DomainTransaction) error {
var missingOutpoints []*externalapi.DomainOutpoint
sighashReusedValues := &consensushashing.SighashReusedValues{}
for i, input := range tx.Inputs {
// Create a new script engine for the script pair.
sigScript := input.SignatureScript
@@ -190,7 +188,8 @@ func (v *transactionValidator) validateTransactionScripts(tx *externalapi.Domain
}
scriptPubKey := utxoEntry.ScriptPublicKey()
vm, err := txscript.NewEngine(scriptPubKey, tx, i, txscript.ScriptNoFlags, v.sigCache, sighashReusedValues)
vm, err := txscript.NewEngine(scriptPubKey, tx,
i, txscript.ScriptNoFlags, v.sigCache)
if err != nil {
return errors.Wrapf(ruleerrors.ErrScriptMalformed, "failed to parse input "+
"%d which references output %s - "+
@@ -222,7 +221,7 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries(
// A value of -1 for each relative lock type represents a relative time
// lock value that will allow a transaction to be included in a block
// at any given height or time.
sequenceLock := &sequenceLock{Milliseconds: -1, BlockDAAScore: -1}
sequenceLock := &sequenceLock{Milliseconds: -1, BlockBlueScore: -1}
// Sequence locks don't apply to coinbase transactions Therefore, we
// return sequence lock values of -1 indicating that this transaction
@@ -239,7 +238,10 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries(
continue
}
inputDAAScore := utxoEntry.BlockDAAScore()
// If the input blue score is set to the mempool blue score, then we
// assume the transaction makes it into the next block when
// evaluating its sequence blocks.
inputBlueScore := utxoEntry.BlockBlueScore()
// Given a sequence number, we apply the relative time lock
// mask in order to obtain the time lock delta required before
@@ -267,21 +269,16 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries(
baseHash := povBlockHash
for {
selectedParentDAAScore, err := v.daaBlocksStore.DAAScore(v.databaseContext, povBlockHash)
if err != nil {
return nil, err
}
if selectedParentDAAScore <= inputDAAScore {
break
}
selectedParentGHOSTDAGData, err := v.ghostdagDataStore.Get(v.databaseContext,
baseGHOSTDAGData.SelectedParent())
if err != nil {
return nil, err
}
if selectedParentGHOSTDAGData.BlueScore() <= inputBlueScore {
break
}
baseHash = baseGHOSTDAGData.SelectedParent()
baseGHOSTDAGData = selectedParentGHOSTDAGData
}
@@ -304,12 +301,12 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries(
default:
// The relative lock-time for this input is expressed
// in blocks so we calculate the relative offset from
// the input's DAA score as its converted absolute
// the input's blue score as its converted absolute
// lock-time. We subtract one from the relative lock in
// order to maintain the original lockTime semantics.
blockDAAScore := int64(inputDAAScore) + relativeLock - 1
if blockDAAScore > sequenceLock.BlockDAAScore {
sequenceLock.BlockDAAScore = blockDAAScore
blockBlueScore := int64(inputBlueScore) + relativeLock - 1
if blockBlueScore > sequenceLock.BlockBlueScore {
sequenceLock.BlockBlueScore = blockBlueScore
}
}
}
@@ -321,27 +318,27 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries(
}
// sequenceLock represents the converted relative lock-time in seconds, and
// absolute block-daa-score for a transaction input's relative lock-times.
// absolute block-blue-score for a transaction input's relative lock-times.
// According to sequenceLock, after the referenced input has been confirmed
// within a block, a transaction spending that input can be included into a
// block either after 'seconds' (according to past median time), or once the
// 'BlockDAAScore' has been reached.
// 'BlockBlueScore' has been reached.
type sequenceLock struct {
Milliseconds int64
BlockDAAScore int64
Milliseconds int64
BlockBlueScore int64
}
// sequenceLockActive determines if a transaction's sequence locks have been
// met, meaning that all the inputs of a given transaction have reached a
// DAA score or time sufficient for their relative lock-time maturity.
func (v *transactionValidator) sequenceLockActive(sequenceLock *sequenceLock, blockDAAScore uint64,
// blue score or time sufficient for their relative lock-time maturity.
func (v *transactionValidator) sequenceLockActive(sequenceLock *sequenceLock, blockBlueScore uint64,
medianTimePast int64) bool {
// If either the milliseconds, or DAA score relative-lock time has not yet
// If either the milliseconds, or blue score relative-lock time has not yet
// reached, then the transaction is not yet mature according to its
// sequence locks.
if sequenceLock.Milliseconds >= medianTimePast ||
sequenceLock.BlockDAAScore >= int64(blockDAAScore) {
sequenceLock.BlockBlueScore >= int64(blockBlueScore) {
return false
}

View File

@@ -9,34 +9,34 @@ import (
// works as expected in all possible combinations/scenarios.
func TestSequenceLocksActive(t *testing.T) {
tests := []struct {
seqLock sequenceLock
blockDAAScore uint64
mtp mstime.Time
seqLock sequenceLock
blockBlueScore uint64
mtp mstime.Time
want bool
}{
// Block based sequence lock with equal block DAA score.
{seqLock: sequenceLock{-1, 1000}, blockDAAScore: 1001, mtp: mstime.UnixMilliseconds(9), want: true},
// Block based sequence lock with equal block blue score.
{seqLock: sequenceLock{-1, 1000}, blockBlueScore: 1001, mtp: mstime.UnixMilliseconds(9), want: true},
// Time based sequence lock with mtp past the absolute time.
{seqLock: sequenceLock{30, -1}, blockDAAScore: 2, mtp: mstime.UnixMilliseconds(31), want: true},
{seqLock: sequenceLock{30, -1}, blockBlueScore: 2, mtp: mstime.UnixMilliseconds(31), want: true},
// Block based sequence lock with current DAA score below seq lock block DAA score.
{seqLock: sequenceLock{-1, 1000}, blockDAAScore: 90, mtp: mstime.UnixMilliseconds(9), want: false},
// Block based sequence lock with current blue score below seq lock block blue score.
{seqLock: sequenceLock{-1, 1000}, blockBlueScore: 90, mtp: mstime.UnixMilliseconds(9), want: false},
// Time based sequence lock with current time before lock time.
{seqLock: sequenceLock{30, -1}, blockDAAScore: 2, mtp: mstime.UnixMilliseconds(29), want: false},
{seqLock: sequenceLock{30, -1}, blockBlueScore: 2, mtp: mstime.UnixMilliseconds(29), want: false},
// Block based sequence lock at the same DAA score, so shouldn't yet be active.
{seqLock: sequenceLock{-1, 1000}, blockDAAScore: 1000, mtp: mstime.UnixMilliseconds(9), want: false},
// Block based sequence lock at the same blue score, so shouldn't yet be active.
{seqLock: sequenceLock{-1, 1000}, blockBlueScore: 1000, mtp: mstime.UnixMilliseconds(9), want: false},
// Time based sequence lock with current time equal to lock time, so shouldn't yet be active.
{seqLock: sequenceLock{30, -1}, blockDAAScore: 2, mtp: mstime.UnixMilliseconds(30), want: false},
{seqLock: sequenceLock{30, -1}, blockBlueScore: 2, mtp: mstime.UnixMilliseconds(30), want: false},
}
validator := transactionValidator{}
for i, test := range tests {
got := validator.sequenceLockActive(&test.seqLock, test.blockDAAScore, test.mtp.UnixMilliseconds())
got := validator.sequenceLockActive(&test.seqLock, test.blockBlueScore, test.mtp.UnixMilliseconds())
if got != test.want {
t.Fatalf("SequenceLockActive #%d got %v want %v", i, got, test.want)
}

View File

@@ -4,6 +4,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
"github.com/pkg/errors"
@@ -26,6 +27,10 @@ func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.Do
if err != nil {
return err
}
err = v.checkTransactionPayloadHash(tx)
if err != nil {
return err
}
err = v.checkGasInBuiltInOrNativeTransactions(tx)
if err != nil {
return err
@@ -125,6 +130,18 @@ func (v *transactionValidator) checkCoinbaseLength(tx *externalapi.DomainTransac
return nil
}
func (v *transactionValidator) checkTransactionPayloadHash(tx *externalapi.DomainTransaction) error {
if tx.SubnetworkID != subnetworks.SubnetworkIDNative {
payloadHash := hashes.PayloadHash(tx.Payload)
if !tx.PayloadHash.Equal(payloadHash) {
return errors.Wrapf(ruleerrors.ErrInvalidPayloadHash, "invalid payload hash")
}
} else if tx.PayloadHash != (externalapi.DomainHash{}) {
return errors.Wrapf(ruleerrors.ErrInvalidPayloadHash, "unexpected non-empty payload hash in native subnetwork")
}
return nil
}
func (v *transactionValidator) checkGasInBuiltInOrNativeTransactions(tx *externalapi.DomainTransaction) error {
// Transactions in native, registry and coinbase subnetworks must have Gas = 0
if subnetworks.IsBuiltInOrNative(tx.SubnetworkID) && tx.Gas > 0 {

View File

@@ -3,6 +3,8 @@ package transactionvalidator_test
import (
"testing"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
@@ -101,6 +103,20 @@ func TestValidateTransactionInIsolation(t *testing.T) {
tx.Payload = []byte{1}
},
ruleerrors.ErrInvalidPayload},
{"invalid payload hash", 1, 1, 0,
externalapi.DomainSubnetworkID{123},
&txSubnetworkData{externalapi.DomainSubnetworkID{123}, 0, []byte{1}},
func(tx *externalapi.DomainTransaction) {
tx.PayloadHash = externalapi.DomainHash{}
},
ruleerrors.ErrInvalidPayloadHash},
{"invalid payload hash in native subnetwork", 1, 1, 0,
subnetworks.SubnetworkIDNative,
nil,
func(tx *externalapi.DomainTransaction) {
tx.PayloadHash = *hashes.PayloadHash(tx.Payload)
},
ruleerrors.ErrInvalidPayloadHash},
}
for _, test := range tests {

View File

@@ -14,7 +14,6 @@ type transactionValidator struct {
databaseContext model.DBReader
pastMedianTimeManager model.PastMedianTimeManager
ghostdagDataStore model.GHOSTDAGDataStore
daaBlocksStore model.DAABlocksStore
enableNonNativeSubnetworks bool
massPerTxByte uint64
massPerScriptPubKeyByte uint64
@@ -32,9 +31,7 @@ func New(blockCoinbaseMaturity uint64,
maxCoinbasePayloadLength uint64,
databaseContext model.DBReader,
pastMedianTimeManager model.PastMedianTimeManager,
ghostdagDataStore model.GHOSTDAGDataStore,
daaBlocksStore model.DAABlocksStore) model.TransactionValidator {
ghostdagDataStore model.GHOSTDAGDataStore) model.TransactionValidator {
return &transactionValidator{
blockCoinbaseMaturity: blockCoinbaseMaturity,
enableNonNativeSubnetworks: enableNonNativeSubnetworks,
@@ -45,7 +42,6 @@ func New(blockCoinbaseMaturity uint64,
databaseContext: databaseContext,
pastMedianTimeManager: pastMedianTimeManager,
ghostdagDataStore: ghostdagDataStore,
daaBlocksStore: daaBlocksStore,
sigCache: txscript.NewSigCache(sigCacheSize),
}
}

View File

@@ -4,12 +4,13 @@ import (
"github.com/kaspanet/go-secp256k1"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
"github.com/kaspanet/kaspad/util"
"math/big"
"testing"
"github.com/kaspanet/kaspad/domain/consensus/model"
@@ -35,7 +36,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
factory := consensus.NewFactory()
pastMedianManager := &mocPastMedianTimeManager{}
factory.SetTestPastMedianTimeManager(func(int, model.DBReader, model.DAGTraversalManager, model.BlockHeaderStore,
model.GHOSTDAGDataStore, *externalapi.DomainHash) model.PastMedianTimeManager {
model.GHOSTDAGDataStore) model.PastMedianTimeManager {
return pastMedianManager
})
tc, tearDown, err := factory.NewTestConsensus(params, false,
@@ -116,16 +117,6 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
SubnetworkID: subnetworks.SubnetworkIDRegistry,
Gas: 0,
LockTime: 0}
for i, input := range validTx.Inputs {
signatureScript, err := txscript.SignatureScript(&validTx, i, consensushashing.SigHashAll, privateKey,
&consensushashing.SighashReusedValues{})
if err != nil {
t.Fatalf("Failed to create a sigScript: %v", err)
}
input.SignatureScript = signatureScript
}
txWithImmatureCoinbase := externalapi.DomainTransaction{
Version: constants.MaxTransactionVersion,
Inputs: []*externalapi.DomainTransactionInput{&txInput},
@@ -155,9 +146,30 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
Gas: 0,
LockTime: 0}
for i, input := range validTx.Inputs {
signatureScript, err := txscript.SignatureScript(&validTx, i, scriptPublicKey, txscript.SigHashAll, privateKey)
if err != nil {
t.Fatalf("Failed to create a sigScript: %v", err)
}
input.SignatureScript = signatureScript
}
povBlockHash := externalapi.NewDomainHashFromByteArray(&[32]byte{0x01})
tc.DAABlocksStore().StageDAAScore(povBlockHash, params.BlockCoinbaseMaturity+txInput.UTXOEntry.BlockDAAScore())
tc.DAABlocksStore().StageDAAScore(povBlockHash, 10)
genesisHash := params.GenesisHash
tc.GHOSTDAGDataStore().Stage(model.VirtualBlockHash, model.NewBlockGHOSTDAGData(
params.BlockCoinbaseMaturity+txInput.UTXOEntry.BlockBlueScore(),
new(big.Int),
genesisHash,
make([]*externalapi.DomainHash, 1000),
make([]*externalapi.DomainHash, 1),
nil))
tc.GHOSTDAGDataStore().Stage(povBlockHash, model.NewBlockGHOSTDAGData(
10,
new(big.Int),
genesisHash,
make([]*externalapi.DomainHash, 1000),
make([]*externalapi.DomainHash, 1),
nil))
tests := []struct {
name string
@@ -176,7 +188,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
expectedError: nil,
},
{ // The calculated block coinbase maturity is smaller than the minimum expected blockCoinbaseMaturity.
// The povBlockHash DAA score is 10 and the UTXO DAA score is 5, hence the The subtraction between
// The povBlockHash blue score is 10 and the UTXO blue score is 5, hence the The subtraction between
// them will yield a smaller result than the required CoinbaseMaturity (currently set to 100).
name: "checkTransactionCoinbaseMaturity",
tx: &txWithImmatureCoinbase,
@@ -226,12 +238,12 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
if test.isValid {
if err != nil {
t.Fatalf("Unexpected error on TestValidateTransactionInContextAndPopulateMassAndFee"+
" on test '%v': %v", test.name, err)
" on test %v: %v", test.name, err)
}
} else {
if err == nil || !errors.Is(err, test.expectedError) {
t.Fatalf("TestValidateTransactionInContextAndPopulateMassAndFee: test %v:"+
" Unexpected error: Expected to: %v, but got : %+v", test.name, test.expectedError, err)
" Unexpected error: Expected to: %v, but got : %v", test.name, test.expectedError, err)
}
}
}

View File

@@ -139,6 +139,9 @@ var (
// a Payload
ErrInvalidPayload = newRuleError("ErrInvalidPayload")
// ErrInvalidPayloadHash invalid hash of transaction's payload
ErrInvalidPayloadHash = newRuleError("ErrInvalidPayloadHash")
// ErrSubnetwork indicates that a block doesn't adhere to the subnetwork
// registry rules
ErrSubnetworkRegistry = newRuleError("ErrSubnetworkRegistry")

View File

@@ -2,8 +2,6 @@ package ruleerrors
import (
"errors"
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"testing"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
@@ -47,11 +45,9 @@ func TestNewErrMissingTxOut(t *testing.T) {
}
func TestNewErrInvalidTransactionsInNewBlock(t *testing.T) {
tx := &externalapi.DomainTransaction{Fee: 1337}
txID := consensushashing.TransactionID(tx)
outer := NewErrInvalidTransactionsInNewBlock([]InvalidTransaction{{tx, ErrNoTxInputs}})
outer := NewErrInvalidTransactionsInNewBlock([]InvalidTransaction{{&externalapi.DomainTransaction{Fee: 1337}, ErrNoTxInputs}})
//TODO: Implement Stringer for `DomainTransaction`
expectedOuterErr := fmt.Sprintf("ErrInvalidTransactionsInNewBlock: [(%s: ErrNoTxInputs)]", txID)
expectedOuterErr := "ErrInvalidTransactionsInNewBlock: [(bbf6e84f5a6333948063aa45ea02ff5bb0355e11e41becf20245791f61179db1: ErrNoTxInputs)]"
inner := &ErrInvalidTransactionsInNewBlock{}
if !errors.As(outer, inner) {
t.Fatal("TestNewErrInvalidTransactionsInNewBlock: Outer should contain ErrInvalidTransactionsInNewBlock in it")

View File

@@ -137,7 +137,3 @@ func (tc *testConsensus) FinalityStore() model.FinalityStore {
func (tc *testConsensus) HeadersSelectedChainStore() model.HeadersSelectedChainStore {
return tc.headersSelectedChainStore
}
func (tc *testConsensus) DAABlocksStore() model.DAABlocksStore {
return tc.daaBlocksStore
}

View File

@@ -1,215 +0,0 @@
package consensushashing
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus/utils/serialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"github.com/pkg/errors"
)
// SigHashType represents hash type bits at the end of a signature.
type SigHashType uint8
// Hash type bits from the end of a signature.
const (
SigHashAll SigHashType = 0b00000001
SigHashNone SigHashType = 0b00000010
SigHashSingle SigHashType = 0b00000100
SigHashAnyOneCanPay SigHashType = 0b10000000
// SigHashMask defines the number of bits of the hash type which is used
// to identify which outputs are signed.
SigHashMask = 0b00000111
)
// IsStandardSigHashType returns true if sht represents a standard SigHashType
func (sht SigHashType) IsStandardSigHashType() bool {
switch sht {
case SigHashAll, SigHashNone, SigHashSingle,
SigHashAll | SigHashAnyOneCanPay, SigHashNone | SigHashAnyOneCanPay, SigHashSingle | SigHashAnyOneCanPay:
return true
default:
return false
}
}
func (sht SigHashType) isSigHashAll() bool {
return sht&SigHashMask == SigHashAll
}
func (sht SigHashType) isSigHashNone() bool {
return sht&SigHashMask == SigHashNone
}
func (sht SigHashType) isSigHashSingle() bool {
return sht&SigHashMask == SigHashSingle
}
func (sht SigHashType) isSigHashAnyOneCanPay() bool {
return sht&SigHashAnyOneCanPay == SigHashAnyOneCanPay
}
// SighashReusedValues holds all fields used in the calculation of a transaction's sigHash, that are
// the same for all transaction inputs.
// Reuse of such values prevents the quadratic hashing problem.
type SighashReusedValues struct {
previousOutputsHash *externalapi.DomainHash
sequencesHash *externalapi.DomainHash
outputsHash *externalapi.DomainHash
payloadHash *externalapi.DomainHash
}
// CalculateSignatureHash will, given a script and hash type calculate the signature hash
// to be used for signing and verification.
// This returns error only if one of the provided parameters are consensus-invalid.
func CalculateSignatureHash(tx *externalapi.DomainTransaction, inputIndex int, hashType SigHashType,
reusedValues *SighashReusedValues) (*externalapi.DomainHash, error) {
if !hashType.IsStandardSigHashType() {
return nil, errors.Errorf("SigHashType %d is not a valid SigHash type", hashType)
}
txIn := tx.Inputs[inputIndex]
prevScriptPublicKey := txIn.UTXOEntry.ScriptPublicKey()
if tx.Version > constants.MaxTransactionVersion {
return nil, errors.Errorf("Transaction version is unknown.")
}
if prevScriptPublicKey.Version > constants.MaxScriptPublicKeyVersion {
return nil, errors.Errorf("Script version is unknown.")
}
return calculateSignatureHash(tx, inputIndex, txIn, prevScriptPublicKey, hashType, reusedValues)
}
func calculateSignatureHash(tx *externalapi.DomainTransaction, inputIndex int, txIn *externalapi.DomainTransactionInput,
prevScriptPublicKey *externalapi.ScriptPublicKey, hashType SigHashType, reusedValues *SighashReusedValues) (
*externalapi.DomainHash, error) {
hashWriter := hashes.NewTransactionSigningHashWriter()
infallibleWriteElement(hashWriter, tx.Version)
previousOutputsHash := getPreviousOutputsHash(tx, hashType, reusedValues)
infallibleWriteElement(hashWriter, previousOutputsHash)
sequencesHash := getSequencesHash(tx, hashType, reusedValues)
infallibleWriteElement(hashWriter, sequencesHash)
hashOutpoint(hashWriter, txIn.PreviousOutpoint)
infallibleWriteElement(hashWriter, prevScriptPublicKey.Version)
infallibleWriteElement(hashWriter, prevScriptPublicKey.Script)
infallibleWriteElement(hashWriter, txIn.UTXOEntry.Amount())
infallibleWriteElement(hashWriter, txIn.Sequence)
outputsHash := getOutputsHash(tx, inputIndex, hashType, reusedValues)
infallibleWriteElement(hashWriter, outputsHash)
infallibleWriteElement(hashWriter, tx.LockTime)
infallibleWriteElement(hashWriter, tx.SubnetworkID)
infallibleWriteElement(hashWriter, tx.Gas)
payloadHash := getPayloadHash(tx, reusedValues)
infallibleWriteElement(hashWriter, payloadHash)
infallibleWriteElement(hashWriter, uint8(hashType))
return hashWriter.Finalize(), nil
}
func getPreviousOutputsHash(tx *externalapi.DomainTransaction, hashType SigHashType, reusedValues *SighashReusedValues) *externalapi.DomainHash {
if hashType.isSigHashAnyOneCanPay() {
return externalapi.NewZeroHash()
}
if reusedValues.previousOutputsHash == nil {
hashWriter := hashes.NewTransactionSigningHashWriter()
for _, txIn := range tx.Inputs {
hashOutpoint(hashWriter, txIn.PreviousOutpoint)
}
reusedValues.previousOutputsHash = hashWriter.Finalize()
}
return reusedValues.previousOutputsHash
}
func getSequencesHash(tx *externalapi.DomainTransaction, hashType SigHashType, reusedValues *SighashReusedValues) *externalapi.DomainHash {
if hashType.isSigHashSingle() || hashType.isSigHashAnyOneCanPay() || hashType.isSigHashNone() {
return externalapi.NewZeroHash()
}
if reusedValues.sequencesHash == nil {
hashWriter := hashes.NewTransactionSigningHashWriter()
for _, txIn := range tx.Inputs {
infallibleWriteElement(hashWriter, txIn.Sequence)
}
reusedValues.sequencesHash = hashWriter.Finalize()
}
return reusedValues.sequencesHash
}
func getOutputsHash(tx *externalapi.DomainTransaction, inputIndex int, hashType SigHashType, reusedValues *SighashReusedValues) *externalapi.DomainHash {
// SigHashNone: return zero-hash
if hashType.isSigHashNone() {
return externalapi.NewZeroHash()
}
// SigHashSingle: If the relevant output exists - return it's hash, otherwise return zero-hash
if hashType.isSigHashSingle() {
if inputIndex >= len(tx.Outputs) {
return externalapi.NewZeroHash()
}
hashWriter := hashes.NewTransactionSigningHashWriter()
hashTxOut(hashWriter, tx.Outputs[inputIndex])
return hashWriter.Finalize()
}
// SigHashAll: Return hash of all outputs. Re-use hash if available.
if reusedValues.outputsHash == nil {
hashWriter := hashes.NewTransactionSigningHashWriter()
for _, txOut := range tx.Outputs {
hashTxOut(hashWriter, txOut)
}
reusedValues.outputsHash = hashWriter.Finalize()
}
return reusedValues.outputsHash
}
func getPayloadHash(tx *externalapi.DomainTransaction, reusedValues *SighashReusedValues) *externalapi.DomainHash {
if tx.SubnetworkID.Equal(&subnetworks.SubnetworkIDNative) {
return externalapi.NewZeroHash()
}
if reusedValues.payloadHash == nil {
hashWriter := hashes.NewTransactionSigningHashWriter()
infallibleWriteElement(hashWriter, tx.Payload)
reusedValues.payloadHash = hashWriter.Finalize()
}
return reusedValues.payloadHash
}
func hashTxOut(hashWriter hashes.HashWriter, txOut *externalapi.DomainTransactionOutput) {
infallibleWriteElement(hashWriter, txOut.Value)
infallibleWriteElement(hashWriter, txOut.ScriptPublicKey.Version)
infallibleWriteElement(hashWriter, txOut.ScriptPublicKey.Script)
}
func hashOutpoint(hashWriter hashes.HashWriter, outpoint externalapi.DomainOutpoint) {
infallibleWriteElement(hashWriter, outpoint.TransactionID)
infallibleWriteElement(hashWriter, outpoint.Index)
}
func infallibleWriteElement(hashWriter hashes.HashWriter, element interface{}) {
err := serialization.WriteElement(hashWriter, element)
if err != nil {
// It seems like this could only happen if the writer returned an error.
// and this writer should never return an error (no allocations or possible failures)
// the only non-writer error path here is unknown types in `WriteElement`
panic(errors.Wrap(err, "TransactionHashForSigning() failed. this should never fail for structurally-valid transactions"))
}
}

Some files were not shown because too many files have changed in this diff Show More