Multi module configuration (#494)

* Replace AppConfig with more specific types

* Rework database configuration

In this commit we:

1) Introduce new database settings for all submodules,
and at the same time remove the singular datbase setting
for the entire project
2) Introduce a new method .initialize on all configs
that is responsible for creating needed directories,
databases and files
3) Introduce a new class BitcoinSAppConfig that wraps
configs for all three other subproject config. We
also provide implicit conversions that enable this
super-config to be passed in wherever a specialized
config is required.
4) Add more tests for our configuration setup.

* Add Ammonite to Docs deps
This commit is contained in:
Torkel Rogstad 2019-06-05 17:48:15 +02:00 committed by Chris Stewart
parent 49ffbea801
commit 3c4157a698
33 changed files with 500 additions and 177 deletions

View File

@ -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,

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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,

View File

@ -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
}
}
}
}

View File

@ -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)
}
}

View File

@ -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._

View File

@ -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
}

View File

@ -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)

View File

@ -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(

View File

@ -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)

View File

@ -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 */

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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))

View File

@ -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,

View File

@ -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)

View File

@ -210,7 +210,7 @@ object Deps {
Test.ammonite
)
val doc = List(
val docs = List(
Compile.ammonite,
Compile.logback,
Test.scalaTest,

View File

@ -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: _*)
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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

View File

@ -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))
}
}
}

View File

@ -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
}

View File

@ -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._

View File

@ -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"))

View File

@ -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._

View File

@ -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

View File

@ -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
}
}

View File

@ -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]] =

View File

@ -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]] =

View File

@ -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]