mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-13 19:37:30 +01:00
Fee Provider from config (#2219)
* Fee Provider from config * Use block targets, add docs * Add FeeProviderFactory
This commit is contained in:
parent
7c887cc144
commit
641538440f
8 changed files with 170 additions and 17 deletions
|
@ -5,16 +5,16 @@ import akka.dispatch.Dispatchers
|
|||
import akka.http.scaladsl.Http
|
||||
import org.bitcoins.chain.blockchain.ChainHandler
|
||||
import org.bitcoins.chain.config.ChainAppConfig
|
||||
import org.bitcoins.chain.models.{
|
||||
BlockHeaderDAO,
|
||||
CompactFilterDAO,
|
||||
CompactFilterHeaderDAO
|
||||
}
|
||||
import org.bitcoins.chain.models._
|
||||
import org.bitcoins.core.Core
|
||||
import org.bitcoins.core.api.chain.ChainApi
|
||||
import org.bitcoins.core.api.feeprovider.FeeRateApi
|
||||
import org.bitcoins.core.api.node.NodeApi
|
||||
import org.bitcoins.core.util.{FutureUtil, NetworkUtil}
|
||||
import org.bitcoins.feeprovider.BitcoinerLiveFeeRateProvider
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.feeprovider.FeeProviderName._
|
||||
import org.bitcoins.feeprovider.MempoolSpaceTarget.HourFeeTarget
|
||||
import org.bitcoins.feeprovider._
|
||||
import org.bitcoins.node._
|
||||
import org.bitcoins.node.config.NodeAppConfig
|
||||
import org.bitcoins.node.models.Peer
|
||||
|
@ -70,9 +70,10 @@ class BitcoinSServerMain(override val args: Array[String])
|
|||
node <- nodeF
|
||||
chainApi <- chainApiF
|
||||
_ = logger.info("Initialized chain api")
|
||||
feeProvider = getFeeProviderOrElse(MempoolSpaceProvider(HourFeeTarget))
|
||||
wallet <- walletConf.createHDWallet(node,
|
||||
chainApi,
|
||||
BitcoinerLiveFeeRateProvider(60),
|
||||
feeProvider,
|
||||
bip39PasswordOpt)
|
||||
callbacks <- createCallbacks(wallet)
|
||||
_ = nodeConf.addCallbacks(callbacks)
|
||||
|
@ -132,10 +133,12 @@ class BitcoinSServerMain(override val args: Array[String])
|
|||
_ = logger.info("Starting bitcoind")
|
||||
_ <- bitcoindRpcConf.start()
|
||||
_ = logger.info("Creating wallet")
|
||||
tmpWallet <- walletConf.createHDWallet(bitcoind,
|
||||
bitcoind,
|
||||
bitcoind,
|
||||
bip39PasswordOpt)
|
||||
feeProvider = getFeeProviderOrElse(bitcoind)
|
||||
tmpWallet <- walletConf.createHDWallet(nodeApi = bitcoind,
|
||||
chainQueryApi = bitcoind,
|
||||
feeRateApi = feeProvider,
|
||||
bip39PasswordOpt =
|
||||
bip39PasswordOpt)
|
||||
wallet = BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks(
|
||||
bitcoind,
|
||||
tmpWallet)
|
||||
|
@ -298,6 +301,39 @@ class BitcoinSServerMain(override val args: Array[String])
|
|||
}
|
||||
server.start()
|
||||
}
|
||||
|
||||
/** Gets a Fee Provider from the given wallet app config
|
||||
* Returns default if there is no config set
|
||||
*/
|
||||
def getFeeProviderOrElse(default: => FeeRateApi)(implicit
|
||||
system: ActorSystem,
|
||||
walletConf: WalletAppConfig): FeeRateApi = {
|
||||
val feeProviderNameOpt =
|
||||
walletConf.feeProviderNameOpt.flatMap(FeeProviderName.fromStringOpt)
|
||||
val feeProvider =
|
||||
(feeProviderNameOpt, walletConf.feeProviderTargetOpt) match {
|
||||
case (None, None) | (None, Some(_)) =>
|
||||
default
|
||||
case (Some(BitcoinerLive), None) =>
|
||||
BitcoinerLiveFeeRateProvider.fromBlockTarget(6)
|
||||
case (Some(BitcoinerLive), Some(target)) =>
|
||||
BitcoinerLiveFeeRateProvider.fromBlockTarget(target)
|
||||
case (Some(BitGo), targetOpt) =>
|
||||
BitGoFeeRateProvider(targetOpt)
|
||||
case (Some(MempoolSpace), None) =>
|
||||
MempoolSpaceProvider(HourFeeTarget)
|
||||
case (Some(MempoolSpace), Some(target)) =>
|
||||
MempoolSpaceProvider.fromBlockTarget(target)
|
||||
case (Some(Constant), Some(num)) =>
|
||||
ConstantFeeRateProvider(SatoshisPerVirtualByte.fromLong(num))
|
||||
case (Some(Constant), None) =>
|
||||
throw new IllegalArgumentException(
|
||||
"Missing a target for a ConstantFeeRateProvider")
|
||||
}
|
||||
|
||||
logger.info(s"Using fee provider: $feeProvider")
|
||||
feeProvider
|
||||
}
|
||||
}
|
||||
|
||||
object BitcoinSServerMain extends App {
|
||||
|
|
|
@ -158,6 +158,29 @@ bitcoin-s {
|
|||
|
||||
}
|
||||
|
||||
# Bitcoin-S provides manny different fee providers
|
||||
# You can configure your server to use any of them
|
||||
# Below is some examples of different options
|
||||
fee-provider {
|
||||
# name = mempoolspace # Uses mempool.space's api
|
||||
# The target is optional for mempool.space
|
||||
# It refers to the expected number of blocks until confirmation
|
||||
# target = 6
|
||||
|
||||
# name = bitcoinerlive # Uses bitcoiner.live's api
|
||||
# The target is optional for Bitcoiner Live
|
||||
# It refers to the expected number of blocks until confirmation
|
||||
# target = 6
|
||||
|
||||
# name = bitgo # Uses BitGo's api
|
||||
# The target is optional for BitGo
|
||||
# It refers to the expected number of blocks until confirmation
|
||||
# target = 6
|
||||
|
||||
# name = constant # A constant fee rate in sats/vbyte
|
||||
# target = 1 # Will always use 1 sat/vbyte
|
||||
}
|
||||
|
||||
server {
|
||||
# The port we bind our rpc server on
|
||||
rpcport = 9999
|
||||
|
|
|
@ -45,3 +45,11 @@ case class BitGoFeeRateProvider(blockTargetOpt: Option[Int])(implicit
|
|||
belowLimit.values.min
|
||||
}
|
||||
}
|
||||
|
||||
object BitGoFeeRateProvider extends FeeProviderFactory[BitGoFeeRateProvider] {
|
||||
|
||||
override def fromBlockTarget(blocks: Int)(implicit
|
||||
system: ActorSystem): BitGoFeeRateProvider = {
|
||||
BitGoFeeRateProvider(Some(blocks))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import akka.http.scaladsl.model.Uri
|
|||
import org.bitcoins.commons.jsonmodels.wallet.BitcoinerLiveResult
|
||||
import org.bitcoins.commons.serializers.JsonSerializers._
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.feeprovider.BitcoinerLiveFeeRateProvider.validMinutes
|
||||
import play.api.libs.json.{JsError, JsSuccess, Json}
|
||||
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
@ -13,11 +14,8 @@ case class BitcoinerLiveFeeRateProvider(minutes: Int)(implicit
|
|||
override val system: ActorSystem)
|
||||
extends CachedHttpFeeRateProvider {
|
||||
|
||||
private val bitcoinerLiveValidMinutes =
|
||||
Vector(30, 60, 120, 180, 360, 720, 1440)
|
||||
require(
|
||||
bitcoinerLiveValidMinutes.contains(minutes),
|
||||
s"$minutes is not a valid selection, must be from $bitcoinerLiveValidMinutes")
|
||||
require(validMinutes.contains(minutes),
|
||||
s"$minutes is not a valid selection, must be from $validMinutes")
|
||||
|
||||
override val uri: Uri =
|
||||
Uri("https://bitcoiner.live/api/fees/estimates/latest")
|
||||
|
@ -34,3 +32,23 @@ case class BitcoinerLiveFeeRateProvider(minutes: Int)(implicit
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
object BitcoinerLiveFeeRateProvider
|
||||
extends FeeProviderFactory[BitcoinerLiveFeeRateProvider] {
|
||||
|
||||
final val validMinutes =
|
||||
Vector(30, 60, 120, 180, 360, 720, 1440)
|
||||
|
||||
override def fromBlockTarget(blocks: Int)(implicit
|
||||
system: ActorSystem): BitcoinerLiveFeeRateProvider = {
|
||||
require(blocks > 0,
|
||||
s"Cannot have a negative or zero block target, got $blocks")
|
||||
|
||||
val blockTargets = validMinutes.map(_ / 10)
|
||||
|
||||
// Find closest
|
||||
val target = blockTargets.minBy(target => Math.abs(target - blocks))
|
||||
|
||||
BitcoinerLiveFeeRateProvider(target)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.bitcoins.feeprovider
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import org.bitcoins.core.api.feeprovider.FeeRateApi
|
||||
|
||||
trait FeeProviderFactory[T <: FeeRateApi] {
|
||||
def fromBlockTarget(blocks: Int)(implicit system: ActorSystem): T
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.bitcoins.feeprovider
|
||||
|
||||
import org.bitcoins.crypto.StringFactory
|
||||
|
||||
sealed abstract class FeeProviderName
|
||||
|
||||
object FeeProviderName extends StringFactory[FeeProviderName] {
|
||||
|
||||
final case object BitcoinerLive extends FeeProviderName
|
||||
|
||||
final case object BitGo extends FeeProviderName
|
||||
|
||||
final case object Constant extends FeeProviderName
|
||||
|
||||
final case object MempoolSpace extends FeeProviderName
|
||||
|
||||
val all: Vector[FeeProviderName] =
|
||||
Vector(BitcoinerLive, BitGo, Constant, MempoolSpace)
|
||||
|
||||
override def fromStringOpt(str: String): Option[FeeProviderName] = {
|
||||
all.find(_.toString.toLowerCase == str.toLowerCase)
|
||||
}
|
||||
|
||||
override def fromString(string: String): FeeProviderName = {
|
||||
fromStringOpt(string) match {
|
||||
case Some(state) => state
|
||||
case None =>
|
||||
sys.error(s"Could not find FeeProviderName for string=$string")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,6 +40,15 @@ case class MempoolSpaceProvider(target: MempoolSpaceTarget)(implicit
|
|||
}
|
||||
}
|
||||
|
||||
object MempoolSpaceProvider extends FeeProviderFactory[MempoolSpaceProvider] {
|
||||
|
||||
override def fromBlockTarget(blocks: Int)(implicit
|
||||
system: ActorSystem): MempoolSpaceProvider = {
|
||||
val target = MempoolSpaceTarget.fromBlockTarget(blocks)
|
||||
MempoolSpaceProvider(target)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MempoolSpaceTarget
|
||||
|
||||
object MempoolSpaceTarget {
|
||||
|
@ -49,4 +58,17 @@ object MempoolSpaceTarget {
|
|||
final case object HalfHourFeeTarget extends MempoolSpaceTarget
|
||||
|
||||
final case object HourFeeTarget extends MempoolSpaceTarget
|
||||
|
||||
def fromBlockTarget(blocks: Int): MempoolSpaceTarget = {
|
||||
if (blocks <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
s"Cannot have a negative or zero block target, got $blocks")
|
||||
} else if (blocks < 3) {
|
||||
FastestFeeTarget
|
||||
} else if (blocks < 6) {
|
||||
HalfHourFeeTarget
|
||||
} else {
|
||||
HourFeeTarget
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.bitcoins.core.wallet.keymanagement.{
|
|||
KeyManagerParams
|
||||
}
|
||||
import org.bitcoins.db.DatabaseDriver.{PostgreSQL, SQLite}
|
||||
import org.bitcoins.db.{AppConfig, AppConfigFactory, JdbcProfileComponent}
|
||||
import org.bitcoins.db._
|
||||
import org.bitcoins.keymanager.WalletStorage
|
||||
import org.bitcoins.keymanager.bip39.{BIP39KeyManager, BIP39LockedKeyManager}
|
||||
import org.bitcoins.wallet.db.WalletDbManagement
|
||||
|
@ -97,6 +97,13 @@ case class WalletAppConfig(
|
|||
confs
|
||||
}
|
||||
|
||||
lazy val feeProviderNameOpt: Option[String] = {
|
||||
config.getStringOrNone("bitcoin-s.fee-provider.name")
|
||||
}
|
||||
|
||||
lazy val feeProviderTargetOpt: Option[Int] =
|
||||
config.getIntOpt("bitcoin-s.fee-provider.target")
|
||||
|
||||
override def start(): Future[Unit] = {
|
||||
for {
|
||||
_ <- super.start()
|
||||
|
|
Loading…
Add table
Reference in a new issue