multi: add SanityChecker interface.

This adds the sanity checker interface and update
the function signature of CheckBlockSanity.
Associated tests and mocks updated/added.
This commit is contained in:
Donald Adu-Poku 2020-07-23 14:35:42 +00:00 committed by Dave Collins
parent f73d738c24
commit dcddbbabb4
5 changed files with 102 additions and 46 deletions

View File

@ -455,3 +455,13 @@ type LogManager interface {
// 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
}

View File

@ -4786,8 +4786,7 @@ func verifyChain(_ context.Context, s *Server, level, depth int64) error {
// Level 1 does basic chain sanity checks.
if level > 0 {
err := blockchain.CheckBlockSanity(block, s.cfg.TimeSource,
s.cfg.ChainParams)
err := s.cfg.SanityChecker.CheckBlockSanity(block)
if err != nil {
log.Errorf("Verify is unable to validate "+
"block at hash %v height %d: %v",
@ -5593,12 +5592,13 @@ type Config struct {
// These fields allow the RPC server to interface with the local block
// chain data and state.
TimeSource blockchain.MedianTimeSource
Chain Chain
ChainParams *chaincfg.Params
DB database.DB
FeeEstimator FeeEstimator
Services wire.ServiceFlag
TimeSource blockchain.MedianTimeSource
Chain Chain
SanityChecker SanityChecker
ChainParams *chaincfg.Params
DB database.DB
FeeEstimator FeeEstimator
Services wire.ServiceFlag
// SubsidyCache defines a cache for efficient access to consensus-critical
// subsidy calculations.

View File

@ -654,6 +654,17 @@ func (l *testLogManager) SupportedSubsystems() []string {
return l.supportedSubsystems
}
// testSanityChecker provides a mock implementation that checks the sanity
// state of a block.
type testSanityChecker struct {
checkBlockSanityErr error
}
// testSanityChecker returns mock sanity state of the provided block.
func (s *testSanityChecker) CheckBlockSanity(block *dcrutil.Block) error {
return s.checkBlockSanityErr
}
// ParseAndSetDebugLevels provides a mock implementation for parsing the
// specified debug level and setting the levels accordingly.
func (l *testLogManager) ParseAndSetDebugLevels(debugLevel string) error {
@ -719,20 +730,21 @@ var block432100 = func() wire.MsgBlock {
}()
type rpcTest struct {
name string
handler commandHandler
cmd interface{}
mockChainParams *chaincfg.Params
mockChain *testRPCChain
mockAddrManager *testAddrManager
mockFeeEstimator *testFeeEstimator
mockSyncManager *testSyncManager
mockConnManager *testConnManager
mockClock *testClock
mockLogManager *testLogManager
result interface{}
wantErr bool
errCode dcrjson.RPCErrorCode
name string
handler commandHandler
cmd interface{}
mockChainParams *chaincfg.Params
mockChain *testRPCChain
mockSanityChecker *testSanityChecker
mockAddrManager *testAddrManager
mockFeeEstimator *testFeeEstimator
mockSyncManager *testSyncManager
mockConnManager *testConnManager
mockClock *testClock
mockLogManager *testLogManager
result interface{}
wantErr bool
errCode dcrjson.RPCErrorCode
}
// defaultChainParams provides a default chaincfg.Params to be used throughout
@ -878,6 +890,15 @@ func defaultMockRPCChain() *testRPCChain {
}
}
// defaultMockSanityChecker provides a default mock sanity checker to be used
// throughout the tests. Tests can override these defaults by calling
// defaultMockSanityChecker, updating fields as necessary on the returned
// *testSanityChecker, and then setting rpcTest.mockSanityChecker as that
// *testSanityChecker.
func defaultMockSanityChecker() *testSanityChecker {
return &testSanityChecker{}
}
// defaultMockAddrManager provides a default mock address manager to be used
// throughout the tests. Tests can override these defaults by calling
// defaultMockAddrManager, updating fields as necessary on the returned
@ -990,17 +1011,18 @@ func defaultMockLogManager() *testLogManager {
// the tests. Defaults can be overridden by tests through the rpcTest struct.
func defaultMockConfig(chainParams *chaincfg.Params) *Config {
return &Config{
ChainParams: chainParams,
Chain: defaultMockRPCChain(),
AddrManager: defaultMockAddrManager(),
FeeEstimator: defaultMockFeeEstimator(),
SyncMgr: defaultMockSyncManager(),
ConnMgr: defaultMockConnManager(),
Clock: &testClock{},
LogManager: defaultMockLogManager(),
TimeSource: blockchain.NewMedianTime(),
Services: wire.SFNodeNetwork | wire.SFNodeCF,
SubsidyCache: standalone.NewSubsidyCache(chainParams),
ChainParams: chainParams,
Chain: defaultMockRPCChain(),
SanityChecker: defaultMockSanityChecker(),
AddrManager: defaultMockAddrManager(),
FeeEstimator: defaultMockFeeEstimator(),
SyncMgr: defaultMockSyncManager(),
ConnMgr: defaultMockConnManager(),
Clock: &testClock{},
LogManager: defaultMockLogManager(),
TimeSource: blockchain.NewMedianTime(),
Services: wire.SFNodeNetwork | wire.SFNodeCF,
SubsidyCache: standalone.NewSubsidyCache(chainParams),
NetInfo: []types.NetworksResult{{
Name: "IPV4",
Limited: false,
@ -3913,6 +3935,9 @@ func testRPCServerHandler(t *testing.T, tests []rpcTest) {
if test.mockLogManager != nil {
rpcserverConfig.LogManager = test.mockLogManager
}
if test.mockSanityChecker != nil {
rpcserverConfig.SanityChecker = test.mockSanityChecker
}
testServer := &Server{cfg: *rpcserverConfig}
result, err := test.handler(nil, testServer, test.cmd)

View File

@ -14,6 +14,7 @@ import (
"github.com/decred/dcrd/blockchain/v3"
"github.com/decred/dcrd/blockchain/v3/indexers"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/dcrutil/v3"
"github.com/decred/dcrd/internal/fees"
"github.com/decred/dcrd/internal/mempool"
@ -496,3 +497,22 @@ func (*rpcLogManager) SupportedSubsystems() []string {
func (*rpcLogManager) ParseAndSetDebugLevels(debugLevel string) error {
return parseAndSetDebugLevels(debugLevel)
}
// rpcSanityChecker provides a block sanity checker for use with the RPC and
// implements the rpcserver.SanityChecker interface.
type rpcSanityChecker struct {
timeSource blockchain.MedianTimeSource
chainParams *chaincfg.Params
}
// Ensure rpcSanityChecker implements the rpcserver.SanityChecker interface.
var _ rpcserver.SanityChecker = (*rpcSanityChecker)(nil)
// CheckBlockSanity checks the correctness of the provided block
// per consensus. An appropriate error is returned if anything is
// invalid.
//
// This function is part of the rpcserver.SanityChecker interface implementation.
func (s *rpcSanityChecker) CheckBlockSanity(block *dcrutil.Block) error {
return blockchain.CheckBlockSanity(block, s.timeSource, s.chainParams)
}

View File

@ -3265,19 +3265,20 @@ func newServer(ctx context.Context, listenAddrs []string, db database.DB, chainP
}
s.rpcServer, err = rpcserver.New(&rpcserver.Config{
Listeners: rpcListeners,
ConnMgr: &rpcConnManager{&s},
SyncMgr: &rpcSyncMgr{&s, s.blockManager},
FeeEstimator: &rpcFeeEstimator{s.feeEstimator},
TimeSource: s.timeSource,
Services: s.services,
AddrManager: &rpcAddrManager{s.addrManager},
Clock: &rpcClock{},
SubsidyCache: s.subsidyCache,
Chain: &rpcChain{s.chain},
ChainParams: chainParams,
DB: db,
TxMemPool: s.txMemPool,
Listeners: rpcListeners,
ConnMgr: &rpcConnManager{&s},
SyncMgr: &rpcSyncMgr{&s, s.blockManager},
FeeEstimator: &rpcFeeEstimator{s.feeEstimator},
TimeSource: s.timeSource,
Services: s.services,
AddrManager: &rpcAddrManager{s.addrManager},
Clock: &rpcClock{},
SubsidyCache: s.subsidyCache,
Chain: &rpcChain{s.chain},
ChainParams: chainParams,
SanityChecker: &rpcSanityChecker{s.timeSource, chainParams},
DB: db,
TxMemPool: s.txMemPool,
BgBlkTmplGenerator: func() *mining.BgBlkTmplGenerator {
return s.bg
},