Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,7 @@ func (backend *Backend) persistETHAccountConfig(
log.Info("persist account")
absoluteKeypath, err := signing.NewAbsoluteKeypath(keypath)
if err != nil {
panic(err)
return errp.WithMessage(err, "could not parse keypath")
}
extendedPublicKey, err := keystore.ExtendedPublicKey(coin, absoluteKeypath)
if err != nil {
Expand Down
35 changes: 29 additions & 6 deletions backend/coins/btc/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,22 @@ func (account *Account) Initialize() error {
if account.initialized {
return nil
}
account.initialized = true
defer func() {
if account.initialized {
return
}
if account.transactions != nil {
account.transactions.Close()
account.transactions = nil
}
if account.db != nil {
if closeErr := account.db.Close(); closeErr != nil {
account.log.WithError(closeErr).Error("couldn't close db")
}
account.db = nil
}
account.subaccounts = nil
}()

signingConfigurations := account.Config().Config.SigningConfigurations
if len(signingConfigurations) == 0 {
Expand Down Expand Up @@ -318,9 +333,10 @@ func (account *Account) Initialize() error {
account.log.Debug("Connection to blockchain backend established")
}
}
account.coin.Initialize()
if err := account.coin.Initialize(); err != nil {
return err
}
account.SetOffline(account.coin.Blockchain().ConnectionError())
account.coin.Blockchain().RegisterOnConnectionErrorChangedEvent(onConnectionStatusChanged)
theHeaders := account.coin.Headers()
account.transactions = transactions.NewTransactions(
account.coin.Net(), account.db, theHeaders, account.Synchronizer,
Expand All @@ -344,9 +360,13 @@ func (account *Account) Initialize() error {
account.subaccounts = append(account.subaccounts, subacc)
}

if err := account.BaseAccount.Initialize(accountIdentifier); err != nil {
return err
}
account.coin.Blockchain().RegisterOnConnectionErrorChangedEvent(onConnectionStatusChanged)
account.initialized = true
go account.ensureAddresses()

return account.BaseAccount.Initialize(accountIdentifier)
return nil
}

// XPubVersionForScriptType returns the xpub version bytes for the given coin and script type.
Expand Down Expand Up @@ -672,7 +692,10 @@ func (account *Account) onAddressStatus(address *addresses.AccountAddress, statu
return
}

account.transactions.UpdateAddressHistory(address.PubkeyScriptHashHex(), history)
if err := account.transactions.UpdateAddressHistory(address.PubkeyScriptHashHex(), history); err != nil {
account.reportFatalSyncError(err, "UpdateAddressHistory failed")
return
}
account.incAndEmitSyncCounter()
account.ensureAddresses()
}
Expand Down
12 changes: 9 additions & 3 deletions backend/coins/btc/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
// Coin models a Bitcoin-related coin.
type Coin struct {
initOnce sync.Once
initErr error
code coinpkg.Code
name string
// unit is the main unit of the coin, e.g. 'BTC'
Expand Down Expand Up @@ -90,7 +91,7 @@ func (coin *Coin) TstSetMakeBlockchain(f func() blockchain.Interface) {
}

// Initialize implements coinpkg.Coin.
func (coin *Coin) Initialize() {
func (coin *Coin) Initialize() error {
coin.initOnce.Do(func() {
// Init blockchain
coin.blockchain = coin.makeBlockchain()
Expand All @@ -107,14 +108,18 @@ func (coin *Coin) Initialize() {
path.Join(coin.dbFolder, fmt.Sprintf("headers-%s.bin", coin.code)),
coin.log)
if err != nil {
coin.log.WithError(err).Panic("Could not open headers DB")
coin.initErr = errp.WithMessage(err, "could not open headers DB")
return
}
coin.headers = headers.NewHeaders(
coin.net,
db,
coin.blockchain,
coin.log)
coin.headers.Initialize()
if err := coin.headers.Initialize(); err != nil {
coin.initErr = errp.WithMessage(err, "could not initialize headers")
return
}
coin.headers.SubscribeEvent(func(event headers.Event) {
if event == headers.EventSyncing || event == headers.EventSynced {
status, err := coin.headers.Status()
Expand All @@ -129,6 +134,7 @@ func (coin *Coin) Initialize() {
}
})
})
return coin.initErr
}

// Name implements coinpkg.Coin.
Expand Down
2 changes: 1 addition & 1 deletion backend/coins/btc/coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (s *testSuite) SetupTest() {

}
s.coin.TstSetMakeBlockchain(func() blockchain.Interface { return blockchainMock })
s.coin.Initialize()
s.Require().NoError(s.coin.Initialize())
}

func (s *testSuite) TearDownTest() {
Expand Down
34 changes: 17 additions & 17 deletions backend/coins/btc/db/transactionsdb/transactionsdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,16 @@ func (tx *Tx) PutTx(txHash chainhash.Hash, msgTx *wire.MsgTx, height int, header
return nil
}

// DeleteTx implements transactions.DBTxInterface. It panics if called from a read-only db
// transaction.
func (tx *Tx) DeleteTx(txHash chainhash.Hash) {
// DeleteTx implements transactions.DBTxInterface.
func (tx *Tx) DeleteTx(txHash chainhash.Hash) error {
bucketTransactions, err := tx.tx.CreateBucketIfNotExists([]byte(bucketTransactionsKey))
if err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
if err := bucketTransactions.Delete(txHash[:]); err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
return nil
}

// AddAddressToTx implements transactions.DBTxInterface.
Expand Down Expand Up @@ -215,10 +215,10 @@ func (tx *Tx) UnverifiedTransactions() ([]chainhash.Hash, error) {
func (tx *Tx) MarkTxVerified(txHash chainhash.Hash, headerTimestamp time.Time) error {
bucketUnverifiedTransactions, err := tx.tx.CreateBucketIfNotExists([]byte(bucketUnverifiedTransactionsKey))
if err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
if err := bucketUnverifiedTransactions.Delete(txHash[:]); err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
return tx.modifyTx(txHash[:], func(walletTx *transactions.DBTxInfo) {
truth := true
Expand Down Expand Up @@ -248,16 +248,16 @@ func (tx *Tx) Input(outPoint wire.OutPoint) (*chainhash.Hash, error) {
return nil, nil
}

// DeleteInput implements transactions.DBTxInterface. It panics if called from a read-only db
// transaction.
func (tx *Tx) DeleteInput(outPoint wire.OutPoint) {
// DeleteInput implements transactions.DBTxInterface.
func (tx *Tx) DeleteInput(outPoint wire.OutPoint) error {
bucketInputs, err := tx.tx.CreateBucketIfNotExists([]byte(bucketInputsKey))
if err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
if err := bucketInputs.Delete([]byte(outPoint.String())); err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
return nil
}

// PutOutput implements transactions.DBTxInterface.
Expand Down Expand Up @@ -308,16 +308,16 @@ func (tx *Tx) Outputs() (map[wire.OutPoint]*wire.TxOut, error) {
return outputs, nil
}

// DeleteOutput implements transactions.DBTxInterface. It panics if called from a read-only db
// transaction.
func (tx *Tx) DeleteOutput(outPoint wire.OutPoint) {
// DeleteOutput implements transactions.DBTxInterface.
func (tx *Tx) DeleteOutput(outPoint wire.OutPoint) error {
bucketOutputs, err := tx.tx.CreateBucketIfNotExists([]byte(bucketOutputsKey))
if err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
if err := bucketOutputs.Delete([]byte(outPoint.String())); err != nil {
panic(errp.WithStack(err))
return errp.WithStack(err)
}
return nil
}

// PutAddressHistory implements transactions.DBTxInterface.
Expand Down
10 changes: 5 additions & 5 deletions backend/coins/btc/db/transactionsdb/transactionsdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ func TestTxQuick(t *testing.T) {
require.True(t,
!txInfo.CreatedTimestamp.After(now) || *txInfo.CreatedTimestamp == now)

tx.DeleteTx(txHash)
require.NoError(t, tx.DeleteTx(txHash))
delete(allTxHashes, txHash)
require.True(t, checkTxHashes())
})
Expand Down Expand Up @@ -328,7 +328,7 @@ func TestInput(t *testing.T) {
require.Nil(t, input)

// no-op, does not exist yet
tx.DeleteInput(outpoint1)
require.NoError(t, tx.DeleteInput(outpoint1))

require.NoError(t, tx.PutInput(outpoint1, txhash1))
require.NoError(t, tx.PutInput(outpoint2, txhash2))
Expand All @@ -351,7 +351,7 @@ func TestInput(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &txhash2, input)

tx.DeleteInput(outpoint1)
require.NoError(t, tx.DeleteInput(outpoint1))
input, err = tx.Input(outpoint1)
require.NoError(t, err)
require.Nil(t, input)
Expand All @@ -376,7 +376,7 @@ func TestInputQuick(t *testing.T) {

for _, outPoint := range allOutpoints {
t.Run("", func(t *testing.T) {
tx.DeleteInput(outPoint)
require.NoError(t, tx.DeleteInput(outPoint))
txHash, err := tx.Input(outPoint)
require.NoError(t, err)
require.Nil(t, txHash)
Expand Down Expand Up @@ -475,7 +475,7 @@ func TestOutputsQuick(t *testing.T) {
for outPoint := range allOutputs {
t.Run("", func(t *testing.T) {
delete(allOutputs, outPoint)
tx.DeleteOutput(outPoint)
require.NoError(t, tx.DeleteOutput(outPoint))
require.True(t, checkOutputs())
output, err := tx.Output(outPoint)
require.NoError(t, err)
Expand Down
31 changes: 15 additions & 16 deletions backend/coins/btc/headers/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ const (

// Interface represents the public API of this package.
//
//go:generate mockery -name Interface
//go:generate mockery --name Interface
type Interface interface {
Initialize()
Initialize() error
SubscribeEvent(f func(Event)) func()
VerifiedHeaderByHeight(int) (*wire.BlockHeader, error)
HeaderByHeight(int) (*wire.BlockHeader, error)
Expand Down Expand Up @@ -180,8 +180,12 @@ func (headers *Headers) TipHeight() int {
}

// Initialize starts the syncing process.
func (headers *Headers) Initialize() {
headers.tipAtInitTime = headers.tip()
func (headers *Headers) Initialize() error {
tip, err := headers.db.Tip()
if err != nil {
return err
}
headers.tipAtInitTime = tip
headers.log.Infof("last tip loaded: %d", headers.tipAtInitTime)
go headers.download()
go headers.blockchain.HeadersSubscribe(
Expand All @@ -190,6 +194,7 @@ func (headers *Headers) Initialize() {
},
)
headers.kickChan <- struct{}{}
return nil
}

func (headers *Headers) download() {
Expand Down Expand Up @@ -370,15 +375,16 @@ func (headers *Headers) canConnect(db DBInterface, tip int, header *wire.BlockHe
return nil
}

func (headers *Headers) reorg(db DBInterface, tip int) {
func (headers *Headers) reorg(db DBInterface, tip int) error {
// Simple reorg method: re-fetch headers up to the maximum reorg limit. The server can shorten
// our chain by sending a fake header and set us back by `reorgLimit` blocks, but it needs to
// contain the correct PoW to do so.
newTip := max(tip-reorgLimit, -1)
if err := db.RevertTo(newTip); err != nil {
panic(err)
return err
}
headers.kick()
return nil
}

func (headers *Headers) notifyEvent(event Event) {
Expand All @@ -395,7 +401,9 @@ func (headers *Headers) processBatch(
err := headers.canConnect(db, tip+1, header)
if errp.Cause(err) == errPrevHash {
headers.log.WithError(err).Infof("Reorg detected at height %d", tip+1)
headers.reorg(db, tip)
if err := headers.reorg(db, tip); err != nil {
return err
}
return nil
}
if err != nil {
Expand Down Expand Up @@ -463,15 +471,6 @@ func (headers *Headers) update(blockHeight int) {
headers.notifyEvent(EventNewTip)
}

func (headers *Headers) tip() int {
defer headers.lock.RLock()()
tip, err := headers.db.Tip()
if err != nil {
panic(err)
}
return tip
}

// Status returns the current sync status.
func (headers *Headers) Status() (*Status, error) {
defer headers.lock.RLock()()
Expand Down
2 changes: 1 addition & 1 deletion backend/coins/btc/headers/headers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestClose(t *testing.T) {
headers.testDownloadFinished = func() {
close(didFinish)
}
headers.Initialize()
require.NoError(t, headers.Initialize())

require.NoError(t, headers.Close())
select {
Expand Down
20 changes: 16 additions & 4 deletions backend/coins/btc/headers/mocks/Interface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading