[lbry] rpc: import invalidate/reconsiderblock from bchd
This commit is contained in:
parent
81862c664e
commit
73d8f4762f
4 changed files with 165 additions and 16 deletions
|
@ -1642,6 +1642,115 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvalidateBlock takes a block hash and invalidates it.
|
||||||
|
//
|
||||||
|
// This function is safe for concurrent access.
|
||||||
|
func (b *BlockChain) InvalidateBlock(hash *chainhash.Hash) error {
|
||||||
|
return b.invalidateBlock(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidateBlock takes a block hash and invalidates it.
|
||||||
|
func (b *BlockChain) invalidateBlock(hash *chainhash.Hash) error {
|
||||||
|
node := b.index.LookupNode(hash)
|
||||||
|
if node == nil {
|
||||||
|
err := fmt.Errorf("block %s is not known", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to invalidate if its already invalid.
|
||||||
|
if node.status.KnownInvalid() {
|
||||||
|
err := fmt.Errorf("block %s is already invalid", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.parent == nil {
|
||||||
|
err := fmt.Errorf("block %s has no parent", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.index.SetStatusFlags(node, statusValidateFailed)
|
||||||
|
b.index.UnsetStatusFlags(node, statusValid)
|
||||||
|
|
||||||
|
b.chainLock.Lock()
|
||||||
|
defer b.chainLock.Unlock()
|
||||||
|
detachNodes, attachNodes := b.getReorganizeNodes(node.parent)
|
||||||
|
|
||||||
|
err := b.reorganizeChain(detachNodes, attachNodes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() {
|
||||||
|
n := e.Value.(*blockNode)
|
||||||
|
|
||||||
|
b.index.SetStatusFlags(n, statusInvalidAncestor)
|
||||||
|
b.index.UnsetStatusFlags(n, statusValid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeErr := b.index.flushToDB(); writeErr != nil {
|
||||||
|
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReconsiderBlock takes a block hash and allows it to be revalidated.
|
||||||
|
//
|
||||||
|
// This function is safe for concurrent access.
|
||||||
|
func (b *BlockChain) ReconsiderBlock(hash *chainhash.Hash) error {
|
||||||
|
return b.reconsiderBlock(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconsiderBlock takes a block hash and allows it to be revalidated.
|
||||||
|
func (b *BlockChain) reconsiderBlock(hash *chainhash.Hash) error {
|
||||||
|
node := b.index.LookupNode(hash)
|
||||||
|
if node == nil {
|
||||||
|
err := fmt.Errorf("block %s is not known", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to reconsider, it is already valid.
|
||||||
|
if node.status.KnownValid() {
|
||||||
|
err := fmt.Errorf("block %s is already valid", hash)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep a reference to the first node in the chain of invalid
|
||||||
|
// blocks so we can reprocess after status flags are updated.
|
||||||
|
firstNode := node
|
||||||
|
|
||||||
|
// Find previous node to the point where the blocks are valid again.
|
||||||
|
for n := node; n.status.KnownInvalid(); n = n.parent {
|
||||||
|
b.index.UnsetStatusFlags(n, statusInvalidAncestor)
|
||||||
|
b.index.UnsetStatusFlags(n, statusValidateFailed)
|
||||||
|
|
||||||
|
firstNode = n
|
||||||
|
}
|
||||||
|
|
||||||
|
var blk *btcutil.Block
|
||||||
|
err := b.db.View(func(dbTx database.Tx) error {
|
||||||
|
var err error
|
||||||
|
blk, err = dbFetchBlockByNode(dbTx, firstNode)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process it all again. This will take care of the
|
||||||
|
// orphans as well.
|
||||||
|
_, _, err = b.ProcessBlock(blk, BFNoDupBlockCheck)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeErr := b.index.flushToDB(); writeErr != nil {
|
||||||
|
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ClaimTrie returns the claimTrie associated wit hthe chain.
|
// ClaimTrie returns the claimTrie associated wit hthe chain.
|
||||||
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
|
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
|
||||||
return b.claimTrie
|
return b.claimTrie
|
||||||
|
|
|
@ -29,6 +29,10 @@ const (
|
||||||
// not be performed.
|
// not be performed.
|
||||||
BFNoPoWCheck
|
BFNoPoWCheck
|
||||||
|
|
||||||
|
// BFNoDupBlockCheck signals if the block should skip existence
|
||||||
|
// checks.
|
||||||
|
BFNoDupBlockCheck
|
||||||
|
|
||||||
// BFNone is a convenience value to specifically indicate no flags.
|
// BFNone is a convenience value to specifically indicate no flags.
|
||||||
BFNone BehaviorFlags = 0
|
BFNone BehaviorFlags = 0
|
||||||
)
|
)
|
||||||
|
@ -148,24 +152,26 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
|
||||||
blockHash := block.Hash()
|
blockHash := block.Hash()
|
||||||
log.Tracef("Processing block %v", blockHash)
|
log.Tracef("Processing block %v", blockHash)
|
||||||
|
|
||||||
// The block must not already exist in the main chain or side chains.
|
if flags&BFNoDupBlockCheck != BFNoDupBlockCheck {
|
||||||
exists, err := b.blockExists(blockHash)
|
// The block must not already exist in the main chain or side chains.
|
||||||
if err != nil {
|
exists, err := b.blockExists(blockHash)
|
||||||
return false, false, err
|
if err != nil {
|
||||||
}
|
return false, false, err
|
||||||
if exists {
|
}
|
||||||
str := fmt.Sprintf("already have block %v", blockHash)
|
if exists {
|
||||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
str := fmt.Sprintf("already have block %v", blockHash)
|
||||||
}
|
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||||
|
}
|
||||||
|
|
||||||
// The block must not already exist as an orphan.
|
// The block must not already exist as an orphan.
|
||||||
if _, exists := b.orphans[*blockHash]; exists {
|
if _, exists := b.orphans[*blockHash]; exists {
|
||||||
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
||||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform preliminary sanity checks on the block and its transactions.
|
// Perform preliminary sanity checks on the block and its transactions.
|
||||||
err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
|
err := checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
|
|
28
rpcserver.go
28
rpcserver.go
|
@ -168,8 +168,10 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
||||||
"getrawtransaction": handleGetRawTransaction,
|
"getrawtransaction": handleGetRawTransaction,
|
||||||
"gettxout": handleGetTxOut,
|
"gettxout": handleGetTxOut,
|
||||||
"help": handleHelp,
|
"help": handleHelp,
|
||||||
|
"invalidateblock": handleInvalidateBlock,
|
||||||
"node": handleNode,
|
"node": handleNode,
|
||||||
"ping": handlePing,
|
"ping": handlePing,
|
||||||
|
"reconsiderblock": handleReconsiderBlock,
|
||||||
"searchrawtransactions": handleSearchRawTransactions,
|
"searchrawtransactions": handleSearchRawTransactions,
|
||||||
"sendrawtransaction": handleSendRawTransaction,
|
"sendrawtransaction": handleSendRawTransaction,
|
||||||
"setgenerate": handleSetGenerate,
|
"setgenerate": handleSetGenerate,
|
||||||
|
@ -237,9 +239,7 @@ var rpcUnimplemented = map[string]struct{}{
|
||||||
"getchaintips": {},
|
"getchaintips": {},
|
||||||
"getmempoolentry": {},
|
"getmempoolentry": {},
|
||||||
"getwork": {},
|
"getwork": {},
|
||||||
"invalidateblock": {},
|
|
||||||
"preciousblock": {},
|
"preciousblock": {},
|
||||||
"reconsiderblock": {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commands that are available to a limited user
|
// Commands that are available to a limited user
|
||||||
|
@ -2977,6 +2977,30 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
|
||||||
return txOutReply, nil
|
return txOutReply, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleInvalidateBlock implements the invalidateblock command
|
||||||
|
func handleInvalidateBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||||
|
c := cmd.(*btcjson.InvalidateBlockCmd)
|
||||||
|
|
||||||
|
hash, err := chainhash.NewHashFromStr(c.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, s.cfg.Chain.InvalidateBlock(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleReconsiderBlock implements the reconsiderblock command
|
||||||
|
func handleReconsiderBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||||
|
c := cmd.(*btcjson.ReconsiderBlockCmd)
|
||||||
|
|
||||||
|
hash, err := chainhash.NewHashFromStr(c.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, s.cfg.Chain.ReconsiderBlock(hash)
|
||||||
|
}
|
||||||
|
|
||||||
// handleHelp implements the help command.
|
// handleHelp implements the help command.
|
||||||
func handleHelp(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
func handleHelp(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||||
c := cmd.(*btcjson.HelpCmd)
|
c := cmd.(*btcjson.HelpCmd)
|
||||||
|
|
|
@ -568,10 +568,18 @@ var helpDescsEnUS = map[string]string{
|
||||||
"help--result0": "List of commands",
|
"help--result0": "List of commands",
|
||||||
"help--result1": "Help for specified command",
|
"help--result1": "Help for specified command",
|
||||||
|
|
||||||
|
// InvalidateBlockCmd
|
||||||
|
"invalidateblock--synopsis": "Invalidate a block.",
|
||||||
|
"invalidateblock-blockhash": "Hash of the block you want to invalidate",
|
||||||
|
|
||||||
// PingCmd help.
|
// PingCmd help.
|
||||||
"ping--synopsis": "Queues a ping to be sent to each connected peer.\n" +
|
"ping--synopsis": "Queues a ping to be sent to each connected peer.\n" +
|
||||||
"Ping times are provided by getpeerinfo via the pingtime and pingwait fields.",
|
"Ping times are provided by getpeerinfo via the pingtime and pingwait fields.",
|
||||||
|
|
||||||
|
// ReconsiderBlockCmd
|
||||||
|
"reconsiderblock--synopsis": "Reconsider a block for validation.",
|
||||||
|
"reconsiderblock-blockhash": "Hash of the block you want to reconsider",
|
||||||
|
|
||||||
// SearchRawTransactionsCmd help.
|
// SearchRawTransactionsCmd help.
|
||||||
"searchrawtransactions--synopsis": "Returns raw data for transactions involving the passed address.\n" +
|
"searchrawtransactions--synopsis": "Returns raw data for transactions involving the passed address.\n" +
|
||||||
"Returned transactions are pulled from both the database, and transactions currently in the mempool.\n" +
|
"Returned transactions are pulled from both the database, and transactions currently in the mempool.\n" +
|
||||||
|
@ -848,7 +856,9 @@ var rpcResultTypes = map[string][]interface{}{
|
||||||
"gettxout": {(*btcjson.GetTxOutResult)(nil)},
|
"gettxout": {(*btcjson.GetTxOutResult)(nil)},
|
||||||
"node": nil,
|
"node": nil,
|
||||||
"help": {(*string)(nil), (*string)(nil)},
|
"help": {(*string)(nil), (*string)(nil)},
|
||||||
|
"invalidateblock": nil,
|
||||||
"ping": nil,
|
"ping": nil,
|
||||||
|
"reconsiderblock": nil,
|
||||||
"searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
"searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
||||||
"sendrawtransaction": {(*string)(nil)},
|
"sendrawtransaction": {(*string)(nil)},
|
||||||
"setgenerate": nil,
|
"setgenerate": nil,
|
||||||
|
|
Loading…
Reference in a new issue