optionnally provide an external seed

usage: `PHOENIX_SEED="focus certain canvas rude exist sausage chuckle
forget bronze brown warm comic" ./phoenixd`
This commit is contained in:
pm47 2024-03-25 11:49:39 +01:00
parent 0432da38e5
commit f2b378484a
No known key found for this signature in database
GPG Key ID: E434ED292E85643A
3 changed files with 24 additions and 10 deletions

View File

@ -18,12 +18,15 @@ import com.github.ajalt.clikt.sources.MapValueSource
import com.github.ajalt.mordant.rendering.TextColors.* import com.github.ajalt.mordant.rendering.TextColors.*
import com.github.ajalt.mordant.rendering.TextStyles.bold import com.github.ajalt.mordant.rendering.TextStyles.bold
import fr.acinq.bitcoin.Chain import fr.acinq.bitcoin.Chain
import fr.acinq.bitcoin.MnemonicCode
import fr.acinq.lightning.BuildVersions import fr.acinq.lightning.BuildVersions
import fr.acinq.lightning.Lightning.randomBytes32 import fr.acinq.lightning.Lightning.randomBytes32
import fr.acinq.lightning.LiquidityEvents import fr.acinq.lightning.LiquidityEvents
import fr.acinq.lightning.NodeParams import fr.acinq.lightning.NodeParams
import fr.acinq.lightning.PaymentEvents import fr.acinq.lightning.PaymentEvents
import fr.acinq.lightning.bin.conf.EnvVars.PHOENIX_SEED
import fr.acinq.lightning.bin.conf.LSP import fr.acinq.lightning.bin.conf.LSP
import fr.acinq.lightning.bin.conf.PhoenixSeed
import fr.acinq.lightning.bin.conf.getOrGenerateSeed import fr.acinq.lightning.bin.conf.getOrGenerateSeed
import fr.acinq.lightning.bin.conf.readConfFile import fr.acinq.lightning.bin.conf.readConfFile
import fr.acinq.lightning.bin.db.SqliteChannelsDb import fr.acinq.lightning.bin.db.SqliteChannelsDb
@ -47,6 +50,7 @@ import fr.acinq.lightning.payment.LiquidityPolicy
import fr.acinq.lightning.utils.Connection import fr.acinq.lightning.utils.Connection
import fr.acinq.lightning.utils.msat import fr.acinq.lightning.utils.msat
import fr.acinq.lightning.utils.sat import fr.acinq.lightning.utils.sat
import fr.acinq.lightning.utils.toByteVector
import fr.acinq.phoenix.db.* import fr.acinq.phoenix.db.*
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.*
@ -69,6 +73,17 @@ fun main(args: Array<String>) = Phoenixd()
class Phoenixd : CliktCommand() { class Phoenixd : CliktCommand() {
private val confFile = datadir / "phoenix.conf" private val confFile = datadir / "phoenix.conf"
private val seed by option("--seed", help = "Manually provide a 12-words seed", hidden = true, envvar = PHOENIX_SEED)
.convert { PhoenixSeed(MnemonicCode.toSeed(it, "").toByteVector(), isNew = false) }
.defaultLazy {
val value = getOrGenerateSeed(datadir)
if (value.isNew) {
terminal.print(yellow("Generating new seed..."))
runBlocking { delay(500.milliseconds) }
terminal.println(white("done"))
}
value
}
private val chain by option("--chain", help = "Bitcoin chain to use").choice( private val chain by option("--chain", help = "Bitcoin chain to use").choice(
"mainnet" to Chain.Mainnet, "testnet" to Chain.Testnet "mainnet" to Chain.Mainnet, "testnet" to Chain.Testnet
).default(Chain.Mainnet, defaultForHelp = "mainnet") ).default(Chain.Mainnet, defaultForHelp = "mainnet")
@ -155,13 +170,8 @@ class Phoenixd : CliktCommand() {
@OptIn(DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
override fun run() { override fun run() {
FileSystem.SYSTEM.createDirectories(datadir) FileSystem.SYSTEM.createDirectories(datadir)
val (seed, new) = getOrGenerateSeed(datadir) if (seed.isNew) {
if (new) {
runBlocking { runBlocking {
terminal.print(yellow("Generating new seed..."))
delay(500.milliseconds)
terminal.println(white("done"))
terminal.println()
terminal.println(green("Backup")) terminal.println(green("Backup"))
terminal.println("This software is self-custodial, you have full control and responsibility over your funds.") terminal.println("This software is self-custodial, you have full control and responsibility over your funds.")
terminal.println("Your 12-words seed is located in ${FileSystem.SYSTEM.canonicalize(datadir)}, ${bold(red("make sure to do a backup or you risk losing your funds"))}.") terminal.println("Your 12-words seed is located in ${FileSystem.SYSTEM.canonicalize(datadir)}, ${bold(red("make sure to do a backup or you risk losing your funds"))}.")
@ -215,7 +225,7 @@ class Phoenixd : CliktCommand() {
skipAbsoluteFeeCheck = false, skipAbsoluteFeeCheck = false,
maxAllowedCredit = liquidityOptions.maxFeeCredit maxAllowedCredit = liquidityOptions.maxFeeCredit
) )
val keyManager = LocalKeyManager(seed, chain, lsp.swapInXpub) val keyManager = LocalKeyManager(seed.seed, chain, lsp.swapInXpub)
val nodeParams = NodeParams(chain, loggerFactory, keyManager) val nodeParams = NodeParams(chain, loggerFactory, keyManager)
.copy( .copy(
zeroConfPeers = setOf(lsp.walletParams.trampolineNode.id), zeroConfPeers = setOf(lsp.walletParams.trampolineNode.id),

View File

@ -2,4 +2,5 @@ package fr.acinq.lightning.bin.conf
object EnvVars { object EnvVars {
const val PHOENIX_DATADIR = "PHOENIX_DATADIR" const val PHOENIX_DATADIR = "PHOENIX_DATADIR"
const val PHOENIX_SEED = "PHOENIX_SEED"
} }

View File

@ -1,18 +1,21 @@
package fr.acinq.lightning.bin.conf package fr.acinq.lightning.bin.conf
import fr.acinq.bitcoin.ByteVector import fr.acinq.bitcoin.ByteVector
import fr.acinq.bitcoin.ByteVector32
import fr.acinq.bitcoin.MnemonicCode import fr.acinq.bitcoin.MnemonicCode
import fr.acinq.lightning.Lightning.randomBytes import fr.acinq.lightning.Lightning.randomBytes
import fr.acinq.lightning.utils.toByteVector import fr.acinq.lightning.utils.toByteVector
import okio.FileSystem import okio.FileSystem
import okio.Path import okio.Path
data class PhoenixSeed(val seed: ByteVector, val isNew: Boolean)
/** /**
* @return a pair with the seed and a boolean indicating whether the seed was newly generated * @return a pair with the seed and a boolean indicating whether the seed was newly generated
*/ */
fun getOrGenerateSeed(dir: Path): Pair<ByteVector, Boolean> { fun getOrGenerateSeed(dir: Path): PhoenixSeed {
val file = dir / "seed.dat" val file = dir / "seed.dat"
val (mnemonics, new) = if (FileSystem.SYSTEM.exists(file)) { val (mnemonics, isNew) = if (FileSystem.SYSTEM.exists(file)) {
FileSystem.SYSTEM.read(file) { readUtf8() } to false FileSystem.SYSTEM.read(file) { readUtf8() } to false
} else { } else {
val entropy = randomBytes(16) val entropy = randomBytes(16)
@ -20,5 +23,5 @@ fun getOrGenerateSeed(dir: Path): Pair<ByteVector, Boolean> {
FileSystem.SYSTEM.write(file) { writeUtf8(mnemonics) } FileSystem.SYSTEM.write(file) { writeUtf8(mnemonics) }
mnemonics to true mnemonics to true
} }
return MnemonicCode.toSeed(mnemonics, "").toByteVector() to new return PhoenixSeed(seed = MnemonicCode.toSeed(mnemonics, "").toByteVector(), isNew = isNew)
} }