Skip to content

Commit

Permalink
Save chainstate and utxo/asset data so you don't need to resync
Browse files Browse the repository at this point in the history
  • Loading branch information
gertjaap committed Jan 24, 2019
1 parent 3c2c570 commit 7164b42
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 31 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ privkey.hex
vertcoin-openassets.conf
server/static/
releases/
vertcoin-openassets
vertcoin-openassets
chainstate.hex
wallet.db
73 changes: 54 additions & 19 deletions blockprocessor/blockprocessor.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package blockprocessor

import (
"bytes"
"fmt"
"io/ioutil"
"time"

"github.com/btcsuite/btcd/chaincfg/chainhash"
Expand All @@ -18,6 +20,7 @@ type BlockProcessor struct {
wallet *wallet.Wallet
config *config.Config
rpcClient *rpcclient.Client
activeChain ChainIndex
synced bool
syncing bool
connected bool
Expand All @@ -31,6 +34,9 @@ func NewBlockProcessor(w *wallet.Wallet, c *rpcclient.Client, conf *config.Confi
bp.wallet = w
bp.rpcClient = c
bp.config = conf
bp.activeChain = ChainIndex{bp.config.Network.StartHash}
bp.tipHeight = bp.config.Network.StartHeight - 1 + len(bp.activeChain)
bp.ReadChainState()
return bp
}

Expand All @@ -43,8 +49,40 @@ type SyncStatus struct {
HeaderQueue int
}

func (bp *BlockProcessor) PersistChainState() {
var buf bytes.Buffer
for _, h := range bp.activeChain {
buf.Write(h[:])
}
ioutil.WriteFile("chainstate.hex", buf.Bytes(), 0644)
}

func (bp *BlockProcessor) ReadChainState() {
b, err := ioutil.ReadFile("chainstate.hex")
if err != nil {
return
}
readIndex := ChainIndex{}
buf := bytes.NewBuffer(b)
hash := make([]byte, 32)
for {
i, err := buf.Read(hash)
if i == 32 && err == nil {
ch, err := chainhash.NewHash(hash)
if err == nil {
readIndex = append(readIndex, ch)
} else {
break
}
} else {
break
}
}
bp.activeChain = readIndex
}

func (bp *BlockProcessor) UpdateClient(c *rpcclient.Client) {
bp.rpcClient = &(*c)
bp.rpcClient = c
bp.connected = true
}

Expand All @@ -63,18 +101,14 @@ func (activeChain ChainIndex) FindBlock(hash *chainhash.Hash) int {
}

func (bp *BlockProcessor) Loop() {
client := bp.rpcClient
activeChain := ChainIndex{bp.config.Network.StartHash}
bp.tipHeight = bp.config.Network.StartHeight - 1 + len(activeChain)

bp.synced = false
for {
bp.syncing = false
time.Sleep(time.Second)
bp.syncing = true
bp.syncHeight = bp.config.Network.StartHeight - 1 + len(activeChain)
bp.syncHeight = bp.config.Network.StartHeight - 1 + len(bp.activeChain)

bestHash, err := client.GetBestBlockHash()
bestHash, err := bp.rpcClient.GetBestBlockHash()
if err != nil {
if util.IsConnectionError(err) {
bp.connected = false
Expand All @@ -85,15 +119,17 @@ func (bp *BlockProcessor) Loop() {
}
bp.connected = true

if bestHash.IsEqual(activeChain[len(activeChain)-1]) {
if bestHash.IsEqual(bp.activeChain[len(bp.activeChain)-1]) {
bp.synced = true
continue

}

hash, _ := chainhash.NewHash(bestHash.CloneBytes())
pendingBlockHashes := make([]*chainhash.Hash, 0)
startIndex := 0
for {
header, err := client.GetBlockHeader(hash)
header, err := bp.rpcClient.GetBlockHeader(hash)
if err != nil {
fmt.Printf("Error getting block: %s\n", err.Error())
continue
Expand All @@ -102,29 +138,27 @@ func (bp *BlockProcessor) Loop() {
newHash, _ := chainhash.NewHash(hash.CloneBytes())
pendingBlockHashes = append([]*chainhash.Hash{newHash}, pendingBlockHashes...)
hash = &header.PrevBlock
idx := activeChain.FindBlock(&header.PrevBlock)
fmt.Printf("Found %d blocks to process\n", len(pendingBlockHashes))
idx := bp.activeChain.FindBlock(&header.PrevBlock)
if idx > -1 {
fmt.Printf("Found prevBlock at index %d...\n", idx)
// We found a way to connect to our activeChain
// Remove all blocks after idx, if any
newChain := activeChain[:idx]
newChain := bp.activeChain[:idx]
newChain = append(newChain, pendingBlockHashes...)
activeChain = newChain
bp.activeChain = newChain
startIndex = idx
break
}
}

if len(activeChain)-startIndex > 5 {
if len(bp.activeChain)-startIndex > 5 {
bp.synced = false
}

bp.tipHeight = bp.config.Network.StartHeight - 1 + len(activeChain)
bp.tipHeight = bp.config.Network.StartHeight - 1 + len(bp.activeChain)

for i, hash := range activeChain[startIndex:] {
bp.headerQueue = len(activeChain) - i - 1
block, err := client.GetBlock(hash)
for i, hash := range bp.activeChain[startIndex:] {
bp.headerQueue = len(bp.activeChain) - i - 1
block, err := bp.rpcClient.GetBlock(hash)
if err != nil {
fmt.Printf("Error getting block: %s\n", err.Error())
continue
Expand All @@ -138,6 +172,7 @@ func (bp *BlockProcessor) Loop() {
}

bp.synced = true
bp.PersistChainState()
}
}

Expand Down
13 changes: 2 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,14 @@ func main() {
bp := blockprocessor.NewBlockProcessor(w, client, cfg)
srv := server.NewHttpServer(w, cfg, bp)

go func(wal *wallet.Wallet, blp *blockprocessor.BlockProcessor, cli *rpcclient.Client, config *rpcclient.ConnConfig) {
go func(wal *wallet.Wallet, blp *blockprocessor.BlockProcessor, config *rpcclient.ConnConfig) {
for {
<-configChanged
fmt.Printf("Creating new RPC Client...\n")

config.Host = cfg.RpcHost
config.User = cfg.RpcUser
config.Pass = cfg.RpcPassword

cli, err := rpcclient.New(config, nil)
if err != nil {
log.Fatal(err)
}
wal.UpdateClient(cli)
blp.UpdateClient(cli)
}
}(w, bp, client, connCfg)
}(w, bp, connCfg)

err = w.InitKey()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions wallet/openassets.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/gertjaap/vertcoin-openassets/leb128"
"github.com/gertjaap/vertcoin-openassets/util"
"github.com/tidwall/buntdb"
)

const MINOUTPUT uint64 = 1000
Expand Down Expand Up @@ -300,6 +301,11 @@ func (w *Wallet) markOpenAssetTxInputsAsSpent(tx *wire.MsgTx) {
}
}
if removeIndex >= 0 {
w.db.Update(func(dtx *buntdb.Tx) error {
key := fmt.Sprintf("autxo-%s-%d", w.assetUtxos[removeIndex].Utxo.TxHash.String(), w.assetUtxos[removeIndex].Utxo.Outpoint)
_, err := dtx.Delete(key)
return err
})
w.assetUtxos = append(w.assetUtxos[:removeIndex], w.assetUtxos[removeIndex+1:]...)
}
}
Expand Down
70 changes: 70 additions & 0 deletions wallet/types.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package wallet

import (
"bytes"
"encoding/binary"

"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)

type Utxo struct {
Expand All @@ -11,13 +15,55 @@ type Utxo struct {
PkScript []byte
}

func (u Utxo) Bytes() []byte {
var buf bytes.Buffer
buf.Write(u.TxHash[:])
binary.Write(&buf, binary.BigEndian, u.Outpoint)
binary.Write(&buf, binary.BigEndian, u.Value)
buf.Write(u.PkScript)
return buf.Bytes()
}

func UtxoFromBytes(b []byte) Utxo {
buf := bytes.NewBuffer(b)
u := Utxo{}
hash, _ := chainhash.NewHash(buf.Next(32))
u.TxHash = *hash
binary.Read(buf, binary.BigEndian, &u.Outpoint)
binary.Read(buf, binary.BigEndian, &u.Value)
copy(u.PkScript, buf.Bytes())
return u
}

type OpenAssetUtxo struct {
AssetID []byte
Utxo Utxo
AssetValue uint64
Ours bool
}

func (oau OpenAssetUtxo) Bytes() []byte {
var buf bytes.Buffer
wire.WriteVarBytes(&buf, 0, oau.AssetID)
binary.Write(&buf, binary.BigEndian, oau.AssetValue)
binary.Write(&buf, binary.BigEndian, oau.Ours)
buf.Write(oau.Utxo.Bytes())
return buf.Bytes()
}

func OpenAssetUtxoFromBytes(b []byte) OpenAssetUtxo {
buf := bytes.NewBuffer(b)
oau := OpenAssetUtxo{}

assetId, _ := wire.ReadVarBytes(buf, 0, 80, "assetId")
oau.AssetID = assetId
binary.Read(buf, binary.BigEndian, &oau.AssetValue)
binary.Read(buf, binary.BigEndian, &oau.Ours)
oau.Utxo = UtxoFromBytes(buf.Bytes())

return oau
}

type OpenAssetIssuanceOutput struct {
RecipientPkh [20]byte
Value uint64
Expand Down Expand Up @@ -48,3 +94,27 @@ type OpenAsset struct {
Metadata OpenAssetMetadata
Follow bool
}

func (oa *OpenAsset) Bytes() []byte {
var buf bytes.Buffer
wire.WriteVarBytes(&buf, 0, oa.AssetID)
wire.WriteVarBytes(&buf, 0, []byte(oa.Metadata.Ticker))
binary.Write(&buf, binary.BigEndian, oa.Metadata.Decimals)
binary.Write(&buf, binary.BigEndian, oa.Follow)
return buf.Bytes()
}

func OpenAssetFromBytes(b []byte) *OpenAsset {
buf := bytes.NewBuffer(b)
oa := new(OpenAsset)

assetId, _ := wire.ReadVarBytes(buf, 0, 80, "assetId")
oa.AssetID = assetId
tickerBytes, _ := wire.ReadVarBytes(buf, 0, 80, "ticker")
oa.Metadata.Ticker = string(tickerBytes)

binary.Read(buf, binary.BigEndian, &oa.Metadata.Decimals)
binary.Read(buf, binary.BigEndian, &oa.Follow)

return oa
}
Loading

0 comments on commit 7164b42

Please sign in to comment.