WIP: Feature/6/jeffreypicard/dockerize for deployment #7
4 changed files with 165 additions and 16 deletions
|
@ -1641,6 +1641,115 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
|
|||
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.
|
||||
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
|
||||
return b.claimTrie
|
||||
|
|
|
@ -29,6 +29,10 @@ const (
|
|||
// not be performed.
|
||||
BFNoPoWCheck
|
||||
|
||||
// BFNoDupBlockCheck signals if the block should skip existence
|
||||
// checks.
|
||||
BFNoDupBlockCheck
|
||||
|
||||
// BFNone is a convenience value to specifically indicate no flags.
|
||||
BFNone BehaviorFlags = 0
|
||||
)
|
||||
|
@ -148,24 +152,26 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
|
|||
blockHash := block.Hash()
|
||||
log.Tracef("Processing block %v", blockHash)
|
||||
|
||||
// The block must not already exist in the main chain or side chains.
|
||||
exists, err := b.blockExists(blockHash)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if exists {
|
||||
str := fmt.Sprintf("already have block %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
}
|
||||
if flags&BFNoDupBlockCheck != BFNoDupBlockCheck {
|
||||
// The block must not already exist in the main chain or side chains.
|
||||
exists, err := b.blockExists(blockHash)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if exists {
|
||||
str := fmt.Sprintf("already have block %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
}
|
||||
|
||||
// The block must not already exist as an orphan.
|
||||
if _, exists := b.orphans[*blockHash]; exists {
|
||||
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
// The block must not already exist as an orphan.
|
||||
if _, exists := b.orphans[*blockHash]; exists {
|
||||
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
|
||||
return false, false, ruleError(ErrDuplicateBlock, str)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return false, false, err
|
||||
}
|
||||
|
|
28
rpcserver.go
28
rpcserver.go
|
@ -168,8 +168,10 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
|||
"getrawtransaction": handleGetRawTransaction,
|
||||
"gettxout": handleGetTxOut,
|
||||
"help": handleHelp,
|
||||
"invalidateblock": handleInvalidateBlock,
|
||||
"node": handleNode,
|
||||
"ping": handlePing,
|
||||
"reconsiderblock": handleReconsiderBlock,
|
||||
"searchrawtransactions": handleSearchRawTransactions,
|
||||
"sendrawtransaction": handleSendRawTransaction,
|
||||
"setgenerate": handleSetGenerate,
|
||||
|
@ -237,9 +239,7 @@ var rpcUnimplemented = map[string]struct{}{
|
|||
"getchaintips": {},
|
||||
"getmempoolentry": {},
|
||||
"getwork": {},
|
||||
"invalidateblock": {},
|
||||
"preciousblock": {},
|
||||
"reconsiderblock": {},
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func handleHelp(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*btcjson.HelpCmd)
|
||||
|
|
|
@ -568,10 +568,18 @@ var helpDescsEnUS = map[string]string{
|
|||
"help--result0": "List of commands",
|
||||
"help--result1": "Help for specified command",
|
||||
|
||||
// InvalidateBlockCmd
|
||||
"invalidateblock--synopsis": "Invalidate a block.",
|
||||
"invalidateblock-blockhash": "Hash of the block you want to invalidate",
|
||||
|
||||
// PingCmd help.
|
||||
"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.",
|
||||
|
||||
// ReconsiderBlockCmd
|
||||
"reconsiderblock--synopsis": "Reconsider a block for validation.",
|
||||
"reconsiderblock-blockhash": "Hash of the block you want to reconsider",
|
||||
|
||||
// SearchRawTransactionsCmd help.
|
||||
"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" +
|
||||
|
@ -848,7 +856,9 @@ var rpcResultTypes = map[string][]interface{}{
|
|||
"gettxout": {(*btcjson.GetTxOutResult)(nil)},
|
||||
"node": nil,
|
||||
"help": {(*string)(nil), (*string)(nil)},
|
||||
"invalidateblock": nil,
|
||||
"ping": nil,
|
||||
"reconsiderblock": nil,
|
||||
"searchrawtransactions": {(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
||||
"sendrawtransaction": {(*string)(nil)},
|
||||
"setgenerate": nil,
|
||||
|
|
Loading…
Reference in a new issue