Merge branch 'master' into ethereum
This commit is contained in:
commit
4de5673bb3
|
@ -331,6 +331,11 @@ func (b *BitcoinRPC) GetBlockChainInfo() (string, error) {
|
||||||
return res.Result.Chain, nil
|
return res.Result.Chain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isErrBlockNotFound(err *bchain.RPCError) bool {
|
||||||
|
return err.Message == "Block not found" ||
|
||||||
|
err.Message == "Block height out of range"
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlockHash returns hash of block in best-block-chain at given height.
|
// GetBlockHash returns hash of block in best-block-chain at given height.
|
||||||
func (b *BitcoinRPC) GetBlockHash(height uint32) (string, error) {
|
func (b *BitcoinRPC) GetBlockHash(height uint32) (string, error) {
|
||||||
glog.V(1).Info("rpc: getblockhash ", height)
|
glog.V(1).Info("rpc: getblockhash ", height)
|
||||||
|
@ -344,6 +349,9 @@ func (b *BitcoinRPC) GetBlockHash(height uint32) (string, error) {
|
||||||
return "", errors.Annotatef(err, "height %v", height)
|
return "", errors.Annotatef(err, "height %v", height)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
if isErrBlockNotFound(res.Error) {
|
||||||
|
return "", bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
return "", errors.Annotatef(res.Error, "height %v", height)
|
return "", errors.Annotatef(res.Error, "height %v", height)
|
||||||
}
|
}
|
||||||
return res.Result, nil
|
return res.Result, nil
|
||||||
|
@ -363,6 +371,9 @@ func (b *BitcoinRPC) GetBlockHeader(hash string) (*bchain.BlockHeader, error) {
|
||||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
if isErrBlockNotFound(res.Error) {
|
||||||
|
return nil, bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||||
}
|
}
|
||||||
return &res.Result, nil
|
return &res.Result, nil
|
||||||
|
@ -370,6 +381,13 @@ func (b *BitcoinRPC) GetBlockHeader(hash string) (*bchain.BlockHeader, error) {
|
||||||
|
|
||||||
// GetBlock returns block with given hash.
|
// GetBlock returns block with given hash.
|
||||||
func (b *BitcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
func (b *BitcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
||||||
|
var err error
|
||||||
|
if hash == "" && height > 0 {
|
||||||
|
hash, err = b.GetBlockHash(height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
if !b.ParseBlocks {
|
if !b.ParseBlocks {
|
||||||
return b.GetBlockFull(hash)
|
return b.GetBlockFull(hash)
|
||||||
}
|
}
|
||||||
|
@ -423,6 +441,9 @@ func (b *BitcoinRPC) GetBlockRaw(hash string) ([]byte, error) {
|
||||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
if isErrBlockNotFound(res.Error) {
|
||||||
|
return nil, bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||||
}
|
}
|
||||||
return hex.DecodeString(res.Result)
|
return hex.DecodeString(res.Result)
|
||||||
|
@ -443,6 +464,9 @@ func (b *BitcoinRPC) GetBlockList(hash string) (*bchain.Block, error) {
|
||||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
if isErrBlockNotFound(res.Error) {
|
||||||
|
return nil, bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,6 +499,9 @@ func (b *BitcoinRPC) GetBlockFull(hash string) (*bchain.Block, error) {
|
||||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
if isErrBlockNotFound(res.Error) {
|
||||||
|
return nil, bchain.ErrBlockNotFound
|
||||||
|
}
|
||||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||||
}
|
}
|
||||||
return &res.Result, nil
|
return &res.Result, nil
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
package bchain
|
package bchain
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errors with specific meaning returned by blockchain rpc
|
||||||
|
var (
|
||||||
|
// ErrBlockNotFound is returned when block is not found
|
||||||
|
// either unknown hash or too high height
|
||||||
|
// can be returned from GetBlockHash, GetBlockHeader, GetBlock
|
||||||
|
ErrBlockNotFound = errors.New("Block not found")
|
||||||
|
)
|
||||||
|
|
||||||
type ScriptSig struct {
|
type ScriptSig struct {
|
||||||
// Asm string `json:"asm"`
|
// Asm string `json:"asm"`
|
||||||
|
|
40
db/sync.go
40
db/sync.go
|
@ -4,7 +4,6 @@ import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/common"
|
"blockbook/common"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -20,6 +19,7 @@ type SyncWorker struct {
|
||||||
syncWorkers, syncChunk int
|
syncWorkers, syncChunk int
|
||||||
dryRun bool
|
dryRun bool
|
||||||
startHeight uint32
|
startHeight uint32
|
||||||
|
startHash string
|
||||||
chanOsSignal chan os.Signal
|
chanOsSignal chan os.Signal
|
||||||
metrics *common.Metrics
|
metrics *common.Metrics
|
||||||
}
|
}
|
||||||
|
@ -67,10 +67,6 @@ func (w *SyncWorker) ResyncIndex(onNewBlock func(hash string)) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func isError(err error, s string) bool {
|
|
||||||
return strings.Contains(err.Error(), s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *SyncWorker) resyncIndex(onNewBlock func(hash string)) error {
|
func (w *SyncWorker) resyncIndex(onNewBlock func(hash string)) error {
|
||||||
remote, err := w.chain.GetBestBlockHash()
|
remote, err := w.chain.GetBestBlockHash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -94,7 +90,7 @@ func (w *SyncWorker) resyncIndex(onNewBlock func(hash string)) error {
|
||||||
header, err = w.chain.GetBlockHeader(local)
|
header, err = w.chain.GetBlockHeader(local)
|
||||||
forked := false
|
forked := false
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isError(err, "Block not found") {
|
if err == bchain.ErrBlockNotFound {
|
||||||
forked = true
|
forked = true
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
|
@ -132,16 +128,15 @@ func (w *SyncWorker) resyncIndex(onNewBlock func(hash string)) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var hash string
|
|
||||||
if header != nil {
|
if header != nil {
|
||||||
glog.Info("resync: local is behind")
|
glog.Info("resync: local is behind")
|
||||||
hash = header.Next
|
w.startHash = header.Next
|
||||||
w.startHeight = localBestHeight
|
w.startHeight = localBestHeight
|
||||||
} else {
|
} else {
|
||||||
// If the local block is missing, we're indexing from the genesis block
|
// If the local block is missing, we're indexing from the genesis block
|
||||||
// or from the start block specified by flags
|
// or from the start block specified by flags
|
||||||
glog.Info("resync: genesis from block ", w.startHeight)
|
glog.Info("resync: genesis from block ", w.startHeight)
|
||||||
hash, err = w.chain.GetBlockHash(w.startHeight)
|
w.startHash, err = w.chain.GetBlockHash(w.startHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -166,15 +161,15 @@ func (w *SyncWorker) resyncIndex(onNewBlock func(hash string)) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.connectBlocks(hash, onNewBlock)
|
return w.connectBlocks(onNewBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *SyncWorker) connectBlocks(hash string, onNewBlock func(hash string)) error {
|
func (w *SyncWorker) connectBlocks(onNewBlock func(hash string)) error {
|
||||||
bch := make(chan blockResult, 8)
|
bch := make(chan blockResult, 8)
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
|
||||||
go w.getBlockChain(hash, bch, done)
|
go w.getBlockChain(bch, done)
|
||||||
|
|
||||||
var lastRes blockResult
|
var lastRes blockResult
|
||||||
for res := range bch {
|
for res := range bch {
|
||||||
|
@ -276,7 +271,7 @@ func (w *SyncWorker) connectBlockChunk(lower, higher uint32) error {
|
||||||
connected, err := w.isBlockConnected(higher)
|
connected, err := w.isBlockConnected(higher)
|
||||||
if err != nil || connected {
|
if err != nil || connected {
|
||||||
// if higher is over the best block, continue with lower block, otherwise return error
|
// if higher is over the best block, continue with lower block, otherwise return error
|
||||||
if isError(err, "Block height out of range") {
|
if err != bchain.ErrBlockNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,7 +322,7 @@ func (w *SyncWorker) ConnectBlocksParallelInChunks(lower, higher uint32) error {
|
||||||
}
|
}
|
||||||
err := w.connectBlockChunk(low, high)
|
err := w.connectBlockChunk(low, high)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isError(err, "Block height out of range") || isError(err, "Block not found") {
|
if err == bchain.ErrBlockNotFound {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
glog.Fatalf("connectBlocksParallel %d-%d %v", low, high, err)
|
glog.Fatalf("connectBlocksParallel %d-%d %v", low, high, err)
|
||||||
|
@ -348,7 +343,7 @@ func (w *SyncWorker) isBlockConnected(height uint32) (bool, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
remote, err := w.db.GetBlockHash(height)
|
remote, err := w.chain.GetBlockHash(height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -363,21 +358,30 @@ type blockResult struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *SyncWorker) getBlockChain(hash string, out chan blockResult, done chan struct{}) {
|
func (w *SyncWorker) getBlockChain(out chan blockResult, done chan struct{}) {
|
||||||
defer close(out)
|
defer close(out)
|
||||||
|
|
||||||
for hash != "" {
|
hash := w.startHash
|
||||||
|
height := w.startHeight
|
||||||
|
|
||||||
|
// some coins do not return Next hash
|
||||||
|
// must loop until error
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
block, err := w.chain.GetBlock(hash, 0)
|
block, err := w.chain.GetBlock(hash, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == bchain.ErrBlockNotFound {
|
||||||
|
break
|
||||||
|
}
|
||||||
out <- blockResult{err: err}
|
out <- blockResult{err: err}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hash = block.Next
|
hash = block.Next
|
||||||
|
height++
|
||||||
out <- blockResult{block: block}
|
out <- blockResult{block: block}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue