implement generating addresses when wallet is initialized if creationTime is > 1 hour ago (#5034)

This commit is contained in:
Chris Stewart 2023-04-04 11:40:26 -05:00 committed by GitHub
parent e791932f99
commit 36ec40dfa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 1 deletions

View File

@ -9,6 +9,7 @@ import org.bitcoins.core.protocol.BitcoinAddress
import org.bitcoins.core.protocol.script._
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.{CryptoUtil, ECPublicKey}
import org.bitcoins.keymanager.{DecryptedMnemonic, WalletStorage}
import org.bitcoins.testkit.chain.MockChainQueryApi
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
import org.bitcoins.testkitcore.util.TransactionTestUtil._
@ -16,6 +17,7 @@ import org.scalatest.FutureOutcome
import org.scalatest.compatible.Assertion
import java.nio.file.Files
import java.time.Instant
import scala.concurrent.Future
class WalletUnitTest extends BitcoinSWalletTest {
@ -317,4 +319,44 @@ class WalletUnitTest extends BitcoinSWalletTest {
toBroadcast <- wallet.getTransactionsToBroadcast
} yield assert(toBroadcast.map(_.txIdBE) == Vector(dummyPrevTx1.txIdBE))
}
it must "generate addresses for a wallet initialized with a old seed" in {
wallet: Wallet =>
for {
isEmpty <- wallet.isEmpty()
_ = assert(isEmpty)
//manually override the seeds creation time
seedPath = wallet.walletConfig.kmConf.seedPath
mnemonic = WalletStorage
.decryptSeedFromDisk(seedPath = seedPath, passphraseOpt = None)
.getOrElse(sys.error(s"failed to decrypt seed for unit test"))
.asInstanceOf[DecryptedMnemonic]
_ = {
//delete old seed file because we do not allow overwriting a seed file
Files.delete(wallet.walletConfig.seedPath)
}
modifiedMnemonic = mnemonic.copy(creationTime =
Instant.now.minusSeconds(60 * 60 + 1)) //1 hour and 1 minute
_ = WalletStorage.writeSeedToDisk(seedPath, modifiedMnemonic)
//delete old wallet database
_ = {
if (pgEnabled) {
//cannot delete database file if using postgres
()
} else {
val path = wallet.walletConfig.datadir
.resolve(wallet.walletConfig.walletName)
.resolve("walletdb.sqlite")
Files.delete(path)
}
}
_ = wallet.walletConfig.migrate()
//initialize it
initOldWallet <- Wallet.initialize(wallet, None)
isOldWalletEmpty <- initOldWallet.isEmpty()
} yield assert(!isOldWalletEmpty)
}
}

View File

@ -46,6 +46,7 @@ import scodec.bits.ByteVector
import slick.dbio.{DBIOAction, Effect, NoStream}
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.concurrent.TimeUnit
import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NonFatal
@ -1061,6 +1062,24 @@ object Wallet extends WalletLogger {
_ = accounts.foreach { a =>
logger.info(s"Created account=${a} to DB")
}
_ <- {
//check if creationTime is well in the past, if so generate a pool of addresses
//see: https://github.com/bitcoin-s/bitcoin-s/issues/5033
val creationTime = wallet.keyManager.creationTime
val threshold = Instant.now().minus(1, ChronoUnit.HOURS)
val isOldCreationTime = creationTime.compareTo(threshold) <= 0
if (isOldCreationTime) {
wallet
.generateScriptPubKeys(account = walletAppConfig.defaultAccount,
addressBatchSize =
walletAppConfig.discoveryBatchSize,
forceGenerateSpks = true)
.map(_ => ())
} else {
//fresh seed, no need to generate addresses
Future.unit
}
}
} yield {
logger.debug(s"Created root level accounts for wallet")
wallet

View File

@ -500,7 +500,7 @@ private[wallet] trait RescanHandling extends WalletLogger {
}
}
private def generateScriptPubKeys(
def generateScriptPubKeys(
account: HDAccount,
addressBatchSize: Int,
forceGenerateSpks: Boolean): Future[Vector[ScriptPubKey]] = {