Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update dependencies #500

Merged
merged 1 commit into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ kotlin {
val ktorVersion: String by extra { "2.0.3" }
fun ktor(module: String) = "io.ktor:ktor-$module:$ktorVersion"
val serializationVersion = "1.5.1"
val coroutineVersion = "1.7.1"
val coroutineVersion = "1.7.2"

val commonMain by sourceSets.getting {
dependencies {
api("fr.acinq.bitcoin:bitcoin-kmp:0.12.0") // when upgrading, keep secp256k1-kmp-jni-jvm in sync below
api("fr.acinq.bitcoin:bitcoin-kmp:0.13.0") // when upgrading, keep secp256k1-kmp-jni-jvm in sync below
api("org.kodein.log:canard:0.18.0")
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion")
api("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
Expand Down Expand Up @@ -63,7 +63,7 @@ kotlin {
api(ktor("client-okhttp"))
api(ktor("network"))
api(ktor("network-tls"))
implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:0.10.0")
implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:0.10.1")
implementation("org.slf4j:slf4j-api:1.7.36")
api("org.xerial:sqlite-jdbc:3.32.3.2")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,23 @@ class ElectrumMiniWallet(
* Depending on the status of the electrum connection, the subscription may or may not be sent to a server.
* It is the responsibility of the caller to resubscribe on reconnection.
*/
suspend fun subscribe(bitcoinAddress: String): Pair<ByteVector32, String> {
val pubkeyScript = ByteVector(Script.write(Bitcoin.addressToPublicKeyScript(chainHash, bitcoinAddress)))
val scriptHash = ElectrumClient.computeScriptHash(pubkeyScript)
kotlin.runCatching { client.startScriptHashSubscription(scriptHash) }
.map { response ->
logger.info { "subscribed to address=$bitcoinAddress pubkeyScript=$pubkeyScript scriptHash=$scriptHash" }
_walletStateFlow.value = _walletStateFlow.value.processSubscriptionResponse(response)
suspend fun subscribe(bitcoinAddress: String): Pair<ByteVector32, String>? {
return when (val result = Bitcoin.addressToPublicKeyScript(chainHash, bitcoinAddress)) {
is AddressToPublicKeyScriptResult.Failure -> {
logger.error { "cannot subscribe to $bitcoinAddress ($result)" }
null
}
return scriptHash to bitcoinAddress

is AddressToPublicKeyScriptResult.Success -> {
val pubkeyScript = ByteVector(Script.write(result.script))
val scriptHash = ElectrumClient.computeScriptHash(pubkeyScript)
kotlin.runCatching { client.startScriptHashSubscription(scriptHash) }.map { response ->
logger.info { "subscribed to address=$bitcoinAddress pubkeyScript=$pubkeyScript scriptHash=$scriptHash" }
_walletStateFlow.value = _walletStateFlow.value.processSubscriptionResponse(response)
}
scriptHash to bitcoinAddress
}
}
}

job = launch {
Expand Down Expand Up @@ -192,8 +200,9 @@ class ElectrumMiniWallet(

is WalletCommand.Companion.AddAddress -> {
logger.mdcinfo { "adding new address=${it.bitcoinAddress}" }
val (scriptHash, address) = subscribe(it.bitcoinAddress)
scriptHashes = scriptHashes + (scriptHash to address)
subscribe(it.bitcoinAddress)?.let {
scriptHashes = scriptHashes + it
}
}
}
}
Expand Down
41 changes: 22 additions & 19 deletions src/commonMain/kotlin/fr/acinq/lightning/crypto/KeyManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ interface KeyManager {

val redeemScript: List<ScriptElt> = Scripts.swapIn2of2(userPublicKey, remoteServerPublicKey, refundDelay)
val pubkeyScript: List<ScriptElt> = Script.pay2wsh(redeemScript)
val address: String = Bitcoin.addressFromPublicKeyScript(chain.chainHash, pubkeyScript)!!
val address: String = Bitcoin.addressFromPublicKeyScript(chain.chainHash, pubkeyScript).result!!

/**
* The output script descriptor matching our swap-in addresses.
Expand Down Expand Up @@ -153,27 +153,30 @@ interface KeyManager {
return if (utxos.isEmpty()) {
null
} else {
val ourOutput = TxOut(utxos.map { it.amount }.sum(), Bitcoin.addressToPublicKeyScript(chain.chainHash, address))
val unsignedTx = Transaction(
version = 2,
txIn = utxos.map { TxIn(OutPoint(swapInTx, swapInTx.txOut.indexOf(it).toLong()), sequence = refundDelay.toLong()) },
txOut = listOf(ourOutput),
lockTime = 0
)
val fees = run {
val recoveryTx = utxos.foldIndexed(unsignedTx) { index, tx, utxo ->
val pubKeyScript = Bitcoin.addressToPublicKeyScript(chain.chainHash, address).result
pubKeyScript?.let { script ->
val ourOutput = TxOut(utxos.map { it.amount }.sum(), script)
val unsignedTx = Transaction(
version = 2,
txIn = utxos.map { TxIn(OutPoint(swapInTx, swapInTx.txOut.indexOf(it).toLong()), sequence = refundDelay.toLong()) },
txOut = listOf(ourOutput),
lockTime = 0
)
val fees = run {
val recoveryTx = utxos.foldIndexed(unsignedTx) { index, tx, utxo ->
val sig = Transactions.signSwapInputUser(tx, index, utxo, userPrivateKey, remoteServerPublicKey, refundDelay)
tx.updateWitness(index, Scripts.witnessSwapIn2of2Refund(sig, userPublicKey, remoteServerPublicKey, refundDelay))
}
Transactions.weight2fee(feeRate, recoveryTx.weight())
}
val unsignedTx1 = unsignedTx.copy(txOut = listOf(ourOutput.copy(amount = ourOutput.amount - fees)))
val recoveryTx = utxos.foldIndexed(unsignedTx1) { index, tx, utxo ->
val sig = Transactions.signSwapInputUser(tx, index, utxo, userPrivateKey, remoteServerPublicKey, refundDelay)
tx.updateWitness(index, Scripts.witnessSwapIn2of2Refund(sig, userPublicKey,remoteServerPublicKey, refundDelay))
tx.updateWitness(index, Scripts.witnessSwapIn2of2Refund(sig, userPublicKey, remoteServerPublicKey, refundDelay))
}
Transactions.weight2fee(feeRate, recoveryTx.weight())
}
val unsignedTx1 = unsignedTx.copy(txOut = listOf(ourOutput.copy(amount = ourOutput.amount - fees)))
val recoveryTx = utxos.foldIndexed(unsignedTx1) { index, tx, utxo ->
val sig = Transactions.signSwapInputUser(tx, index, utxo, userPrivateKey, remoteServerPublicKey, refundDelay)
tx.updateWitness(index, Scripts.witnessSwapIn2of2Refund(sig, userPublicKey,remoteServerPublicKey, refundDelay))
// this tx is signed but cannot be published until swapInTx has `refundDelay` confirmations
recoveryTx
}
// this tx is signed but cannot be published until swapInTx has `refundDelay` confirmations
recoveryTx
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class ElectrumMiniWalletTest : LightningTestSuite() {
),
actual = walletState.utxos.map {
val txOut = it.previousTx.txOut[it.outputIndex]
val address = Bitcoin.addressFromPublicKeyScript(Block.LivenetGenesisBlock.hash, txOut.publicKeyScript.toByteArray())
val address = Bitcoin.addressFromPublicKeyScript(Block.LivenetGenesisBlock.hash, txOut.publicKeyScript.toByteArray()).result!!
Triple(address, it.previousTx.txid to it.outputIndex, txOut.amount)
}.toSet()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ class LocalKeyManagerTestsCommon : LightningTestSuite() {
val swapInTx = Transaction(version = 2,
txIn = listOf(),
txOut = listOf(
TxOut(Satoshi(100000), Bitcoin.addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, TestConstants.Alice.keyManager.swapInOnChainWallet.address)),
TxOut(Satoshi(150000), Bitcoin.addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, TestConstants.Alice.keyManager.swapInOnChainWallet.address))
TxOut(Satoshi(100000), Bitcoin.addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, TestConstants.Alice.keyManager.swapInOnChainWallet.address).result!!),
TxOut(Satoshi(150000), Bitcoin.addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, TestConstants.Alice.keyManager.swapInOnChainWallet.address).result!!)
),
lockTime = 0)
val recoveryTx = TestConstants.Alice.keyManager.swapInOnChainWallet.createRecoveryTransaction(swapInTx, TestConstants.Alice.keyManager.finalOnChainWallet.address(0), FeeratePerKw(FeeratePerByte(Satoshi(5))))!!
Expand Down