Skip to content

Commit

Permalink
Better policy for used outpoints and wait for first sync when creatin…
Browse files Browse the repository at this point in the history
…g an unsigned tx
  • Loading branch information
someone235 committed Dec 26, 2023
1 parent c28eaa6 commit 82a4b42
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 26 deletions.
5 changes: 3 additions & 2 deletions cmd/kaspawallet/daemon/server/create_unsigned_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, isSen
if !s.isSynced() {
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
}

// make sure address string is correct before proceeding to a
// potentially long UTXO refreshment operation
toAddress, err := util.DecodeAddress(address, s.params.Prefix)
Expand Down Expand Up @@ -113,7 +112,9 @@ func (s *server) selectUTXOs(spendAmount uint64, isSendAll bool, feePerInput uin
}

if broadcastTime, ok := s.usedOutpoints[*utxo.Outpoint]; ok {
if time.Since(broadcastTime) > time.Minute {
// We want to free an outpoint from the used outpoints set if we refresh the UTXOs since it was
// marked as used, and it least one minute has passed.
if time.Since(broadcastTime) > time.Minute && s.startTimeOfLastCompletedRefresh.After(broadcastTime) {
delete(s.usedOutpoints, *utxo.Outpoint)
} else {
continue
Expand Down
21 changes: 12 additions & 9 deletions cmd/kaspawallet/daemon/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net"
"os"
"sync"
"sync/atomic"
"time"

"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
Expand All @@ -31,15 +32,17 @@ type server struct {
rpcClient *rpcclient.RPCClient
params *dagconfig.Params

lock sync.RWMutex
utxosSortedByAmount []*walletUTXO
nextSyncStartIndex uint32
keysFile *keys.File
shutdown chan struct{}
forceSyncChan chan struct{}
addressSet walletAddressSet
txMassCalculator *txmass.Calculator
usedOutpoints map[externalapi.DomainOutpoint]time.Time
lock sync.RWMutex
utxosSortedByAmount []*walletUTXO
nextSyncStartIndex uint32
keysFile *keys.File
shutdown chan struct{}
forceSyncChan chan struct{}
startTimeOfLastCompletedRefresh time.Time
addressSet walletAddressSet
txMassCalculator *txmass.Calculator
usedOutpoints map[externalapi.DomainOutpoint]time.Time
firstSyncDone atomic.Bool

isLogFinalProgressLineShown bool
maxUsedAddressesForLog uint32
Expand Down
38 changes: 23 additions & 15 deletions cmd/kaspawallet/daemon/server/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ func (s *server) syncLoop() error {
return err
}

time.Sleep(20 * time.Second)
s.firstSyncDone.Store(true)
log.Infof("Wallet is synced and ready for operation")

for {
select {
case <-ticker.C:
err := s.sync()
if err != nil {
return err
}
case <-s.forceSyncChan:
err := s.sync()
if err != nil {
return err
}
}

err := s.sync()
if err != nil {
return err
}
}
}
Expand Down Expand Up @@ -219,7 +220,7 @@ func (s *server) updateAddressesAndLastUsedIndexes(requestedAddressSet walletAdd
}

// updateUTXOSet clears the current UTXO set, and re-fills it with the given entries
func (s *server) updateUTXOSet(entries []*appmessage.UTXOsByAddressesEntry, mempoolEntries []*appmessage.MempoolEntryByAddress) error {
func (s *server) updateUTXOSet(entries []*appmessage.UTXOsByAddressesEntry, mempoolEntries []*appmessage.MempoolEntryByAddress, refreshStart time.Time) error {
utxos := make([]*walletUTXO, 0, len(entries))

exclude := make(map[appmessage.RPCOutpoint]struct{})
Expand Down Expand Up @@ -260,13 +261,15 @@ func (s *server) updateUTXOSet(entries []*appmessage.UTXOsByAddressesEntry, memp
sort.Slice(utxos, func(i, j int) bool { return utxos[i].UTXOEntry.Amount() > utxos[j].UTXOEntry.Amount() })

s.lock.Lock()
s.startTimeOfLastCompletedRefresh = refreshStart
s.utxosSortedByAmount = utxos
s.lock.Unlock()

return nil
}

func (s *server) refreshUTXOs() error {
refreshStart := time.Now()
// It's important to check the mempool before calling `GetUTXOsByAddresses`:
// If we would do it the other way around an output can be spent in the mempool
// and not in consensus, and between the calls its spending transaction will be
Expand All @@ -282,19 +285,21 @@ func (s *server) refreshUTXOs() error {
return err
}

return s.updateUTXOSet(getUTXOsByAddressesResponse.Entries, mempoolEntriesByAddresses.Entries)
return s.updateUTXOSet(getUTXOsByAddressesResponse.Entries, mempoolEntriesByAddresses.Entries, refreshStart)
}

func (s *server) forceSync() {
if len(s.forceSyncChan) != 0 {
// Technically if two callers check the `if` simultaneously they will both spawn a
// goroutine, but we don't care about the small redundancy in such a rare case.
if len(s.forceSyncChan) == 0 {
go func() {
s.forceSyncChan <- struct{}{}
}()
}
}

func (s *server) isSynced() bool {
return s.nextSyncStartIndex > s.maxUsedIndex()
return s.nextSyncStartIndex > s.maxUsedIndex() && s.firstSyncDone.Load()
}

func (s *server) formatSyncStateReport() string {
Expand All @@ -304,8 +309,11 @@ func (s *server) formatSyncStateReport() string {
maxUsedIndex = s.nextSyncStartIndex
}

return fmt.Sprintf("scanned %d out of %d addresses (%.2f%%)",
s.nextSyncStartIndex, maxUsedIndex, float64(s.nextSyncStartIndex)*100.0/float64(maxUsedIndex))
if s.nextSyncStartIndex < s.maxUsedIndex() {
return fmt.Sprintf("scanned %d out of %d addresses (%.2f%%)",
s.nextSyncStartIndex, maxUsedIndex, float64(s.nextSyncStartIndex)*100.0/float64(maxUsedIndex))
}
return "loading the wallet UTXO set"
}

func (s *server) updateSyncingProgressLog(currProcessedAddresses, currMaxUsedAddresses uint32) {
Expand All @@ -324,7 +332,7 @@ func (s *server) updateSyncingProgressLog(currProcessedAddresses, currMaxUsedAdd

if s.maxProcessedAddressesForLog >= s.maxUsedAddressesForLog {
if !s.isLogFinalProgressLineShown {
log.Infof("Wallet is synced, ready for queries")
log.Infof("Finished scanning recent addresses")
s.isLogFinalProgressLineShown = true
}
} else {
Expand Down

0 comments on commit 82a4b42

Please sign in to comment.