dcrd/internal/rpcserver/interface.go
Donald Adu-Poku dcddbbabb4 multi: add SanityChecker interface.
This adds the sanity checker interface and update
the function signature of CheckBlockSanity.
Associated tests and mocks updated/added.
2020-07-25 19:17:27 -05:00

468 lines
18 KiB
Go

// Copyright (c) 2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package rpcserver
import (
"math/big"
"net"
"time"
"github.com/decred/dcrd/addrmgr"
"github.com/decred/dcrd/blockchain/stake/v3"
"github.com/decred/dcrd/blockchain/v3"
"github.com/decred/dcrd/blockchain/v3/indexers"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrutil/v3"
"github.com/decred/dcrd/gcs/v2"
"github.com/decred/dcrd/internal/mempool"
"github.com/decred/dcrd/peer/v2"
"github.com/decred/dcrd/wire"
)
// Peer represents a peer for use with the RPC server.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type Peer interface {
// Addr returns the peer address.
Addr() string
// Connected returns whether or not the peer is currently connected.
Connected() bool
// ID returns the peer id.
ID() int32
// Inbound returns whether the peer is inbound.
Inbound() bool
// StatsSnapshot returns a snapshot of the current peer flags and statistics.
StatsSnapshot() *peer.StatsSnap
// LocalAddr returns the local address of the connection.
LocalAddr() net.Addr
// LastPingNonce returns the last ping nonce of the remote peer.
LastPingNonce() uint64
// IsTxRelayDisabled returns whether or not the peer has disabled
// transaction relay.
IsTxRelayDisabled() bool
// BanScore returns the current integer value that represents how close
// the peer is to being banned.
BanScore() uint32
}
// AddrManager represents an address manager for use with the RPC server.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type AddrManager interface {
// LocalAddresses returns a summary of local addresses information for
// the getnetworkinfo rpc.
LocalAddresses() []addrmgr.LocalAddr
}
// ConnManager represents a connection manager for use with the RPC server.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type ConnManager interface {
// Connect adds the provided address as a new outbound peer. The
// permanent flag indicates whether or not to make the peer persistent
// and reconnect if the connection is lost. Attempting to connect to an
// already existing peer will return an error.
Connect(addr string, permanent bool) error
// RemoveByID removes the peer associated with the provided id from the
// list of persistent peers. Attempting to remove an id that does not
// exist will return an error.
RemoveByID(id int32) error
// RemoveByAddr removes the peer associated with the provided address
// from the list of persistent peers. Attempting to remove an address
// that does not exist will return an error.
RemoveByAddr(addr string) error
// DisconnectByID disconnects the peer associated with the provided id.
// This applies to both inbound and outbound peers. Attempting to
// remove an id that does not exist will return an error.
DisconnectByID(id int32) error
// DisconnectByAddr disconnects the peer associated with the provided
// address. This applies to both inbound and outbound peers.
// Attempting to remove an address that does not exist will return an
// error.
DisconnectByAddr(addr string) error
// ConnectedCount returns the number of currently connected peers.
ConnectedCount() int32
// NetTotals returns the sum of all bytes received and sent across the
// network for all peers.
NetTotals() (uint64, uint64)
// ConnectedPeers returns an array consisting of all connected peers.
ConnectedPeers() []Peer
// PersistentPeers returns an array consisting of all the persistent
// peers.
PersistentPeers() []Peer
// BroadcastMessage sends the provided message to all currently
// connected peers.
BroadcastMessage(msg wire.Message)
// AddRebroadcastInventory adds the provided inventory to the list of
// inventories to be rebroadcast at random intervals until they show up
// in a block.
AddRebroadcastInventory(iv *wire.InvVect, data interface{})
// RelayTransactions generates and relays inventory vectors for all of
// the passed transactions to all connected peers.
RelayTransactions(txns []*dcrutil.Tx)
// AddedNodeInfo returns information describing persistent (added) nodes.
AddedNodeInfo() []Peer
// Lookup defines the DNS lookup function to be used.
Lookup(host string) ([]net.IP, error)
}
// SyncManager represents a sync manager for use with the RPC server.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type SyncManager interface {
// IsCurrent returns whether or not the sync manager believes the chain
// is current as compared to the rest of the network.
IsCurrent() bool
// SubmitBlock submits the provided block to the network after
// processing it locally.
SubmitBlock(block *dcrutil.Block, flags blockchain.BehaviorFlags) (bool, error)
// SyncPeerID returns the id of the current peer being synced with.
SyncPeerID() int32
// LocateBlocks returns the hashes of the blocks after the first known block
// in the locator until the provided stop hash is reached, or up to the
// provided max number of block hashes.
LocateBlocks(locator blockchain.BlockLocator, hashStop *chainhash.Hash,
maxHashes uint32) []chainhash.Hash
// ExistsAddrIndex returns the address index.
ExistsAddrIndex() *indexers.ExistsAddrIndex
// CFIndex returns the committed filter (cf) by hash index.
CFIndex() *indexers.CFIndex
// TipGeneration returns the entire generation of blocks stemming from the
// parent of the current tip.
TipGeneration() ([]chainhash.Hash, error)
// SyncHeight returns latest known block being synced to.
SyncHeight() int64
// ProcessTransaction relays the provided transaction validation and
// insertion into the memory pool.
ProcessTransaction(tx *dcrutil.Tx, allowOrphans bool, rateLimit bool,
allowHighFees bool, tag mempool.Tag) ([]*dcrutil.Tx, error)
}
// UtxoEntry represents a utxo entry for use with the RPC server.
//
// The interface contract does NOT require that these methods are safe for
// concurrent access.
type UtxoEntry interface {
// ToUtxoEntry returns the underlying UtxoEntry instance.
ToUtxoEntry() *blockchain.UtxoEntry
// TransactionType returns the type of the transaction the utxo entry
// represents.
TransactionType() stake.TxType
// IsOutputSpent returns whether or not the provided output index has been
// spent based upon the current state of the unspent transaction output view
// the entry was obtained from.
//
// Returns true if the output index references an output that does not exist
// either due to it being invalid or because the output is not part of the view
// due to previously being spent/pruned.
IsOutputSpent(outputIndex uint32) bool
// BlockHeight returns the height of the block containing the transaction the
// utxo entry represents.
BlockHeight() int64
// TxVersion returns the version of the transaction the utxo represents.
TxVersion() uint16
// AmountByIndex returns the amount of the provided output index.
//
// Returns 0 if the output index references an output that does not exist
// either due to it being invalid or because the output is not part of the view
// due to previously being spent/pruned.
AmountByIndex(outputIndex uint32) int64
// ScriptVersionByIndex returns the public key script for the provided output
// index.
//
// Returns 0 if the output index references an output that does not exist
// either due to it being invalid or because the output is not part of the view
// due to previously being spent/pruned.
ScriptVersionByIndex(outputIndex uint32) uint16
// PkScriptByIndex returns the public key script for the provided output index.
//
// Returns nil if the output index references an output that does not exist
// either due to it being invalid or because the output is not part of the view
// due to previously being spent/pruned.
PkScriptByIndex(outputIndex uint32) []byte
// IsCoinBase returns whether or not the transaction the utxo entry represents
// is a coinbase.
IsCoinBase() bool
}
// Chain represents a chain for use with the RPC server.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type Chain interface {
// BestSnapshot returns information about the current best chain block and
// related state as of the current point in time. The returned instance must be
// treated as immutable since it is shared by all callers.
BestSnapshot() *blockchain.BestState
// BlockByHash returns the block for the given hash, regardless of whether the
// block is part of the main chain or not.
BlockByHash(hash *chainhash.Hash) (*dcrutil.Block, error)
// BlockByHeight returns the block at the given height in the main chain.
BlockByHeight(height int64) (*dcrutil.Block, error)
// BlockHashByHeight returns the hash of the block at the given height in the
// main chain.
BlockHashByHeight(height int64) (*chainhash.Hash, error)
// BlockHeightByHash returns the height of the block with the given hash in the
// main chain.
BlockHeightByHash(hash *chainhash.Hash) (int64, error)
// CalcNextRequiredStakeDifficulty calculates the required stake difficulty for
// the block after the end of the current best chain based on the active stake
// difficulty retarget rules.
CalcNextRequiredStakeDifficulty() (int64, error)
// CalcWantHeight calculates the height of the final block of the previous
// interval given a block height.
CalcWantHeight(interval, height int64) int64
// ChainTips returns information, in JSON-RPC format, about all of the currently
// known chain tips in the block index.
ChainTips() []blockchain.ChainTipInfo
// ChainWork returns the total work up to and including the block of the
// provided block hash.
ChainWork(hash *chainhash.Hash) (*big.Int, error)
// CheckExpiredTicket returns whether or not a ticket was ever expired.
CheckExpiredTickets(hashes []chainhash.Hash) []bool
// CheckLiveTicket returns whether or not a ticket exists in the live ticket
// treap of the best node.
CheckLiveTicket(hash chainhash.Hash) bool
// CheckLiveTickets returns a slice of bools representing whether each ticket
// exists in the live ticket treap of the best node.
CheckLiveTickets(hashes []chainhash.Hash) []bool
// CheckMissedTickets returns a slice of bools representing whether each ticket
// hash has been missed in the live ticket treap of the best node.
CheckMissedTickets(hashes []chainhash.Hash) []bool
// ConvertUtxosToMinimalOutputs converts the contents of a UTX to a series of
// minimal outputs. It does this so that these can be passed to stake subpackage
// functions, where they will be evaluated for correctness.
ConvertUtxosToMinimalOutputs(entry UtxoEntry) []*stake.MinimalOutput
// CountVoteVersion returns the total number of version votes for the current
// rule change activation interval.
CountVoteVersion(version uint32) (uint32, error)
// EstimateNextStakeDifficulty estimates the next stake difficulty by pretending
// the provided number of tickets will be purchased in the remainder of the
// interval unless the flag to use max tickets is set in which case it will use
// the max possible number of tickets that can be purchased in the remainder of
// the interval.
EstimateNextStakeDifficulty(newTickets int64, useMaxTickets bool) (int64, error)
// FetchUtxoEntry loads and returns the unspent transaction output entry for the
// passed hash from the point of view of the end of the main chain.
//
// NOTE: Requesting a hash for which there is no data must NOT return an error.
// Instead both the entry and the error must be nil. This is done to allow
// pruning of fully spent transactions. In practice this means the caller must
// check if the returned entry is nil before invoking methods on it.
//
// This function is safe for concurrent access however the returned entry (if
// any) is NOT.
FetchUtxoEntry(txHash *chainhash.Hash) (UtxoEntry, error)
// FetchUtxoStats returns statistics on the current utxo set.
FetchUtxoStats() (*blockchain.UtxoStats, error)
// FilterByBlockHash returns the version 2 GCS filter for the given block hash
// when it exists. This function returns the filters regardless of whether or
// not their associated block is part of the main chain.
//
// An error of type blockchain.NoFilterError must be returned when the filter
// for the given block hash does not exist.
FilterByBlockHash(hash *chainhash.Hash) (*gcs.FilterV2, error)
// GetStakeVersions returns a cooked array of StakeVersions. We do this in
// order to not bloat memory by returning raw blocks.
GetStakeVersions(hash *chainhash.Hash, count int32) ([]blockchain.StakeVersions, error)
// GetVoteCounts returns the vote counts for the specified version and
// deployment identifier for the current rule change activation interval.
GetVoteCounts(version uint32, deploymentID string) (blockchain.VoteCounts, error)
// GetVoteInfo returns information on consensus deployment agendas
// and their respective states at the provided hash, for the provided
// deployment version.
GetVoteInfo(hash *chainhash.Hash, version uint32) (*blockchain.VoteInfo, error)
// HeaderByHash returns the block header identified by the given hash or an
// error if it doesn't exist. Note that this will return headers from both the
// main chain and any side chains.
HeaderByHash(hash *chainhash.Hash) (wire.BlockHeader, error)
// HeaderByHeight returns the block header at the given height in the main
// chain.
HeaderByHeight(height int64) (wire.BlockHeader, error)
// HeightRange returns a range of block hashes for the given start and end
// heights. It is inclusive of the start height and exclusive of the end
// height. In other words, it is the half open range [startHeight, endHeight).
//
// The end height will be limited to the current main chain height.
HeightRange(startHeight, endHeight int64) ([]chainhash.Hash, error)
// IsCurrent returns whether or not the chain believes it is current. Several
// factors are used to guess, but the key factors that allow the chain to
// believe it is current are:
// - Total amount of cumulative work is more than the minimum known work
// specified by the parameters for the network
// - Latest block has a timestamp newer than 24 hours ago
IsCurrent() bool
// LiveTickets returns all currently live tickets.
LiveTickets() ([]chainhash.Hash, error)
// LocateHeaders returns the headers of the blocks after the first known block
// in the locator until the provided stop hash is reached, or up to a max of
// wire.MaxBlockHeadersPerMsg headers.
//
// In addition, there are two special cases:
//
// - When no locators are provided, the stop hash is treated as a request for
// that header, so it will either return the header for the stop hash itself
// if it is known, or nil if it is unknown
// - When locators are provided, but none of them are known, headers starting
// after the genesis block will be returned
LocateHeaders(locator blockchain.BlockLocator, hashStop *chainhash.Hash) []wire.BlockHeader
// LotteryDataForBlock returns lottery data for a given block in the block
// chain, including side chain blocks.
LotteryDataForBlock(hash *chainhash.Hash) ([]chainhash.Hash, int, [6]byte, error)
// MainChainHasBlock returns whether or not the block with the given hash is in
// the main chain.
MainChainHasBlock(hash *chainhash.Hash) bool
// MaxBlockSize returns the maximum permitted block size for the block AFTER
// the end of the current best chain.
MaxBlockSize() (int64, error)
// MissedTickets returns all currently missed tickets.
MissedTickets() ([]chainhash.Hash, error)
// NextThresholdState returns the current rule change threshold state of the
// given deployment ID for the block AFTER the provided block hash.
NextThresholdState(hash *chainhash.Hash, version uint32, deploymentID string) (blockchain.ThresholdStateTuple, error)
// StateLastChangedHeight returns the height at which the provided consensus
// deployment agenda last changed state. Note that, unlike the
// NextThresholdState function, this function returns the information as of the
// passed block hash.
StateLastChangedHeight(hash *chainhash.Hash, version uint32, deploymentID string) (int64, error)
// TicketPoolValue returns the current value of all the locked funds in the
// ticket pool.
TicketPoolValue() (dcrutil.Amount, error)
// TicketsWithAddress returns a slice of ticket hashes that are currently live
// corresponding to the given address.
TicketsWithAddress(address dcrutil.Address) ([]chainhash.Hash, error)
// TipGeneration returns the entire generation of blocks stemming from the
// parent of the current tip.
TipGeneration() ([]chainhash.Hash, error)
}
// Clock represents a clock for use with the RPC server. The purpose of this
// interface is to allow an alternative implementation to be used for testing.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type Clock interface {
// Now returns the current local time.
Now() time.Time
// Since returns the time elapsed since t.
Since(t time.Time) time.Duration
}
// FeeEstimator provides an interface that tracks historical data for published
// and mined transactions in order to estimate fees to be used in new
// transactions for confirmation within a target block window.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type FeeEstimator interface {
// EstimateFee calculates the suggested fee for a transaction to be
// confirmed in at most `targetConfs` blocks after publishing with a
// high degree of certainty.
EstimateFee(targetConfs int32) (dcrutil.Amount, error)
}
// LogManager represents a log manager for use with the RPC server.
//
// The interface contract does NOT require that these methods are safe for
// concurrent access.
type LogManager interface {
// SupportedSubsystems returns a sorted slice of the supported subsystems for
// logging purposes.
SupportedSubsystems() []string
// ParseAndSetDebugLevels attempts to parse the specified debug level and set
// the levels accordingly. An appropriate error must be returned if anything
// is invalid.
ParseAndSetDebugLevels(debugLevel string) error
}
// SanityChecker represents a block sanity checker for use with the RPC server.
//
// The interface contract requires that all of these methods are safe for
// concurrent access.
type SanityChecker interface {
// CheckBlockSanity checks the correctness of the provided block
// per consensus.
CheckBlockSanity(block *dcrutil.Block) error
}