Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i1722-avoid-wallet-rescan-after-init #1723

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class ErgoWalletActor(settings: ErgoSettings,
ergoWalletService.initWallet(state, settings, pass, mnemonicPassOpt) match {
case Success((mnemonic, newState)) =>
log.info("Wallet is initialized")
context.become(loadedWallet(newState))
context.become(loadedWallet(newState.copy(walletState = WalletPhase.Initialized)))
self ! UnlockWallet(pass)
sender() ! Success(mnemonic)
case Failure(t) =>
Expand All @@ -111,7 +111,7 @@ class ErgoWalletActor(settings: ErgoSettings,
ergoWalletService.restoreWallet(state, settings, mnemonic, mnemonicPassOpt, walletPass) match {
case Success(newState) =>
log.info("Wallet is restored")
context.become(loadedWallet(newState))
context.become(loadedWallet(newState.copy(walletState = WalletPhase.Restored)))
self ! UnlockWallet(walletPass)
sender() ! Success(())
case Failure(t) =>
Expand Down Expand Up @@ -265,7 +265,8 @@ class ErgoWalletActor(settings: ErgoSettings,
case ScanOnChain(newBlock) =>
if (state.secretIsSet(settings.walletSettings.testMnemonic)) { // scan blocks only if wallet is initialized
val nextBlockHeight = state.expectedNextBlockHeight(newBlock.height, settings.nodeSettings.isFullBlocksPruned)
if (nextBlockHeight == newBlock.height) {
// we want to scan a block either when it is its turn or when wallet is freshly initialized in order to prevent rescanning
if (nextBlockHeight == newBlock.height || (state.walletState == WalletPhase.Initialized && state.getWalletHeight == 0)) {
log.info(s"Wallet is going to scan a block ${newBlock.id} on chain at height ${newBlock.height}")
val newState =
ergoWalletService.scanBlockUpdate(state, newBlock, settings.walletSettings.dustLimit) match {
Expand All @@ -279,7 +280,7 @@ class ErgoWalletActor(settings: ErgoSettings,
context.become(loadedWallet(newState))
} else if (nextBlockHeight < newBlock.height) {
log.warn(s"Wallet: skipped blocks found starting from $nextBlockHeight, going back to scan them")
self ! ScanInThePast(nextBlockHeight, false)
self ! ScanInThePast(nextBlockHeight, rescan = false)
} else {
log.warn(s"Wallet: block in the past reported at ${newBlock.height}, blockId: ${newBlock.id}")
}
Expand Down Expand Up @@ -520,6 +521,17 @@ object ErgoWalletActor extends ScorexLogging {
walletActorRef
}

/** Wallet transitions either from Empty -> Initialized or Empty -> Restored */
trait WalletPhase
object WalletPhase {
/** Stage of a wallet that is either empty or initialized/restored in previous runs */
case object Default extends WalletPhase
/** New wallet initialized with generated mnemonic in this runtime */
case object Initialized extends WalletPhase
/** Wallet restored from existing mnemonic in this runtime */
case object Restored extends WalletPhase
}

// Private signals the wallet actor sends to itself
/**
* A signal the wallet actor sends to itself to scan a block in the past
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.ergoplatform._
import org.ergoplatform.nodeView.history.ErgoHistory.Height
import org.ergoplatform.nodeView.mempool.ErgoMemPoolReader
import org.ergoplatform.nodeView.state.{ErgoStateContext, ErgoStateReader, UtxoStateReader}
import org.ergoplatform.nodeView.wallet.ErgoWalletActor.WalletPhase
import org.ergoplatform.nodeView.wallet.ErgoWalletState.FilterFn
import org.ergoplatform.nodeView.wallet.persistence.{OffChainRegistry, WalletRegistry, WalletStorage}
import org.ergoplatform.settings.{ErgoSettings, Parameters}
Expand All @@ -27,6 +28,7 @@ case class ErgoWalletState(
utxoStateReaderOpt: Option[UtxoStateReader],
parameters: Parameters,
maxInputsToUse: Int,
walletState: WalletPhase,
error: Option[String] = None,
rescanInProgress: Boolean
) extends ScorexLogging {
Expand Down Expand Up @@ -90,7 +92,11 @@ case class ErgoWalletState(
}
}

// Read a box from UTXO set if the node has it, otherwise, from the wallet
/**
* Read a box from UTXO set if the node has it, otherwise, from the wallet
* @param boxId of the box to read
* @return maybe ErgoBox
*/
def readBoxFromUtxoWithWalletFallback(boxId: BoxId): Option[ErgoBox] = {
utxoStateReaderOpt match {
case Some(utxoReader) =>
Expand All @@ -100,7 +106,10 @@ case class ErgoWalletState(
}
}

// expected height of a next block when the wallet is receiving a new block with the height blockHeight
/** Get expected height of a next block when the wallet is receiving a new block with the height blockHeight
* @param blockHeight height of the block being currently received
* @param isFullBlocksPruned whether node has all the full blocks and applies them sequentially
*/
def expectedNextBlockHeight(blockHeight: Height, isFullBlocksPruned: Boolean): Height = {
val walletHeight = getWalletHeight
if (!isFullBlocksPruned) {
Expand Down Expand Up @@ -153,6 +162,7 @@ object ErgoWalletState {
utxoStateReaderOpt = None,
parameters,
maxInputsToUse,
walletState = WalletPhase.Default,
rescanInProgress = false
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.ergoplatform._
import org.ergoplatform.db.DBSpec
import org.ergoplatform.modifiers.mempool.ErgoTransaction
import org.ergoplatform.nodeView.mempool.ErgoMemPoolReader
import org.ergoplatform.nodeView.wallet.ErgoWalletActor.WalletPhase
import org.ergoplatform.nodeView.wallet.WalletScanLogic.ScanResults
import org.ergoplatform.nodeView.wallet.persistence.{OffChainRegistry, WalletRegistry, WalletStorage}
import org.ergoplatform.nodeView.wallet.requests.{AssetIssueRequest, PaymentRequest}
Expand Down Expand Up @@ -61,6 +62,7 @@ class ErgoWalletServiceSpec
utxoStateReaderOpt = Option.empty,
parameters,
maxInputsToUse = 1000,
walletState = WalletPhase.Default,
rescanInProgress = false
)
}
Expand Down Expand Up @@ -297,6 +299,8 @@ class ErgoWalletServiceSpec
val pass = Random.nextString(10)
val initializedState = walletService.initWallet(walletState, settings, SecretString.create(pass), Option.empty).get._2

initializedState.getWalletHeight shouldBe 0
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kushti this test is passing only locally, there seem to be some racing condition on CI, but we rely on the fact that freshly init wallet has waletHeight=0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I see, so let's remove this condition? Now it should not be true for wallet just initialized


// Wallet unlocked after init, so we're locking it
val initLockedWalletState = walletService.lockWallet(initializedState)
initLockedWalletState.secretStorageOpt.get.isLocked shouldBe true
Expand Down