Read sapling activation height from RPC
This commit is contained in:
@@ -8,13 +8,13 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/adityapk00/btcd/rpcclient"
|
"github.com/adityapk00/btcd/rpcclient"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/adityapk00/lightwalletd/frontend"
|
"github.com/adityapk00/lightwalletd/frontend"
|
||||||
@@ -26,10 +26,11 @@ var log *logrus.Entry
|
|||||||
var logger = logrus.New()
|
var logger = logrus.New()
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
|
|
||||||
|
// Options is a struct holding command line options
|
||||||
type Options struct {
|
type Options struct {
|
||||||
dbPath string
|
dbPath string
|
||||||
logLevel uint64
|
logLevel uint64
|
||||||
logPath string
|
logPath string
|
||||||
zcashConfPath string
|
zcashConfPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,65 +116,74 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"error": err,
|
"error": err,
|
||||||
}).Warn("unable to get current height from local db storage")
|
}).Warn("Unable to get current height from local db storage. This is OK if you're starting this for the first time.")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//ingest from Sapling testnet height
|
// Get the sapling activation height from the RPC
|
||||||
if height < 280000 {
|
saplingHeight, err := getSaplingActivationHeight(rpcClient)
|
||||||
height = 280000
|
if err != nil {
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"error": err,
|
"error": err,
|
||||||
}).Warn("invalid current height read from local db storage")
|
}).Warn("Unable to get sapling activation height")
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout_count := 0
|
log.WithField("saplingHeight", saplingHeight).Info("Got sapling height ", saplingHeight)
|
||||||
reorg_count := -1
|
|
||||||
|
//ingest from Sapling testnet height
|
||||||
|
if height < saplingHeight {
|
||||||
|
height = saplingHeight
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Warn("invalid current height read from local db storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutCount := 0
|
||||||
|
reorgCount := -1
|
||||||
hash := ""
|
hash := ""
|
||||||
phash := ""
|
phash := ""
|
||||||
// Start listening for new blocks
|
// Start listening for new blocks
|
||||||
for {
|
for {
|
||||||
if reorg_count > 0 {
|
if reorgCount > 0 {
|
||||||
reorg_count = -1
|
reorgCount = -1
|
||||||
height -= 10
|
height -= 10
|
||||||
}
|
}
|
||||||
block, err := getBlock(rpcClient, height)
|
block, err := getBlock(rpcClient, height)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"height": height,
|
"height": height,
|
||||||
"error": err,
|
"error": err,
|
||||||
}).Warn("error with getblock")
|
}).Warn("error with getblock")
|
||||||
timeout_count++
|
timeoutCount++
|
||||||
if timeout_count == 3 {
|
if timeoutCount == 3 {
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"timeouts": timeout_count,
|
"timeouts": timeoutCount,
|
||||||
}).Warn("unable to issue RPC call to zcashd node 3 times")
|
}).Warn("unable to issue RPC call to zcashd node 3 times")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if block != nil {
|
if block != nil {
|
||||||
handleBlock(db, block)
|
handleBlock(db, block)
|
||||||
if timeout_count > 0 {
|
if timeoutCount > 0 {
|
||||||
timeout_count--
|
timeoutCount--
|
||||||
}
|
}
|
||||||
phash = hex.EncodeToString(block.GetPrevHash())
|
phash = hex.EncodeToString(block.GetPrevHash())
|
||||||
//check for reorgs once we have inital block hash from startup
|
//check for reorgs once we have inital block hash from startup
|
||||||
if hash != phash && reorg_count != -1 {
|
if hash != phash && reorgCount != -1 {
|
||||||
reorg_count++
|
reorgCount++
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"height": height,
|
"height": height,
|
||||||
"hash": hash,
|
"hash": hash,
|
||||||
"phash": phash,
|
"phash": phash,
|
||||||
"reorg": reorg_count,
|
"reorg": reorgCount,
|
||||||
}).Warn("REORG")
|
}).Warn("REORG")
|
||||||
} else {
|
} else {
|
||||||
hash = hex.EncodeToString(block.GetDisplayHash())
|
|
||||||
}
|
|
||||||
if reorg_count == -1 {
|
|
||||||
hash = hex.EncodeToString(block.GetDisplayHash())
|
hash = hex.EncodeToString(block.GetDisplayHash())
|
||||||
reorg_count =0
|
}
|
||||||
}
|
if reorgCount == -1 {
|
||||||
|
hash = hex.EncodeToString(block.GetDisplayHash())
|
||||||
|
reorgCount = 0
|
||||||
|
}
|
||||||
height++
|
height++
|
||||||
} else {
|
} else {
|
||||||
//TODO implement blocknotify to minimize polling on corner cases
|
//TODO implement blocknotify to minimize polling on corner cases
|
||||||
@@ -182,6 +192,36 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSaplingActivationHeight(rpcClient *rpcclient.Client) (int, error) {
|
||||||
|
result, rpcErr := rpcClient.RawRequest("getblockchaininfo", make([]json.RawMessage, 0))
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var errCode int64
|
||||||
|
|
||||||
|
// For some reason, the error responses are not JSON
|
||||||
|
if rpcErr != nil {
|
||||||
|
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
|
||||||
|
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
|
||||||
|
//Check to see if we are requesting a height the zcashd doesn't have yet
|
||||||
|
if err == nil && errCode == -8 {
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
return -1, errors.Wrap(rpcErr, "error requesting block")
|
||||||
|
}
|
||||||
|
|
||||||
|
var f interface{}
|
||||||
|
err = json.Unmarshal(result, &f)
|
||||||
|
if err != nil {
|
||||||
|
return -1, errors.Wrap(err, "error reading JSON response")
|
||||||
|
}
|
||||||
|
|
||||||
|
upgradeJSON := f.(map[string]interface{})["upgrades"]
|
||||||
|
saplingJSON := upgradeJSON.(map[string]interface{})["76b809bb"] // Sapling ID
|
||||||
|
saplingHeight := saplingJSON.(map[string]interface{})["activationheight"].(float64)
|
||||||
|
|
||||||
|
return int(saplingHeight), nil
|
||||||
|
}
|
||||||
|
|
||||||
func getBlock(rpcClient *rpcclient.Client, height int) (*parser.Block, error) {
|
func getBlock(rpcClient *rpcclient.Client, height int) (*parser.Block, error) {
|
||||||
params := make([]json.RawMessage, 2)
|
params := make([]json.RawMessage, 2)
|
||||||
params[0] = json.RawMessage("\"" + strconv.Itoa(height) + "\"")
|
params[0] = json.RawMessage("\"" + strconv.Itoa(height) + "\"")
|
||||||
@@ -204,7 +244,7 @@ func getBlock(rpcClient *rpcclient.Client, height int) (*parser.Block, error) {
|
|||||||
|
|
||||||
var blockDataHex string
|
var blockDataHex string
|
||||||
err = json.Unmarshal(result, &blockDataHex)
|
err = json.Unmarshal(result, &blockDataHex)
|
||||||
if err != nil{
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "error reading JSON response")
|
return nil, errors.Wrap(err, "error reading JSON response")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,12 +264,11 @@ func getBlock(rpcClient *rpcclient.Client, height int) (*parser.Block, error) {
|
|||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func handleBlock(db *sql.DB, block *parser.Block) {
|
func handleBlock(db *sql.DB, block *parser.Block) {
|
||||||
prevBlockHash := hex.EncodeToString(block.GetPrevHash())
|
prevBlockHash := hex.EncodeToString(block.GetPrevHash())
|
||||||
blockHash := hex.EncodeToString(block.GetEncodableHash())
|
blockHash := hex.EncodeToString(block.GetEncodableHash())
|
||||||
marshaledBlock, _ := proto.Marshal(block.ToCompact())
|
marshaledBlock, _ := proto.Marshal(block.ToCompact())
|
||||||
|
|
||||||
err := storage.StoreBlock(
|
err := storage.StoreBlock(
|
||||||
db,
|
db,
|
||||||
block.GetHeight(),
|
block.GetHeight(),
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func CreateTables(conn *sql.DB) error {
|
|||||||
// TODO consider max/count queries instead of state table. bit of a coupling assumption though.
|
// TODO consider max/count queries instead of state table. bit of a coupling assumption though.
|
||||||
|
|
||||||
func GetCurrentHeight(ctx context.Context, db *sql.DB) (int, error) {
|
func GetCurrentHeight(ctx context.Context, db *sql.DB) (int, error) {
|
||||||
var height int
|
var height int = -1
|
||||||
query := "SELECT current_height FROM state WHERE rowid = 1"
|
query := "SELECT current_height FROM state WHERE rowid = 1"
|
||||||
err := db.QueryRowContext(ctx, query).Scan(&height)
|
err := db.QueryRowContext(ctx, query).Scan(&height)
|
||||||
return height, err
|
return height, err
|
||||||
|
|||||||
Reference in New Issue
Block a user