diff --git a/build.sbt b/build.sbt index 020c0eb2cc..5fe044f69d 100644 --- a/build.sbt +++ b/build.sbt @@ -353,7 +353,7 @@ lazy val nodeTest = { lazy val testkit = project .in(file("testkit")) - .settings(commonProdSettings: _*) + .settings(commonSettings: _*) .dependsOn( core, chain, @@ -383,7 +383,8 @@ lazy val docs = project bitcoins / Compile / unidoc, Compile / docusaurusPublishGhpages ) - .value + .value, + libraryDependencies ++= Deps.docs ) .dependsOn( bitcoindRpc, diff --git a/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala index 8896c7423b..0e6da4e9bd 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala @@ -4,7 +4,6 @@ import akka.actor.ActorSystem import org.bitcoins.chain.config.ChainAppConfig import org.bitcoins.chain.models.BlockHeaderDAO import org.bitcoins.core.protocol.blockchain.MainNetChainParams -import org.bitcoins.db.AppConfig import org.bitcoins.testkit.chain.fixture.{ChainFixture, ChainFixtureTag} import org.bitcoins.testkit.chain.{ChainTestUtil, ChainUnitTest} import org.scalatest.FutureOutcome @@ -15,18 +14,18 @@ class BitcoinPowTest extends ChainUnitTest { override type FixtureParam = ChainFixture - override lazy implicit val appConfig: ChainAppConfig = mainnetAppConfig + implicit override lazy val appConfig: ChainAppConfig = mainnetAppConfig override def withFixture(test: OneArgAsyncTest): FutureOutcome = withChainFixture(test) - override implicit val system: ActorSystem = ActorSystem("BitcoinPowTest") + implicit override val system: ActorSystem = ActorSystem("BitcoinPowTest") behavior of "BitcoinPow" it must "NOT calculate a POW change when one is not needed" inFixtured { case ChainFixture.Empty => - val blockHeaderDAO = BlockHeaderDAO(appConfig) + val blockHeaderDAO = BlockHeaderDAO() val header1 = ChainTestUtil.ValidPOWChange.blockHeaderDb566494 val header2 = ChainTestUtil.ValidPOWChange.blockHeaderDb566495 diff --git a/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala index 35893cefb5..bdf0d07089 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala @@ -16,7 +16,6 @@ import org.bitcoins.testkit.chain.{ import org.scalatest.{Assertion, FutureOutcome} import scala.concurrent.Future -import org.bitcoins.db.AppConfig import org.bitcoins.chain.config.ChainAppConfig import com.typesafe.config.ConfigFactory @@ -25,12 +24,12 @@ class TipValidationTest extends ChainUnitTest { override type FixtureParam = BlockHeaderDAO // we're working with mainnet data - override lazy implicit val appConfig: ChainAppConfig = mainnetAppConfig + implicit override lazy val appConfig: ChainAppConfig = mainnetAppConfig override def withFixture(test: OneArgAsyncTest): FutureOutcome = withBlockHeaderDAO(test) - override implicit val system: ActorSystem = ActorSystem("TipValidationTest") + implicit override val system: ActorSystem = ActorSystem("TipValidationTest") behavior of "TipValidation" diff --git a/chain/src/main/resources/chain.conf b/chain/src/main/resources/chain.conf deleted file mode 100644 index 7e9e34aca2..0000000000 --- a/chain/src/main/resources/chain.conf +++ /dev/null @@ -1,5 +0,0 @@ -bitcoin-s { - database { - name = "chaindb.sqlite" - } -} \ No newline at end of file diff --git a/chain/src/main/scala/org/bitcoins/chain/api/ChainApi.scala b/chain/src/main/scala/org/bitcoins/chain/api/ChainApi.scala index 3f1a321528..a47c12d315 100644 --- a/chain/src/main/scala/org/bitcoins/chain/api/ChainApi.scala +++ b/chain/src/main/scala/org/bitcoins/chain/api/ChainApi.scala @@ -1,18 +1,18 @@ package org.bitcoins.chain.api -import org.bitcoins.db._ import org.bitcoins.chain.models.BlockHeaderDb import org.bitcoins.core.crypto.DoubleSha256DigestBE import org.bitcoins.core.protocol.blockchain.BlockHeader import scala.concurrent.{ExecutionContext, Future} +import org.bitcoins.chain.config.ChainAppConfig /** * Entry api to the chain project for adding new things to our blockchain */ trait ChainApi { - def chainConfig: AppConfig + def chainConfig: ChainAppConfig /** * Adds a block header to our chain project diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala index cdc786eb59..891dadec2c 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala @@ -54,7 +54,7 @@ object Blockchain extends BitcoinSLogger { val nested: Vector[Future[BlockchainUpdate]] = blockchains.map { blockchain => val tip = blockchain.tip - logger.info( + logger.debug( s"Attempting to add new tip=${header.hashBE.hex} with prevhash=${header.previousBlockHashBE.hex} to chain with current tips=${tip.hashBE.hex}") val tipResultF = TipValidation.checkNewTip(newPotentialTip = header, currentTip = tip, diff --git a/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala b/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala index 81e3ef176f..36db487993 100644 --- a/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala +++ b/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala @@ -14,23 +14,29 @@ import scala.util.Failure case class ChainAppConfig(val confs: Config*) extends AppConfig { override protected val configOverrides: List[Config] = confs.toList - override protected val moduleConfigName: String = "chain.conf" + override protected val moduleName: String = "chain" override protected type ConfigType = ChainAppConfig override protected def newConfigOfType( configs: List[Config]): ChainAppConfig = ChainAppConfig(configs: _*) + /** + * Checks whether or not the chain project is initialized by + * trying to read the genesis block header from our block + * header table + */ def isInitialized()(implicit ec: ExecutionContext): Future[Boolean] = { - val bhDAO = BlockHeaderDAO(this) + val bhDAO = + BlockHeaderDAO()(ec = implicitly[ExecutionContext], appConfig = this) val p = Promise[Boolean]() val isDefinedOptF = { bhDAO.read(chain.genesisBlock.blockHeader.hashBE).map(_.isDefined) } isDefinedOptF.onComplete { case Success(bool) => - logger.info(s"Chain project is initialized") + logger.debug(s"Chain project is initialized") p.success(bool) case Failure(err) => - logger.info(s"Failed to init chain app err=${err.getMessage}") + logger.info(s"Chain project is not initialized") p.success(false) } @@ -41,8 +47,7 @@ case class ChainAppConfig(val confs: Config*) extends AppConfig { * This creates the necessary tables for the chain project * and inserts preliminary data like the genesis block header * */ - def initialize(implicit ec: ExecutionContext): Future[Unit] = { - val blockHeaderDAO = BlockHeaderDAO(this) + override def initialize()(implicit ec: ExecutionContext): Future[Unit] = { val isInitF = isInitialized() isInitF.flatMap { isInit => if (isInit) { @@ -53,9 +58,14 @@ case class ChainAppConfig(val confs: Config*) extends AppConfig { BlockHeaderDbHelper.fromBlockHeader(height = 0, bh = chain.genesisBlock.blockHeader) + val blockHeaderDAO = + BlockHeaderDAO()(ec = implicitly[ExecutionContext], appConfig = this) val bhCreatedF = createdF.flatMap(_ => blockHeaderDAO.create(genesisHeader)) - bhCreatedF.flatMap(_ => FutureUtil.unit) + bhCreatedF.flatMap { _ => + logger.info(s"Inserted genesis block header into DB") + FutureUtil.unit + } } } } diff --git a/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala b/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala index 05ad18bc9e..59015ec355 100644 --- a/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala +++ b/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala @@ -6,6 +6,8 @@ import org.bitcoins.db.{DbManagement} import slick.lifted.TableQuery import scala.concurrent.Future +import scala.concurrent.ExecutionContext +import org.bitcoins.chain.config.ChainAppConfig /** * Responsible for creating and destroying database @@ -19,11 +21,12 @@ sealed abstract class ChainDbManagement extends DbManagement { override val allTables = List(chainTable) def createHeaderTable(createIfNotExists: Boolean = true)( - implicit config: AppConfig): Future[Unit] = { + implicit config: ChainAppConfig, + ec: ExecutionContext): Future[Unit] = { createTable(chainTable, createIfNotExists) } - def dropHeaderTable()(implicit config: AppConfig): Future[Unit] = { + def dropHeaderTable()(implicit config: ChainAppConfig): Future[Unit] = { dropTable(chainTable) } } diff --git a/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala b/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala index 27b83d3159..c2b42b2240 100644 --- a/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala +++ b/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala @@ -15,8 +15,9 @@ import scala.concurrent.{ExecutionContext, Future} * to [[org.bitcoins.core.protocol.blockchain.BlockHeader]]s in * our chain project */ -case class BlockHeaderDAO(appConfig: ChainAppConfig)( - implicit override val ec: ExecutionContext) +case class BlockHeaderDAO()( + implicit override val ec: ExecutionContext, + override val appConfig: ChainAppConfig) extends CRUD[BlockHeaderDb, DoubleSha256DigestBE] { import org.bitcoins.db.DbCommonsColumnMappers._ diff --git a/db-commons/src/main/resources/db.conf b/db-commons/src/main/resources/db.conf index 7e3a6bdd25..79022c6ab3 100644 --- a/db-commons/src/main/resources/db.conf +++ b/db-commons/src/main/resources/db.conf @@ -1,17 +1,43 @@ -bitcoin-s { - database { - dataSourceClass = slick.jdbc.DatabaseUrlDataSource - profile = "slick.jdbc.SQLiteProfile$" - dbPath = ${bitcoin-s.datadir}/${bitcoin-s.network}/ +common = { + dataSourceClass = slick.jdbc.DatabaseUrlDataSource + profile = "slick.jdbc.SQLiteProfile$" + db { + path = ${bitcoin-s.datadir}/${bitcoin-s.network}/ + driver = org.sqlite.JDBC + + # as long as we're on SQLite there's no point + # in doing connection pooling + connectionPool = disabled + } +} + +bitcoin-s { + wallet = ${common} + wallet { # this config key is read by Slick db { - driver = org.sqlite.JDBC - url = "jdbc:sqlite:"${bitcoin-s.database.dbPath}${bitcoin-s.database.name} + name = walletdb.sqlite + url = "jdbc:sqlite:"${bitcoin-s.wallet.db.path}${bitcoin-s.wallet.db.name} - # as long as we're on SQLite there's no point - # in doing connection pooling - connectionPool = disabled + } + } + + node = ${common} + node { + # this config key is read by Slick + db { + name = nodedb.sqlite + url = "jdbc:sqlite:"${bitcoin-s.node.db.path}${bitcoin-s.node.db.name} + } + } + + chain = ${common} + chain { + # this config key is read by Slick + db { + name = chaindb.sqlite + url = "jdbc:sqlite:"${bitcoin-s.chain.db.path}${bitcoin-s.chain.db.name} } } } diff --git a/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala b/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala index 31295da891..0bd1592c56 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala @@ -24,6 +24,8 @@ import java.nio.file.Files import scala.util.Properties import scala.util.matching.Regex +import scala.concurrent.ExecutionContext +import scala.concurrent.Future /** * Everything needed to configure functionality @@ -34,6 +36,17 @@ import scala.util.matching.Regex */ abstract class AppConfig extends BitcoinSLogger { + /** + * Initializes this project. + * After this future resolves, all operations should be + * able to be performed correctly. + * + * Initializing may include creating database tables, + * making directories or files needed latern or + * something else entirely. + */ + def initialize()(implicit ec: ExecutionContext): Future[Unit] + /** Sub members of AppConfig should override this type with * the type of themselves, ensuring `withOverrides` return * the correct type @@ -92,24 +105,18 @@ abstract class AppConfig extends BitcoinSLogger { } /** - * Name of module specific - * config file. `wallet.conf`, `node.conf`, - * etc. + * Name of the module. `chain`, `wallet`, `node` etc. */ - protected def moduleConfigName: String + protected def moduleName: String /** * The configuration details for connecting/using the database for our projects * that require datbase connections */ lazy val dbConfig: DatabaseConfig[SQLiteProfile] = { - //if we don't pass specific class, non-deterministic - //errors around the loaded configuration depending - //on the state of the default classLoader - //https://github.com/lightbend/config#debugging-your-configuration val dbConfig = { Try { - DatabaseConfig.forConfig[SQLiteProfile](path = "database", config) + DatabaseConfig.forConfig[SQLiteProfile](path = moduleName, config) } match { case Success(value) => value @@ -120,7 +127,7 @@ abstract class AppConfig extends BitcoinSLogger { } } - logger.trace(s"Resolved DB config: ${dbConfig.config}") + logger.debug(s"Resolved DB config: ${dbConfig.config}") val _ = createDbFileIfDNE() @@ -133,20 +140,33 @@ abstract class AppConfig extends BitcoinSLogger { } /** The path where our DB is located */ - // todo: what happens when to this if we + // todo: what happens to this if we // dont use SQLite? lazy val dbPath: Path = { - val pathStr = config.getString("database.dbPath") + val pathStr = config.getString(s"$moduleName.db.path") val path = Paths.get(pathStr) logger.debug(s"DB path: $path") path } + /** The name of our database */ + // todo: what happens to this if we + // dont use SQLite? + lazy val dbName: String = { + config.getString(s"$moduleName.db.name") + } + private def createDbFileIfDNE(): Unit = { //should add a check in here that we are using sqlite if (!Files.exists(dbPath)) { - logger.debug(s"Creating database directory=$dbPath") - val _ = Files.createDirectories(dbPath) + val _ = { + logger.debug(s"Creating database directory=$dbPath") + Files.createDirectories(dbPath) + val dbFilePath = dbPath.resolve(dbName) + logger.debug(s"Creating database file=$dbFilePath") + Files.createFile(dbFilePath) + } + () } } @@ -171,13 +191,7 @@ abstract class AppConfig extends BitcoinSLogger { * The underlying config that we derive the * rest of the fields in this class from */ - protected lazy val config: Config = { - val moduleConfig = - ConfigFactory.load(moduleConfigName) - - logger.debug( - s"Module config: ${moduleConfig.getConfig("bitcoin-s").asReadableJson}") - + private[bitcoins] lazy val config: Config = { // `load` tries to resolve substitions, // `parseResources` does not val dbConfig = ConfigFactory @@ -186,9 +200,14 @@ abstract class AppConfig extends BitcoinSLogger { logger.trace( s"DB config: ${dbConfig.getConfig("bitcoin-s").asReadableJson}") - val classPathConfig = - ConfigFactory - .load() + // we want to NOT resolve substitutions in the configuraton until the user + // provided configs also has been loaded. .parseResources() does not do that + // whereas .load() does + val classPathConfig = { + val applicationConf = ConfigFactory.parseResources("application.conf") + val referenceConf = ConfigFactory.parseResources("reference.conf") + applicationConf.withFallback(referenceConf) + } logger.trace( s"Classpath config: ${classPathConfig.getConfig("bitcoin-s").asReadableJson}") @@ -196,7 +215,6 @@ abstract class AppConfig extends BitcoinSLogger { // loads reference.conf as well as application.conf, // if the user has made one val unresolvedConfig = classPathConfig - .withFallback(moduleConfig) .withFallback(dbConfig) logger.trace(s"Unresolved bitcoin-s config:") @@ -219,6 +237,7 @@ abstract class AppConfig extends BitcoinSLogger { // in this order overrides.withFallback(unresolvedConfig) } else { + logger.trace(s"No user-provided overrides") unresolvedConfig } diff --git a/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala b/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala index e5d4362b8e..0fbf59ddfe 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala @@ -30,7 +30,10 @@ abstract class CRUD[T, PrimaryKeyType] extends BitcoinSLogger { * @param t - the record to be inserted * @return the inserted record */ - def create(t: T): Future[T] = createAll(Vector(t)).map(_.head) + def create(t: T): Future[T] = { + logger.trace(s"Writing $t to DB with config: ${appConfig.config}") + createAll(Vector(t)).map(_.head) + } def createAll(ts: Vector[T]): Future[Vector[T]] @@ -41,6 +44,7 @@ abstract class CRUD[T, PrimaryKeyType] extends BitcoinSLogger { * @return Option[T] - the record if found, else none */ def read(id: PrimaryKeyType): Future[Option[T]] = { + logger.trace(s"Reading from DB with config: ${appConfig.config}") val query = findByPrimaryKey(id) val rows: Future[Seq[T]] = database.run(query.result) rows.map(_.headOption) diff --git a/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala b/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala index 5ba21b6ffd..2734bbc16f 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala @@ -16,29 +16,38 @@ abstract class DbManagement extends BitcoinSLogger { db.run(query) } + /** Lists all tables in the given database */ + def listTables(db: SafeDatabase): Future[Vector[SQLiteTableInfo]] = + listTables(db.config.database) + def createAll()( implicit config: AppConfig, - ec: ExecutionContext): Future[List[Unit]] = { - Future.sequence(allTables.map(createTable(_))) + ec: ExecutionContext): Future[Unit] = { + Future.sequence(allTables.map(createTable(_))).map(_ => ()) } def dropAll()( implicit config: AppConfig, - ec: ExecutionContext): Future[List[Unit]] = { - Future.sequence(allTables.reverse.map(dropTable(_))) + ec: ExecutionContext): Future[Unit] = { + Future.sequence(allTables.reverse.map(dropTable(_))).map(_ => ()) } def createTable( table: TableQuery[_ <: Table[_]], createIfNotExists: Boolean = true)( - implicit config: AppConfig): Future[Unit] = { + implicit config: AppConfig, + ec: ExecutionContext): Future[Unit] = { + val tableName = table.baseTableRow.tableName + logger.debug( + s"Creating table $tableName with DB config: ${config.dbConfig.config} ") + import config.database - val result = if (createIfNotExists) { - database.run(table.schema.createIfNotExists) + val query = if (createIfNotExists) { + table.schema.createIfNotExists } else { - database.run(table.schema.create) + table.schema.create } - result + database.run(query).map(_ => logger.debug(s"Created table $tableName")) } def dropTable( diff --git a/node-test/src/test/scala/org/bitcoins/node/networking/ClientTest.scala b/node-test/src/test/scala/org/bitcoins/node/networking/ClientTest.scala index d7cbd45c4a..8ee9189a28 100644 --- a/node-test/src/test/scala/org/bitcoins/node/networking/ClientTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/networking/ClientTest.scala @@ -15,6 +15,7 @@ import org.scalatest._ import scala.concurrent.Future import scala.concurrent.duration.DurationInt +import org.bitcoins.testkit.BitcoinSAppConfig /** * Created by chris on 6/7/16. @@ -28,21 +29,22 @@ class ClientTest implicit val system = ActorSystem( s"Client-Test-System-${System.currentTimeMillis()}") - private val appConfig = NodeTestUtil.nodeAppConfig + implicit private val config: BitcoinSAppConfig = + BitcoinSAppConfig.getTestConfig() + implicit private val chainConf = config.chainConf + implicit private val nodeConf = config.nodeConf - private val chainAppConfig = ChainAppConfig() + implicit val np = config.chainConf.network - implicit val np = appConfig.network + lazy val bitcoindRpcF = BitcoindRpcTestUtil.startedBitcoindRpcClient() - val bitcoindRpcF = BitcoindRpcTestUtil.startedBitcoindRpcClient() - - val bitcoindPeerF = bitcoindRpcF.map { bitcoind => + lazy val bitcoindPeerF = bitcoindRpcF.map { bitcoind => NodeTestUtil.getBitcoindPeer(bitcoind) } - val bitcoindRpc2F = BitcoindRpcTestUtil.startedBitcoindRpcClient() + lazy val bitcoindRpc2F = BitcoindRpcTestUtil.startedBitcoindRpcClient() - val bitcoindPeer2F = bitcoindRpcF.map { bitcoind => + lazy val bitcoindPeer2F = bitcoindRpcF.map { bitcoind => NodeTestUtil.getBitcoindPeer(bitcoind) } @@ -75,9 +77,7 @@ class ClientTest val probe = TestProbe() val remote = peer.socket val peerMessageReceiver = - PeerMessageReceiver(state = Preconnection, - nodeAppConfig = appConfig, - chainAppConfig = chainAppConfig) + PeerMessageReceiver(state = Preconnection) val client = TestActorRef(Client.props(peer, peerMessageReceiver), probe.ref) diff --git a/node-test/src/test/scala/org/bitcoins/node/util/BitcoinSpvNodeUtilTest.scala b/node-test/src/test/scala/org/bitcoins/node/util/BitcoinSpvNodeUtilTest.scala index c8cb2da7b4..75a02bb310 100644 --- a/node-test/src/test/scala/org/bitcoins/node/util/BitcoinSpvNodeUtilTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/util/BitcoinSpvNodeUtilTest.scala @@ -16,16 +16,17 @@ import org.bitcoins.node.messages.HeadersMessage import org.bitcoins.node.messages.control.VersionMessage import org.bitcoins.node.messages.data.HeadersMessage import org.bitcoins.testkit.util.BitcoinSUnitTest +import org.bitcoins.testkit.BitcoinSAppConfig +import org.bitcoins.node.config.NodeAppConfig -/** - * Created by chris on 9/6/16. - */ class BitcoinSpvNodeUtilTest extends BitcoinSUnitTest { + lazy val config: NodeAppConfig = BitcoinSAppConfig.getTestConfig() + "BitcoinSpvNodeUtil" must "return the entire byte array if a message is not aligned to a byte frame" in { val versionMessage = - VersionMessage(TestNet3.dnsSeeds(0), Constants.networkParameters) - val networkMsg = NetworkMessage(Constants.networkParameters, versionMessage) + VersionMessage(TestNet3.dnsSeeds(0), config.network) + val networkMsg = NetworkMessage(config.network, versionMessage) //remove last byte so the message is not aligned val bytes = networkMsg.bytes.slice(0, networkMsg.bytes.size - 1) val (_, unAlignedBytes) = BitcoinSpvNodeUtil.parseIndividualMessages(bytes) @@ -60,7 +61,7 @@ class BitcoinSpvNodeUtilTest extends BitcoinSUnitTest { ) ) ) - val networkMsg = NetworkMessage(Constants.networkParameters, headersMsg) + val networkMsg = NetworkMessage(config.network, headersMsg) //split the network msg at a random index to simulate a tcp frame not being aligned val randomIndex = scala.util.Random.nextInt().abs % networkMsg.bytes.size val (firstHalf, secondHalf) = networkMsg.bytes.splitAt(randomIndex) diff --git a/node/src/main/resources/node.conf b/node/src/main/resources/node.conf deleted file mode 100644 index c8ee57d6e7..0000000000 --- a/node/src/main/resources/node.conf +++ /dev/null @@ -1,5 +0,0 @@ -bitcoin-s { - database { - name = "nodedb.sqlite" - } -} diff --git a/node/src/main/scala/org/bitcoins/node/Main.scala b/node/src/main/scala/org/bitcoins/node/Main.scala index 9c99a943d9..fdde61ede1 100644 --- a/node/src/main/scala/org/bitcoins/node/Main.scala +++ b/node/src/main/scala/org/bitcoins/node/Main.scala @@ -24,7 +24,7 @@ object Main extends App with BitcoinSLogger { implicit val chainAppConfig = ChainAppConfig() logger.info(s"Chain config: ${chainAppConfig.dbConfig.config}") - val bhDAO = BlockHeaderDAO(chainAppConfig) + val bhDAO = BlockHeaderDAO() val chainApi = ChainHandler(bhDAO, chainAppConfig) val table = TableQuery[BlockHeaderTable] diff --git a/node/src/main/scala/org/bitcoins/node/SpvNode.scala b/node/src/main/scala/org/bitcoins/node/SpvNode.scala index e9333ed038..91a3f41748 100644 --- a/node/src/main/scala/org/bitcoins/node/SpvNode.scala +++ b/node/src/main/scala/org/bitcoins/node/SpvNode.scala @@ -24,7 +24,7 @@ case class SpvNode(peer: Peer, chainApi: ChainApi)( import system.dispatcher private val peerMsgRecv = - PeerMessageReceiver.newReceiver(nodeAppConfig, chainAppConfig) + PeerMessageReceiver.newReceiver private val client: Client = Client(context = system, peer = peer, peerMessageReceiver = peerMsgRecv) @@ -35,21 +35,24 @@ case class SpvNode(peer: Peer, chainApi: ChainApi)( /** Starts our spv node */ def start(): Future[SpvNode] = { - peerMsgSender.connect() + for { + _ <- nodeAppConfig.initialize() + node <- { + peerMsgSender.connect() - val isInitializedF = - AsyncUtil.retryUntilSatisfied(peerMsgRecv.isInitialized) + val isInitializedF = + AsyncUtil.retryUntilSatisfied(peerMsgRecv.isInitialized) - isInitializedF.map { _ => - logger.info(s"Our peer=${peer} has been initialized") - } + isInitializedF.failed.foreach(err => + logger.error(s"Failed to conenct with peer=$peer with err=${err}")) - isInitializedF.failed.foreach { err => - logger.error(s"Failed to conenct with peer=$peer with err=${err}") + isInitializedF.map { _ => + logger.info(s"Our peer=${peer} has been initialized") + this + } + } - } - - isInitializedF.map(_ => this) + } yield node } /** Stops our spv node */ diff --git a/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala b/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala index 2f188c2405..0daaee94ff 100644 --- a/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala +++ b/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala @@ -2,12 +2,32 @@ package org.bitcoins.node.config import com.typesafe.config.Config import org.bitcoins.db.AppConfig +import scala.concurrent.ExecutionContext +import scala.concurrent.Future +import org.bitcoins.node.db.NodeDbManagement +import scala.util.Failure +import scala.util.Success case class NodeAppConfig(confs: Config*) extends AppConfig { override val configOverrides: List[Config] = confs.toList - override protected def moduleConfigName: String = "node.conf" + override protected def moduleName: String = "node" override protected type ConfigType = NodeAppConfig override protected def newConfigOfType(configs: List[Config]): NodeAppConfig = NodeAppConfig(configs: _*) + /** + * Ensures correct tables and other required information is in + * place for our node. + */ + override def initialize()(implicit ec: ExecutionContext): Future[Unit] = { + logger.debug(s"Initializing node setup") + val initF = NodeDbManagement.createAll()(config = this, ec) + initF.onComplete { + case Failure(err) => + logger.error(s"Error when initializing node: ${err.getMessage}") + case Success(_) => + logger.debug(s"Initializing node setup: done") + } + initF + } } diff --git a/node/src/main/scala/org/bitcoins/node/constant/Constants.scala b/node/src/main/scala/org/bitcoins/node/constant/Constants.scala index 11b591663f..85ccb28931 100644 --- a/node/src/main/scala/org/bitcoins/node/constant/Constants.scala +++ b/node/src/main/scala/org/bitcoins/node/constant/Constants.scala @@ -1,22 +1,14 @@ package org.bitcoins.node.constant import akka.actor.ActorSystem -import org.bitcoins.core.config.{MainNet, NetworkParameters, RegTest, TestNet3} -import org.bitcoins.core.protocol.blockchain.{ - ChainParams, - MainNetChainParams, - RegTestNetChainParams, - TestNetChainParams -} -import org.bitcoins.node.config.NodeAppConfig import org.bitcoins.node.versions.ProtocolVersion70013 -import slick.jdbc.PostgresProfile.api._ import scala.concurrent.duration.DurationInt +import com.typesafe.config.ConfigFactory case object Constants { - lazy val actorSystem = ActorSystem("BitcoinSpvNode") - def networkParameters: NetworkParameters = appConfig.network + val emptyConfig = ConfigFactory.parseString("") + lazy val actorSystem = ActorSystem("BitcoinSpvNode", emptyConfig) def version = ProtocolVersion70013 def timeout = 5.seconds @@ -25,19 +17,4 @@ case object Constants { /** This is the file where our block headers are stored */ def blockHeaderFile = new java.io.File("src/main/resources/block_headers.dat") - lazy val appConfig: NodeAppConfig = NodeAppConfig() - - /** The [[ChainParams]] for the blockchain we are currently connected to */ - def chainParams: ChainParams = networkParameters match { - case MainNet => MainNetChainParams - case TestNet3 => TestNetChainParams - case RegTest => RegTestNetChainParams - } - - /** This is the database we are currently bound to, this - * should be the database that stores information corresponding to the network - * we are currently connected to inside of the [[networkParameters]] function - * @return - */ - def database: Database = appConfig.database } diff --git a/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala b/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala index 24e03b0a47..e6cc6d2508 100644 --- a/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala +++ b/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala @@ -3,11 +3,12 @@ package org.bitcoins.node.models import org.bitcoins.db.{CRUDAutoInc} import slick.jdbc.SQLiteProfile.api._ -import org.bitcoins.db.AppConfig import scala.concurrent.ExecutionContext +import org.bitcoins.node.config.NodeAppConfig -case class PeerDAO(appConfig: AppConfig)( - implicit override val ec: ExecutionContext) +case class PeerDAO()( + implicit override val ec: ExecutionContext, + override val appConfig: NodeAppConfig) extends CRUDAutoInc[Peer] { override val table = TableQuery[PeerTable] } diff --git a/node/src/main/scala/org/bitcoins/node/networking/BlockActor.scala b/node/src/main/scala/org/bitcoins/node/networking/BlockActor.scala index bb78575753..90998dc989 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/BlockActor.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/BlockActor.scala @@ -22,7 +22,7 @@ sealed abstract class BlockActor extends Actor with BitcoinSLogger { val inv = Inventory(TypeIdentifier.MsgBlock, hash) val getDataMessage = GetDataMessage(inv) val networkMessage = - NetworkMessage(Constants.networkParameters, getDataMessage) + NetworkMessage(network = ???, getDataMessage) peerMsgHandler ! networkMessage context.become(awaitBlockMsg) case blockHeader: BlockHeader => diff --git a/node/src/main/scala/org/bitcoins/node/networking/Client.scala b/node/src/main/scala/org/bitcoins/node/networking/Client.scala index 41a3db7897..5e3178875f 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/Client.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/Client.scala @@ -7,7 +7,7 @@ import akka.util.ByteString import org.bitcoins.core.config.NetworkParameters import org.bitcoins.core.util.BitcoinSLogger import org.bitcoins.node.NetworkMessage -import org.bitcoins.node.constant.Constants +import org.bitcoins.node.config.NodeAppConfig import org.bitcoins.node.messages.NetworkPayload import org.bitcoins.node.models.Peer import org.bitcoins.node.networking.peer.PeerMessageReceiver @@ -41,6 +41,8 @@ import scodec.bits.ByteVector */ sealed abstract class ClientActor extends Actor with BitcoinSLogger { + val config: NodeAppConfig + def peer: Peer /** The place we send messages that we successfully parsed from our @@ -61,7 +63,7 @@ sealed abstract class ClientActor extends Actor with BitcoinSLogger { * i.e. [[org.bitcoins.core.config.MainNet]] or [[org.bitcoins.core.config.TestNet3]] * @return */ - def network: NetworkParameters = Constants.networkParameters + def network: NetworkParameters = config.network /** * This actor signifies the node we are connected to on the p2p network @@ -223,16 +225,20 @@ case class Client(actor: ActorRef, peer: Peer) object Client { private case class ClientActorImpl( peer: Peer, - peerMsgHandlerReceiver: PeerMessageReceiver) - extends ClientActor + peerMsgHandlerReceiver: PeerMessageReceiver)( + implicit override val config: NodeAppConfig + ) extends ClientActor - def props(peer: Peer, peerMsgHandlerReceiver: PeerMessageReceiver): Props = - Props(classOf[ClientActorImpl], peer, peerMsgHandlerReceiver) + def props(peer: Peer, peerMsgHandlerReceiver: PeerMessageReceiver)( + implicit config: NodeAppConfig + ): Props = + Props(classOf[ClientActorImpl], peer, peerMsgHandlerReceiver, config) def apply( context: ActorRefFactory, peer: Peer, - peerMessageReceiver: PeerMessageReceiver): Client = { + peerMessageReceiver: PeerMessageReceiver)( + implicit config: NodeAppConfig): Client = { val actorRef = context.actorOf( props(peer = peer, peerMsgHandlerReceiver = peerMessageReceiver), BitcoinSpvNodeUtil.createActorName(this.getClass)) diff --git a/node/src/main/scala/org/bitcoins/node/networking/PaymentActor.scala b/node/src/main/scala/org/bitcoins/node/networking/PaymentActor.scala index c24b37055b..1ab3863b17 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/PaymentActor.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/PaymentActor.scala @@ -49,7 +49,7 @@ sealed abstract class PaymentActor extends Actor with BitcoinSLogger { BloomFilter(10, 0.0001, UInt32.zero, BloomUpdateNone).insert(hash) val filterLoadMsg = FilterLoadMessage(bloomFilter) val bloomFilterNetworkMsg = - NetworkMessage(Constants.networkParameters, filterLoadMsg) + NetworkMessage(network = ???, filterLoadMsg) peerMsgHandler ! bloomFilterNetworkMsg } @@ -111,7 +111,7 @@ sealed abstract class PaymentActor extends Actor with BitcoinSLogger { Inventory(TypeIdentifier.MsgFilteredBlock, blockHashes.head) val getDataMsg = GetDataMessage(merkleBlockInventory) val getDataNetworkMessage = - NetworkMessage(Constants.networkParameters, getDataMsg) + NetworkMessage(network = ???, getDataMsg) peerMessageHandler ! getDataNetworkMessage logger.debug("Switching to awaitMerkleBlockMessage") context.become( diff --git a/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala b/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala index 78360c8847..431df172b6 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala @@ -17,11 +17,12 @@ import scala.concurrent.{ExecutionContext, Future} * that a peer to sent to us on the p2p network, for instance, if we a receive a * [[HeadersMessage]] we should store those headers in our database */ -class DataMessageHandler(appConfig: ChainAppConfig)( - implicit ec: ExecutionContext) +class DataMessageHandler()( + implicit ec: ExecutionContext, + appConfig: ChainAppConfig) extends BitcoinSLogger { - private val blockHeaderDAO: BlockHeaderDAO = BlockHeaderDAO(appConfig) + private val blockHeaderDAO: BlockHeaderDAO = BlockHeaderDAO() def handleDataPayload( payload: DataPayload, diff --git a/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageReceiver.scala b/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageReceiver.scala index bce7d5205c..2075e400b5 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageReceiver.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageReceiver.scala @@ -30,6 +30,9 @@ class PeerMessageReceiver( chainAppConfig: ChainAppConfig)(implicit ref: ActorRefFactory) extends BitcoinSLogger { + implicit private val nodeConfig = nodeAppConfig + implicit private val chainConfig = chainAppConfig + import ref.dispatcher //TODO: Really bad to just modify this internal state @@ -136,7 +139,7 @@ class PeerMessageReceiver( private def handleDataPayload( payload: DataPayload, sender: PeerMessageSender): Unit = { - val dataMsgHandler = new DataMessageHandler(chainAppConfig) + val dataMsgHandler = new DataMessageHandler() //else it means we are receiving this data payload from a peer, //we need to handle it dataMsgHandler.handleDataPayload(payload, sender) @@ -227,16 +230,18 @@ object PeerMessageReceiver { case class NetworkMessageReceived(msg: NetworkMessage, client: Client) extends PeerMessageReceiverMsg - def apply( - state: PeerMessageReceiverState, + def apply(state: PeerMessageReceiverState)( + implicit ref: ActorRefFactory, nodeAppConfig: NodeAppConfig, - chainAppConfig: ChainAppConfig)( - implicit ref: ActorRefFactory): PeerMessageReceiver = { + chainAppConfig: ChainAppConfig + ): PeerMessageReceiver = { new PeerMessageReceiver(state, nodeAppConfig, chainAppConfig)(ref) } - def newReceiver(nodeAppConfig: NodeAppConfig, chainAppConfig: ChainAppConfig)( - implicit ref: ActorRefFactory): PeerMessageReceiver = { + def newReceiver( + implicit nodeAppConfig: NodeAppConfig, + chainAppConfig: ChainAppConfig, + ref: ActorRefFactory): PeerMessageReceiver = { new PeerMessageReceiver(state = PeerMessageReceiverState.fresh(), nodeAppConfig, chainAppConfig)(ref) diff --git a/project/Deps.scala b/project/Deps.scala index eff3bf040b..e49e82ee06 100644 --- a/project/Deps.scala +++ b/project/Deps.scala @@ -210,7 +210,7 @@ object Deps { Test.ammonite ) - val doc = List( + val docs = List( Compile.ammonite, Compile.logback, Test.scalaTest, diff --git a/testkit/src/main/resources/application.conf b/testkit/src/main/resources/application.conf deleted file mode 100644 index 49800e5ab0..0000000000 --- a/testkit/src/main/resources/application.conf +++ /dev/null @@ -1,19 +0,0 @@ -bitcoin-s { - datadir = ${HOME}/.bitcoin-s/.unittest - - database { - db { - # run against a file-based database - # url="jdbc:sqlite:"${dbPath}${dbName} - - # run against an in-memory database - # cache=shared is needed to make it persist across DB connections - # (each query is one connection). DB is wiped on JVM being killed - # with this option set. - url = "jdbc:sqlite:file::memory:?cache=shared" - - connectionPool = disabled - keepAliveConnection = true - } - } -} \ No newline at end of file diff --git a/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSAppConfig.scala b/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSAppConfig.scala new file mode 100644 index 0000000000..bf555d8cae --- /dev/null +++ b/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSAppConfig.scala @@ -0,0 +1,103 @@ +package org.bitcoins.testkit + +import com.typesafe.config.Config +import org.bitcoins.wallet.config.WalletAppConfig +import org.bitcoins.node.config.NodeAppConfig +import org.bitcoins.chain.config.ChainAppConfig +import scala.concurrent.ExecutionContext +import scala.concurrent.Future +import java.nio.file.Files +import com.typesafe.config.ConfigFactory + +/** + * A unified config class for all submodules of Bitcoin-S + * that accepts configuration. Thanks to implicit definitions + * in this case class' companion object an instance + * of this class can be passed in anywhere a wallet, + * chain or node config is required. + */ +case class BitcoinSAppConfig(confs: Config*) { + val walletConf = WalletAppConfig(confs: _*) + val nodeConf = NodeAppConfig(confs: _*) + val chainConf = ChainAppConfig(confs: _*) + + /** Initializes the wallet, node and chain projects */ + def initialize()(implicit ec: ExecutionContext): Future[Unit] = { + val futures = List(walletConf.initialize(), + nodeConf.initialize(), + chainConf.initialize()) + + Future.sequence(futures).map(_ => ()) + } +} + +/** + * Implicit conversions that allow a unified configuration + * to be passed in wherever a specializes one is required + */ +object BitcoinSAppConfig { + import scala.language.implicitConversions + + /** Converts the given implicit config to a wallet config */ + implicit def implicitToWalletConf( + implicit conf: BitcoinSAppConfig): WalletAppConfig = + conf.walletConf + + /** Converts the given config to a wallet config */ + implicit def toWalletConf(conf: BitcoinSAppConfig): WalletAppConfig = + conf.walletConf + + /** Converts the given implicit config to a chain config */ + implicit def implicitToChainConf( + implicit conf: BitcoinSAppConfig): ChainAppConfig = + conf.chainConf + + /** Converts the given config to a chain config */ + implicit def toChainConf(conf: BitcoinSAppConfig): ChainAppConfig = + conf.chainConf + + /** Converts the given implicit config to a node config */ + implicit def implicitToNodeConf( + implicit conf: BitcoinSAppConfig): NodeAppConfig = + conf.nodeConf + + /** Converts the given config to a node config */ + implicit def toNodeConf(conf: BitcoinSAppConfig): NodeAppConfig = + conf.nodeConf + + /** + * App configuration suitable for test purposes: + + * 1) Data directory is set to user temp directory + * 2) All databases are in-memory + */ + def getTestConfig(config: Config*) = { + val tmpDir = Files.createTempDirectory("bitcoin-s-") + val confStr = s""" + | bitcoin-s { + | datadir = $tmpDir + | + | wallet.db { + | url = "jdbc:sqlite:file::memory:?cache=shared" + | connectionPool = disabled + | keepAliveConnection = true + | } + | node.db { + | url = "jdbc:sqlite:file::memory:?cache=shared" + | connectionPool = disabled + | keepAliveConnection = true + | } + | chain.db { + | url = "jdbc:sqlite:file::memory:?cache=shared" + | connectionPool = disabled + | keepAliveConnection = true + | } + | } + | + |""".stripMargin + val conf = ConfigFactory.parseString(confStr) + val allConfs = conf +: config + BitcoinSAppConfig(allConfs: _*) + } + +} diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala index d1987ae346..e31eebafa6 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala @@ -14,13 +14,13 @@ import org.bitcoins.chain.models.{ } import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader, ChainParams} import org.bitcoins.core.util.BitcoinSLogger -import org.bitcoins.db.AppConfig import org.bitcoins.rpc.client.common.BitcoindRpcClient import org.bitcoins.testkit.chain import org.bitcoins.testkit.chain.fixture._ import org.bitcoins.testkit.fixtures.BitcoinSFixture import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil import org.bitcoins.zmq.ZMQSubscriber +import org.bitcoins.testkit.BitcoinSAppConfig import org.scalatest._ import play.api.libs.json.{JsError, JsSuccess, Json} import scodec.bits.ByteVector @@ -28,6 +28,7 @@ import scodec.bits.ByteVector import scala.annotation.tailrec import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} +import org.bitcoins.db.AppConfig trait ChainUnitTest extends org.scalatest.fixture.AsyncFlatSpec @@ -44,16 +45,16 @@ trait ChainUnitTest implicit lazy val chainParam: ChainParams = appConfig.chain - implicit lazy val appConfig: ChainAppConfig = ChainAppConfig() + implicit lazy val appConfig: ChainAppConfig = + BitcoinSAppConfig.getTestConfig() /** * Behaves exactly like the default conf, execpt * network is set to mainnet */ lazy val mainnetAppConfig: ChainAppConfig = { - val defaultConfig = ChainAppConfig() val mainnetConf = ConfigFactory.parseString("bitcoin-s.network = mainnet") - defaultConfig.withOverrides(mainnetConf) + BitcoinSAppConfig.getTestConfig(mainnetConf) } override def beforeAll(): Unit = { @@ -378,7 +379,7 @@ object ChainUnitTest extends BitcoinSLogger { } } - def destroyHeaderTable()(implicit appConfig: AppConfig): Future[Unit] = { + def destroyHeaderTable()(implicit appConfig: ChainAppConfig): Future[Unit] = { ChainDbManagement.dropHeaderTable() } @@ -389,7 +390,8 @@ object ChainUnitTest extends BitcoinSLogger { /** Creates the [[org.bitcoins.chain.models.BlockHeaderTable]] */ private def setupHeaderTable()( - implicit appConfig: AppConfig): Future[Unit] = { + implicit appConfig: ChainAppConfig, + ec: ExecutionContext): Future[Unit] = { ChainDbManagement.createHeaderTable(createIfNotExists = true) } @@ -411,7 +413,7 @@ object ChainUnitTest extends BitcoinSLogger { def makeChainHandler()( implicit appConfig: ChainAppConfig, ec: ExecutionContext): ChainHandler = { - lazy val blockHeaderDAO = BlockHeaderDAO(appConfig) + lazy val blockHeaderDAO = BlockHeaderDAO() ChainHandler(blockHeaderDAO = blockHeaderDAO, appConfig) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala index df829b6faa..fc47784c3c 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala @@ -71,10 +71,9 @@ abstract class NodeTestUtil { ) } - def nodeAppConfig: NodeAppConfig = NodeAppConfig() - def client(peer: Peer, peerMsgReceiver: PeerMessageReceiver)( - implicit ref: ActorRefFactory): Client = { + implicit ref: ActorRefFactory, + conf: NodeAppConfig): Client = { Client.apply(ref, peer, peerMsgReceiver) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala index b280271d7f..7fb7fb65be 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala @@ -3,12 +3,10 @@ package org.bitcoins.testkit.node import java.net.InetSocketAddress import akka.actor.ActorSystem -import org.bitcoins.chain.config.ChainAppConfig import org.bitcoins.core.config.NetworkParameters import org.bitcoins.core.util.BitcoinSLogger import org.bitcoins.db.AppConfig import org.bitcoins.node.SpvNode -import org.bitcoins.node.config.NodeAppConfig import org.bitcoins.node.models.Peer import org.bitcoins.node.networking.peer.{ PeerHandler, @@ -31,6 +29,9 @@ import org.scalatest.{ import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} +import org.bitcoins.testkit.BitcoinSAppConfig +import org.bitcoins.testkit.BitcoinSAppConfig._ + trait NodeUnitTest extends BitcoinSFixture with MustMatchers @@ -39,7 +40,7 @@ trait NodeUnitTest with BeforeAndAfterAll { override def beforeAll(): Unit = { - AppConfig.throwIfDefaultDatadir(nodeAppConfig) + AppConfig.throwIfDefaultDatadir(config.nodeConf) } override def afterAll(): Unit = { @@ -56,9 +57,11 @@ trait NodeUnitTest val timeout: FiniteDuration = 10.seconds - implicit lazy val nodeAppConfig: NodeAppConfig = NodeAppConfig() - implicit lazy val chainAppConfig: ChainAppConfig = ChainAppConfig() - implicit val np: NetworkParameters = nodeAppConfig.network + /** Wallet config with data directory set to user temp directory */ + implicit protected lazy val config: BitcoinSAppConfig = + BitcoinSAppConfig.getTestConfig() + + implicit lazy val np: NetworkParameters = config.nodeConf.network lazy val startedBitcoindF = BitcoindRpcTestUtil.startedBitcoindRpcClient() @@ -66,7 +69,7 @@ trait NodeUnitTest def buildPeerMessageReceiver(): PeerMessageReceiver = { val receiver = - PeerMessageReceiver.newReceiver(nodeAppConfig, chainAppConfig) + PeerMessageReceiver.newReceiver receiver } @@ -143,7 +146,7 @@ trait NodeUnitTest object NodeUnitTest { def destroySpvNode(spvNode: SpvNode)( - implicit appConfig: NodeAppConfig, + implicit config: BitcoinSAppConfig, ec: ExecutionContext): Future[Unit] = { val stopF = spvNode.stop() stopF.flatMap(_ => ChainUnitTest.destroyHeaderTable()) @@ -152,7 +155,7 @@ object NodeUnitTest { def destorySpvNodeConnectedWithBitcoind( spvNodeConnectedWithBitcoind: SpvNodeConnectedWithBitcoind)( implicit system: ActorSystem, - appConfig: NodeAppConfig): Future[Unit] = { + appConfig: BitcoinSAppConfig): Future[Unit] = { import system.dispatcher val spvNode = spvNodeConnectedWithBitcoind.spvNode val bitcoind = spvNodeConnectedWithBitcoind.bitcoind diff --git a/testkit/src/test/scala/org/bitcoins/testkit/db/AppConfigTest.scala b/testkit/src/test/scala/org/bitcoins/testkit/db/AppConfigTest.scala new file mode 100644 index 0000000000..d276611af1 --- /dev/null +++ b/testkit/src/test/scala/org/bitcoins/testkit/db/AppConfigTest.scala @@ -0,0 +1,126 @@ +package org.bitcoins.testkit.db + +import org.bitcoins.testkit.util.BitcoinSUnitTest +import org.bitcoins.testkit.BitcoinSAppConfig +import org.bitcoins.testkit.BitcoinSAppConfig._ +import com.typesafe.config.ConfigFactory +import org.bitcoins.core.config.TestNet3 +import org.bitcoins.chain.models.BlockHeaderDAO +import akka.actor.ActorSystem +import scala.concurrent.ExecutionContext +import org.bitcoins.wallet.models.AccountDAO +import org.bitcoins.testkit.chain.ChainTestUtil +import org.bitcoins.chain.models.BlockHeaderDb +import org.bitcoins.chain.models.BlockHeaderDbHelper +import org.bitcoins.wallet.models.AccountDb +import org.bitcoins.core.hd.HDAccount +import org.bitcoins.core.hd.HDCoin +import org.bitcoins.core.hd.HDPurposes +import org.bitcoins.core.hd.HDCoinType +import org.bitcoins.testkit.core.gen.CryptoGenerators +import os.write +import org.bitcoins.node.db.NodeDbManagement +import org.bitcoins.db.DbManagement +import org.bitcoins.wallet.db.WalletDbManagement +import org.bitcoins.db.SQLiteTableInfo +import slick.jdbc.SQLiteProfile.api._ +import org.bitcoins.db.CRUD +import java.nio.file.Files + +class AppConfigTest extends BitcoinSUnitTest { + + val system = ActorSystem() + implicit val ec: ExecutionContext = system.dispatcher + + behavior of "BitcoinSAppConfig" + + it must "propagate values correctly to all sub configs" in { + val networkOverride = + ConfigFactory.parseString("bitcoin-s.network = testnet3") + + val config = BitcoinSAppConfig.getTestConfig(networkOverride) + val chainConf = config.chainConf + val walletConf = config.walletConf + val nodeConf = config.nodeConf + + assert(chainConf.datadir == walletConf.datadir) + assert(walletConf.datadir == nodeConf.datadir) + + assert(chainConf.network == TestNet3) + assert(walletConf.network == TestNet3) + assert(nodeConf.network == TestNet3) + } + + it must "have the same DB path" in { + val conf = BitcoinSAppConfig.getTestConfig() + val chainConf = conf.chainConf + val walletConf = conf.walletConf + val nodeConf = conf.nodeConf + assert(chainConf.dbPath == walletConf.dbPath) + assert(walletConf.dbPath == nodeConf.dbPath) + } + + it must "have distinct databases" in { + val conf = BitcoinSAppConfig.getTestConfig() + val chainConf = conf.chainConf + val walletConf = conf.walletConf + val nodeConf = conf.nodeConf + assert(chainConf.dbName != walletConf.dbName) + assert(walletConf.dbName != nodeConf.dbName) + } + + it must "be able to write to distinct databases" in { + implicit val config = BitcoinSAppConfig.getTestConfig() + val chainConf = config.chainConf + val walletConf = config.walletConf + val nodeConf = config.nodeConf + val allConfs = List(chainConf, walletConf, nodeConf) + + val bhDAO = BlockHeaderDAO() + val accountDAO = AccountDAO() + + allConfs.foreach { conf => + val fullDbPath = conf.dbPath.resolve(conf.dbName) + assert(!Files.exists(fullDbPath)) + } + + val writeF = { + for { + _ <- config.initialize() + _ = { + allConfs.foreach { conf => + val fullDbPath = conf.dbPath.resolve(conf.dbName) + assert(Files.isRegularFile(fullDbPath)) + } + } + _ <- { + bhDAO.create(ChainTestUtil.regTestGenesisHeaderDb) + } + _ <- { + val hdAccount = + HDAccount(HDCoin(HDPurposes.Legacy, HDCoinType.Bitcoin), 0) + val xpub = CryptoGenerators.extPublicKey.sample.get + val account = AccountDb(xpub, hdAccount) + accountDAO.create(account) + } + } yield () + } + + for { + _ <- writeF + nodeTables <- NodeDbManagement.listTables(bhDAO.database) + walletTables <- WalletDbManagement.listTables(accountDAO.database) + } yield { + def hasTable(tables: Seq[SQLiteTableInfo], dao: CRUD[_, _]): Boolean = + tables.exists(_.name == dao.table.baseTableRow.tableName) + + assert(hasTable(walletTables, accountDAO)) + assert(!hasTable(walletTables, bhDAO)) + + assert(hasTable(nodeTables, bhDAO)) + assert(!hasTable(nodeTables, accountDAO)) + } + + } + +} diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletStorageTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletStorageTest.scala index df6daf5037..de3ac90799 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletStorageTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletStorageTest.scala @@ -19,15 +19,21 @@ import java.nio.file.Paths import org.bitcoins.wallet.ReadMnemonicError.DecryptionError import java.{util => ju} import org.bitcoins.wallet.ReadMnemonicError.JsonParsingError +import org.bitcoins.testkit.BitcoinSAppConfig._ +import scala.concurrent.Await +import scala.concurrent.duration._ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach with EmptyFixture { - val datadir = appConfig.datadir + val datadir = config.walletConf.datadir override def beforeEach(): Unit = { + // make sure datadir is created for reading/writing mnemonics + Await.result(config.walletConf.initialize(), 5.seconds) + Files .walk(datadir) .iterator() diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AccountDAOFixture.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AccountDAOFixture.scala index 7f69506af7..981f0f4e1e 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AccountDAOFixture.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AccountDAOFixture.scala @@ -6,10 +6,15 @@ import org.bitcoins.wallet.util.BitcoinSWalletTest import org.scalatest._ import scala.concurrent.Future +import org.bitcoins.wallet.config.WalletAppConfig trait AccountDAOFixture extends fixture.AsyncFlatSpec with BitcoinSWalletTest { override final type FixtureParam = AccountDAO + // to get around the config in `BitcoinSWalletTest` not resolving + // as an AppConfig + private implicit val walletConfig: WalletAppConfig = config.walletConf + override final def withFixture(test: OneArgAsyncTest): FutureOutcome = makeDependentFixture(createAccountTable, dropAccountTable)(test) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AddressDAOFixture.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AddressDAOFixture.scala index 935bb7daf1..393b0c1a81 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AddressDAOFixture.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/AddressDAOFixture.scala @@ -6,6 +6,7 @@ import org.bitcoins.wallet.db.WalletDbManagement import org.bitcoins.wallet.models.{AccountDAO, AddressDAO} import org.bitcoins.wallet.util.BitcoinSWalletTest import org.scalatest._ +import org.bitcoins.wallet.config.WalletAppConfig /** * This fixture has a tuple of DAOs, because @@ -18,6 +19,10 @@ trait AddressDAOFixture extends fixture.AsyncFlatSpec with BitcoinSWalletTest { override final def withFixture(test: OneArgAsyncTest): FutureOutcome = makeDependentFixture(createTables, dropTables)(test) + // to get around the config in `BitcoinSWalletTest` not resolving + // as an AppConfig + private implicit val walletConfig: WalletAppConfig = config.walletConf + private def dropTables(daos: FixtureParam): Future[Unit] = { val (account, address) = daos val dropAccountF = WalletDbManagement.dropTable(account.table) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/DAOFixture.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/DAOFixture.scala index 52ab19d401..f41aef2e5c 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/DAOFixture.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/DAOFixture.scala @@ -7,6 +7,7 @@ import slick.jdbc.SQLiteProfile.api._ import scala.language.reflectiveCalls import scala.concurrent.{Await, Future} +import org.bitcoins.wallet.config.WalletAppConfig private[fixtures] trait DAOFixture extends fixture.AsyncFlatSpec @@ -17,6 +18,10 @@ private[fixtures] trait DAOFixture private[fixtures] val daoAccumulator = Vector.newBuilder[HasTable] + // to get around the config in `BitcoinSWalletTest` not resolving + // as an AppConfig + private implicit val walletConfig: WalletAppConfig = config.walletConf + override def beforeAll(): Unit = { val tables = daoAccumulator.result() diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/UtxoDAOFixture.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/UtxoDAOFixture.scala index 6bc84b40d8..9fe26c7c6c 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/UtxoDAOFixture.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/fixtures/UtxoDAOFixture.scala @@ -6,6 +6,7 @@ import org.bitcoins.wallet.util.BitcoinSWalletTest import org.scalatest._ import scala.concurrent.Future +import org.bitcoins.wallet.config.WalletAppConfig trait UtxoDAOFixture extends fixture.AsyncFlatSpec with BitcoinSWalletTest { @@ -14,6 +15,10 @@ trait UtxoDAOFixture extends fixture.AsyncFlatSpec with BitcoinSWalletTest { override final def withFixture(test: OneArgAsyncTest): FutureOutcome = makeDependentFixture(createUtxoTable, dropUtxoTable)(test) + // to get around the config in `BitcoinSWalletTest` not resolving + // as an AppConfig + private implicit val walletConfig: WalletAppConfig = config.walletConf + private def dropUtxoTable(utxoDAO: FixtureParam): Future[Unit] = { WalletDbManagement.dropTable(utxoDAO.table) } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/util/BitcoinSWalletTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/util/BitcoinSWalletTest.scala index a17e89dc84..81009e080d 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/util/BitcoinSWalletTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/util/BitcoinSWalletTest.scala @@ -21,6 +21,8 @@ import org.scalatest._ import scala.concurrent.duration.{DurationInt, FiniteDuration} import scala.concurrent.{ExecutionContext, Future} import org.bitcoins.db.AppConfig +import org.bitcoins.testkit.BitcoinSAppConfig +import org.bitcoins.testkit.BitcoinSAppConfig._ trait BitcoinSWalletTest extends fixture.AsyncFlatSpec @@ -31,7 +33,10 @@ trait BitcoinSWalletTest implicit val ec: ExecutionContext = actorSystem.dispatcher protected lazy val chainParams: ChainParams = WalletTestUtil.chainParams - protected implicit lazy val appConfig: WalletAppConfig = WalletAppConfig() + + /** Wallet config with data directory set to user temp directory */ + implicit protected lazy val config: BitcoinSAppConfig = + BitcoinSAppConfig.getTestConfig() /** Timeout for async operations */ protected val timeout: FiniteDuration = 10.seconds @@ -43,19 +48,24 @@ trait BitcoinSWalletTest } override def beforeAll(): Unit = { - AppConfig.throwIfDefaultDatadir(appConfig) + AppConfig.throwIfDefaultDatadir(config.walletConf) } - def destroyWallet(wallet: UnlockedWalletApi): Future[Unit] = - WalletDbManagement.dropAll().map(_ => ()) + def destroyWallet(wallet: UnlockedWalletApi): Future[Unit] = { + WalletDbManagement + .dropAll()(config = config.walletConf, ec = implicitly[ExecutionContext]) + .map(_ => ()) + } def createNewWallet(): Future[UnlockedWalletApi] = { for { - _ <- WalletDbManagement.createAll() + _ <- config.initialize() wallet <- Wallet.initialize().map { case InitializeWalletSuccess(wallet) => wallet - case err: InitializeWalletError => fail(err) + case err: InitializeWalletError => + logger.error(s"Could not initialize wallet: $err") + fail(err) } } yield wallet } diff --git a/wallet/src/main/resources/wallet.conf b/wallet/src/main/resources/wallet.conf deleted file mode 100644 index bf755e8785..0000000000 --- a/wallet/src/main/resources/wallet.conf +++ /dev/null @@ -1,5 +0,0 @@ -bitcoin-s { - database { - name = "walletdb.sqlite" - } -} \ No newline at end of file diff --git a/wallet/src/main/scala/org/bitcoins/wallet/HDUtil.scala b/wallet/src/main/scala/org/bitcoins/wallet/HDUtil.scala index 46c2cd37e8..4129513366 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/HDUtil.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/HDUtil.scala @@ -3,13 +3,13 @@ package org.bitcoins.wallet import org.bitcoins.core.hd._ import org.bitcoins.core.crypto._ import org.bitcoins.core.config._ -import org.bitcoins.db.AppConfig +import org.bitcoins.wallet.config.WalletAppConfig private[wallet] object HDUtil { /** Gets the xpriv version required for the given HD purpose */ def getXprivVersion(hdPurpose: HDPurpose)( - implicit config: AppConfig): ExtKeyPrivVersion = { + implicit config: WalletAppConfig): ExtKeyPrivVersion = { import config.network import org.bitcoins.core.hd.HDPurposes._ import ExtKeyVersion._ @@ -28,7 +28,7 @@ private[wallet] object HDUtil { /** Gets the xpub version required for the given HD purpose */ def getXpubVersion(hdPurpose: HDPurpose)( - implicit config: AppConfig): ExtKeyPubVersion = { + implicit config: WalletAppConfig): ExtKeyPubVersion = { import config.network import org.bitcoins.core.hd.HDPurposes._ import ExtKeyVersion._ diff --git a/wallet/src/main/scala/org/bitcoins/wallet/LockedWallet.scala b/wallet/src/main/scala/org/bitcoins/wallet/LockedWallet.scala index df6f6756f3..ae5421cb20 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/LockedWallet.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/LockedWallet.scala @@ -20,10 +20,10 @@ import org.bitcoins.wallet.models._ import scala.concurrent.Future import scala.util.Success import scala.util.Failure -import org.bitcoins.db.AppConfig import scala.concurrent.ExecutionContext import org.bitcoins.wallet.ReadMnemonicError.DecryptionError import org.bitcoins.wallet.ReadMnemonicError.JsonParsingError +import org.bitcoins.wallet.config.WalletAppConfig abstract class LockedWallet extends LockedWalletApi with BitcoinSLogger { @@ -263,9 +263,11 @@ abstract class LockedWallet extends LockedWalletApi with BitcoinSLogger { object LockedWallet { private case class LockedWalletImpl()( implicit val ec: ExecutionContext, - val walletConfig: AppConfig) + val walletConfig: WalletAppConfig) extends LockedWallet - def apply()(implicit ec: ExecutionContext, config: AppConfig): LockedWallet = - LockedWalletImpl() + def apply()( + implicit ec: ExecutionContext, + config: WalletAppConfig): LockedWallet = LockedWalletImpl() + } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala index 07af071cc2..3e5c3ce480 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala @@ -16,7 +16,7 @@ import scodec.bits.BitVector import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success, Try} import org.bitcoins.core.hd._ -import org.bitcoins.db.AppConfig +import org.bitcoins.wallet.config.WalletAppConfig sealed abstract class Wallet extends LockedWallet @@ -108,7 +108,7 @@ object Wallet extends CreateWalletApi with BitcoinSLogger { private case class WalletImpl( mnemonicCode: MnemonicCode )( - implicit override val walletConfig: AppConfig, + implicit override val walletConfig: WalletAppConfig, override val ec: ExecutionContext) extends Wallet { @@ -117,7 +117,7 @@ object Wallet extends CreateWalletApi with BitcoinSLogger { } def apply(mnemonicCode: MnemonicCode)( - implicit config: AppConfig, + implicit config: WalletAppConfig, ec: ExecutionContext): Wallet = WalletImpl(mnemonicCode) @@ -126,7 +126,7 @@ object Wallet extends CreateWalletApi with BitcoinSLogger { // todo fix signature override def initializeWithEntropy(entropy: BitVector)( - implicit config: AppConfig, + implicit config: WalletAppConfig, ec: ExecutionContext): Future[InitializeWalletResult] = { import org.bitcoins.core.util.EitherUtil.EitherOps._ @@ -182,6 +182,7 @@ object Wallet extends CreateWalletApi with BitcoinSLogger { logger.debug(s"Saved encrypted wallet mnemonic to $mnemonicPath") for { + _ <- config.initialize() _ <- wallet.accountDAO .create(accountDb) .map(_ => logger.trace(s"Saved account to DB")) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/WalletStorage.scala b/wallet/src/main/scala/org/bitcoins/wallet/WalletStorage.scala index 87a8aea236..45313ff558 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/WalletStorage.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/WalletStorage.scala @@ -13,7 +13,7 @@ import scala.util.Success import java.nio.file.Paths import java.nio.file.Path import scala.util.Try -import org.bitcoins.db.AppConfig +import org.bitcoins.wallet.config.WalletAppConfig // what do we do if seed exists? error if they aren't equal? object WalletStorage extends BitcoinSLogger { @@ -35,7 +35,7 @@ object WalletStorage extends BitcoinSLogger { * the file name. */ def writeMnemonicToDisk(mnemonic: EncryptedMnemonic)( - implicit config: AppConfig): Path = { + implicit config: WalletAppConfig): Path = { import mnemonic.{value => encrypted} val jsObject = { @@ -98,7 +98,7 @@ object WalletStorage extends BitcoinSLogger { * performing no decryption */ private def readEncryptedMnemonicFromDisk()( - implicit config: AppConfig): Either[ + implicit config: WalletAppConfig): Either[ ReadMnemonicError, EncryptedMnemonic] = { @@ -175,7 +175,7 @@ object WalletStorage extends BitcoinSLogger { */ def decryptMnemonicFromDisk(passphrase: AesPassword)( implicit - config: AppConfig): ReadMnemonicResult = { + config: WalletAppConfig): ReadMnemonicResult = { val encryptedEither = readEncryptedMnemonicFromDisk() import org.bitcoins.core.util.EitherUtil.EitherOps._ diff --git a/wallet/src/main/scala/org/bitcoins/wallet/api/CreateWalletApi.scala b/wallet/src/main/scala/org/bitcoins/wallet/api/CreateWalletApi.scala index 41e2a652cd..e5c58f4d55 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/api/CreateWalletApi.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/api/CreateWalletApi.scala @@ -4,7 +4,7 @@ import org.bitcoins.core.crypto.MnemonicCode import scodec.bits.BitVector import scala.concurrent.{ExecutionContext, Future} -import org.bitcoins.db.AppConfig +import org.bitcoins.wallet.config.WalletAppConfig /** * @define initialize @@ -25,7 +25,7 @@ trait CreateWalletApi { private def initializeInternal()( implicit executionContext: ExecutionContext, - appConfig: AppConfig): Future[InitializeWalletResult] = + config: WalletAppConfig): Future[InitializeWalletResult] = initializeWithEntropy(entropy = MnemonicCode.getEntropy256Bits) /** @@ -33,19 +33,19 @@ trait CreateWalletApi { */ final def initialize()( implicit executionContext: ExecutionContext, - appConfig: AppConfig): Future[InitializeWalletResult] = + config: WalletAppConfig): Future[InitializeWalletResult] = initializeInternal() /** * $initializeWithEnt */ def initializeWithEntropy(entropy: BitVector)( - implicit config: AppConfig, + implicit config: WalletAppConfig, executionContext: ExecutionContext): Future[InitializeWalletResult] // todo: scaladoc final def initializeWithMnemonic(mnemonicCode: MnemonicCode)( - implicit config: AppConfig, + implicit config: WalletAppConfig, executionContext: ExecutionContext): Future[InitializeWalletResult] = { val entropy = mnemonicCode.toEntropy initializeWithEntropy(entropy) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/api/WalletApi.scala b/wallet/src/main/scala/org/bitcoins/wallet/api/WalletApi.scala index 4e02ae9542..e3f2db0d71 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/api/WalletApi.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/api/WalletApi.scala @@ -14,7 +14,7 @@ import org.bitcoins.wallet.models.{AccountDb, AddressDb, UTXOSpendingInfoDb} import scala.concurrent.Future import scala.concurrent.ExecutionContext -import org.bitcoins.db.AppConfig +import org.bitcoins.wallet.config.WalletAppConfig /** * API for the wallet project. @@ -25,7 +25,7 @@ import org.bitcoins.db.AppConfig */ sealed trait WalletApi { - implicit val walletConfig: AppConfig + implicit val walletConfig: WalletAppConfig implicit val ec: ExecutionContext def chainParams: ChainParams = walletConfig.chain diff --git a/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala b/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala index b7a5f8f720..3d640c1d9a 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala @@ -2,11 +2,37 @@ package org.bitcoins.wallet.config import com.typesafe.config.Config import org.bitcoins.db.AppConfig +import scala.concurrent.{ExecutionContext, Future} +import org.bitcoins.wallet.db.WalletDbManagement +import scala.util.Failure +import scala.util.Success +import java.nio.file.Files case class WalletAppConfig(conf: Config*) extends AppConfig { override val configOverrides: List[Config] = conf.toList - override def moduleConfigName: String = "wallet.conf" + override def moduleName: String = "wallet" override type ConfigType = WalletAppConfig override def newConfigOfType(configs: List[Config]): WalletAppConfig = WalletAppConfig(configs: _*) + + override def initialize()(implicit ec: ExecutionContext): Future[Unit] = { + logger.debug(s"Initializing wallet setup") + + if (Files.notExists(datadir)) { + Files.createDirectories(datadir) + } + + val initF = { + WalletDbManagement.createAll()(this, ec) + } + initF.onComplete { + case Failure(exception) => + logger.error(s"Error on wallet setup: ${exception.getMessage}") + case Success(_) => + logger.debug(s"Initializing wallet setup: done") + } + + initF + } + } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala index 0da65b93c3..1290d3ff36 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala @@ -7,16 +7,15 @@ import slick.jdbc.SQLiteProfile.api._ import scala.concurrent.{Future} import org.bitcoins.db.CRUD import org.bitcoins.db.SlickUtil -import org.bitcoins.db.AppConfig import scala.concurrent.ExecutionContext -case class AccountDAO()(implicit val ec: ExecutionContext) +case class AccountDAO()( + implicit val ec: ExecutionContext, + val appConfig: WalletAppConfig) extends CRUD[AccountDb, (HDCoin, Int)] { import org.bitcoins.db.DbCommonsColumnMappers._ - override def appConfig: WalletAppConfig = WalletAppConfig() - override val table: TableQuery[AccountTable] = TableQuery[AccountTable] override def createAll(ts: Vector[AccountDb]): Future[Vector[AccountDb]] = diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala index 251737b6ea..d5d725d158 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala @@ -9,16 +9,14 @@ import slick.sql.SqlAction import scala.concurrent.{ExecutionContext, Future} import org.bitcoins.core.hd.HDChainType -import org.bitcoins.db.AppConfig import org.bitcoins.wallet.config.WalletAppConfig case class AddressDAO()( - implicit val ec: ExecutionContext + implicit val ec: ExecutionContext, + val appConfig: WalletAppConfig ) extends CRUD[AddressDb, BitcoinAddress] { import org.bitcoins.db.DbCommonsColumnMappers._ - override def appConfig: WalletAppConfig = WalletAppConfig() - override val table: TableQuery[AddressTable] = TableQuery[AddressTable] override def createAll(ts: Vector[AddressDb]): Future[Vector[AddressDb]] = diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/UTXOSpendingInfoDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/UTXOSpendingInfoDAO.scala index 99af848be3..389a3046ba 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/UTXOSpendingInfoDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/UTXOSpendingInfoDAO.scala @@ -6,13 +6,12 @@ import slick.jdbc.SQLiteProfile.api._ import scala.concurrent.Future import scala.concurrent.ExecutionContext -import org.bitcoins.db.AppConfig -case class UTXOSpendingInfoDAO()(implicit val ec: ExecutionContext) +case class UTXOSpendingInfoDAO()( + implicit val ec: ExecutionContext, + val appConfig: WalletAppConfig) extends CRUDAutoInc[UTXOSpendingInfoDb] { - override def appConfig: WalletAppConfig = WalletAppConfig() - /** The table inside our database we are inserting into */ override val table = TableQuery[UTXOSpendingInfoTable]