mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
Mempool redesign (#1752)
* Added model and stubs for all main methods * Add constructors to all main objects * Implement BlockCandidateTransactions * implement expireOldTransactions and expireOrphanTransactions * Rename isHighPriority to neverExpires * Add stub for checkDoubleSpends * Revert "Rename isHighPriority to neverExpires" This reverts commit b2da9a4a00c02fb380d2518cf54fa16257bd8423. * Imeplement transactionsOrderedByFeeRate * Orphan maps should be idToOrphan * Add error.go to mempool * Invert the condition for banning when mempool rejects a transaction * Move all model objects to model package * Implement getParentsInPool * Implemented mempoolUTXOSet.addTransaction * Implement removeTransaction, remove sanity checks * Implemented mempoolUTXOSet.checkDoubleSpends * Implemented removeOrphan * Implement removeOrphan * Implement maybeAddOrphan and AddOrphan * Implemented processOrphansAfterAcceptedTransaction * Implement transactionsPool.addTransaction * Implement RemoveTransaction * If a transaction was removed from the mempool - update it's redeemers in orphan pool as well * Use maximumOrphanTransactionCount * Add allowOrphans to ValidateAndInsertTransaction stub * Implement validateTransaction functions * Implement fillInputs * Implement ValidateAndInsertTransaction * Implement HandleNewBlockTransactions * Implement missing mempool interface methods * Add comments to exported functions * Call ValidateTransactionInIsolation where needed * Implement RevalidateHighPriorityTransactions * Rewire kaspad to use new mempool, and fix compilation errors * Update rebroadcast logic to use new structure * Handle non-standard transaction errors properly * Add mutex to mempool * bugfix: GetTransaction panics when ok is false * properly calculate targetBlocksPerSecond in config.go * Fix various lint errors and tests * Fix expected text in test for duplicate transactions * Skip the coinbase transaction in HandleNewBlockTransactions * Unorphan the correct transactions * Call ValidateTransactionAndPopulateWithConsensusData on unorphanTransaction * Re-apply policy_test as check_transactions_standard_test * removeTransaction: Remove redeemers in orphan pool as well * Remove redundant check for uint64 < 0 * Export and rename isDust -> IsTransactionOutputDust to allow usage by rothschild * Add allowOrphan to SubmitTransaction RPC request * Remove all implementation from mempool.go * tidy go mod * Don't pass acceptedOrphans to handleNewBlockTransactions * Use t.Errorf in stead of t.Fatalf * Remove minimum relay fee from TestDust, as it's no longer configurable * Add separate VirtualDAASCore method for faster retrieval where it's repeated multiple times * Broadcast all transactions that were accepted * Don't re-use GetVirtualDAAScore in GetVirtualInfo - this causes a deadlock * Use real transaction count, and not Orphan * Get mempool config from outside, incorporating values received from cli * Use MinRelayFee and MaxOrphanTxs from global kaspad config * Add explanation for the seemingly redundant check for transaction version in checkTransactionStandard * Update some comment * Convert creation of acceptedTransactions to a single line * Move mempoolUTXOSet out of checkDoubleSpends * Add test for attempt to insert double spend into mempool * fillInputs: Skip check for coinbase - it's always false in mempool * Clarify comment about removeRedeemers when removing random orphan * Don't remove high-priority transactions in limitTransactionCount * Use mempool.removeTransaction in limitTransactionCount * Add mutex comment to handleNewBlockTransactions * Return error from limitTransactionCount * Pluralize the map types * mempoolUTXOSet.removeTransaction: Don't restore utxo if it was not created in mempool * Don't evacuate from orphanPool high-priority transactions * Disallow double-spends in orphan pool * Don't use exported (and locking) methods from inside mempool * Check for double spends in mempool during revalidateTransaction * Add checkOrphanDuplicate * Add orphan to acceptedOrphans, not current * Add TestHighPriorityTransactions * Fix off-by-one error in limitTransactionCount * Add TestRevalidateHighPriorityTransactions * Remove checkDoubleSpends from revalidateTransaction * Fix TestRevalidateHighPriorityTransactions * Move check for MaximumOrphanCount to beggining of maybeAddOrphan * Rename all map type to singulateToSingularMap * limitOrphanPool only after the orphan was added * TestDoubleSpendInMempool: use createChildTxWhenParentTxWasAddedByConsensus instead of createTransactionWithUTXOEntry * Fix some comments * Have separate min/max transaction versions for mempool * Add comment on defaultMaximumOrphanTransactionCount to keep it small as long as we have recursion * Fix comment * Rename: createChildTxWhenParentTxWasAddedByConsensus -> createChildTxWhereParentTxWasAddedByConsensus * Handle error from createChildTxWhereParentTxWasAddedByConsensus * Rename createChildTxWhereParentTxWasAddedByConsensus -> createChildAndParentTxsAndAddParentToConsensus * Convert all MaximumXXX constants to uint64 * Add comment * remove mutex comments
This commit is contained in:
parent
4ba8b14675
commit
c13a4d90ed
@ -5,6 +5,7 @@ package appmessage
|
||||
type SubmitTransactionRequestMessage struct {
|
||||
baseMessage
|
||||
Transaction *RPCTransaction
|
||||
AllowOrphan bool
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/protocol"
|
||||
"github.com/kaspanet/kaspad/app/rpc"
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
@ -79,8 +81,11 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database,
|
||||
IsArchival: cfg.IsArchivalNode,
|
||||
EnableSanityCheckPruningUTXOSet: cfg.EnableSanityCheckPruningUTXOSet,
|
||||
}
|
||||
mempoolConfig := mempool.DefaultConfig(&consensusConfig.Params)
|
||||
mempoolConfig.MaximumOrphanTransactionCount = cfg.MaxOrphanTxs
|
||||
mempoolConfig.MinimumRelayTransactionFee = cfg.MinRelayTxFee
|
||||
|
||||
domain, err := domain.New(&consensusConfig, db)
|
||||
domain, err := domain.New(&consensusConfig, mempoolConfig, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -3,11 +3,10 @@ package flowcontext
|
||||
import (
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"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/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||
@ -71,8 +70,6 @@ func (f *FlowContext) OnPruningPointUTXOSetOverride() error {
|
||||
func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
||||
addedBlocks []*externalapi.DomainBlock, transactionsAcceptedToMempool []*externalapi.DomainTransaction) error {
|
||||
|
||||
f.updateTransactionsToRebroadcast(addedBlocks)
|
||||
|
||||
// Don't relay transactions when in IBD.
|
||||
if f.IsIBDRunning() {
|
||||
return nil
|
||||
@ -80,7 +77,11 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
|
||||
|
||||
var txIDsToRebroadcast []*externalapi.DomainTransactionID
|
||||
if f.shouldRebroadcastTransactions() {
|
||||
txIDsToRebroadcast = f.txIDsToRebroadcast()
|
||||
txsToRebroadcast, err := f.Domain().MiningManager().RevalidateHighPriorityTransactions()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
txIDsToRebroadcast = consensushashing.TransactionIDs(txsToRebroadcast)
|
||||
}
|
||||
|
||||
txIDsToBroadcast := make([]*externalapi.DomainTransactionID, len(transactionsAcceptedToMempool)+len(txIDsToRebroadcast))
|
||||
|
@ -1,10 +1,11 @@
|
||||
package flowcontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
@ -46,10 +47,8 @@ type FlowContext struct {
|
||||
onPruningPointUTXOSetOverrideHandler OnPruningPointUTXOSetOverrideHandler
|
||||
onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler
|
||||
|
||||
transactionsToRebroadcastLock sync.Mutex
|
||||
transactionsToRebroadcast map[externalapi.DomainTransactionID]*externalapi.DomainTransaction
|
||||
lastRebroadcastTime time.Time
|
||||
sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions
|
||||
lastRebroadcastTime time.Time
|
||||
sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions
|
||||
|
||||
sharedRequestedBlocks *blockrelay.SharedRequestedBlocks
|
||||
|
||||
@ -78,7 +77,6 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage
|
||||
sharedRequestedTransactions: transactionrelay.NewSharedRequestedTransactions(),
|
||||
sharedRequestedBlocks: blockrelay.NewSharedRequestedBlocks(),
|
||||
peers: make(map[id.ID]*peerpkg.Peer),
|
||||
transactionsToRebroadcast: make(map[externalapi.DomainTransactionID]*externalapi.DomainTransaction),
|
||||
orphans: make(map[externalapi.DomainHash]*externalapi.DomainBlock),
|
||||
timeStarted: mstime.Now().UnixMilliseconds(),
|
||||
shutdownChan: make(chan struct{}),
|
||||
|
@ -10,53 +10,23 @@ import (
|
||||
)
|
||||
|
||||
// AddTransaction adds transaction to the mempool and propagates it.
|
||||
func (f *FlowContext) AddTransaction(tx *externalapi.DomainTransaction) error {
|
||||
f.transactionsToRebroadcastLock.Lock()
|
||||
defer f.transactionsToRebroadcastLock.Unlock()
|
||||
|
||||
err := f.Domain().MiningManager().ValidateAndInsertTransaction(tx, false)
|
||||
func (f *FlowContext) AddTransaction(tx *externalapi.DomainTransaction, allowOrphan bool) error {
|
||||
acceptedTransactions, err := f.Domain().MiningManager().ValidateAndInsertTransaction(tx, true, allowOrphan)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
transactionID := consensushashing.TransactionID(tx)
|
||||
f.transactionsToRebroadcast[*transactionID] = tx
|
||||
inv := appmessage.NewMsgInvTransaction([]*externalapi.DomainTransactionID{transactionID})
|
||||
acceptedTransactionIDs := consensushashing.TransactionIDs(acceptedTransactions)
|
||||
inv := appmessage.NewMsgInvTransaction(acceptedTransactionIDs)
|
||||
|
||||
return f.Broadcast(inv)
|
||||
}
|
||||
|
||||
func (f *FlowContext) updateTransactionsToRebroadcast(addedBlocks []*externalapi.DomainBlock) {
|
||||
f.transactionsToRebroadcastLock.Lock()
|
||||
defer f.transactionsToRebroadcastLock.Unlock()
|
||||
|
||||
for _, block := range addedBlocks {
|
||||
// Note: if a transaction is included in the DAG but not accepted,
|
||||
// it won't be rebroadcast anymore, although it is not included in
|
||||
// the UTXO set
|
||||
for _, tx := range block.Transactions {
|
||||
delete(f.transactionsToRebroadcast, *consensushashing.TransactionID(tx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FlowContext) shouldRebroadcastTransactions() bool {
|
||||
const rebroadcastInterval = 30 * time.Second
|
||||
return time.Since(f.lastRebroadcastTime) > rebroadcastInterval
|
||||
}
|
||||
|
||||
func (f *FlowContext) txIDsToRebroadcast() []*externalapi.DomainTransactionID {
|
||||
f.transactionsToRebroadcastLock.Lock()
|
||||
defer f.transactionsToRebroadcastLock.Unlock()
|
||||
|
||||
txIDs := make([]*externalapi.DomainTransactionID, len(f.transactionsToRebroadcast))
|
||||
i := 0
|
||||
for _, tx := range f.transactionsToRebroadcast {
|
||||
txIDs[i] = consensushashing.TransactionID(tx)
|
||||
i++
|
||||
}
|
||||
return txIDs
|
||||
}
|
||||
|
||||
// SharedRequestedTransactions returns a *transactionrelay.SharedRequestedTransactions for sharing
|
||||
// data about requested transactions between different peers.
|
||||
func (f *FlowContext) SharedRequestedTransactions() *transactionrelay.SharedRequestedTransactions {
|
||||
|
@ -273,6 +273,10 @@ func (f *fakeRelayInvsContext) GetVirtualInfo() (*externalapi.VirtualInfo, error
|
||||
panic(errors.Errorf("called unimplemented function from test '%s'", f.testName))
|
||||
}
|
||||
|
||||
func (f *fakeRelayInvsContext) GetVirtualDAAScore() (uint64, error) {
|
||||
panic(errors.Errorf("called unimplemented function from test '%s'", f.testName))
|
||||
}
|
||||
|
||||
func (f *fakeRelayInvsContext) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) {
|
||||
f.rwLock.RLock()
|
||||
defer f.rwLock.RUnlock()
|
||||
|
@ -173,17 +173,18 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact
|
||||
expectedID, txID)
|
||||
}
|
||||
|
||||
err = flow.Domain().MiningManager().ValidateAndInsertTransaction(tx, true)
|
||||
acceptedTransactions, err :=
|
||||
flow.Domain().MiningManager().ValidateAndInsertTransaction(tx, false, true)
|
||||
if err != nil {
|
||||
ruleErr := &mempool.RuleError{}
|
||||
if !errors.As(err, ruleErr) {
|
||||
return errors.Wrapf(err, "failed to process transaction %s", txID)
|
||||
}
|
||||
|
||||
shouldBan := true
|
||||
shouldBan := false
|
||||
if txRuleErr := (&mempool.TxRuleError{}); errors.As(ruleErr.Err, txRuleErr) {
|
||||
if txRuleErr.RejectCode != mempool.RejectInvalid {
|
||||
shouldBan = false
|
||||
if txRuleErr.RejectCode == mempool.RejectInvalid {
|
||||
shouldBan = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,7 +194,7 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact
|
||||
|
||||
return protocolerrors.Errorf(true, "rejected transaction %s: %s", txID, ruleErr)
|
||||
}
|
||||
err = flow.broadcastAcceptedTransactions([]*externalapi.DomainTransactionID{txID})
|
||||
err = flow.broadcastAcceptedTransactions(consensushashing.TransactionIDs(acceptedTransactions))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -2,16 +2,18 @@ package transactionrelay_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
"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/miningmanager/mempool"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
@ -63,7 +65,7 @@ func TestHandleRelayedTransactionsNotFound(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a NetAdapter: %v", err)
|
||||
}
|
||||
domainInstance, err := domain.New(consensusConfig, tc.Database())
|
||||
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set up a domain instance: %v", err)
|
||||
}
|
||||
@ -156,7 +158,7 @@ func TestOnClosedIncomingRoute(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to creat a NetAdapter : %v", err)
|
||||
}
|
||||
domainInstance, err := domain.New(consensusConfig, tc.Database())
|
||||
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set up a domain instance: %v", err)
|
||||
}
|
||||
|
@ -1,19 +1,21 @@
|
||||
package transactionrelay_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay"
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
"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/miningmanager/mempool"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
"github.com/pkg/errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHandleRequestedTransactionsNotFound tests the flow of HandleRequestedTransactions
|
||||
@ -34,7 +36,7 @@ func TestHandleRequestedTransactionsNotFound(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a NetAdapter: %v", err)
|
||||
}
|
||||
domainInstance, err := domain.New(consensusConfig, tc.Database())
|
||||
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), tc.Database())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set up a domain Instance: %v", err)
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
@ -61,8 +62,8 @@ func (m *Manager) IBDPeer() *peerpkg.Peer {
|
||||
}
|
||||
|
||||
// AddTransaction adds transaction to the mempool and propagates it.
|
||||
func (m *Manager) AddTransaction(tx *externalapi.DomainTransaction) error {
|
||||
return m.context.AddTransaction(tx)
|
||||
func (m *Manager) AddTransaction(tx *externalapi.DomainTransaction, allowOrphan bool) error {
|
||||
return m.context.AddTransaction(tx, allowOrphan)
|
||||
}
|
||||
|
||||
// AddBlock adds the given block to the DAG and propagates it.
|
||||
|
@ -162,12 +162,12 @@ func (m *Manager) notifyVirtualDaaScoreChanged() error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualDaaScoreChanged")
|
||||
defer onEnd()
|
||||
|
||||
virtualInfo, err := m.context.Domain.Consensus().GetVirtualInfo()
|
||||
virtualDAAScore, err := m.context.Domain.Consensus().GetVirtualDAAScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
notification := appmessage.NewVirtualDaaScoreChangedNotificationMessage(virtualInfo.DAAScore)
|
||||
notification := appmessage.NewVirtualDaaScoreChangedNotificationMessage(virtualDAAScore)
|
||||
return m.context.NotificationManager.NotifyVirtualDaaScoreChanged(notification)
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ func HandleSubmitTransaction(context *rpccontext.Context, _ *router.Router, requ
|
||||
}
|
||||
|
||||
transactionID := consensushashing.TransactionID(domainTransaction)
|
||||
err = context.ProtocolManager.AddTransaction(domainTransaction)
|
||||
err = context.ProtocolManager.AddTransaction(domainTransaction, submitTransactionRequest.AllowOrphan)
|
||||
if err != nil {
|
||||
if !errors.As(err, &mempool.RuleError{}) {
|
||||
return nil, err
|
||||
|
@ -401,6 +401,15 @@ func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *consensus) GetVirtualDAAScore() (uint64, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
return s.daaBlocksStore.DAAScore(s.databaseContext, stagingArea, model.VirtualBlockHash)
|
||||
}
|
||||
|
||||
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
@ -28,6 +28,7 @@ type Consensus interface {
|
||||
GetSyncInfo() (*SyncInfo, error)
|
||||
Tips() ([]*DomainHash, error)
|
||||
GetVirtualInfo() (*VirtualInfo, error)
|
||||
GetVirtualDAAScore() (uint64, error)
|
||||
IsValidPruningPoint(blockHash *DomainHash) (bool, error)
|
||||
GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedChainPath, error)
|
||||
IsInSelectedParentChainOf(blockHashA *DomainHash, blockHashB *DomainHash) (bool, error)
|
||||
|
@ -65,6 +65,15 @@ func TransactionID(tx *externalapi.DomainTransaction) *externalapi.DomainTransac
|
||||
return tx.ID
|
||||
}
|
||||
|
||||
// TransactionIDs converts the provided slice of DomainTransactions to a corresponding slice of TransactionIDs
|
||||
func TransactionIDs(txs []*externalapi.DomainTransaction) []*externalapi.DomainTransactionID {
|
||||
txIDs := make([]*externalapi.DomainTransactionID, len(txs))
|
||||
for i, tx := range txs {
|
||||
txIDs[i] = TransactionID(tx)
|
||||
}
|
||||
return txIDs
|
||||
}
|
||||
|
||||
func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodingFlags txEncoding) error {
|
||||
err := binaryserializer.PutUint16(w, tx.Version)
|
||||
if err != nil {
|
||||
|
@ -1,16 +1,18 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
||||
"github.com/kaspanet/kaspad/domain/prefixmanager"
|
||||
"github.com/kaspanet/kaspad/domain/prefixmanager/prefix"
|
||||
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/pkg/errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Domain provides a reference to the domain's external aps
|
||||
@ -157,7 +159,7 @@ func (d *domain) DeleteStagingConsensus() error {
|
||||
}
|
||||
|
||||
// New instantiates a new instance of a Domain object
|
||||
func New(consensusConfig *consensus.Config, db infrastructuredatabase.Database) (Domain, error) {
|
||||
func New(consensusConfig *consensus.Config, mempoolConfig *mempool.Config, db infrastructuredatabase.Database) (Domain, error) {
|
||||
err := prefixmanager.DeleteInactivePrefix(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -183,7 +185,7 @@ func New(consensusConfig *consensus.Config, db infrastructuredatabase.Database)
|
||||
}
|
||||
|
||||
miningManagerFactory := miningmanager.NewFactory()
|
||||
miningManager := miningManagerFactory.NewMiningManager(consensusInstance, &consensusConfig.Params)
|
||||
miningManager := miningManagerFactory.NewMiningManager(consensusInstance, &consensusConfig.Params, mempoolConfig)
|
||||
|
||||
return &domain{
|
||||
consensus: &consensusInstance,
|
||||
|
@ -2,16 +2,18 @@ package domain_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateStagingConsensus(t *testing.T) {
|
||||
@ -27,7 +29,7 @@ func TestCreateStagingConsensus(t *testing.T) {
|
||||
t.Fatalf("NewLevelDB: %+v", err)
|
||||
}
|
||||
|
||||
domainInstance, err := domain.New(consensusConfig, db)
|
||||
domainInstance, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), db)
|
||||
if err != nil {
|
||||
t.Fatalf("New: %+v", err)
|
||||
}
|
||||
@ -101,7 +103,7 @@ func TestCreateStagingConsensus(t *testing.T) {
|
||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||
}
|
||||
|
||||
domainInstance2, err := domain.New(consensusConfig, db)
|
||||
domainInstance2, err := domain.New(consensusConfig, mempool.DefaultConfig(&consensusConfig.Params), db)
|
||||
if err != nil {
|
||||
t.Fatalf("New: %+v", err)
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ func (btb *blockTemplateBuilder) GetBlockTemplate(coinbaseData *consensusexterna
|
||||
for _, tx := range invalidTxsErr.InvalidTransactions {
|
||||
invalidTxs = append(invalidTxs, tx.Transaction)
|
||||
}
|
||||
err = btb.mempool.RemoveTransactions(invalidTxs)
|
||||
err = btb.mempool.RemoveTransactions(invalidTxs, true)
|
||||
if err != nil {
|
||||
// mempool.RemoveTransactions might return errors in situations that are perfectly fine in this context.
|
||||
// TODO: Once the mempool invariants are clear, this should be converted back `return nil, err`:
|
||||
|
@ -9,14 +9,16 @@ import (
|
||||
|
||||
// Factory instantiates new mining managers
|
||||
type Factory interface {
|
||||
NewMiningManager(consensus externalapi.Consensus, params *dagconfig.Params) MiningManager
|
||||
NewMiningManager(consensus externalapi.Consensus, params *dagconfig.Params, mempoolConfig *mempoolpkg.Config) MiningManager
|
||||
}
|
||||
|
||||
type factory struct{}
|
||||
|
||||
// NewMiningManager instantiate a new mining manager
|
||||
func (f *factory) NewMiningManager(consensus externalapi.Consensus, params *dagconfig.Params) MiningManager {
|
||||
mempool := mempoolpkg.New(consensus, params)
|
||||
func (f *factory) NewMiningManager(consensus externalapi.Consensus, params *dagconfig.Params,
|
||||
mempoolConfig *mempoolpkg.Config) MiningManager {
|
||||
|
||||
mempool := mempoolpkg.New(mempoolConfig, consensus)
|
||||
blockTemplateBuilder := blocktemplatebuilder.New(consensus, mempool, params.MaxMassAcceptedByBlock)
|
||||
|
||||
return &miningManager{
|
||||
|
@ -1,72 +0,0 @@
|
||||
mempool
|
||||
=======
|
||||
|
||||
[](https://choosealicense.com/licenses/isc/)
|
||||
[](http://godoc.org/github.com/kaspanet/kaspad/mempool)
|
||||
|
||||
Package mempool provides a policy-enforced pool of unmined kaspa transactions.
|
||||
|
||||
A key responsbility of the kaspa network is mining user-generated transactions
|
||||
into blocks. In order to facilitate this, the mining process relies on having a
|
||||
readily-available source of transactions to include in a block that is being
|
||||
solved.
|
||||
|
||||
At a high level, this package satisfies that requirement by providing an
|
||||
in-memory pool of fully validated transactions that can also optionally be
|
||||
further filtered based upon a configurable policy.
|
||||
|
||||
One of the policy configuration options controls whether or not "standard"
|
||||
transactions are accepted. In essence, a "standard" transaction is one that
|
||||
satisfies a fairly strict set of requirements that are largely intended to help
|
||||
provide fair use of the system to all users. It is important to note that what
|
||||
is considered a "standard" transaction changes over time. For some insight, at
|
||||
the time of this writing, an example of _some_ of the criteria that are required
|
||||
for a transaction to be considered standard are that it is of the most-recently
|
||||
supported version, finalized, does not exceed a specific size, and only consists
|
||||
of specific script forms.
|
||||
|
||||
Since this package does not deal with other kaspa specifics such as network
|
||||
communication and transaction relay, it returns a list of transactions that were
|
||||
accepted which gives the caller a high level of flexibility in how they want to
|
||||
proceed. Typically, this will involve things such as relaying the transactions
|
||||
to other peers on the network and notifying the mining process that new
|
||||
transactions are available.
|
||||
|
||||
This package has intentionally been designed so it can be used as a standalone
|
||||
package for any projects needing the ability create an in-memory pool of bitcoin
|
||||
transactions that are not only valid by consensus rules, but also adhere to a
|
||||
configurable policy.
|
||||
|
||||
## Feature Overview
|
||||
|
||||
The following is a quick overview of the major features. It is not intended to
|
||||
be an exhaustive list.
|
||||
|
||||
- Maintain a pool of fully validated transactions
|
||||
- Reject non-fully-spent duplicate transactions
|
||||
- Reject coinbase transactions
|
||||
- Reject double spends (both from the DAG and other transactions in pool)
|
||||
- Reject invalid transactions according to the network consensus rules
|
||||
- Full script execution and validation with signature cache support
|
||||
- Individual transaction query support
|
||||
- Orphan transaction support (transactions that spend from unknown outputs)
|
||||
- Configurable limits (see transaction acceptance policy)
|
||||
- Automatic addition of orphan transactions that are no longer orphans as new
|
||||
transactions are added to the pool
|
||||
- Individual orphan transaction query support
|
||||
- Configurable transaction acceptance policy
|
||||
- Option to accept or reject standard transactions
|
||||
- Option to accept or reject transactions based on priority calculations
|
||||
- Rate limiting of low-fee and free transactions
|
||||
- Non-zero fee threshold
|
||||
- Max signature operations per transaction
|
||||
- Max orphan transaction size
|
||||
- Max number of orphan transactions allowed
|
||||
- Additional metadata tracking for each transaction
|
||||
- Timestamp when the transaction was added to the pool
|
||||
- Most recent block height when the transaction was added to the pool
|
||||
- The fee the transaction pays
|
||||
- The starting priority for the transaction
|
||||
- Manual control of transaction removal
|
||||
- Recursive removal of all dependent transactions
|
||||
|
211
domain/miningmanager/mempool/check_transaction_standard.go
Normal file
211
domain/miningmanager/mempool/check_transaction_standard.go
Normal file
@ -0,0 +1,211 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxStandardP2SHSigOps is the maximum number of signature operations
|
||||
// that are considered standard in a pay-to-script-hash script.
|
||||
maxStandardP2SHSigOps = 15
|
||||
|
||||
// maximumStandardSignatureScriptSize is the maximum size allowed for a
|
||||
// transaction input signature script to be considered standard. This
|
||||
// value allows for a 15-of-15 CHECKMULTISIG pay-to-script-hash with
|
||||
// compressed keys.
|
||||
//
|
||||
// The form of the overall script is: OP_0 <15 signatures> OP_PUSHDATA2
|
||||
// <2 bytes len> [OP_15 <15 pubkeys> OP_15 OP_CHECKMULTISIG]
|
||||
//
|
||||
// For the p2sh script portion, each of the 15 compressed pubkeys are
|
||||
// 33 bytes (plus one for the OP_DATA_33 opcode), and the thus it totals
|
||||
// to (15*34)+3 = 513 bytes. Next, each of the 15 signatures is a max
|
||||
// of 73 bytes (plus one for the OP_DATA_73 opcode). Also, there is one
|
||||
// extra byte for the initial extra OP_0 push and 3 bytes for the
|
||||
// OP_PUSHDATA2 needed to specify the 513 bytes for the script push.
|
||||
// That brings the total to 1+(15*74)+3+513 = 1627. This value also
|
||||
// adds a few extra bytes to provide a little buffer.
|
||||
// (1 + 15*74 + 3) + (15*34 + 3) + 23 = 1650
|
||||
maximumStandardSignatureScriptSize = 1650
|
||||
|
||||
// maximumStandardTransactionSize is the maximum size allowed for transactions that
|
||||
// are considered standard and will therefore be relayed and considered
|
||||
// for mining.
|
||||
maximumStandardTransactionSize = 100000
|
||||
)
|
||||
|
||||
func (mp *mempool) checkTransactionStandardInIsolation(transaction *externalapi.DomainTransaction) error {
|
||||
// The transaction must be a currently supported version.
|
||||
//
|
||||
// This check is currently mirrored in consensus.
|
||||
// However, in a later version of Kaspa the consensus-valid transaction version range might diverge from the
|
||||
// standard transaction version range, and thus the validation should happen in both levels.
|
||||
if transaction.Version > mp.config.MaximumStandardTransactionVersion ||
|
||||
transaction.Version < mp.config.MinimumStandardTransactionVersion {
|
||||
str := fmt.Sprintf("transaction version %d is not in the valid range of %d-%d", transaction.Version,
|
||||
mp.config.MinimumStandardTransactionVersion, mp.config.MaximumStandardTransactionVersion)
|
||||
return transactionRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
// Since extremely large transactions with a lot of inputs can cost
|
||||
// almost as much to process as the sender fees, limit the maximum
|
||||
// size of a transaction. This also helps mitigate CPU exhaustion
|
||||
// attacks.
|
||||
serializedLength := estimatedsize.TransactionEstimatedSerializedSize(transaction)
|
||||
if serializedLength > maximumStandardTransactionSize {
|
||||
str := fmt.Sprintf("transaction size of %d is larger than max allowed size of %d",
|
||||
serializedLength, maximumStandardTransactionSize)
|
||||
return transactionRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
for i, input := range transaction.Inputs {
|
||||
// Each transaction input signature script must not exceed the
|
||||
// maximum size allowed for a standard transaction. See
|
||||
// the comment on maximumStandardSignatureScriptSize for more details.
|
||||
signatureScriptLen := len(input.SignatureScript)
|
||||
if signatureScriptLen > maximumStandardSignatureScriptSize {
|
||||
str := fmt.Sprintf("transaction input %d: signature script size of %d bytes is larger than the "+
|
||||
"maximum allowed size of %d bytes", i, signatureScriptLen, maximumStandardSignatureScriptSize)
|
||||
return transactionRuleError(RejectNonstandard, str)
|
||||
}
|
||||
}
|
||||
|
||||
// None of the output public key scripts can be a non-standard script or be "dust".
|
||||
for i, output := range transaction.Outputs {
|
||||
if output.ScriptPublicKey.Version > constants.MaxScriptPublicKeyVersion {
|
||||
return transactionRuleError(RejectNonstandard, "The version of the scriptPublicKey is higher than the known version.")
|
||||
}
|
||||
scriptClass := txscript.GetScriptClass(output.ScriptPublicKey.Script)
|
||||
if scriptClass == txscript.NonStandardTy {
|
||||
str := fmt.Sprintf("transaction output %d: non-standard script form", i)
|
||||
return transactionRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
if mp.IsTransactionOutputDust(output) {
|
||||
str := fmt.Sprintf("transaction output %d: payment "+
|
||||
"of %d is dust", i, output.Value)
|
||||
return transactionRuleError(RejectDust, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsTransactionOutputDust returns whether or not the passed transaction output amount
|
||||
// is considered dust or not based on the configured minimum transaction relay fee.
|
||||
// Dust is defined in terms of the minimum transaction relay fee. In
|
||||
// particular, if the cost to the network to spend coins is more than 1/3 of the
|
||||
// minimum transaction relay fee, it is considered dust.
|
||||
//
|
||||
// It is exported for use by transaction generators and wallets
|
||||
func (mp *mempool) IsTransactionOutputDust(output *externalapi.DomainTransactionOutput) bool {
|
||||
// Unspendable outputs are considered dust.
|
||||
if txscript.IsUnspendable(output.ScriptPublicKey.Script) {
|
||||
return true
|
||||
}
|
||||
|
||||
// The total serialized size consists of the output and the associated
|
||||
// input script to redeem it. Since there is no input script
|
||||
// to redeem it yet, use the minimum size of a typical input script.
|
||||
//
|
||||
// Pay-to-pubkey bytes breakdown:
|
||||
//
|
||||
// Output to pubkey (43 bytes):
|
||||
// 8 value, 1 script len, 34 script [1 OP_DATA_32,
|
||||
// 32 pubkey, 1 OP_CHECKSIG]
|
||||
//
|
||||
// Input (105 bytes):
|
||||
// 36 prev outpoint, 1 script len, 64 script [1 OP_DATA_64,
|
||||
// 64 sig], 4 sequence
|
||||
//
|
||||
// The most common scripts are pay-to-pubkey, and as per the above
|
||||
// breakdown, the minimum size of a p2pk input script is 148 bytes. So
|
||||
// that figure is used.
|
||||
totalSerializedSize := estimatedsize.TransactionOutputEstimatedSerializedSize(output) + 148
|
||||
|
||||
// The output is considered dust if the cost to the network to spend the
|
||||
// coins is more than 1/3 of the minimum free transaction relay fee.
|
||||
// mp.config.MinimumRelayTransactionFee is in sompi/KB, so multiply
|
||||
// by 1000 to convert to bytes.
|
||||
//
|
||||
// Using the typical values for a pay-to-pubkey transaction from
|
||||
// the breakdown above and the default minimum free transaction relay
|
||||
// fee of 1000, this equates to values less than 546 sompi being
|
||||
// considered dust.
|
||||
//
|
||||
// The following is equivalent to (value/totalSerializedSize) * (1/3) * 1000
|
||||
// without needing to do floating point math.
|
||||
return output.Value*1000/(3*totalSerializedSize) < uint64(mp.config.MinimumRelayTransactionFee)
|
||||
}
|
||||
|
||||
// checkTransactionStandardInContext performs a series of checks on a transaction's
|
||||
// inputs to ensure they are "standard". A standard transaction input within the
|
||||
// context of this function is one whose referenced public key script is of a
|
||||
// standard form and, for pay-to-script-hash, does not have more than
|
||||
// maxStandardP2SHSigOps signature operations.
|
||||
// In addition, makes sure that the transaction's fee is above the minimum for acceptance
|
||||
// into the mempool and relay
|
||||
func (mp *mempool) checkTransactionStandardInContext(transaction *externalapi.DomainTransaction) error {
|
||||
for i, input := range transaction.Inputs {
|
||||
// It is safe to elide existence and index checks here since
|
||||
// they have already been checked prior to calling this
|
||||
// function.
|
||||
utxoEntry := input.UTXOEntry
|
||||
originScriptPubKey := utxoEntry.ScriptPublicKey()
|
||||
switch txscript.GetScriptClass(originScriptPubKey.Script) {
|
||||
case txscript.ScriptHashTy:
|
||||
numSigOps := txscript.GetPreciseSigOpCount(
|
||||
input.SignatureScript, originScriptPubKey, true)
|
||||
if numSigOps > maxStandardP2SHSigOps {
|
||||
str := fmt.Sprintf("transaction input #%d has %d signature operations which is more "+
|
||||
"than the allowed max amount of %d", i, numSigOps, maxStandardP2SHSigOps)
|
||||
return transactionRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
case txscript.NonStandardTy:
|
||||
str := fmt.Sprintf("transaction input #%d has a non-standard script form", i)
|
||||
return transactionRuleError(RejectNonstandard, str)
|
||||
}
|
||||
}
|
||||
|
||||
serializedSize := estimatedsize.TransactionEstimatedSerializedSize(transaction)
|
||||
minimumFee := mp.minimumRequiredTransactionRelayFee(serializedSize)
|
||||
if transaction.Fee < minimumFee {
|
||||
str := fmt.Sprintf("transaction %s has %d fees which is under the required amount of %d",
|
||||
consensushashing.TransactionID(transaction), transaction.Fee, minimumFee)
|
||||
return transactionRuleError(RejectInsufficientFee, str)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// minimumRequiredTransactionRelayFee returns the minimum transaction fee required for a
|
||||
// transaction with the passed serialized size to be accepted into the memory
|
||||
// pool and relayed.
|
||||
func (mp *mempool) minimumRequiredTransactionRelayFee(serializedSize uint64) uint64 {
|
||||
// Calculate the minimum fee for a transaction to be allowed into the
|
||||
// mempool and relayed by scaling the base fee. MinimumRelayTransactionFee is in
|
||||
// sompi/kB so multiply by serializedSize (which is in bytes) and
|
||||
// divide by 1000 to get minimum sompis.
|
||||
minimumFee := (serializedSize * uint64(mp.config.MinimumRelayTransactionFee)) / 1000
|
||||
|
||||
if minimumFee == 0 && mp.config.MinimumRelayTransactionFee > 0 {
|
||||
minimumFee = uint64(mp.config.MinimumRelayTransactionFee)
|
||||
}
|
||||
|
||||
// Set the minimum fee to the maximum possible value if the calculated
|
||||
// fee is not in the valid range for monetary amounts.
|
||||
if minimumFee > util.MaxSompi {
|
||||
minimumFee = util.MaxSompi
|
||||
}
|
||||
|
||||
return minimumFee
|
||||
}
|
349
domain/miningmanager/mempool/check_transaction_standard_test.go
Normal file
349
domain/miningmanager/mempool/check_transaction_standard_test.go
Normal file
@ -0,0 +1,349 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestCalcMinRequiredTxRelayFee(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // test description.
|
||||
size uint64 // Transaction size in bytes.
|
||||
minimumRelayTransactionFee util.Amount // minimum relay transaction fee.
|
||||
want uint64 // Expected fee.
|
||||
}{
|
||||
{
|
||||
// Ensure combination of size and fee that are less than 1000
|
||||
// produce a non-zero fee.
|
||||
"250 bytes with relay fee of 3",
|
||||
250,
|
||||
3,
|
||||
3,
|
||||
},
|
||||
{
|
||||
"100 bytes with default minimum relay fee",
|
||||
100,
|
||||
defaultMinimumRelayTransactionFee,
|
||||
100,
|
||||
},
|
||||
{
|
||||
"max standard tx size with default minimum relay fee",
|
||||
maximumStandardTransactionSize,
|
||||
defaultMinimumRelayTransactionFee,
|
||||
100000,
|
||||
},
|
||||
{
|
||||
"max standard tx size with max sompi relay fee",
|
||||
maximumStandardTransactionSize,
|
||||
util.MaxSompi,
|
||||
util.MaxSompi,
|
||||
},
|
||||
{
|
||||
"1500 bytes with 5000 relay fee",
|
||||
1500,
|
||||
5000,
|
||||
7500,
|
||||
},
|
||||
{
|
||||
"1500 bytes with 3000 relay fee",
|
||||
1500,
|
||||
3000,
|
||||
4500,
|
||||
},
|
||||
{
|
||||
"782 bytes with 5000 relay fee",
|
||||
782,
|
||||
5000,
|
||||
3910,
|
||||
},
|
||||
{
|
||||
"782 bytes with 3000 relay fee",
|
||||
782,
|
||||
3000,
|
||||
2346,
|
||||
},
|
||||
{
|
||||
"782 bytes with 2550 relay fee",
|
||||
782,
|
||||
2550,
|
||||
1994,
|
||||
},
|
||||
}
|
||||
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCalcMinRequiredTxRelayFee")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
for _, test := range tests {
|
||||
mempoolConfig := DefaultConfig(tc.DAGParams())
|
||||
mempoolConfig.MinimumRelayTransactionFee = test.minimumRelayTransactionFee
|
||||
mempool := New(mempoolConfig, tc).(*mempool)
|
||||
|
||||
got := mempool.minimumRequiredTransactionRelayFee(test.size)
|
||||
if got != test.want {
|
||||
t.Errorf("TestCalcMinRequiredTxRelayFee test '%s' "+
|
||||
"failed: got %v want %v", test.name, got,
|
||||
test.want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsTransactionOutputDust(t *testing.T) {
|
||||
scriptPublicKey := &externalapi.ScriptPublicKey{
|
||||
[]byte{0x76, 0xa9, 0x21, 0x03, 0x2f, 0x7e, 0x43,
|
||||
0x0a, 0xa4, 0xc9, 0xd1, 0x59, 0x43, 0x7e, 0x84, 0xb9,
|
||||
0x75, 0xdc, 0x76, 0xd9, 0x00, 0x3b, 0xf0, 0x92, 0x2c,
|
||||
0xf3, 0xaa, 0x45, 0x28, 0x46, 0x4b, 0xab, 0x78, 0x0d,
|
||||
0xba, 0x5e}, 0}
|
||||
|
||||
tests := []struct {
|
||||
name string // test description
|
||||
txOut externalapi.DomainTransactionOutput
|
||||
minimumRelayTransactionFee util.Amount // minimum relay transaction fee.
|
||||
isDust bool
|
||||
}{
|
||||
{
|
||||
// Any value is allowed with a zero relay fee.
|
||||
"zero value with zero relay fee",
|
||||
externalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: scriptPublicKey},
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Zero value is dust with any relay fee"
|
||||
"zero value with very small tx fee",
|
||||
externalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: scriptPublicKey},
|
||||
1,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"36 byte public key script with value 605",
|
||||
externalapi.DomainTransactionOutput{Value: 605, ScriptPublicKey: scriptPublicKey},
|
||||
1000,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"36 byte public key script with value 606",
|
||||
externalapi.DomainTransactionOutput{Value: 606, ScriptPublicKey: scriptPublicKey},
|
||||
1000,
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Maximum allowed value is never dust.
|
||||
"max sompi amount is never dust",
|
||||
externalapi.DomainTransactionOutput{Value: util.MaxSompi, ScriptPublicKey: scriptPublicKey},
|
||||
util.MaxSompi,
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Maximum uint64 value causes overflow.
|
||||
"maximum uint64 value",
|
||||
externalapi.DomainTransactionOutput{Value: math.MaxUint64, ScriptPublicKey: scriptPublicKey},
|
||||
math.MaxUint64,
|
||||
true,
|
||||
},
|
||||
{
|
||||
// Unspendable ScriptPublicKey due to an invalid public key
|
||||
// script.
|
||||
"unspendable ScriptPublicKey",
|
||||
externalapi.DomainTransactionOutput{Value: 5000, ScriptPublicKey: &externalapi.ScriptPublicKey{[]byte{0x01}, 0}},
|
||||
0, // no relay fee
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestIsTransactionOutputDust")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
for _, test := range tests {
|
||||
mempoolConfig := DefaultConfig(tc.DAGParams())
|
||||
mempoolConfig.MinimumRelayTransactionFee = test.minimumRelayTransactionFee
|
||||
mempool := New(mempoolConfig, tc).(*mempool)
|
||||
|
||||
res := mempool.IsTransactionOutputDust(&test.txOut)
|
||||
if res != test.isDust {
|
||||
t.Errorf("Dust test '%s' failed: want %v got %v",
|
||||
test.name, test.isDust, res)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckTransactionStandardInIsolation(t *testing.T) {
|
||||
// Create some dummy, but otherwise standard, data for transactions.
|
||||
prevOutTxID := &externalapi.DomainTransactionID{}
|
||||
dummyPrevOut := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1}
|
||||
dummySigScript := bytes.Repeat([]byte{0x00}, 65)
|
||||
dummyTxIn := externalapi.DomainTransactionInput{
|
||||
PreviousOutpoint: dummyPrevOut,
|
||||
SignatureScript: dummySigScript,
|
||||
Sequence: constants.MaxTxInSequenceNum,
|
||||
}
|
||||
addrHash := [32]byte{0x01}
|
||||
addr, err := util.NewAddressPublicKey(addrHash[:], util.Bech32PrefixKaspaTest)
|
||||
if err != nil {
|
||||
t.Fatalf("NewAddressPublicKey: unexpected error: %v", err)
|
||||
}
|
||||
dummyScriptPublicKey, err := txscript.PayToAddrScript(addr)
|
||||
if err != nil {
|
||||
t.Fatalf("PayToAddrScript: unexpected error: %v", err)
|
||||
}
|
||||
dummyTxOut := externalapi.DomainTransactionOutput{
|
||||
Value: 100000000, // 1 KAS
|
||||
ScriptPublicKey: dummyScriptPublicKey,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tx *externalapi.DomainTransaction
|
||||
height uint64
|
||||
isStandard bool
|
||||
code RejectCode
|
||||
}{
|
||||
{
|
||||
name: "Typical pay-to-pubkey transaction",
|
||||
tx: &externalapi.DomainTransaction{Version: 0, Inputs: []*externalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*externalapi.DomainTransactionOutput{&dummyTxOut}},
|
||||
height: 300000,
|
||||
isStandard: true,
|
||||
},
|
||||
{
|
||||
name: "Transaction version too high",
|
||||
tx: &externalapi.DomainTransaction{Version: constants.MaxTransactionVersion + 1, Inputs: []*externalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*externalapi.DomainTransactionOutput{&dummyTxOut}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Transaction size is too large",
|
||||
tx: &externalapi.DomainTransaction{Version: 0, Inputs: []*externalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*externalapi.DomainTransactionOutput{{
|
||||
Value: 0,
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{bytes.Repeat([]byte{0x00}, maximumStandardTransactionSize+1), 0},
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
{
|
||||
name: "Signature script size is too large",
|
||||
tx: &externalapi.DomainTransaction{Version: 0, Inputs: []*externalapi.DomainTransactionInput{{
|
||||
PreviousOutpoint: dummyPrevOut,
|
||||
SignatureScript: bytes.Repeat([]byte{0x00}, maximumStandardSignatureScriptSize+1),
|
||||
Sequence: constants.MaxTxInSequenceNum,
|
||||
}}, Outputs: []*externalapi.DomainTransactionOutput{&dummyTxOut}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
{
|
||||
name: "Valid but non standard public key script",
|
||||
tx: &externalapi.DomainTransaction{Version: 0, Inputs: []*externalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*externalapi.DomainTransactionOutput{{
|
||||
Value: 100000000,
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{[]byte{txscript.OpTrue}, 0},
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
{ //Todo : check on ScriptPublicKey type.
|
||||
name: "Dust output",
|
||||
tx: &externalapi.DomainTransaction{Version: 0, Inputs: []*externalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*externalapi.DomainTransactionOutput{{
|
||||
Value: 0,
|
||||
ScriptPublicKey: dummyScriptPublicKey,
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectDust,
|
||||
},
|
||||
{
|
||||
name: "Nulldata transaction",
|
||||
tx: &externalapi.DomainTransaction{Version: 0, Inputs: []*externalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*externalapi.DomainTransactionOutput{{
|
||||
Value: 0,
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{[]byte{txscript.OpReturn}, 0},
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
}
|
||||
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckTransactionStandardInIsolation")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
for _, test := range tests {
|
||||
mempoolConfig := DefaultConfig(tc.DAGParams())
|
||||
mempool := New(mempoolConfig, tc).(*mempool)
|
||||
|
||||
// Ensure standardness is as expected.
|
||||
err := mempool.checkTransactionStandardInIsolation(test.tx)
|
||||
if err == nil && test.isStandard {
|
||||
// Test passes since function returned standard for a
|
||||
// transaction which is intended to be standard.
|
||||
continue
|
||||
}
|
||||
if err == nil && !test.isStandard {
|
||||
t.Errorf("checkTransactionStandardInIsolation (%s): standard when "+
|
||||
"it should not be", test.name)
|
||||
continue
|
||||
}
|
||||
if err != nil && test.isStandard {
|
||||
t.Errorf("checkTransactionStandardInIsolation (%s): nonstandard "+
|
||||
"when it should not be: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure error type is a TxRuleError inside of a RuleError.
|
||||
var ruleErr RuleError
|
||||
if !errors.As(err, &ruleErr) {
|
||||
t.Errorf("checkTransactionStandardInIsolation (%s): unexpected "+
|
||||
"error type - got %T", test.name, err)
|
||||
continue
|
||||
}
|
||||
txRuleErr, ok := ruleErr.Err.(TxRuleError)
|
||||
if !ok {
|
||||
t.Errorf("checkTransactionStandardInIsolation (%s): unexpected "+
|
||||
"error type - got %T", test.name, ruleErr.Err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure the reject code is the expected one.
|
||||
if txRuleErr.RejectCode != test.code {
|
||||
t.Errorf("checkTransactionStandardInIsolation (%s): unexpected "+
|
||||
"error code - got %v, want %v", test.name,
|
||||
txRuleErr.RejectCode, test.code)
|
||||
continue
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
70
domain/miningmanager/mempool/config.go
Normal file
70
domain/miningmanager/mempool/config.go
Normal file
@ -0,0 +1,70 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaximumTransactionCount = 1_000_000
|
||||
|
||||
defaultTransactionExpireIntervalSeconds uint64 = 60
|
||||
defaultTransactionExpireScanIntervalSeconds uint64 = 10
|
||||
defaultOrphanExpireIntervalSeconds uint64 = 60
|
||||
defaultOrphanExpireScanIntervalSeconds uint64 = 10
|
||||
|
||||
defaultMaximumOrphanTransactionSize = 100000
|
||||
// defaultMaximumOrphanTransactionCount should remain small as long as we have recursion in
|
||||
// removeOrphans when removeRedeemers = true
|
||||
defaultMaximumOrphanTransactionCount = 50
|
||||
|
||||
defaultMinimumRelayTransactionFee = util.Amount(1000)
|
||||
|
||||
// Standard transaction version range might be different from what consensus accepts, therefore
|
||||
// we define separate values in mempool.
|
||||
// However, currently there's exactly one transaction version, so mempool accepts the same version
|
||||
// as consensus.
|
||||
defaultMinimumStandardTransactionVersion = constants.MaxTransactionVersion
|
||||
defaultMaximumStandardTransactionVersion = constants.MaxTransactionVersion
|
||||
)
|
||||
|
||||
// Config represents a mempool configuration
|
||||
type Config struct {
|
||||
MaximumTransactionCount uint64
|
||||
TransactionExpireIntervalDAAScore uint64
|
||||
TransactionExpireScanIntervalDAAScore uint64
|
||||
OrphanExpireIntervalDAAScore uint64
|
||||
OrphanExpireScanIntervalDAAScore uint64
|
||||
MaximumOrphanTransactionSize uint64
|
||||
MaximumOrphanTransactionCount uint64
|
||||
AcceptNonStandard bool
|
||||
MaximumMassAcceptedByBlock uint64
|
||||
MinimumRelayTransactionFee util.Amount
|
||||
MinimumStandardTransactionVersion uint16
|
||||
MaximumStandardTransactionVersion uint16
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default mempool configuration
|
||||
func DefaultConfig(dagParams *dagconfig.Params) *Config {
|
||||
targetBlocksPerSecond := uint64(time.Second / dagParams.TargetTimePerBlock)
|
||||
|
||||
return &Config{
|
||||
MaximumTransactionCount: defaultMaximumTransactionCount,
|
||||
TransactionExpireIntervalDAAScore: defaultTransactionExpireIntervalSeconds / targetBlocksPerSecond,
|
||||
TransactionExpireScanIntervalDAAScore: defaultTransactionExpireScanIntervalSeconds / targetBlocksPerSecond,
|
||||
OrphanExpireIntervalDAAScore: defaultOrphanExpireIntervalSeconds / targetBlocksPerSecond,
|
||||
OrphanExpireScanIntervalDAAScore: defaultOrphanExpireScanIntervalSeconds / targetBlocksPerSecond,
|
||||
MaximumOrphanTransactionSize: defaultMaximumOrphanTransactionSize,
|
||||
MaximumOrphanTransactionCount: defaultMaximumOrphanTransactionCount,
|
||||
AcceptNonStandard: dagParams.RelayNonStdTxs,
|
||||
MaximumMassAcceptedByBlock: dagParams.MaxMassAcceptedByBlock,
|
||||
MinimumRelayTransactionFee: defaultMinimumRelayTransactionFee,
|
||||
MinimumStandardTransactionVersion: defaultMinimumStandardTransactionVersion,
|
||||
MaximumStandardTransactionVersion: defaultMaximumStandardTransactionVersion,
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
Package mempool provides a policy-enforced pool of unmined kaspa transactions.
|
||||
|
||||
A key responsbility of the kaspa network is mining user-generated transactions
|
||||
into blocks. In order to facilitate this, the mining process relies on having a
|
||||
readily-available source of transactions to include in a block that is being
|
||||
solved.
|
||||
|
||||
At a high level, this package satisfies that requirement by providing an
|
||||
in-memory pool of fully validated transactions that can also optionally be
|
||||
further filtered based upon a configurable policy.
|
||||
|
||||
One of the policy configuration options controls whether or not "standard"
|
||||
transactions are accepted. In essence, a "standard" transaction is one that
|
||||
satisfies a fairly strict set of requirements that are largely intended to help
|
||||
provide fair use of the system to all users. It is important to note that what
|
||||
is considered a "standard" transaction changes over time. For some insight, at
|
||||
the time of this writing, an example of SOME of the criteria that are required
|
||||
for a transaction to be considered standard are that it is of the most-recently
|
||||
supported version, finalized, does not exceed a specific size, and only consists
|
||||
of specific script forms.
|
||||
|
||||
Since this package does not deal with other kaspa specifics such as network
|
||||
communication and transaction relay, it returns a list of transactions that were
|
||||
accepted which gives the caller a high level of flexibility in how they want to
|
||||
proceed. Typically, this will involve things such as relaying the transactions
|
||||
to other peers on the network and notifying the mining process that new
|
||||
transactions are available.
|
||||
|
||||
Feature Overview
|
||||
|
||||
The following is a quick overview of the major features. It is not intended to
|
||||
be an exhaustive list.
|
||||
|
||||
- Maintain a pool of fully validated transactions
|
||||
- Reject non-fully-spent duplicate transactions
|
||||
- Reject coinbase transactions
|
||||
- Reject double spends (both from the DAG and other transactions in pool)
|
||||
- Reject invalid transactions according to the network consensus rules
|
||||
- Full script execution and validation with signature cache support
|
||||
- Individual transaction query support
|
||||
- Orphan transaction support (transactions that spend from unknown outputs)
|
||||
- Configurable limits (see transaction acceptance policy)
|
||||
- Automatic addition of orphan transactions that are no longer orphans as new
|
||||
transactions are added to the pool
|
||||
- Individual orphan transaction query support
|
||||
- Configurable transaction acceptance policy
|
||||
- Option to accept or reject standard transactions
|
||||
- Option to accept or reject transactions based on priority calculations
|
||||
- Max signature operations per transaction
|
||||
- Max number of orphan transactions allowed
|
||||
- Additional metadata tracking for each transaction
|
||||
- Timestamp when the transaction was added to the pool
|
||||
- The fee the transaction pays
|
||||
- The starting priority for the transaction
|
||||
- Manual control of transaction removal
|
||||
- Recursive removal of all dependent transactions
|
||||
|
||||
Errors
|
||||
|
||||
Errors returned by this package are either the raw errors provided by underlying
|
||||
calls or of type mempool.RuleError. Since there are two classes of rules
|
||||
(mempool acceptance rules and blockDAG (consensus) acceptance rules), the
|
||||
mempool.RuleError type contains a single Err field which will, in turn, either
|
||||
be a mempool.TxRuleError or a ruleerrors.RuleError. The first indicates a
|
||||
violation of mempool acceptance rules while the latter indicates a violation of
|
||||
consensus acceptance rules. This allows the caller to easily differentiate
|
||||
between unexpected errors, such as database errors, versus errors due to rule
|
||||
violations through type assertions. In addition, callers can programmatically
|
||||
determine the specific rule violation by type asserting the Err field to one of
|
||||
the aforementioned types and examining their underlying ErrorCode field.
|
||||
*/
|
||||
package mempool
|
@ -50,6 +50,7 @@ const (
|
||||
RejectFinality RejectCode = 0x43
|
||||
RejectDifficulty RejectCode = 0x44
|
||||
RejectImmatureSpend RejectCode = 0x45
|
||||
RejectBadOrphan RejectCode = 0x64
|
||||
)
|
||||
|
||||
// Map of reject codes back strings for pretty printing.
|
||||
@ -58,13 +59,14 @@ var rejectCodeStrings = map[RejectCode]string{
|
||||
RejectInvalid: "REJECT_INVALID",
|
||||
RejectObsolete: "REJECT_OBSOLETE",
|
||||
RejectDuplicate: "REJECT_DUPLICATE",
|
||||
RejectNonstandard: "REJECT_NONSTANDARD",
|
||||
RejectNonstandard: "REJECT_NON_STANDARD",
|
||||
RejectDust: "REJECT_DUST",
|
||||
RejectInsufficientFee: "REJECT_INSUFFICIENTFEE",
|
||||
RejectInsufficientFee: "REJECT_INSUFFICIENT_FEE",
|
||||
RejectFinality: "REJECT_FINALITY",
|
||||
RejectDifficulty: "REJECT_DIFFICULTY",
|
||||
RejectNotRequested: "REJECT_NOTREQUESTED",
|
||||
RejectImmatureSpend: "REJECT_IMMATURESPEND",
|
||||
RejectNotRequested: "REJECT_NOT_REQUESTED",
|
||||
RejectImmatureSpend: "REJECT_IMMATURE_SPEND",
|
||||
RejectBadOrphan: "REJECT_BAD_ORPHAN",
|
||||
}
|
||||
|
||||
// String returns the RejectCode in human-readable form.
|
||||
@ -91,12 +93,10 @@ func (e TxRuleError) Error() string {
|
||||
return e.Description
|
||||
}
|
||||
|
||||
// txRuleError creates an underlying TxRuleError with the given a set of
|
||||
// transactionRuleError creates an underlying TxRuleError with the given a set of
|
||||
// arguments and returns a RuleError that encapsulates it.
|
||||
func txRuleError(c RejectCode, desc string) RuleError {
|
||||
return RuleError{
|
||||
Err: TxRuleError{RejectCode: c, Description: desc},
|
||||
}
|
||||
func transactionRuleError(c RejectCode, desc string) RuleError {
|
||||
return newRuleError(TxRuleError{RejectCode: c, Description: desc})
|
||||
}
|
||||
|
||||
func newRuleError(err error) RuleError {
|
||||
|
@ -0,0 +1,47 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (mp *mempool) fillInputsAndGetMissingParents(transaction *externalapi.DomainTransaction) (
|
||||
parents model.OutpointToTransactionMap, missingOutpoints []*externalapi.DomainOutpoint, err error) {
|
||||
|
||||
parentsInPool := mp.transactionsPool.getParentTransactionsInPool(transaction)
|
||||
|
||||
fillInputs(transaction, parentsInPool)
|
||||
|
||||
err = mp.consensus.ValidateTransactionAndPopulateWithConsensusData(transaction)
|
||||
if err != nil {
|
||||
errMissingOutpoints := ruleerrors.ErrMissingTxOut{}
|
||||
if errors.As(err, &errMissingOutpoints) {
|
||||
return parentsInPool, errMissingOutpoints.MissingOutpoints, nil
|
||||
}
|
||||
if errors.Is(err, ruleerrors.ErrImmatureSpend) {
|
||||
return nil, nil, transactionRuleError(
|
||||
RejectImmatureSpend, "one of the transaction inputs spends an immature UTXO")
|
||||
}
|
||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||
return nil, nil, newRuleError(err)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return parentsInPool, nil, nil
|
||||
}
|
||||
|
||||
func fillInputs(transaction *externalapi.DomainTransaction, parentsInPool model.OutpointToTransactionMap) {
|
||||
for _, input := range transaction.Inputs {
|
||||
parent, ok := parentsInPool[input.PreviousOutpoint]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
relevantOutput := parent.Transaction().Outputs[input.PreviousOutpoint.Index]
|
||||
input.UTXOEntry = utxo.NewUTXOEntry(relevantOutput.Value, relevantOutput.ScriptPublicKey,
|
||||
false, model.UnacceptedDAAScore)
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
)
|
||||
|
||||
func (mp *mempool) handleNewBlockTransactions(blockTransactions []*externalapi.DomainTransaction) (
|
||||
[]*externalapi.DomainTransaction, error) {
|
||||
|
||||
// Skip the coinbase transaction
|
||||
blockTransactions = blockTransactions[transactionhelper.CoinbaseTransactionIndex+1:]
|
||||
|
||||
acceptedOrphans := []*externalapi.DomainTransaction{}
|
||||
for _, transaction := range blockTransactions {
|
||||
transactionID := consensushashing.TransactionID(transaction)
|
||||
err := mp.removeTransaction(transactionID, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = mp.removeDoubleSpends(transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = mp.orphansPool.removeOrphan(transactionID, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acceptedOrphansFromThisTransaction, err := mp.orphansPool.processOrphansAfterAcceptedTransaction(transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acceptedOrphans = append(acceptedOrphans, acceptedOrphansFromThisTransaction...)
|
||||
}
|
||||
err := mp.orphansPool.expireOrphanTransactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = mp.transactionsPool.expireOldTransactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return acceptedOrphans, nil
|
||||
}
|
||||
|
||||
func (mp *mempool) removeDoubleSpends(transaction *externalapi.DomainTransaction) error {
|
||||
for _, input := range transaction.Inputs {
|
||||
if redeemer, ok := mp.mempoolUTXOSet.transactionByPreviousOutpoint[input.PreviousOutpoint]; ok {
|
||||
err := mp.removeTransaction(redeemer.TransactionID(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
80
domain/miningmanager/mempool/mempool_utxo_set.go
Normal file
80
domain/miningmanager/mempool/mempool_utxo_set.go
Normal file
@ -0,0 +1,80 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||
)
|
||||
|
||||
type mempoolUTXOSet struct {
|
||||
mempool *mempool
|
||||
poolUnspentOutputs model.OutpointToUTXOEntryMap
|
||||
transactionByPreviousOutpoint model.OutpointToTransactionMap
|
||||
}
|
||||
|
||||
func newMempoolUTXOSet(mp *mempool) *mempoolUTXOSet {
|
||||
return &mempoolUTXOSet{
|
||||
mempool: mp,
|
||||
poolUnspentOutputs: model.OutpointToUTXOEntryMap{},
|
||||
transactionByPreviousOutpoint: model.OutpointToTransactionMap{},
|
||||
}
|
||||
}
|
||||
|
||||
func (mpus *mempoolUTXOSet) addTransaction(transaction *model.MempoolTransaction) {
|
||||
outpoint := &externalapi.DomainOutpoint{TransactionID: *transaction.TransactionID()}
|
||||
|
||||
for i, input := range transaction.Transaction().Inputs {
|
||||
outpoint.Index = uint32(i)
|
||||
|
||||
// Delete the output this input spends, in case it was created by mempool.
|
||||
// If the outpoint doesn't exist in mpus.poolUnspentOutputs - this means
|
||||
// it was created in the DAG (a.k.a. in consensus).
|
||||
delete(mpus.poolUnspentOutputs, *outpoint)
|
||||
|
||||
mpus.transactionByPreviousOutpoint[input.PreviousOutpoint] = transaction
|
||||
}
|
||||
|
||||
for i, output := range transaction.Transaction().Outputs {
|
||||
outpoint := externalapi.DomainOutpoint{TransactionID: *transaction.TransactionID(), Index: uint32(i)}
|
||||
|
||||
mpus.poolUnspentOutputs[outpoint] =
|
||||
utxo.NewUTXOEntry(output.Value, output.ScriptPublicKey, false, model.UnacceptedDAAScore)
|
||||
}
|
||||
}
|
||||
|
||||
func (mpus *mempoolUTXOSet) removeTransaction(transaction *model.MempoolTransaction) {
|
||||
for _, input := range transaction.Transaction().Inputs {
|
||||
// If the transaction creating the output spent by this input is in the mempool - restore it's UTXO
|
||||
if _, ok := mpus.mempool.transactionsPool.getTransaction(&input.PreviousOutpoint.TransactionID); ok {
|
||||
mpus.poolUnspentOutputs[input.PreviousOutpoint] = input.UTXOEntry
|
||||
}
|
||||
delete(mpus.transactionByPreviousOutpoint, input.PreviousOutpoint)
|
||||
}
|
||||
|
||||
outpoint := externalapi.DomainOutpoint{TransactionID: *transaction.TransactionID()}
|
||||
for i := range transaction.Transaction().Outputs {
|
||||
outpoint.Index = uint32(i)
|
||||
|
||||
delete(mpus.poolUnspentOutputs, outpoint)
|
||||
}
|
||||
}
|
||||
|
||||
func (mpus *mempoolUTXOSet) checkDoubleSpends(transaction *externalapi.DomainTransaction) error {
|
||||
outpoint := externalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(transaction)}
|
||||
|
||||
for i, input := range transaction.Inputs {
|
||||
outpoint.Index = uint32(i)
|
||||
|
||||
if existingTransaction, exists := mpus.transactionByPreviousOutpoint[input.PreviousOutpoint]; exists {
|
||||
str := fmt.Sprintf("output %s already spent by transaction %s in the memory pool",
|
||||
input.PreviousOutpoint, existingTransaction.TransactionID())
|
||||
return transactionRuleError(RejectDuplicate, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
|
||||
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const unacceptedDAAScore = math.MaxUint64
|
||||
|
||||
func newMempoolUTXOSet() *mempoolUTXOSet {
|
||||
return &mempoolUTXOSet{
|
||||
transactionByPreviousOutpoint: make(map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.DomainTransaction),
|
||||
poolUnspentOutputs: make(map[consensusexternalapi.DomainOutpoint]consensusexternalapi.UTXOEntry),
|
||||
}
|
||||
}
|
||||
|
||||
type mempoolUTXOSet struct {
|
||||
transactionByPreviousOutpoint map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.DomainTransaction
|
||||
poolUnspentOutputs map[consensusexternalapi.DomainOutpoint]consensusexternalapi.UTXOEntry
|
||||
}
|
||||
|
||||
// Populate UTXO Entries in the transaction, to allow chained txs.
|
||||
func (mpus *mempoolUTXOSet) populateUTXOEntries(tx *consensusexternalapi.DomainTransaction) (parentsInPool []consensusexternalapi.DomainOutpoint) {
|
||||
for _, txIn := range tx.Inputs {
|
||||
if utxoEntry, exists := mpus.poolUnspentOutputs[txIn.PreviousOutpoint]; exists {
|
||||
txIn.UTXOEntry = utxoEntry
|
||||
parentsInPool = append(parentsInPool, txIn.PreviousOutpoint)
|
||||
}
|
||||
}
|
||||
return parentsInPool
|
||||
}
|
||||
|
||||
func (mpus *mempoolUTXOSet) checkExists(tx *consensusexternalapi.DomainTransaction) bool {
|
||||
// Check if it was already spent.
|
||||
for _, txIn := range tx.Inputs {
|
||||
if _, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; exists {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it creates an already existing UTXO
|
||||
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx)}
|
||||
for i := range tx.Outputs {
|
||||
outpoint.Index = uint32(i)
|
||||
if _, exists := mpus.poolUnspentOutputs[outpoint]; exists {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// addTx adds a transaction to the mempool UTXO set. It assumes that it doesn't double spend another transaction
|
||||
// in the mempool, and that its outputs doesn't exist in the mempool UTXO set, and returns error otherwise.
|
||||
func (mpus *mempoolUTXOSet) addTx(tx *consensusexternalapi.DomainTransaction) error {
|
||||
for _, txIn := range tx.Inputs {
|
||||
if existingTx, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; exists {
|
||||
return errors.Errorf("outpoint %s is already used by %s", txIn.PreviousOutpoint, consensushashing.TransactionID(existingTx))
|
||||
}
|
||||
mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint] = tx
|
||||
}
|
||||
|
||||
for i, txOut := range tx.Outputs {
|
||||
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx), Index: uint32(i)}
|
||||
if _, exists := mpus.poolUnspentOutputs[outpoint]; exists {
|
||||
return errors.Errorf("outpoint %s already exists", outpoint)
|
||||
}
|
||||
mpus.poolUnspentOutputs[outpoint] =
|
||||
utxo.NewUTXOEntry(txOut.Value, txOut.ScriptPublicKey, false, unacceptedDAAScore)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// removeTx removes a transaction to the mempool UTXO set.
|
||||
// Note: it doesn't re-add its previous outputs to the mempool UTXO set.
|
||||
func (mpus *mempoolUTXOSet) removeTx(tx *consensusexternalapi.DomainTransaction) error {
|
||||
for _, txIn := range tx.Inputs {
|
||||
if _, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; !exists {
|
||||
return errors.Errorf("outpoint %s doesn't exist", txIn.PreviousOutpoint)
|
||||
}
|
||||
delete(mpus.transactionByPreviousOutpoint, txIn.PreviousOutpoint)
|
||||
}
|
||||
|
||||
outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx)}
|
||||
for i := range tx.Outputs {
|
||||
outpoint.Index = uint32(i)
|
||||
if _, exists := mpus.poolUnspentOutputs[outpoint]; !exists {
|
||||
return errors.Errorf("outpoint %s doesn't exist", outpoint)
|
||||
}
|
||||
delete(mpus.poolUnspentOutputs, outpoint)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mpus *mempoolUTXOSet) poolTransactionBySpendingOutpoint(outpoint consensusexternalapi.DomainOutpoint) (*consensusexternalapi.DomainTransaction, bool) {
|
||||
tx, exists := mpus.transactionByPreviousOutpoint[outpoint]
|
||||
return tx, exists
|
||||
}
|
6
domain/miningmanager/mempool/model/constants.go
Normal file
6
domain/miningmanager/mempool/model/constants.go
Normal file
@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
import "math"
|
||||
|
||||
// UnacceptedDAAScore is used to for UTXOEntries that were created by transactions in the mempool.
|
||||
const UnacceptedDAAScore = math.MaxUint64
|
14
domain/miningmanager/mempool/model/map_types.go
Normal file
14
domain/miningmanager/mempool/model/map_types.go
Normal file
@ -0,0 +1,14 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
)
|
||||
|
||||
// IDToTransactionMap maps transactionID to a MempoolTransaction
|
||||
type IDToTransactionMap map[externalapi.DomainTransactionID]*MempoolTransaction
|
||||
|
||||
// OutpointToUTXOEntryMap maps an outpoint to a UTXOEntry
|
||||
type OutpointToUTXOEntryMap map[externalapi.DomainOutpoint]externalapi.UTXOEntry
|
||||
|
||||
// OutpointToTransactionMap maps an outpoint to a MempoolTransaction
|
||||
type OutpointToTransactionMap map[externalapi.DomainOutpoint]*MempoolTransaction
|
54
domain/miningmanager/mempool/model/mempool_transaction.go
Normal file
54
domain/miningmanager/mempool/model/mempool_transaction.go
Normal file
@ -0,0 +1,54 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
)
|
||||
|
||||
// MempoolTransaction represents a transaction inside the main TransactionPool
|
||||
type MempoolTransaction struct {
|
||||
transaction *externalapi.DomainTransaction
|
||||
parentTransactionsInPool OutpointToTransactionMap
|
||||
isHighPriority bool
|
||||
addedAtDAAScore uint64
|
||||
}
|
||||
|
||||
// NewMempoolTransaction constructs a new MempoolTransaction
|
||||
func NewMempoolTransaction(
|
||||
transaction *externalapi.DomainTransaction,
|
||||
parentTransactionsInPool OutpointToTransactionMap,
|
||||
isHighPriority bool,
|
||||
addedAtDAAScore uint64,
|
||||
) *MempoolTransaction {
|
||||
return &MempoolTransaction{
|
||||
transaction: transaction,
|
||||
parentTransactionsInPool: parentTransactionsInPool,
|
||||
isHighPriority: isHighPriority,
|
||||
addedAtDAAScore: addedAtDAAScore,
|
||||
}
|
||||
}
|
||||
|
||||
// TransactionID returns the ID of this MempoolTransaction
|
||||
func (mt *MempoolTransaction) TransactionID() *externalapi.DomainTransactionID {
|
||||
return consensushashing.TransactionID(mt.transaction)
|
||||
}
|
||||
|
||||
// Transaction return the DomainTransaction associated with this MempoolTransaction:
|
||||
func (mt *MempoolTransaction) Transaction() *externalapi.DomainTransaction {
|
||||
return mt.transaction
|
||||
}
|
||||
|
||||
// ParentTransactionsInPool a list of parent transactions that exist in the mempool, indexed by outpoint
|
||||
func (mt *MempoolTransaction) ParentTransactionsInPool() OutpointToTransactionMap {
|
||||
return mt.parentTransactionsInPool
|
||||
}
|
||||
|
||||
// IsHighPriority returns whether this MempoolTransaction is a high-priority one
|
||||
func (mt *MempoolTransaction) IsHighPriority() bool {
|
||||
return mt.isHighPriority
|
||||
}
|
||||
|
||||
// AddedAtDAAScore returns the virtual DAA score at which this MempoolTransaction was added to the mempool
|
||||
func (mt *MempoolTransaction) AddedAtDAAScore() uint64 {
|
||||
return mt.addedAtDAAScore
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// TransactionsOrderedByFeeRate represents a set of MempoolTransactions ordered by their fee / mass rate
|
||||
type TransactionsOrderedByFeeRate struct {
|
||||
slice []*MempoolTransaction
|
||||
}
|
||||
|
||||
// GetByIndex returns the transaction in the given index
|
||||
func (tobf *TransactionsOrderedByFeeRate) GetByIndex(index int) *MempoolTransaction {
|
||||
return tobf.slice[index]
|
||||
}
|
||||
|
||||
// Push inserts a transaction into the set, placing it in the correct place to preserve order
|
||||
func (tobf *TransactionsOrderedByFeeRate) Push(transaction *MempoolTransaction) error {
|
||||
index, err := tobf.findTransactionIndex(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tobf.slice = append(tobf.slice[:index],
|
||||
append([]*MempoolTransaction{transaction}, tobf.slice[index:]...)...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes the given transaction from the set.
|
||||
// Returns an error if transaction does not exist in the set, or if the given transaction does not have mass
|
||||
// and fee filled in.
|
||||
func (tobf *TransactionsOrderedByFeeRate) Remove(transaction *MempoolTransaction) error {
|
||||
index, err := tobf.findTransactionIndex(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txID := transaction.TransactionID()
|
||||
if !tobf.slice[index].TransactionID().Equal(txID) {
|
||||
return errors.Errorf("Couldn't find %s in mp.orderedTransactionsByFeeRate", txID)
|
||||
}
|
||||
|
||||
return tobf.RemoveAtIndex(index)
|
||||
}
|
||||
|
||||
// RemoveAtIndex removes the transaction at the given index.
|
||||
// Returns an error in case of out-of-bounds index.
|
||||
func (tobf *TransactionsOrderedByFeeRate) RemoveAtIndex(index int) error {
|
||||
if index < 0 || index > len(tobf.slice)-1 {
|
||||
return errors.Errorf("Index %d is out of bound of this TransactionsOrderedByFeeRate", index)
|
||||
}
|
||||
tobf.slice = append(tobf.slice[:index], tobf.slice[index+1:]...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tobf *TransactionsOrderedByFeeRate) findTransactionIndex(transaction *MempoolTransaction) (int, error) {
|
||||
if transaction.Transaction().Fee == 0 || transaction.Transaction().Mass == 0 {
|
||||
return 0, errors.Errorf("findTxIndexInOrderedTransactionsByFeeRate expects a transaction with " +
|
||||
"populated fee and mass")
|
||||
}
|
||||
txID := transaction.TransactionID()
|
||||
txFeeRate := float64(transaction.Transaction().Fee) / float64(transaction.Transaction().Mass)
|
||||
|
||||
return sort.Search(len(tobf.slice), func(i int) bool {
|
||||
iElement := tobf.slice[i]
|
||||
elementFeeRate := float64(iElement.Transaction().Fee) / float64(iElement.Transaction().Mass)
|
||||
if elementFeeRate > txFeeRate {
|
||||
return true
|
||||
}
|
||||
|
||||
if elementFeeRate == txFeeRate && txID.LessOrEqual(iElement.TransactionID()) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}), nil
|
||||
}
|
46
domain/miningmanager/mempool/model/orphan_transaction.go
Normal file
46
domain/miningmanager/mempool/model/orphan_transaction.go
Normal file
@ -0,0 +1,46 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
)
|
||||
|
||||
// OrphanTransaction represents a transaction in the OrphanPool
|
||||
type OrphanTransaction struct {
|
||||
transaction *externalapi.DomainTransaction
|
||||
isHighPriority bool
|
||||
addedAtDAAScore uint64
|
||||
}
|
||||
|
||||
// NewOrphanTransaction constructs a new OrphanTransaction
|
||||
func NewOrphanTransaction(
|
||||
transaction *externalapi.DomainTransaction,
|
||||
isHighPriority bool,
|
||||
addedAtDAAScore uint64,
|
||||
) *OrphanTransaction {
|
||||
return &OrphanTransaction{
|
||||
transaction: transaction,
|
||||
isHighPriority: isHighPriority,
|
||||
addedAtDAAScore: addedAtDAAScore,
|
||||
}
|
||||
}
|
||||
|
||||
// TransactionID returns the ID of this OrphanTransaction
|
||||
func (ot *OrphanTransaction) TransactionID() *externalapi.DomainTransactionID {
|
||||
return consensushashing.TransactionID(ot.transaction)
|
||||
}
|
||||
|
||||
// Transaction return the DomainTransaction associated with this OrphanTransaction:
|
||||
func (ot *OrphanTransaction) Transaction() *externalapi.DomainTransaction {
|
||||
return ot.transaction
|
||||
}
|
||||
|
||||
// IsHighPriority returns whether this OrphanTransaction is a high-priority one
|
||||
func (ot *OrphanTransaction) IsHighPriority() bool {
|
||||
return ot.isHighPriority
|
||||
}
|
||||
|
||||
// AddedAtDAAScore returns the virtual DAA score at which this OrphanTransaction was added to the mempool
|
||||
func (ot *OrphanTransaction) AddedAtDAAScore() uint64 {
|
||||
return ot.addedAtDAAScore
|
||||
}
|
9
domain/miningmanager/mempool/model/transaction.go
Normal file
9
domain/miningmanager/mempool/model/transaction.go
Normal file
@ -0,0 +1,9 @@
|
||||
package model
|
||||
|
||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
// Transaction represents a generic transaction either in the mempool's main TransactionPool or OrphanPool
|
||||
type Transaction interface {
|
||||
TransactionID() *externalapi.DomainTransactionID
|
||||
Transaction() *externalapi.DomainTransaction
|
||||
}
|
332
domain/miningmanager/mempool/orphan_pool.go
Normal file
332
domain/miningmanager/mempool/orphan_pool.go
Normal file
@ -0,0 +1,332 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type idToOrphanMap map[externalapi.DomainTransactionID]*model.OrphanTransaction
|
||||
type previousOutpointToOrphanMap map[externalapi.DomainOutpoint]*model.OrphanTransaction
|
||||
|
||||
type orphansPool struct {
|
||||
mempool *mempool
|
||||
allOrphans idToOrphanMap
|
||||
orphansByPreviousOutpoint previousOutpointToOrphanMap
|
||||
lastExpireScan uint64
|
||||
}
|
||||
|
||||
func newOrphansPool(mp *mempool) *orphansPool {
|
||||
return &orphansPool{
|
||||
mempool: mp,
|
||||
allOrphans: idToOrphanMap{},
|
||||
orphansByPreviousOutpoint: previousOutpointToOrphanMap{},
|
||||
lastExpireScan: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (op *orphansPool) maybeAddOrphan(transaction *externalapi.DomainTransaction, isHighPriority bool) error {
|
||||
if op.mempool.config.MaximumOrphanTransactionCount == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := op.checkOrphanDuplicate(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = op.checkOrphanSize(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = op.checkOrphanDoubleSpend(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = op.addOrphan(transaction, isHighPriority)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = op.limitOrphanPoolSize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) limitOrphanPoolSize() error {
|
||||
for uint64(len(op.allOrphans)) > op.mempool.config.MaximumOrphanTransactionCount {
|
||||
orphanToRemove := op.randomNonHighPriorityOrphan()
|
||||
if orphanToRemove == nil { // this means all orphans are HighPriority
|
||||
log.Warnf(
|
||||
"Number of high-priority transactions in orphanPool (%d) is higher than maximum allowed (%d)",
|
||||
len(op.allOrphans),
|
||||
op.mempool.config.MaximumOrphanTransactionCount)
|
||||
break
|
||||
}
|
||||
|
||||
// Don't remove redeemers in the case of a random eviction since the evicted transaction is
|
||||
// not invalid, therefore it's redeemers are as good as any orphan that just arrived.
|
||||
err := op.removeOrphan(orphanToRemove.TransactionID(), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) checkOrphanSize(transaction *externalapi.DomainTransaction) error {
|
||||
serializedLength := estimatedsize.TransactionEstimatedSerializedSize(transaction)
|
||||
if serializedLength > op.mempool.config.MaximumOrphanTransactionSize {
|
||||
str := fmt.Sprintf("orphan transaction size of %d bytes is "+
|
||||
"larger than max allowed size of %d bytes",
|
||||
serializedLength, op.mempool.config.MaximumOrphanTransactionSize)
|
||||
return transactionRuleError(RejectBadOrphan, str)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) checkOrphanDuplicate(transaction *externalapi.DomainTransaction) error {
|
||||
if _, ok := op.allOrphans[*consensushashing.TransactionID(transaction)]; ok {
|
||||
str := fmt.Sprintf("Orphan transacion %s is already in the orphan pool",
|
||||
consensushashing.TransactionID(transaction))
|
||||
return transactionRuleError(RejectDuplicate, str)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) checkOrphanDoubleSpend(transaction *externalapi.DomainTransaction) error {
|
||||
for _, input := range transaction.Inputs {
|
||||
if doubleSpendOrphan, ok := op.orphansByPreviousOutpoint[input.PreviousOutpoint]; ok {
|
||||
str := fmt.Sprintf("Orphan transacion %s is double spending an input from already existing orphan %s",
|
||||
consensushashing.TransactionID(transaction), doubleSpendOrphan.TransactionID())
|
||||
return transactionRuleError(RejectDuplicate, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) addOrphan(transaction *externalapi.DomainTransaction, isHighPriority bool) error {
|
||||
virtualDAAScore, err := op.mempool.consensus.GetVirtualDAAScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
orphanTransaction := model.NewOrphanTransaction(transaction, isHighPriority, virtualDAAScore)
|
||||
|
||||
op.allOrphans[*orphanTransaction.TransactionID()] = orphanTransaction
|
||||
for _, input := range transaction.Inputs {
|
||||
if input.UTXOEntry == nil {
|
||||
op.orphansByPreviousOutpoint[input.PreviousOutpoint] = orphanTransaction
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) processOrphansAfterAcceptedTransaction(acceptedTransaction *externalapi.DomainTransaction) (
|
||||
acceptedOrphans []*externalapi.DomainTransaction, err error) {
|
||||
|
||||
acceptedOrphans = []*externalapi.DomainTransaction{}
|
||||
queue := []*externalapi.DomainTransaction{acceptedTransaction}
|
||||
|
||||
for len(queue) > 0 {
|
||||
var current *externalapi.DomainTransaction
|
||||
current, queue = queue[0], queue[1:]
|
||||
|
||||
currentTransactionID := consensushashing.TransactionID(current)
|
||||
outpoint := externalapi.DomainOutpoint{TransactionID: *currentTransactionID}
|
||||
for i, output := range current.Outputs {
|
||||
outpoint.Index = uint32(i)
|
||||
orphan, ok := op.orphansByPreviousOutpoint[outpoint]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, input := range orphan.Transaction().Inputs {
|
||||
if input.PreviousOutpoint.Equal(&outpoint) {
|
||||
input.UTXOEntry = utxo.NewUTXOEntry(output.Value, output.ScriptPublicKey, false,
|
||||
model.UnacceptedDAAScore)
|
||||
break
|
||||
}
|
||||
}
|
||||
if countUnfilledInputs(orphan) == 0 {
|
||||
err := op.unorphanTransaction(orphan)
|
||||
if err != nil {
|
||||
if errors.As(err, &RuleError{}) {
|
||||
log.Infof("Failed to unorphan transaction %s due to rule error: %s",
|
||||
currentTransactionID, err)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
acceptedOrphans = append(acceptedOrphans, orphan.Transaction())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return acceptedOrphans, nil
|
||||
}
|
||||
|
||||
func countUnfilledInputs(orphan *model.OrphanTransaction) int {
|
||||
unfilledInputs := 0
|
||||
for _, input := range orphan.Transaction().Inputs {
|
||||
if input.UTXOEntry == nil {
|
||||
unfilledInputs++
|
||||
}
|
||||
}
|
||||
return unfilledInputs
|
||||
}
|
||||
|
||||
func (op *orphansPool) unorphanTransaction(transaction *model.OrphanTransaction) error {
|
||||
err := op.removeOrphan(transaction.TransactionID(), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = op.mempool.consensus.ValidateTransactionAndPopulateWithConsensusData(transaction.Transaction())
|
||||
if err != nil {
|
||||
if errors.Is(err, ruleerrors.ErrImmatureSpend) {
|
||||
return transactionRuleError(RejectImmatureSpend, "one of the transaction inputs spends an immature UTXO")
|
||||
}
|
||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||
return newRuleError(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
err = op.mempool.validateTransactionInContext(transaction.Transaction())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
virtualDAAScore, err := op.mempool.consensus.GetVirtualDAAScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mempoolTransaction := model.NewMempoolTransaction(
|
||||
transaction.Transaction(),
|
||||
op.mempool.transactionsPool.getParentTransactionsInPool(transaction.Transaction()),
|
||||
false,
|
||||
virtualDAAScore,
|
||||
)
|
||||
err = op.mempool.transactionsPool.addMempoolTransaction(mempoolTransaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) removeOrphan(orphanTransactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||
orphanTransaction, ok := op.allOrphans[*orphanTransactionID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
delete(op.allOrphans, *orphanTransactionID)
|
||||
|
||||
for i, input := range orphanTransaction.Transaction().Inputs {
|
||||
if _, ok := op.orphansByPreviousOutpoint[input.PreviousOutpoint]; !ok {
|
||||
return errors.Errorf("Input No. %d of %s (%s) doesn't exist in orphansByPreviousOutpoint",
|
||||
i, orphanTransactionID, input.PreviousOutpoint)
|
||||
}
|
||||
delete(op.orphansByPreviousOutpoint, input.PreviousOutpoint)
|
||||
}
|
||||
|
||||
if removeRedeemers {
|
||||
err := op.removeRedeemersOf(orphanTransaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) removeRedeemersOf(transaction model.Transaction) error {
|
||||
outpoint := externalapi.DomainOutpoint{TransactionID: *transaction.TransactionID()}
|
||||
for i := range transaction.Transaction().Outputs {
|
||||
outpoint.Index = uint32(i)
|
||||
if orphan, ok := op.orphansByPreviousOutpoint[outpoint]; ok {
|
||||
// Recursive call is bound by size of orphan pool (which is very small)
|
||||
err := op.removeOrphan(orphan.TransactionID(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) expireOrphanTransactions() error {
|
||||
virtualDAAScore, err := op.mempool.consensus.GetVirtualDAAScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if virtualDAAScore-op.lastExpireScan < op.mempool.config.OrphanExpireScanIntervalDAAScore {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, orphanTransaction := range op.allOrphans {
|
||||
// Never expire high priority transactions
|
||||
if orphanTransaction.IsHighPriority() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Remove all transactions whose addedAtDAAScore is older then TransactionExpireIntervalDAAScore
|
||||
if virtualDAAScore-orphanTransaction.AddedAtDAAScore() > op.mempool.config.OrphanExpireIntervalDAAScore {
|
||||
err = op.removeOrphan(orphanTransaction.TransactionID(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
op.lastExpireScan = virtualDAAScore
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) updateOrphansAfterTransactionRemoved(
|
||||
removedTransaction *model.MempoolTransaction, removeRedeemers bool) error {
|
||||
|
||||
if removeRedeemers {
|
||||
return op.removeRedeemersOf(removedTransaction)
|
||||
}
|
||||
|
||||
outpoint := externalapi.DomainOutpoint{TransactionID: *removedTransaction.TransactionID()}
|
||||
for i := range removedTransaction.Transaction().Outputs {
|
||||
outpoint.Index = uint32(i)
|
||||
if orphan, ok := op.orphansByPreviousOutpoint[outpoint]; ok {
|
||||
for _, input := range orphan.Transaction().Inputs {
|
||||
if input.PreviousOutpoint.TransactionID.Equal(removedTransaction.TransactionID()) {
|
||||
input.UTXOEntry = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (op *orphansPool) randomNonHighPriorityOrphan() *model.OrphanTransaction {
|
||||
for _, orphan := range op.allOrphans {
|
||||
if !orphan.IsHighPriority() {
|
||||
return orphan
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,222 +0,0 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
|
||||
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxStandardP2SHSigOps is the maximum number of signature operations
|
||||
// that are considered standard in a pay-to-script-hash script.
|
||||
maxStandardP2SHSigOps = 15
|
||||
|
||||
// maxStandardSigScriptSize is the maximum size allowed for a
|
||||
// transaction input signature script to be considered standard. This
|
||||
// value allows for a 15-of-15 CHECKMULTISIG pay-to-script-hash with
|
||||
// compressed keys.
|
||||
//
|
||||
// The form of the overall script is: OP_0 <15 signatures> OP_PUSHDATA2
|
||||
// <2 bytes len> [OP_15 <15 pubkeys> OP_15 OP_CHECKMULTISIG]
|
||||
//
|
||||
// For the p2sh script portion, each of the 15 compressed pubkeys are
|
||||
// 33 bytes (plus one for the OP_DATA_33 opcode), and the thus it totals
|
||||
// to (15*34)+3 = 513 bytes. Next, each of the 15 signatures is a max
|
||||
// of 73 bytes (plus one for the OP_DATA_73 opcode). Also, there is one
|
||||
// extra byte for the initial extra OP_0 push and 3 bytes for the
|
||||
// OP_PUSHDATA2 needed to specify the 513 bytes for the script push.
|
||||
// That brings the total to 1+(15*74)+3+513 = 1627. This value also
|
||||
// adds a few extra bytes to provide a little buffer.
|
||||
// (1 + 15*74 + 3) + (15*34 + 3) + 23 = 1650
|
||||
maxStandardSigScriptSize = 1650
|
||||
|
||||
// MaxStandardTxSize is the maximum size allowed for transactions that
|
||||
// are considered standard and will therefore be relayed and considered
|
||||
// for mining.
|
||||
MaxStandardTxSize = 100000
|
||||
|
||||
// DefaultMinRelayTxFee is the minimum fee in sompi that is required
|
||||
// for a transaction to be treated as free for relay and mining
|
||||
// purposes. It is also used to help determine if a transaction is
|
||||
// considered dust and as a base for calculating minimum required fees
|
||||
// for larger transactions. This value is in sompi/1000 bytes.
|
||||
DefaultMinRelayTxFee = util.Amount(1000)
|
||||
)
|
||||
|
||||
// calcMinRequiredTxRelayFee returns the minimum transaction fee required for a
|
||||
// transaction with the passed serialized size to be accepted into the memory
|
||||
// pool and relayed.
|
||||
func calcMinRequiredTxRelayFee(serializedSize int64, minRelayTxFee util.Amount) int64 {
|
||||
// Calculate the minimum fee for a transaction to be allowed into the
|
||||
// mempool and relayed by scaling the base fee. minTxRelayFee is in
|
||||
// sompi/kB so multiply by serializedSize (which is in bytes) and
|
||||
// divide by 1000 to get minimum sompis.
|
||||
minFee := (serializedSize * int64(minRelayTxFee)) / 1000
|
||||
|
||||
if minFee == 0 && minRelayTxFee > 0 {
|
||||
minFee = int64(minRelayTxFee)
|
||||
}
|
||||
|
||||
// Set the minimum fee to the maximum possible value if the calculated
|
||||
// fee is not in the valid range for monetary amounts.
|
||||
if minFee < 0 || minFee > util.MaxSompi {
|
||||
minFee = util.MaxSompi
|
||||
}
|
||||
|
||||
return minFee
|
||||
}
|
||||
|
||||
// checkInputsStandard performs a series of checks on a transaction's inputs
|
||||
// to ensure they are "standard". A standard transaction input within the
|
||||
// context of this function is one whose referenced public key script is of a
|
||||
// standard form and, for pay-to-script-hash, does not have more than
|
||||
// maxStandardP2SHSigOps signature operations.
|
||||
func checkInputsStandard(tx *consensusexternalapi.DomainTransaction) error {
|
||||
// NOTE: The reference implementation also does a coinbase check here,
|
||||
// but coinbases have already been rejected prior to calling this
|
||||
// function so no need to recheck.
|
||||
|
||||
for i, txIn := range tx.Inputs {
|
||||
// It is safe to elide existence and index checks here since
|
||||
// they have already been checked prior to calling this
|
||||
// function.
|
||||
entry := txIn.UTXOEntry
|
||||
originScriptPubKey := entry.ScriptPublicKey()
|
||||
switch txscript.GetScriptClass(originScriptPubKey.Script) {
|
||||
case txscript.ScriptHashTy:
|
||||
numSigOps := txscript.GetPreciseSigOpCount(
|
||||
txIn.SignatureScript, originScriptPubKey, true)
|
||||
if numSigOps > maxStandardP2SHSigOps {
|
||||
str := fmt.Sprintf("transaction input #%d has "+
|
||||
"%d signature operations which is more "+
|
||||
"than the allowed max amount of %d",
|
||||
i, numSigOps, maxStandardP2SHSigOps)
|
||||
return txRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
case txscript.NonStandardTy:
|
||||
str := fmt.Sprintf("transaction input #%d has a "+
|
||||
"non-standard script form", i)
|
||||
return txRuleError(RejectNonstandard, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isDust returns whether or not the passed transaction output amount is
|
||||
// considered dust or not based on the passed minimum transaction relay fee.
|
||||
// Dust is defined in terms of the minimum transaction relay fee. In
|
||||
// particular, if the cost to the network to spend coins is more than 1/3 of the
|
||||
// minimum transaction relay fee, it is considered dust.
|
||||
func isDust(txOut *consensusexternalapi.DomainTransactionOutput, minRelayTxFee util.Amount) bool {
|
||||
// Unspendable outputs are considered dust.
|
||||
if txscript.IsUnspendable(txOut.ScriptPublicKey.Script) {
|
||||
return true
|
||||
}
|
||||
|
||||
// The total serialized size consists of the output and the associated
|
||||
// input script to redeem it. Since there is no input script
|
||||
// to redeem it yet, use the minimum size of a typical input script.
|
||||
//
|
||||
// Pay-to-pubkey bytes breakdown:
|
||||
//
|
||||
// Output to pubkey (43 bytes):
|
||||
// 8 value, 1 script len, 34 script [1 OP_DATA_32,
|
||||
// 32 pubkey, 1 OP_CHECKSIG]
|
||||
//
|
||||
// Input (105 bytes):
|
||||
// 36 prev outpoint, 1 script len, 64 script [1 OP_DATA_64,
|
||||
// 64 sig], 4 sequence
|
||||
//
|
||||
// The most common scripts are pay-to-pubkey, and as per the above
|
||||
// breakdown, the minimum size of a p2pk input script is 148 bytes. So
|
||||
// that figure is used.
|
||||
totalSize := estimatedsize.TransactionOutputEstimatedSerializedSize(txOut) + 148
|
||||
|
||||
// The output is considered dust if the cost to the network to spend the
|
||||
// coins is more than 1/3 of the minimum free transaction relay fee.
|
||||
// minFreeTxRelayFee is in sompi/KB, so multiply by 1000 to
|
||||
// convert to bytes.
|
||||
//
|
||||
// Using the typical values for a pay-to-pubkey transaction from
|
||||
// the breakdown above and the default minimum free transaction relay
|
||||
// fee of 1000, this equates to values less than 546 sompi being
|
||||
// considered dust.
|
||||
//
|
||||
// The following is equivalent to (value/totalSize) * (1/3) * 1000
|
||||
// without needing to do floating point math.
|
||||
return txOut.Value*1000/(3*totalSize) < uint64(minRelayTxFee)
|
||||
}
|
||||
|
||||
// checkTransactionStandard performs a series of checks on a transaction to
|
||||
// ensure it is a "standard" transaction. A standard transaction is one that
|
||||
// conforms to several additional limiting cases over what is considered a
|
||||
// "sane" transaction such as having a version in the supported range, being
|
||||
// finalized, conforming to more stringent size constraints, having scripts
|
||||
// of recognized forms, and not containing "dust" outputs (those that are
|
||||
// so small it costs more to process them than they are worth).
|
||||
func checkTransactionStandard(tx *consensusexternalapi.DomainTransaction, policy *policy) error {
|
||||
|
||||
// The transaction must be a currently supported version.
|
||||
if tx.Version > policy.MaxTxVersion {
|
||||
str := fmt.Sprintf("transaction version %d is not in the "+
|
||||
"valid range of %d-%d", tx.Version, 0,
|
||||
policy.MaxTxVersion)
|
||||
return txRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
// Since extremely large transactions with a lot of inputs can cost
|
||||
// almost as much to process as the sender fees, limit the maximum
|
||||
// size of a transaction. This also helps mitigate CPU exhaustion
|
||||
// attacks.
|
||||
serializedLen := estimatedsize.TransactionEstimatedSerializedSize(tx)
|
||||
if serializedLen > MaxStandardTxSize {
|
||||
str := fmt.Sprintf("transaction size of %d is larger than max "+
|
||||
"allowed size of %d", serializedLen, MaxStandardTxSize)
|
||||
return txRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
for i, txIn := range tx.Inputs {
|
||||
// Each transaction input signature script must not exceed the
|
||||
// maximum size allowed for a standard transaction. See
|
||||
// the comment on maxStandardSigScriptSize for more details.
|
||||
sigScriptLen := len(txIn.SignatureScript)
|
||||
if sigScriptLen > maxStandardSigScriptSize {
|
||||
str := fmt.Sprintf("transaction input %d: signature "+
|
||||
"script size of %d bytes is large than max "+
|
||||
"allowed size of %d bytes", i, sigScriptLen,
|
||||
maxStandardSigScriptSize)
|
||||
return txRuleError(RejectNonstandard, str)
|
||||
}
|
||||
}
|
||||
|
||||
// None of the output public key scripts can be a non-standard script or
|
||||
// be "dust".
|
||||
for i, txOut := range tx.Outputs {
|
||||
if txOut.ScriptPublicKey.Version > constants.MaxScriptPublicKeyVersion {
|
||||
return txRuleError(RejectNonstandard, "The version of the scriptPublicKey is higher than the known version.")
|
||||
}
|
||||
scriptClass := txscript.GetScriptClass(txOut.ScriptPublicKey.Script)
|
||||
if scriptClass == txscript.NonStandardTy {
|
||||
str := fmt.Sprintf("transaction output %d: non-standard script form", i)
|
||||
return txRuleError(RejectNonstandard, str)
|
||||
}
|
||||
|
||||
if isDust(txOut, policy.MinRelayTxFee) {
|
||||
str := fmt.Sprintf("transaction output %d: payment "+
|
||||
"of %d is dust", i, txOut.Value)
|
||||
return txRuleError(RejectDust, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,311 +0,0 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
|
||||
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// TestCalcMinRequiredTxRelayFee tests the calcMinRequiredTxRelayFee API.
|
||||
func TestCalcMinRequiredTxRelayFee(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // test description.
|
||||
size int64 // Transaction size in bytes.
|
||||
relayFee util.Amount // minimum relay transaction fee.
|
||||
want int64 // Expected fee.
|
||||
}{
|
||||
{
|
||||
// Ensure combination of size and fee that are less than 1000
|
||||
// produce a non-zero fee.
|
||||
"250 bytes with relay fee of 3",
|
||||
250,
|
||||
3,
|
||||
3,
|
||||
},
|
||||
{
|
||||
"100 bytes with default minimum relay fee",
|
||||
100,
|
||||
DefaultMinRelayTxFee,
|
||||
100,
|
||||
},
|
||||
{
|
||||
"max standard tx size with default minimum relay fee",
|
||||
MaxStandardTxSize,
|
||||
DefaultMinRelayTxFee,
|
||||
100000,
|
||||
},
|
||||
{
|
||||
"max standard tx size with max sompi relay fee",
|
||||
MaxStandardTxSize,
|
||||
util.MaxSompi,
|
||||
util.MaxSompi,
|
||||
},
|
||||
{
|
||||
"1500 bytes with 5000 relay fee",
|
||||
1500,
|
||||
5000,
|
||||
7500,
|
||||
},
|
||||
{
|
||||
"1500 bytes with 3000 relay fee",
|
||||
1500,
|
||||
3000,
|
||||
4500,
|
||||
},
|
||||
{
|
||||
"782 bytes with 5000 relay fee",
|
||||
782,
|
||||
5000,
|
||||
3910,
|
||||
},
|
||||
{
|
||||
"782 bytes with 3000 relay fee",
|
||||
782,
|
||||
3000,
|
||||
2346,
|
||||
},
|
||||
{
|
||||
"782 bytes with 2550 relay fee",
|
||||
782,
|
||||
2550,
|
||||
1994,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := calcMinRequiredTxRelayFee(test.size, test.relayFee)
|
||||
if got != test.want {
|
||||
t.Errorf("TestCalcMinRequiredTxRelayFee test '%s' "+
|
||||
"failed: got %v want %v", test.name, got,
|
||||
test.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDust tests the isDust API.
|
||||
func TestDust(t *testing.T) {
|
||||
scriptPublicKey := &consensusexternalapi.ScriptPublicKey{
|
||||
[]byte{0x76, 0xa9, 0x21, 0x03, 0x2f, 0x7e, 0x43,
|
||||
0x0a, 0xa4, 0xc9, 0xd1, 0x59, 0x43, 0x7e, 0x84, 0xb9,
|
||||
0x75, 0xdc, 0x76, 0xd9, 0x00, 0x3b, 0xf0, 0x92, 0x2c,
|
||||
0xf3, 0xaa, 0x45, 0x28, 0x46, 0x4b, 0xab, 0x78, 0x0d,
|
||||
0xba, 0x5e}, 0}
|
||||
|
||||
tests := []struct {
|
||||
name string // test description
|
||||
txOut consensusexternalapi.DomainTransactionOutput
|
||||
relayFee util.Amount // minimum relay transaction fee.
|
||||
isDust bool
|
||||
}{
|
||||
{
|
||||
// Any value is allowed with a zero relay fee.
|
||||
"zero value with zero relay fee",
|
||||
consensusexternalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: scriptPublicKey},
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Zero value is dust with any relay fee"
|
||||
"zero value with very small tx fee",
|
||||
consensusexternalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: scriptPublicKey},
|
||||
1,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"36 byte public key script with value 605",
|
||||
consensusexternalapi.DomainTransactionOutput{Value: 605, ScriptPublicKey: scriptPublicKey},
|
||||
1000,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"36 byte public key script with value 606",
|
||||
consensusexternalapi.DomainTransactionOutput{Value: 606, ScriptPublicKey: scriptPublicKey},
|
||||
1000,
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Maximum allowed value is never dust.
|
||||
"max sompi amount is never dust",
|
||||
consensusexternalapi.DomainTransactionOutput{Value: util.MaxSompi, ScriptPublicKey: scriptPublicKey},
|
||||
util.MaxSompi,
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Maximum int64 value causes overflow.
|
||||
"maximum int64 value",
|
||||
consensusexternalapi.DomainTransactionOutput{Value: 1<<63 - 1, ScriptPublicKey: scriptPublicKey},
|
||||
1<<63 - 1,
|
||||
true,
|
||||
},
|
||||
{
|
||||
// Unspendable ScriptPublicKey due to an invalid public key
|
||||
// script.
|
||||
"unspendable ScriptPublicKey",
|
||||
consensusexternalapi.DomainTransactionOutput{Value: 5000, ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{[]byte{0x01}, 0}},
|
||||
0, // no relay fee
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
res := isDust(&test.txOut, test.relayFee)
|
||||
if res != test.isDust {
|
||||
t.Fatalf("Dust test '%s' failed: want %v got %v",
|
||||
test.name, test.isDust, res)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckTransactionStandard tests the checkTransactionStandard API.
|
||||
func TestCheckTransactionStandard(t *testing.T) {
|
||||
// Create some dummy, but otherwise standard, data for transactions.
|
||||
prevOutTxID := &consensusexternalapi.DomainTransactionID{}
|
||||
dummyPrevOut := consensusexternalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1}
|
||||
dummySigScript := bytes.Repeat([]byte{0x00}, 65)
|
||||
dummyTxIn := consensusexternalapi.DomainTransactionInput{
|
||||
PreviousOutpoint: dummyPrevOut,
|
||||
SignatureScript: dummySigScript,
|
||||
Sequence: constants.MaxTxInSequenceNum,
|
||||
}
|
||||
addrHash := [32]byte{0x01}
|
||||
addr, err := util.NewAddressPublicKey(addrHash[:], util.Bech32PrefixKaspaTest)
|
||||
if err != nil {
|
||||
t.Fatalf("NewAddressPublicKey: unexpected error: %v", err)
|
||||
}
|
||||
dummyScriptPublicKey, err := txscript.PayToAddrScript(addr)
|
||||
if err != nil {
|
||||
t.Fatalf("PayToAddrScript: unexpected error: %v", err)
|
||||
}
|
||||
dummyTxOut := consensusexternalapi.DomainTransactionOutput{
|
||||
Value: 100000000, // 1 KAS
|
||||
ScriptPublicKey: dummyScriptPublicKey,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tx consensusexternalapi.DomainTransaction
|
||||
height uint64
|
||||
isStandard bool
|
||||
code RejectCode
|
||||
}{
|
||||
{
|
||||
name: "Typical pay-to-pubkey transaction",
|
||||
tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}},
|
||||
height: 300000,
|
||||
isStandard: true,
|
||||
},
|
||||
{
|
||||
name: "Transaction version too high",
|
||||
tx: consensusexternalapi.DomainTransaction{Version: constants.MaxTransactionVersion + 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Transaction size is too large",
|
||||
tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{
|
||||
Value: 0,
|
||||
ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{bytes.Repeat([]byte{0x00}, MaxStandardTxSize+1), 0},
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
{
|
||||
name: "Signature script size is too large",
|
||||
tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{{
|
||||
PreviousOutpoint: dummyPrevOut,
|
||||
SignatureScript: bytes.Repeat([]byte{0x00},
|
||||
maxStandardSigScriptSize+1),
|
||||
Sequence: constants.MaxTxInSequenceNum,
|
||||
}}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
{
|
||||
name: "Valid but non standard public key script",
|
||||
tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{
|
||||
Value: 100000000,
|
||||
ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{[]byte{txscript.OpTrue}, 0},
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
{ //Todo : check on ScriptPublicKey type.
|
||||
name: "Dust output",
|
||||
tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{
|
||||
Value: 0,
|
||||
ScriptPublicKey: dummyScriptPublicKey,
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectDust,
|
||||
},
|
||||
{
|
||||
name: "Nulldata transaction",
|
||||
tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{
|
||||
Value: 0,
|
||||
ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{[]byte{txscript.OpReturn}, 0},
|
||||
}}},
|
||||
height: 300000,
|
||||
isStandard: false,
|
||||
code: RejectNonstandard,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
// Ensure standardness is as expected.
|
||||
err := checkTransactionStandard(&test.tx, &policy{MinRelayTxFee: DefaultMinRelayTxFee, MaxTxVersion: 0})
|
||||
if err == nil && test.isStandard {
|
||||
// Test passes since function returned standard for a
|
||||
// transaction which is intended to be standard.
|
||||
continue
|
||||
}
|
||||
if err == nil && !test.isStandard {
|
||||
t.Errorf("checkTransactionStandard (%s): standard when "+
|
||||
"it should not be", test.name)
|
||||
continue
|
||||
}
|
||||
if err != nil && test.isStandard {
|
||||
t.Errorf("checkTransactionStandard (%s): nonstandard "+
|
||||
"when it should not be: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure error type is a TxRuleError inside of a RuleError.
|
||||
var ruleErr RuleError
|
||||
if !errors.As(err, &ruleErr) {
|
||||
t.Errorf("checkTransactionStandard (%s): unexpected "+
|
||||
"error type - got %T", test.name, err)
|
||||
continue
|
||||
}
|
||||
txRuleErr, ok := ruleErr.Err.(TxRuleError)
|
||||
if !ok {
|
||||
t.Errorf("checkTransactionStandard (%s): unexpected "+
|
||||
"error type - got %T", test.name, ruleErr.Err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure the reject code is the expected one.
|
||||
if txRuleErr.RejectCode != test.code {
|
||||
t.Errorf("checkTransactionStandard (%s): unexpected "+
|
||||
"error code - got %v, want %v", test.name,
|
||||
txRuleErr.RejectCode, test.code)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
66
domain/miningmanager/mempool/remove_transaction.go
Normal file
66
domain/miningmanager/mempool/remove_transaction.go
Normal file
@ -0,0 +1,66 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||
)
|
||||
|
||||
func (mp *mempool) removeTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error {
|
||||
for _, transaction := range transactions {
|
||||
err := mp.removeTransaction(consensushashing.TransactionID(transaction), removeRedeemers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *mempool) removeTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||
if _, ok := mp.orphansPool.allOrphans[*transactionID]; ok {
|
||||
return mp.orphansPool.removeOrphan(transactionID, true)
|
||||
}
|
||||
|
||||
mempoolTransaction, ok := mp.transactionsPool.allTransactions[*transactionID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
transactionsToRemove := []*model.MempoolTransaction{mempoolTransaction}
|
||||
if removeRedeemers {
|
||||
redeemers := mp.transactionsPool.getRedeemers(mempoolTransaction)
|
||||
transactionsToRemove = append(transactionsToRemove, redeemers...)
|
||||
}
|
||||
|
||||
for _, transactionToRemove := range transactionsToRemove {
|
||||
err := mp.removeTransactionFromSets(transactionToRemove, removeRedeemers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if removeRedeemers {
|
||||
err := mp.orphansPool.removeRedeemersOf(mempoolTransaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *mempool) removeTransactionFromSets(mempoolTransaction *model.MempoolTransaction, removeRedeemers bool) error {
|
||||
mp.mempoolUTXOSet.removeTransaction(mempoolTransaction)
|
||||
|
||||
err := mp.transactionsPool.removeTransaction(mempoolTransaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mp.orphansPool.updateOrphansAfterTransactionRemoved(mempoolTransaction, removeRedeemers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||
)
|
||||
|
||||
func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTransaction, error) {
|
||||
validTransactions := []*externalapi.DomainTransaction{}
|
||||
|
||||
for _, transaction := range mp.transactionsPool.highPriorityTransactions {
|
||||
isValid, err := mp.revalidateTransaction(transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isValid {
|
||||
continue
|
||||
}
|
||||
|
||||
validTransactions = append(validTransactions, transaction.Transaction())
|
||||
}
|
||||
|
||||
return validTransactions, nil
|
||||
}
|
||||
|
||||
func (mp *mempool) revalidateTransaction(transaction *model.MempoolTransaction) (isValid bool, err error) {
|
||||
clearInputs(transaction)
|
||||
|
||||
_, missingParents, err := mp.fillInputsAndGetMissingParents(transaction.Transaction())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(missingParents) > 0 {
|
||||
err := mp.removeTransaction(transaction.TransactionID(), true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func clearInputs(transaction *model.MempoolTransaction) {
|
||||
for _, input := range transaction.Transaction().Inputs {
|
||||
input.UTXOEntry = nil
|
||||
}
|
||||
}
|
203
domain/miningmanager/mempool/transactions_pool.go
Normal file
203
domain/miningmanager/mempool/transactions_pool.go
Normal file
@ -0,0 +1,203 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||
)
|
||||
|
||||
type transactionsPool struct {
|
||||
mempool *mempool
|
||||
allTransactions model.IDToTransactionMap
|
||||
highPriorityTransactions model.IDToTransactionMap
|
||||
chainedTransactionsByPreviousOutpoint model.OutpointToTransactionMap
|
||||
transactionsOrderedByFeeRate model.TransactionsOrderedByFeeRate
|
||||
lastExpireScan uint64
|
||||
}
|
||||
|
||||
func newTransactionsPool(mp *mempool) *transactionsPool {
|
||||
return &transactionsPool{
|
||||
mempool: mp,
|
||||
allTransactions: model.IDToTransactionMap{},
|
||||
highPriorityTransactions: model.IDToTransactionMap{},
|
||||
chainedTransactionsByPreviousOutpoint: model.OutpointToTransactionMap{},
|
||||
transactionsOrderedByFeeRate: model.TransactionsOrderedByFeeRate{},
|
||||
lastExpireScan: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransaction,
|
||||
parentTransactionsInPool model.OutpointToTransactionMap, isHighPriority bool) (*model.MempoolTransaction, error) {
|
||||
|
||||
virtualDAAScore, err := tp.mempool.consensus.GetVirtualDAAScore()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mempoolTransaction := model.NewMempoolTransaction(
|
||||
transaction, parentTransactionsInPool, isHighPriority, virtualDAAScore)
|
||||
|
||||
err = tp.addMempoolTransaction(mempoolTransaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mempoolTransaction, nil
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) addMempoolTransaction(transaction *model.MempoolTransaction) error {
|
||||
tp.allTransactions[*transaction.TransactionID()] = transaction
|
||||
|
||||
for outpoint, parentTransactionInPool := range transaction.ParentTransactionsInPool() {
|
||||
tp.chainedTransactionsByPreviousOutpoint[outpoint] = parentTransactionInPool
|
||||
}
|
||||
|
||||
tp.mempool.mempoolUTXOSet.addTransaction(transaction)
|
||||
|
||||
err := tp.transactionsOrderedByFeeRate.Push(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if transaction.IsHighPriority() {
|
||||
tp.highPriorityTransactions[*transaction.TransactionID()] = transaction
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) removeTransaction(transaction *model.MempoolTransaction) error {
|
||||
delete(tp.allTransactions, *transaction.TransactionID())
|
||||
|
||||
err := tp.transactionsOrderedByFeeRate.Remove(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(tp.highPriorityTransactions, *transaction.TransactionID())
|
||||
|
||||
for outpoint := range transaction.ParentTransactionsInPool() {
|
||||
delete(tp.chainedTransactionsByPreviousOutpoint, outpoint)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) expireOldTransactions() error {
|
||||
virtualDAAScore, err := tp.mempool.consensus.GetVirtualDAAScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if virtualDAAScore-tp.lastExpireScan < tp.mempool.config.TransactionExpireScanIntervalDAAScore {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, mempoolTransaction := range tp.allTransactions {
|
||||
// Never expire high priority transactions
|
||||
if mempoolTransaction.IsHighPriority() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Remove all transactions whose addedAtDAAScore is older then TransactionExpireIntervalDAAScore
|
||||
if virtualDAAScore-mempoolTransaction.AddedAtDAAScore() > tp.mempool.config.TransactionExpireIntervalDAAScore {
|
||||
err = tp.mempool.removeTransaction(mempoolTransaction.TransactionID(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tp.lastExpireScan = virtualDAAScore
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) allReadyTransactions() []*externalapi.DomainTransaction {
|
||||
result := []*externalapi.DomainTransaction{}
|
||||
|
||||
for _, mempoolTransaction := range tp.allTransactions {
|
||||
if len(mempoolTransaction.ParentTransactionsInPool()) == 0 {
|
||||
result = append(result, mempoolTransaction.Transaction())
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) getParentTransactionsInPool(
|
||||
transaction *externalapi.DomainTransaction) model.OutpointToTransactionMap {
|
||||
|
||||
parentsTransactionsInPool := model.OutpointToTransactionMap{}
|
||||
|
||||
for _, input := range transaction.Inputs {
|
||||
if transaction, ok := tp.allTransactions[input.PreviousOutpoint.TransactionID]; ok {
|
||||
parentsTransactionsInPool[input.PreviousOutpoint] = transaction
|
||||
}
|
||||
}
|
||||
|
||||
return parentsTransactionsInPool
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) getRedeemers(transaction *model.MempoolTransaction) []*model.MempoolTransaction {
|
||||
queue := []*model.MempoolTransaction{transaction}
|
||||
redeemers := []*model.MempoolTransaction{}
|
||||
for len(queue) > 0 {
|
||||
var current *model.MempoolTransaction
|
||||
current, queue = queue[0], queue[1:]
|
||||
|
||||
outpoint := externalapi.DomainOutpoint{TransactionID: *current.TransactionID()}
|
||||
for i := range current.Transaction().Outputs {
|
||||
outpoint.Index = uint32(i)
|
||||
if redeemerTransaction, ok := tp.chainedTransactionsByPreviousOutpoint[outpoint]; ok {
|
||||
queue = append(queue, redeemerTransaction)
|
||||
redeemers = append(redeemers, redeemerTransaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
return redeemers
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) limitTransactionCount() error {
|
||||
currentIndex := 0
|
||||
|
||||
for uint64(len(tp.allTransactions)) > tp.mempool.config.MaximumTransactionCount {
|
||||
var transactionToRemove *model.MempoolTransaction
|
||||
for {
|
||||
transactionToRemove = tp.transactionsOrderedByFeeRate.GetByIndex(currentIndex)
|
||||
if !transactionToRemove.IsHighPriority() {
|
||||
break
|
||||
}
|
||||
currentIndex++
|
||||
if currentIndex >= len(tp.allTransactions) {
|
||||
log.Warnf(
|
||||
"Number of high-priority transactions in mempool (%d) is higher than maximum allowed (%d)",
|
||||
len(tp.allTransactions), tp.mempool.config.MaximumTransactionCount)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
err := tp.mempool.removeTransaction(transactionToRemove.TransactionID(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) getTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
||||
if mempoolTransaction, ok := tp.allTransactions[*transactionID]; ok {
|
||||
return mempoolTransaction.Transaction(), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) getAllTransactions() []*externalapi.DomainTransaction {
|
||||
allTransactions := make([]*externalapi.DomainTransaction, 0, len(tp.allTransactions))
|
||||
for _, mempoolTransaction := range tp.allTransactions {
|
||||
allTransactions = append(allTransactions, mempoolTransaction.Transaction())
|
||||
}
|
||||
return allTransactions
|
||||
}
|
||||
|
||||
func (tp *transactionsPool) transactionCount() int {
|
||||
return len(tp.allTransactions)
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
)
|
||||
|
||||
func (mp *mempool) validateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool,
|
||||
allowOrphan bool) (acceptedTransactions []*externalapi.DomainTransaction, err error) {
|
||||
|
||||
err = mp.validateTransactionPreUTXOEntry(transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parentsInPool, missingOutpoints, err := mp.fillInputsAndGetMissingParents(transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(missingOutpoints) > 0 {
|
||||
if !allowOrphan {
|
||||
str := fmt.Sprintf("Transaction %s is an orphan, where allowOrphan = false",
|
||||
consensushashing.TransactionID(transaction))
|
||||
return nil, transactionRuleError(RejectBadOrphan, str)
|
||||
}
|
||||
|
||||
return nil, mp.orphansPool.maybeAddOrphan(transaction, isHighPriority)
|
||||
}
|
||||
|
||||
err = mp.validateTransactionInContext(transaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mempoolTransaction, err := mp.transactionsPool.addTransaction(transaction, parentsInPool, isHighPriority)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acceptedOrphans, err := mp.orphansPool.processOrphansAfterAcceptedTransaction(mempoolTransaction.Transaction())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acceptedTransactions = append([]*externalapi.DomainTransaction{transaction}, acceptedOrphans...)
|
||||
|
||||
err = mp.transactionsPool.limitTransactionCount()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return acceptedTransactions, nil
|
||||
}
|
71
domain/miningmanager/mempool/validate_transaction.go
Normal file
71
domain/miningmanager/mempool/validate_transaction.go
Normal file
@ -0,0 +1,71 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
)
|
||||
|
||||
func (mp *mempool) validateTransactionPreUTXOEntry(transaction *externalapi.DomainTransaction) error {
|
||||
err := mp.validateTransactionInIsolation(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mp.mempoolUTXOSet.checkDoubleSpends(transaction); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *mempool) validateTransactionInIsolation(transaction *externalapi.DomainTransaction) error {
|
||||
transactionID := consensushashing.TransactionID(transaction)
|
||||
if _, ok := mp.transactionsPool.allTransactions[*transactionID]; ok {
|
||||
return transactionRuleError(RejectDuplicate,
|
||||
fmt.Sprintf("transaction %s is already in the mempool", transactionID))
|
||||
}
|
||||
|
||||
if !mp.config.AcceptNonStandard {
|
||||
if err := mp.checkTransactionStandardInIsolation(transaction); err != nil {
|
||||
// Attempt to extract a reject code from the error so
|
||||
// it can be retained. When not possible, fall back to
|
||||
// a non standard error.
|
||||
rejectCode, found := extractRejectCode(err)
|
||||
if !found {
|
||||
rejectCode = RejectNonstandard
|
||||
}
|
||||
str := fmt.Sprintf("transaction %s is not standard: %s", transactionID, err)
|
||||
return transactionRuleError(rejectCode, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainTransaction) error {
|
||||
transactionID := consensushashing.TransactionID(transaction)
|
||||
if transaction.Mass > mp.config.MaximumMassAcceptedByBlock {
|
||||
return transactionRuleError(RejectInvalid, fmt.Sprintf("transaction %s mass is %d which is "+
|
||||
"higher than the maxmimum of %d", transactionID,
|
||||
transaction.Mass, mp.config.MaximumMassAcceptedByBlock))
|
||||
}
|
||||
|
||||
if !mp.config.AcceptNonStandard {
|
||||
err := mp.checkTransactionStandardInContext(transaction)
|
||||
if err != nil {
|
||||
// Attempt to extract a reject code from the error so
|
||||
// it can be retained. When not possible, fall back to
|
||||
// a non standard error.
|
||||
rejectCode, found := extractRejectCode(err)
|
||||
if !found {
|
||||
rejectCode = RejectNonstandard
|
||||
}
|
||||
str := fmt.Sprintf("transaction inputs %s are not standard: %s",
|
||||
consensushashing.TransactionID(transaction), err)
|
||||
return transactionRuleError(rejectCode, str)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,19 +1,21 @@
|
||||
package miningmanager
|
||||
|
||||
import (
|
||||
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model"
|
||||
)
|
||||
|
||||
// MiningManager creates block templates for mining as well as maintaining
|
||||
// known transactions that have no yet been added to any block
|
||||
type MiningManager interface {
|
||||
GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error)
|
||||
GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool)
|
||||
AllTransactions() []*consensusexternalapi.DomainTransaction
|
||||
GetBlockTemplate(coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainBlock, error)
|
||||
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
||||
AllTransactions() []*externalapi.DomainTransaction
|
||||
TransactionCount() int
|
||||
HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error)
|
||||
ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error
|
||||
HandleNewBlockTransactions(txs []*externalapi.DomainTransaction) ([]*externalapi.DomainTransaction, error)
|
||||
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
||||
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
||||
RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error)
|
||||
}
|
||||
|
||||
type miningManager struct {
|
||||
@ -22,32 +24,40 @@ type miningManager struct {
|
||||
}
|
||||
|
||||
// GetBlockTemplate creates a block template for a miner to consume
|
||||
func (mm *miningManager) GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) {
|
||||
func (mm *miningManager) GetBlockTemplate(coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainBlock, error) {
|
||||
return mm.blockTemplateBuilder.GetBlockTemplate(coinbaseData)
|
||||
}
|
||||
|
||||
// HandleNewBlock handles the transactions for a new block that was just added to the DAG
|
||||
func (mm *miningManager) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error) {
|
||||
func (mm *miningManager) HandleNewBlockTransactions(txs []*externalapi.DomainTransaction) ([]*externalapi.DomainTransaction, error) {
|
||||
return mm.mempool.HandleNewBlockTransactions(txs)
|
||||
}
|
||||
|
||||
// ValidateAndInsertTransaction validates the given transaction, and
|
||||
// adds it to the set of known transactions that have not yet been
|
||||
// added to any block
|
||||
func (mm *miningManager) ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error {
|
||||
return mm.mempool.ValidateAndInsertTransaction(transaction, allowOrphan)
|
||||
func (mm *miningManager) ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction,
|
||||
isHighPriority bool, allowOrphan bool) (acceptedTransactions []*externalapi.DomainTransaction, err error) {
|
||||
|
||||
return mm.mempool.ValidateAndInsertTransaction(transaction, isHighPriority, allowOrphan)
|
||||
}
|
||||
|
||||
func (mm *miningManager) GetTransaction(
|
||||
transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool) {
|
||||
transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) {
|
||||
|
||||
return mm.mempool.GetTransaction(transactionID)
|
||||
}
|
||||
|
||||
func (mm *miningManager) AllTransactions() []*consensusexternalapi.DomainTransaction {
|
||||
func (mm *miningManager) AllTransactions() []*externalapi.DomainTransaction {
|
||||
return mm.mempool.AllTransactions()
|
||||
}
|
||||
|
||||
func (mm *miningManager) TransactionCount() int {
|
||||
return mm.mempool.TransactionCount()
|
||||
}
|
||||
|
||||
func (mm *miningManager) RevalidateHighPriorityTransactions() (
|
||||
validTransactions []*externalapi.DomainTransaction, err error) {
|
||||
|
||||
return mm.mempool.RevalidateHighPriorityTransactions()
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
package miningmanager_test
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
@ -33,11 +35,11 @@ func TestValidateAndInsertTransaction(t *testing.T) {
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
||||
for i := range transactionsToInsert {
|
||||
transactionsToInsert[i] = createTransactionWithUTXOEntry(t, i)
|
||||
err = miningManager.ValidateAndInsertTransaction(transactionsToInsert[i], true)
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transactionsToInsert[i], false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
@ -56,11 +58,11 @@ func TestValidateAndInsertTransaction(t *testing.T) {
|
||||
|
||||
// The parent's transaction was inserted by consensus(AddBlock), and we want to verify that
|
||||
// the transaction is not considered an orphan and inserted into the mempool.
|
||||
transactionNotAnOrphan, err := createChildTxWhenParentTxWasAddedByConsensus(consensusConfig, tc)
|
||||
transactionNotAnOrphan, err := createChildAndParentTxsAndAddParentToConsensus(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error in createParentAndChildrenTransaction: %v", err)
|
||||
}
|
||||
err = miningManager.ValidateAndInsertTransaction(transactionNotAnOrphan, true)
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transactionNotAnOrphan, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
@ -81,9 +83,9 @@ func TestImmatureSpend(t *testing.T) {
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||
tx := createTransactionWithUTXOEntry(t, 0)
|
||||
err = miningManager.ValidateAndInsertTransaction(tx, false)
|
||||
_, err = miningManager.ValidateAndInsertTransaction(tx, false, false)
|
||||
txRuleError := &mempool.TxRuleError{}
|
||||
if !errors.As(err, txRuleError) || txRuleError.RejectCode != mempool.RejectImmatureSpend {
|
||||
t.Fatalf("Unexpected error %+v", err)
|
||||
@ -108,14 +110,48 @@ func TestInsertDoubleTransactionsToMempool(t *testing.T) {
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||
transaction := createTransactionWithUTXOEntry(t, 0)
|
||||
err = miningManager.ValidateAndInsertTransaction(transaction, true)
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
err = miningManager.ValidateAndInsertTransaction(transaction, true)
|
||||
if err == nil || !strings.Contains(err.Error(), "already have transaction") {
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
||||
if err == nil || !strings.Contains(err.Error(), "is already in the mempool") {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestDoubleSpendInMempool verifies that an attempt to insert a transaction double-spending
|
||||
// another transaction already in the mempool will result in raising an appropriate error.
|
||||
func TestDoubleSpendInMempool(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDoubleSpendInMempool")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||
transaction, err := createChildAndParentTxsAndAddParentToConsensus(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating transaction: %+v", err)
|
||||
}
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
|
||||
doubleSpendingTransaction := transaction.Clone()
|
||||
doubleSpendingTransaction.ID = nil
|
||||
doubleSpendingTransaction.Outputs[0].Value-- // do some minor change so that txID is different
|
||||
|
||||
_, err = miningManager.ValidateAndInsertTransaction(doubleSpendingTransaction, false, true)
|
||||
if err == nil || !strings.Contains(err.Error(), "already spent by transaction") {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
})
|
||||
@ -133,12 +169,12 @@ func TestHandleNewBlockTransactions(t *testing.T) {
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
||||
for i := range transactionsToInsert {
|
||||
transaction := createTransactionWithUTXOEntry(t, i)
|
||||
transactionsToInsert[i] = transaction
|
||||
err = miningManager.ValidateAndInsertTransaction(transaction, true)
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
@ -186,22 +222,22 @@ func domainBlocksToBlockIds(blocks []*externalapi.DomainTransaction) []*external
|
||||
return blockIDs
|
||||
}
|
||||
|
||||
// TestDoubleSpends verifies that any transactions which are now double spends as a result of the block's new transactions
|
||||
// TestDoubleSpendWithBlock verifies that any transactions which are now double spends as a result of the block's new transactions
|
||||
// will be removed from the mempool.
|
||||
func TestDoubleSpends(t *testing.T) {
|
||||
func TestDoubleSpendWithBlock(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDoubleSpends")
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDoubleSpendWithBlock")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||
transactionInTheMempool := createTransactionWithUTXOEntry(t, 0)
|
||||
err = miningManager.ValidateAndInsertTransaction(transactionInTheMempool, true)
|
||||
_, err = miningManager.ValidateAndInsertTransaction(transactionInTheMempool, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
@ -222,7 +258,6 @@ func TestDoubleSpends(t *testing.T) {
|
||||
// TestOrphanTransactions verifies that a transaction could be a part of a new block template, only if it's not an orphan.
|
||||
func TestOrphanTransactions(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestOrphanTransactions")
|
||||
@ -232,14 +267,14 @@ func TestOrphanTransactions(t *testing.T) {
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||
// Before each parent transaction, We will add two blocks by consensus in order to fund the parent transactions.
|
||||
parentTransactions, childTransactions, err := createArraysOfParentAndChildrenTransactions(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error in createArraysOfParentAndChildrenTransactions: %v", err)
|
||||
}
|
||||
for _, orphanTransaction := range childTransactions {
|
||||
err = miningManager.ValidateAndInsertTransaction(orphanTransaction, true)
|
||||
_, err = miningManager.ValidateAndInsertTransaction(orphanTransaction, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||
}
|
||||
@ -284,7 +319,7 @@ func TestOrphanTransactions(t *testing.T) {
|
||||
}
|
||||
_, err = miningManager.HandleNewBlockTransactions(blockParentsTransactions.Transactions)
|
||||
if err != nil {
|
||||
t.Fatalf("HandleNewBlockTransactions: %v", err)
|
||||
t.Fatalf("HandleNewBlockTransactions: %+v", err)
|
||||
}
|
||||
transactionsMempool = miningManager.AllTransactions()
|
||||
if len(transactionsMempool) != len(childTransactions) {
|
||||
@ -318,6 +353,198 @@ func TestOrphanTransactions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestHighPriorityTransactions(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDoubleSpendWithBlock")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
mempoolConfig := mempool.DefaultConfig(&consensusConfig.Params)
|
||||
mempoolConfig.MaximumTransactionCount = 1
|
||||
mempoolConfig.MaximumOrphanTransactionCount = 1
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempoolConfig)
|
||||
|
||||
// Create 3 pairs of transaction parent-and-child pairs: 1 low priority and 2 high priority
|
||||
lowPriorityParentTransaction, lowPriorityChildTransaction, err := createParentAndChildrenTransactions(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating low-priority transaction pair: %+v", err)
|
||||
}
|
||||
firstHighPriorityParentTransaction, firstHighPriorityChildTransaction, err := createParentAndChildrenTransactions(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating first high-priority transaction pair: %+v", err)
|
||||
}
|
||||
secondHighPriorityParentTransaction, secondHighPriorityChildTransaction, err := createParentAndChildrenTransactions(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating second high-priority transaction pair: %+v", err)
|
||||
}
|
||||
|
||||
// Submit all the children, make sure the 2 highPriority ones remain in the orphan pool
|
||||
_, err = miningManager.ValidateAndInsertTransaction(lowPriorityChildTransaction, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("error submitting low-priority transaction: %+v", err)
|
||||
}
|
||||
_, err = miningManager.ValidateAndInsertTransaction(firstHighPriorityChildTransaction, true, true)
|
||||
if err != nil {
|
||||
t.Fatalf("error submitting first high-priority transaction: %+v", err)
|
||||
}
|
||||
_, err = miningManager.ValidateAndInsertTransaction(secondHighPriorityChildTransaction, true, true)
|
||||
if err != nil {
|
||||
t.Fatalf("error submitting second high-priority transaction: %+v", err)
|
||||
}
|
||||
// There's no API to check what stayed in the orphan pool, but we'll find it out when we begin to unorphan
|
||||
|
||||
// Submit all the parents.
|
||||
// Low priority transaction will only accept the parent, since the child was evicted from orphanPool
|
||||
lowPriorityAcceptedTransactions, err :=
|
||||
miningManager.ValidateAndInsertTransaction(lowPriorityParentTransaction, false, true)
|
||||
if err != nil {
|
||||
t.Fatalf("error submitting low-priority transaction: %+v", err)
|
||||
}
|
||||
expectedLowPriorityAcceptedTransactions := []*externalapi.DomainTransaction{lowPriorityParentTransaction}
|
||||
if !reflect.DeepEqual(lowPriorityAcceptedTransactions, expectedLowPriorityAcceptedTransactions) {
|
||||
t.Errorf("Expected only lowPriorityParent (%v) to be in lowPriorityAcceptedTransactions, but got %v",
|
||||
consensushashing.TransactionIDs(expectedLowPriorityAcceptedTransactions),
|
||||
consensushashing.TransactionIDs(lowPriorityAcceptedTransactions))
|
||||
}
|
||||
|
||||
// Both high priority transactions should accept parent and child
|
||||
|
||||
// Insert firstHighPriorityParentTransaction
|
||||
firstHighPriorityAcceptedTransactions, err :=
|
||||
miningManager.ValidateAndInsertTransaction(firstHighPriorityParentTransaction, true, true)
|
||||
if err != nil {
|
||||
t.Fatalf("error submitting first high-priority transaction: %+v", err)
|
||||
}
|
||||
expectedFirstHighPriorityAcceptedTransactions :=
|
||||
[]*externalapi.DomainTransaction{firstHighPriorityParentTransaction, firstHighPriorityChildTransaction}
|
||||
if !reflect.DeepEqual(firstHighPriorityAcceptedTransactions, expectedFirstHighPriorityAcceptedTransactions) {
|
||||
t.Errorf(
|
||||
"Expected both firstHighPriority transaction (%v) to be in firstHighPriorityAcceptedTransactions, but got %v",
|
||||
consensushashing.TransactionIDs(firstHighPriorityAcceptedTransactions),
|
||||
consensushashing.TransactionIDs(expectedFirstHighPriorityAcceptedTransactions))
|
||||
}
|
||||
// Insert secondHighPriorityParentTransaction
|
||||
secondHighPriorityAcceptedTransactions, err :=
|
||||
miningManager.ValidateAndInsertTransaction(secondHighPriorityParentTransaction, true, true)
|
||||
if err != nil {
|
||||
t.Fatalf("error submitting second high-priority transaction: %+v", err)
|
||||
}
|
||||
expectedSecondHighPriorityAcceptedTransactions :=
|
||||
[]*externalapi.DomainTransaction{secondHighPriorityParentTransaction, secondHighPriorityChildTransaction}
|
||||
if !reflect.DeepEqual(secondHighPriorityAcceptedTransactions, expectedSecondHighPriorityAcceptedTransactions) {
|
||||
t.Errorf(
|
||||
"Expected both secondHighPriority transaction (%v) to be in secondHighPriorityAcceptedTransactions, but got %v",
|
||||
consensushashing.TransactionIDs(secondHighPriorityAcceptedTransactions),
|
||||
consensushashing.TransactionIDs(expectedSecondHighPriorityAcceptedTransactions))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestRevalidateHighPriorityTransactions(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestRevalidateHighPriorityTransactions")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
mempoolConfig := mempool.DefaultConfig(&consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params, mempoolConfig)
|
||||
|
||||
// Create two valid transactions that double-spend each other (childTransaction1, childTransaction2)
|
||||
parentTransaction, childTransaction1, err := createParentAndChildrenTransactions(tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating parentTransaction and childTransaction1: %+v", err)
|
||||
}
|
||||
tips, err := tc.Tips()
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting tips: %+v", err)
|
||||
}
|
||||
|
||||
fundingBlock, _, err := tc.AddBlock(tips, nil, []*externalapi.DomainTransaction{parentTransaction})
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting function block: %+v", err)
|
||||
}
|
||||
|
||||
childTransaction2 := childTransaction1.Clone()
|
||||
childTransaction2.Outputs[0].Value-- // decrement value to change id
|
||||
|
||||
// Mine 1 block with confirming childTransaction1 and 2 blocks confirming childTransaction2, so that
|
||||
// childTransaction2 is accepted
|
||||
tip1, _, err := tc.AddBlock([]*externalapi.DomainHash{fundingBlock}, nil,
|
||||
[]*externalapi.DomainTransaction{childTransaction1})
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding tip1: %+v", err)
|
||||
}
|
||||
tip2, _, err := tc.AddBlock([]*externalapi.DomainHash{fundingBlock}, nil,
|
||||
[]*externalapi.DomainTransaction{childTransaction2})
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding tip2: %+v", err)
|
||||
}
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{tip2}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error mining on top of tip2: %+v", err)
|
||||
}
|
||||
|
||||
// Add to mempool transaction that spends childTransaction2 (as high priority)
|
||||
spendingTransaction, err := testutils.CreateTransaction(childTransaction2, 1000)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating spendingTransaction: %+v", err)
|
||||
}
|
||||
_, err = miningManager.ValidateAndInsertTransaction(spendingTransaction, true, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Error inserting spendingTransaction: %+v", err)
|
||||
}
|
||||
|
||||
// Revalidate, to make sure spendingTransaction is still valid
|
||||
validTransactions, err := miningManager.RevalidateHighPriorityTransactions()
|
||||
if err != nil {
|
||||
t.Fatalf("Error from first RevalidateHighPriorityTransactions: %+v", err)
|
||||
}
|
||||
if len(validTransactions) != 1 || !validTransactions[0].Equal(spendingTransaction) {
|
||||
t.Fatalf("Expected to have spendingTransaction as only validTransaction returned from "+
|
||||
"RevalidateHighPriorityTransactions, but got %v instead", validTransactions)
|
||||
}
|
||||
|
||||
// Mine 2 more blocks on top of tip1, to re-org out childTransaction1, thus making spendingTransaction invalid
|
||||
for i := 0; i < 2; i++ {
|
||||
tip1, _, err = tc.AddBlock([]*externalapi.DomainHash{tip1}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error mining on top of tip1: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure spendingTransaction is still in mempool
|
||||
allTransactions := miningManager.AllTransactions()
|
||||
if len(allTransactions) != 1 || !allTransactions[0].Equal(spendingTransaction) {
|
||||
t.Fatalf("Expected to have spendingTransaction as only validTransaction returned from "+
|
||||
"RevalidateHighPriorityTransactions, but got %v instead", validTransactions)
|
||||
}
|
||||
|
||||
// Revalidate again, this time validTransactions should be empty
|
||||
validTransactions, err = miningManager.RevalidateHighPriorityTransactions()
|
||||
if err != nil {
|
||||
t.Fatalf("Error from first RevalidateHighPriorityTransactions: %+v", err)
|
||||
}
|
||||
if len(validTransactions) != 0 {
|
||||
t.Fatalf("Expected to have empty validTransactions, but got %v instead", validTransactions)
|
||||
}
|
||||
// And also AllTransactions should be empty as well
|
||||
allTransactions = miningManager.AllTransactions()
|
||||
if len(allTransactions) != 0 {
|
||||
t.Fatalf("Expected to have empty allTransactions, but got %v instead", allTransactions)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func createTransactionWithUTXOEntry(t *testing.T, i int) *externalapi.DomainTransaction {
|
||||
prevOutTxID := externalapi.DomainTransactionID{}
|
||||
prevOutPoint := externalapi.DomainOutpoint{TransactionID: prevOutTxID, Index: uint32(i)}
|
||||
@ -369,8 +596,8 @@ func createArraysOfParentAndChildrenTransactions(tc testapi.TestConsensus) ([]*e
|
||||
return parentTransactions, transactions, nil
|
||||
}
|
||||
|
||||
func createParentAndChildrenTransactions(tc testapi.TestConsensus) (*externalapi.DomainTransaction,
|
||||
*externalapi.DomainTransaction, error) {
|
||||
func createParentAndChildrenTransactions(tc testapi.TestConsensus) (txParent *externalapi.DomainTransaction,
|
||||
txChild *externalapi.DomainTransaction, err error) {
|
||||
|
||||
// We will add two blocks by consensus before the parent transactions, in order to fund the parent transactions.
|
||||
tips, err := tc.Tips()
|
||||
@ -397,19 +624,19 @@ func createParentAndChildrenTransactions(tc testapi.TestConsensus) (*externalapi
|
||||
return nil, nil, errors.Wrap(err, "GetBlock: ")
|
||||
}
|
||||
fundingTransactionForParent := fundingBlockForParent.Transactions[transactionhelper.CoinbaseTransactionIndex]
|
||||
txParent, err := testutils.CreateTransaction(fundingTransactionForParent, 1000)
|
||||
txParent, err = testutils.CreateTransaction(fundingTransactionForParent, 1000)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
txChild, err := testutils.CreateTransaction(txParent, 1000)
|
||||
txChild, err = testutils.CreateTransaction(txParent, 1000)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return txParent, txChild, nil
|
||||
}
|
||||
|
||||
func createChildTxWhenParentTxWasAddedByConsensus(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainTransaction, error) {
|
||||
firstBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
func createChildAndParentTxsAndAddParentToConsensus(tc testapi.TestConsensus) (*externalapi.DomainTransaction, error) {
|
||||
firstBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{tc.DAGParams().GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "AddBlock: %v", err)
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
)
|
||||
|
||||
// Mempool maintains a set of known transactions that
|
||||
// are intended to be mined into new blocks
|
||||
type Mempool interface {
|
||||
HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error)
|
||||
BlockCandidateTransactions() []*consensusexternalapi.DomainTransaction
|
||||
ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error
|
||||
RemoveTransactions(txs []*consensusexternalapi.DomainTransaction) error
|
||||
GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool)
|
||||
AllTransactions() []*consensusexternalapi.DomainTransaction
|
||||
HandleNewBlockTransactions(txs []*externalapi.DomainTransaction) ([]*externalapi.DomainTransaction, error)
|
||||
BlockCandidateTransactions() []*externalapi.DomainTransaction
|
||||
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
||||
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
||||
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
||||
GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool)
|
||||
AllTransactions() []*externalapi.DomainTransaction
|
||||
TransactionCount() int
|
||||
RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error)
|
||||
IsTransactionOutputDust(output *externalapi.DomainTransactionOutput) bool
|
||||
}
|
||||
|
13
go.mod
13
go.mod
@ -3,27 +3,15 @@ module github.com/kaspanet/kaspad
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/aokoli/goutils v1.1.1 // indirect
|
||||
github.com/btcsuite/btcutil v1.0.2
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd
|
||||
github.com/btcsuite/winsvc v1.0.0
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/jessevdk/go-flags v1.4.0
|
||||
github.com/jrick/logrotate v1.0.0
|
||||
github.com/kaspanet/go-muhash v0.0.4
|
||||
github.com/kaspanet/go-secp256k1 v0.0.7
|
||||
github.com/kaspanet/protoc-gen-doc v1.4.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mwitkow/go-proto-validators v0.3.2 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
@ -33,4 +21,5 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 // indirect
|
||||
google.golang.org/grpc v1.38.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
)
|
||||
|
121
go.sum
121
go.sum
@ -1,73 +1,35 @@
|
||||
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
|
||||
github.com/aokoli/goutils v1.1.1 h1:/hA+Ywo3AxoDZY5ZMnkiEkUvkK4BPp927ax110KCqqg=
|
||||
github.com/aokoli/goutils v1.1.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
|
||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
||||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415 h1:q1oJaUPdmpDm/VyXosjgPgr6wS7c5iV2p0PwJD73bUI=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.1 h1:4CF52PCseTFt4bE+Yk3dIpdVi7XWuPVMhPtm4FaIJPM=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
@ -87,20 +49,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 h1:ux/56T2xqZO/3cP1I2F86qpeoYPCOzk+KF/UH/Ar+lk=
|
||||
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
@ -110,84 +61,37 @@ github.com/kaspanet/go-muhash v0.0.4 h1:CQrm1RTJpQy+h4ZFjj9qq42K5fmA5QTGifzb47p4
|
||||
github.com/kaspanet/go-muhash v0.0.4/go.mod h1:10bPW5mO1vNHPSejaAh9ZTtLZE16jzEvgaP7f3Q5s/8=
|
||||
github.com/kaspanet/go-secp256k1 v0.0.7 h1:WHnrwopKB6ZeHSbdAwwxNhTqflm56XT1mM6LF4/OvOs=
|
||||
github.com/kaspanet/go-secp256k1 v0.0.7/go.mod h1:cFbxhxKkxqHX5eIwUGKARkph19PehipDPJejWB+H0jM=
|
||||
github.com/kaspanet/protoc-gen-doc v1.4.0 h1:d2U/0F9b8AVP6mCymHaHn3Ry+Zc8LXV0UGpfj+WS/w0=
|
||||
github.com/kaspanet/protoc-gen-doc v1.4.0/go.mod h1:0kD54MmtdrGv/V/z+24+WN3LS607NTvPbraKoxIMDPM=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/lyft/protoc-gen-star v0.5.1 h1:sImehRT+p7lW9n6R7MQc5hVgzWGEkDVZU4AsBQ4Isu8=
|
||||
github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=
|
||||
github.com/mwitkow/go-proto-validators v0.3.2 h1:qRlmpTzm2pstMKKzTdvwPCF5QfBNURSlAgN/R+qbKos=
|
||||
github.com/mwitkow/go-proto-validators v0.3.2/go.mod h1:ej0Qp0qMgHN/KtDyUt+Q1/tA7a5VarXUOUxD+oeD30w=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/pseudomuto/protokit v0.2.0 h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM=
|
||||
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.3.4 h1:8q6vk3hthlpb2SouZcnBVKboxWQWMDNF38bwholZrJc=
|
||||
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -196,26 +100,18 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -226,36 +122,26 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 h1:pc16UedxnxXXtGxHCSUhafAoVHQZ0yXl8ZelMH4EETc=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
@ -263,8 +149,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
@ -279,19 +163,14 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -109,7 +109,7 @@ type Flags struct {
|
||||
LogLevel string `short:"d" long:"loglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`
|
||||
Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"`
|
||||
MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in KAS/kB to be considered a non-zero fee."`
|
||||
MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"`
|
||||
MaxOrphanTxs uint64 `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"`
|
||||
BlockMaxMass uint64 `long:"blockmaxmass" description:"Maximum transaction mass to be used when creating a block"`
|
||||
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
|
||||
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
|
||||
@ -485,16 +485,6 @@ func LoadConfig() (*Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Limit the max orphan count to a sane value.
|
||||
if cfg.MaxOrphanTxs < 0 {
|
||||
str := "%s: The maxorphantx option may not be less than 0 " +
|
||||
"-- parsed [%d]"
|
||||
err := errors.Errorf(str, funcName, cfg.MaxOrphanTxs)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
fmt.Fprintln(os.Stderr, usageMessage)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Look for illegal characters in the user agent comments.
|
||||
for _, uaComment := range cfg.UserAgentComments {
|
||||
if strings.ContainsAny(uaComment, "/:()") {
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
const _ = grpc.SupportPackageIsVersion6
|
||||
|
||||
// P2PClient is the client API for P2P service.
|
||||
//
|
||||
@ -71,19 +71,12 @@ type P2PServer interface {
|
||||
type UnimplementedP2PServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error {
|
||||
func (*UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method MessageStream not implemented")
|
||||
}
|
||||
func (UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {}
|
||||
func (*UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {}
|
||||
|
||||
// UnsafeP2PServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to P2PServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeP2PServer interface {
|
||||
mustEmbedUnimplementedP2PServer()
|
||||
}
|
||||
|
||||
func RegisterP2PServer(s grpc.ServiceRegistrar, srv P2PServer) {
|
||||
func RegisterP2PServer(s *grpc.Server, srv P2PServer) {
|
||||
s.RegisterService(&_P2P_serviceDesc, srv)
|
||||
}
|
||||
|
||||
@ -186,19 +179,12 @@ type RPCServer interface {
|
||||
type UnimplementedRPCServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error {
|
||||
func (*UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method MessageStream not implemented")
|
||||
}
|
||||
func (UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {}
|
||||
func (*UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {}
|
||||
|
||||
// UnsafeRPCServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to RPCServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeRPCServer interface {
|
||||
mustEmbedUnimplementedRPCServer()
|
||||
}
|
||||
|
||||
func RegisterRPCServer(s grpc.ServiceRegistrar, srv RPCServer) {
|
||||
func RegisterRPCServer(s *grpc.Server, srv RPCServer) {
|
||||
s.RegisterService(&_RPC_serviceDesc, srv)
|
||||
}
|
||||
|
||||
|
@ -2268,6 +2268,7 @@ type SubmitTransactionRequestMessage struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Transaction *RpcTransaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"`
|
||||
AllowOrphan bool `protobuf:"varint,2,opt,name=allowOrphan,proto3" json:"allowOrphan,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SubmitTransactionRequestMessage) Reset() {
|
||||
@ -2309,6 +2310,13 @@ func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SubmitTransactionRequestMessage) GetAllowOrphan() bool {
|
||||
if x != nil {
|
||||
return x.AllowOrphan
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type SubmitTransactionResponseMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -5552,363 +5560,366 @@ var file_rpc_proto_rawDesc = []byte{
|
||||
0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05,
|
||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54,
|
||||
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e,
|
||||
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61,
|
||||
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54,
|
||||
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61,
|
||||
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12,
|
||||
0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45,
|
||||
0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x37, 0x0a, 0x35, 0x4e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65,
|
||||
0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69,
|
||||
0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a,
|
||||
0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xb3, 0x01, 0x0a, 0x34, 0x56,
|
||||
0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61,
|
||||
0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
|
||||
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x43, 0x68,
|
||||
0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01,
|
||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x43, 0x68, 0x61,
|
||||
0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x41, 0x0a,
|
||||
0x10, 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x10,
|
||||
0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73,
|
||||
0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61,
|
||||
0x73, 0x68, 0x12, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x22, 0x5b, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64,
|
||||
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x36, 0x0a, 0x16, 0x61, 0x63, 0x63,
|
||||
0x65, 0x70, 0x74, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x70,
|
||||
0x74, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64,
|
||||
0x73, 0x22, 0x5e, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68,
|
||||
0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12,
|
||||
0x30, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x69, 0x6e,
|
||||
0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x22, 0x70, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x05,
|
||||
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x22, 0x41, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x66, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62,
|
||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01,
|
||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x80, 0x01, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74,
|
||||
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61,
|
||||
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 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, 0x20, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4f,
|
||||
0x72, 0x70, 0x68, 0x61, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c, 0x6c,
|
||||
0x6f, 0x77, 0x4f, 0x72, 0x70, 0x68, 0x61, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d,
|
||||
0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d,
|
||||
0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52,
|
||||
0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x54,
|
||||
0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65,
|
||||
0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46,
|
||||
0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48,
|
||||
0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74,
|
||||
0x48, 0x61, 0x73, 0x68, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74,
|
||||
0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e,
|
||||
0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38,
|
||||
0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x65,
|
||||
0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43,
|
||||
0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x10, 0x61, 0x64, 0x64, 0x65, 0x64,
|
||||
0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65,
|
||||
0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x8b, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x24, 0x0a,
|
||||
0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72,
|
||||
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65,
|
||||
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61,
|
||||
0x73, 0x68, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x03,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x52, 0x70, 0x63, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50,
|
||||
0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x1d, 0x0a,
|
||||
0x1b, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8c, 0x01, 0x0a,
|
||||
0x1c, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a,
|
||||
0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a,
|
||||
0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12,
|
||||
0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45,
|
||||
0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x1f, 0x0a, 0x1d, 0x47,
|
||||
0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x9e, 0x03, 0x0a,
|
||||
0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73,
|
||||
0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65,
|
||||
0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74,
|
||||
0x79, 0x12, 0x26, 0x0a, 0x0e, 0x70, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x70, 0x61, 0x73, 0x74, 0x4d,
|
||||
0x65, 0x64, 0x69, 0x61, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x76, 0x69, 0x72,
|
||||
0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73,
|
||||
0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50,
|
||||
0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x70,
|
||||
0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18,
|
||||
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75,
|
||||
0x61, 0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72,
|
||||
0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x37,
|
||||
0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53,
|
||||
0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61,
|
||||
0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66,
|
||||
0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64,
|
||||
0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50,
|
||||
0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a,
|
||||
0x25, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69,
|
||||
0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x48, 0x61, 0x73, 0x68, 0x22, 0x54, 0x0a, 0x26, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46,
|
||||
0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a,
|
||||
0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xb3, 0x01,
|
||||
0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65,
|
||||
0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65,
|
||||
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64,
|
||||
0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73,
|
||||
0x12, 0x41, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x52, 0x10, 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x73, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65,
|
||||
0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,
|
||||
0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65,
|
||||
0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x5b, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x70,
|
||||
0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x36, 0x0a, 0x16,
|
||||
0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x61, 0x63,
|
||||
0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x49, 0x64, 0x73, 0x22, 0x5e, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61,
|
||||
0x73, 0x68, 0x12, 0x30, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61,
|
||||
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x22, 0x70, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x29, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x41, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62,
|
||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62,
|
||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x66, 0x0a, 0x1c, 0x47, 0x65, 0x74,
|
||||
0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x61, 0x73,
|
||||
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73,
|
||||
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8,
|
||||
0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72,
|
||||
0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x22, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53,
|
||||
0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61,
|
||||
0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61,
|
||||
0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74,
|
||||
0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56,
|
||||
0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61,
|
||||
0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x12, 0x38, 0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69,
|
||||
0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e,
|
||||
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x10, 0x61,
|
||||
0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18,
|
||||
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72,
|
||||
0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x10, 0x61, 0x64,
|
||||
0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2a,
|
||||
0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x27, 0x0a, 0x25, 0x4e, 0x6f,
|
||||
0x74, 0x69, 0x66, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x6c, 0x69, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x22, 0x54, 0x0a, 0x26, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x73, 0x52, 0x65,
|
||||
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x8b, 0x01, 0x0a, 0x17, 0x47,
|
||||
0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73,
|
||||
0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68,
|
||||
0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
|
||||
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
|
||||
0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e,
|
||||
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74,
|
||||
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61,
|
||||
0x73, 0x68, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x06, 0x62, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x22, 0x1d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
|
||||
0x8c, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x12, 0x20, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52,
|
||||
0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x1f,
|
||||
0x0a, 0x1d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
|
||||
0x9e, 0x03, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65,
|
||||
0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73,
|
||||
0x68, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61,
|
||||
0x73, 0x68, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c,
|
||||
0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63,
|
||||
0x75, 0x6c, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x70, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x64, 0x69,
|
||||
0x61, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x70, 0x61,
|
||||
0x73, 0x74, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13,
|
||||
0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73,
|
||||
0x68, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x76, 0x69, 0x72, 0x74, 0x75,
|
||||
0x61, 0x6c, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2a,
|
||||
0x0a, 0x10, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61,
|
||||
0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e,
|
||||
0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, 0x76, 0x69,
|
||||
0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x09, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x61, 0x53,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x22, 0x55, 0x0a, 0x25, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c,
|
||||
0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x54, 0x0a, 0x26, 0x52, 0x65, 0x73, 0x6f, 0x6c,
|
||||
0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69,
|
||||
0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50,
|
||||
0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x27, 0x0a,
|
||||
0x25, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x54, 0x0a, 0x26, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
|
||||
0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74,
|
||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43,
|
||||
0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x23,
|
||||
0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74,
|
||||
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67,
|
||||
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x12, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
|
||||
0x61, 0x73, 0x68, 0x22, 0x5b, 0x0a, 0x2b, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x4e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66,
|
||||
0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68,
|
||||
0x22, 0x18, 0x0a, 0x16, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x45, 0x0a, 0x17, 0x53, 0x68,
|
||||
0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8,
|
||||
0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72,
|
||||
0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x22, 0x70, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c,
|
||||
0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69,
|
||||
0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64,
|
||||
0x69, 0x6e, 0x67, 0x22, 0x61, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
|
||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
|
||||
0x09, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
|
||||
0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64,
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69,
|
||||
0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x23, 0x46, 0x69, 0x6e,
|
||||
0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x4e, 0x6f, 0x74,
|
||||
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x12, 0x2e, 0x0a, 0x12, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x76, 0x69,
|
||||
0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68,
|
||||
0x22, 0x5b, 0x0a, 0x2b, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x6c, 0x69, 0x63, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69,
|
||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x2c, 0x0a, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6e, 0x61,
|
||||
0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x18, 0x0a,
|
||||
0x16, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x45, 0x0a, 0x17, 0x53, 0x68, 0x75, 0x74, 0x44,
|
||||
0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52,
|
||||
0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x70,
|
||||
0x0a, 0x18, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74,
|
||||
0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73,
|
||||
0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69,
|
||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20,
|
||||
0x0a, 0x0b, 0x69, 0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
|
||||
0x22, 0x61, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
|
||||
0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78,
|
||||
0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55,
|
||||
0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73,
|
||||
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64,
|
||||
0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64,
|
||||
0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e,
|
||||
0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73,
|
||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c,
|
||||
0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75,
|
||||
0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e,
|
||||
0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74,
|
||||
0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x47, 0x0a,
|
||||
0x27, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, 0x74,
|
||||
0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x28, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f,
|
||||
0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52,
|
||||
0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x41,
|
||||
0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65,
|
||||
0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79,
|
||||
0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72,
|
||||
0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74,
|
||||
0x72, 0x69, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x22, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65,
|
||||
0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61,
|
||||
0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42,
|
||||
0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 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, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8,
|
||||
0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74,
|
||||
0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a,
|
||||
0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79,
|
||||
0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05,
|
||||
0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64,
|
||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
|
||||
0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e,
|
||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
|
||||
0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78,
|
||||
0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f,
|
||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||
0x22, 0x47, 0x0a, 0x27, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e,
|
||||
0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x28, 0x53, 0x74, 0x6f,
|
||||
0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8,
|
||||
0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72,
|
||||
0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x22, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75,
|
||||
0x72, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f,
|
||||
0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65,
|
||||
0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79,
|
||||
0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07,
|
||||
0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x22, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61,
|
||||
0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42,
|
||||
0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72,
|
||||
0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65,
|
||||
0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 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, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65,
|
||||
0x72, 0x72, 0x6f, 0x72, 0x22, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69,
|
||||
0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75,
|
||||
0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74,
|
||||
0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68,
|
||||
0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53,
|
||||
0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75,
|
||||
0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05,
|
||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72,
|
||||
0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65,
|
||||
0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c,
|
||||
0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c,
|
||||
0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76,
|
||||
0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61,
|
||||
0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x2c, 0x0a,
|
||||
0x2a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61,
|
||||
0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x59, 0x0a, 0x2b, 0x4e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x61, 0x53,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x29, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45,
|
||||
0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x82, 0x01, 0x0a, 0x38,
|
||||
0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50,
|
||||
0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68,
|
||||
0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74,
|
||||
0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e,
|
||||
0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65,
|
||||
0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x22, 0x2c, 0x0a, 0x2a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61,
|
||||
0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
|
||||
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61,
|
||||
0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x76, 0x69,
|
||||
0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x31, 0x0a,
|
||||
0x2f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x22, 0x5e, 0x0a, 0x30, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x59,
|
||||
0x0a, 0x2b, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44,
|
||||
0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x29, 0x56, 0x69, 0x72,
|
||||
0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61,
|
||||
0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x22, 0x31, 0x0a, 0x2f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e,
|
||||
0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x4f, 0x76, 0x65,
|
||||
0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x22, 0x30, 0x0a, 0x2e, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x4e,
|
||||
0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x22, 0x38, 0x0a, 0x36, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
|
||||
0x69, 0x6e, 0x67, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55,
|
||||
0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x65, 0x0a, 0x37,
|
||||
0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x75,
|
||||
0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x22, 0x5e, 0x0a, 0x30, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x50, 0x72, 0x75,
|
||||
0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74,
|
||||
0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x22, 0x23, 0x0a, 0x11, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x40, 0x0a, 0x12, 0x42, 0x61, 0x6e, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a,
|
||||
0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x25, 0x0a, 0x13, 0x55, 0x6e,
|
||||
0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
||||
0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05,
|
||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c,
|
||||
0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x32, 0x70, 0x49,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, 0x12, 0x20,
|
||||
0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x69, 0x7a, 0x65,
|
||||
0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43,
|
||||
0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x6c, 0x0a, 0x2c,
|
||||
0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48,
|
||||
0x61, 0x73, 0x68, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a,
|
||||
0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||
0x52, 0x0a, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09,
|
||||
0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x93, 0x01, 0x0a, 0x2d, 0x45,
|
||||
0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61,
|
||||
0x73, 0x68, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x16,
|
||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x50, 0x65, 0x72,
|
||||
0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x6e, 0x65,
|
||||
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65,
|
||||
0x63, 0x6f, 0x6e, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x42, 0x26, 0x5a, 0x24, 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, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x72, 0x6f, 0x72, 0x22, 0x30, 0x0a, 0x2e, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x38, 0x0a, 0x36, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74,
|
||||
0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69,
|
||||
0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
|
||||
0x65, 0x0a, 0x37, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67,
|
||||
0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f,
|
||||
0x53, 0x65, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x23, 0x0a, 0x11, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x40, 0x0a, 0x12, 0x42,
|
||||
0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50,
|
||||
0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x25, 0x0a,
|
||||
0x13, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05,
|
||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x22, 0x7c, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70,
|
||||
0x32, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x32, 0x70, 0x49,
|
||||
0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x69, 0x7a, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53,
|
||||
0x69, 0x7a, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e,
|
||||
0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22,
|
||||
0x6c, 0x0a, 0x2c, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f,
|
||||
0x72, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e,
|
||||
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x1e, 0x0a, 0x0a, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0d, 0x52, 0x0a, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x69, 0x7a, 0x65, 0x12,
|
||||
0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x93, 0x01,
|
||||
0x0a, 0x2d, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
|
||||
0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
|
||||
0x36, 0x0a, 0x16, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73,
|
||||
0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x16, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x50, 0x65,
|
||||
0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x42, 0x26, 0x5a, 0x24, 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, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -273,6 +273,7 @@ message AddPeerResponseMessage{
|
||||
// SubmitTransactionRequestMessage submits a transaction to the mempool
|
||||
message SubmitTransactionRequestMessage{
|
||||
RpcTransaction transaction = 1;
|
||||
bool allowOrphan = 2;
|
||||
}
|
||||
|
||||
message SubmitTransactionResponseMessage{
|
||||
|
@ -1,9 +1,10 @@
|
||||
package protowire
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/pkg/errors"
|
||||
"math"
|
||||
)
|
||||
|
||||
func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Message, error) {
|
||||
@ -16,6 +17,7 @@ func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Mess
|
||||
func (x *KaspadMessage_SubmitTransactionRequest) fromAppMessage(message *appmessage.SubmitTransactionRequestMessage) error {
|
||||
x.SubmitTransactionRequest = &SubmitTransactionRequestMessage{
|
||||
Transaction: &RpcTransaction{},
|
||||
AllowOrphan: message.AllowOrphan,
|
||||
}
|
||||
x.SubmitTransactionRequest.Transaction.fromAppMessage(message.Transaction)
|
||||
return nil
|
||||
@ -31,6 +33,7 @@ func (x *SubmitTransactionRequestMessage) toAppMessage() (appmessage.Message, er
|
||||
}
|
||||
return &appmessage.SubmitTransactionRequestMessage{
|
||||
Transaction: rpcTransaction,
|
||||
AllowOrphan: x.AllowOrphan,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user