Skip to content

Commit

Permalink
Use bitcoin-lib 0.29 (#2708)
Browse files Browse the repository at this point in the history
  • Loading branch information
sstone committed Aug 21, 2023
1 parent ef25e32 commit 3547f87
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 57 deletions.
19 changes: 14 additions & 5 deletions eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,17 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging {
}

override def spliceOut(channelId: ByteVector32, amountOut: Satoshi, scriptOrAddress: Either[ByteVector, String])(implicit timeout: Timeout): Future[CommandResponse[CMD_SPLICE]] = {
val script = scriptOrAddress match {
case Left(script) => script
case Right(address) => addressToPublicKeyScript(this.appKit.nodeParams.chainHash, address) match {
case Left(failure) => throw new IllegalArgumentException(failure.toString)
case Right(script) => Script.write(script)
}
}
sendToChannelTyped(channel = Left(channelId),
cmdBuilder = CMD_SPLICE(_,
spliceIn_opt = None,
spliceOut_opt = Some(SpliceOut(amount = amountOut, scriptPubKey = scriptOrAddress match {
case Left(script) => script
case Right(address) => Script.write(addressToPublicKeyScript(appKit.nodeParams.chainHash, address))
}))
spliceOut_opt = Some(SpliceOut(amount = amountOut, scriptPubKey = script))
))
}

Expand Down Expand Up @@ -312,7 +316,12 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging {
}

override def receive(description: Either[String, ByteVector32], amount_opt: Option[MilliSatoshi], expire_opt: Option[Long], fallbackAddress_opt: Option[String], paymentPreimage_opt: Option[ByteVector32])(implicit timeout: Timeout): Future[Bolt11Invoice] = {
fallbackAddress_opt.map { fa => fr.acinq.eclair.addressToPublicKeyScript(fa, appKit.nodeParams.chainHash) } // if it's not a bitcoin address throws an exception
fallbackAddress_opt.foreach { fa =>
addressToPublicKeyScript(appKit.nodeParams.chainHash, fa) match {
case Left(failure) => throw new IllegalArgumentException(failure.toString)
case Right(_) => ()
}
} // if it's not a bitcoin address throws an exception
appKit.paymentHandler.toTyped.ask(ref => ReceiveStandardPayment(ref, amount_opt, description, expire_opt, fallbackAddress_opt = fallbackAddress_opt, paymentPreimage_opt = paymentPreimage_opt))
}

Expand Down
9 changes: 0 additions & 9 deletions eclair-core/src/main/scala/fr/acinq/eclair/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,6 @@ package object eclair {

def nodeFee(relayFees: RelayFees, paymentAmount: MilliSatoshi): MilliSatoshi = nodeFee(relayFees.feeBase, relayFees.feeProportionalMillionths, paymentAmount)

/**
* @param address bitcoin address.
* @param chainHash hash of the chain we're on, which will be checked against the input address
* @return the public key script that matches the input address.
*/
def addressToPublicKeyScript(address: String, chainHash: ByteVector32): Seq[ScriptElt] = {
Bitcoin.addressToPublicKeyScript(chainHash, address).asScala.toSeq.map(kmp2scala)
}

implicit class MilliSatoshiLong(private val n: Long) extends AnyVal {
def msat = MilliSatoshi(n)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I
assert(receive.fallbackAddress_opt.contains(fallBackAddressRaw))

// try with wrong address format
assertThrows[IllegalStateException](eclair.receive(Left("some desc"), Some(123 msat), Some(456), Some("wassa wassa"), None))
assertThrows[IllegalArgumentException](eclair.receive(Left("some desc"), Some(123 msat), Some(456), Some("wassa wassa"), None))
}

test("passing a payment_preimage to /createinvoice should result in an invoice with payment_hash=H(payment_preimage)") { f =>
Expand Down
70 changes: 33 additions & 37 deletions eclair-core/src/test/scala/fr/acinq/eclair/PackageSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@
package fr.acinq.eclair

import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey
import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, Script}
import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, Crypto, Script, addressToPublicKeyScript}
import fr.acinq.bitcoin.{Base58, Base58Check, Bech32}
import org.scalatest.funsuite.AnyFunSuite
import scodec.bits._

import scala.util.Try

/**
* Created by PM on 27/01/2017.
*/
Expand All @@ -49,63 +47,61 @@ class PackageSpec extends AnyFunSuite {

// p2pkh
// valid chain
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160), Block.TestnetGenesisBlock.hash) == Script.pay2pkh(pub))
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160), Block.RegtestGenesisBlock.hash) == Script.pay2pkh(pub))
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160), Block.SignetGenesisBlock.hash) == Script.pay2pkh(pub))
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160), Block.LivenetGenesisBlock.hash) == Script.pay2pkh(pub))
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160)) == Right(Script.pay2pkh(pub)))
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160)) == Right(Script.pay2pkh(pub)))
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160)) == Right(Script.pay2pkh(pub)))
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160)) == Right(Script.pay2pkh(pub)))

// wrong chain
intercept[RuntimeException] {
addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160), Block.TestnetGenesisBlock.hash)
}
assert(Try(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160), Block.TestnetGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160), Block.RegtestGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160), Block.SignetGenesisBlock.hash)).isFailure)
val Left(failure) = addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160))
assert(failure.toString.contains("chain hash mismatch"))

assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160)).isLeft)
assert(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160)).isLeft)
assert(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160)).isLeft)

// p2sh
val script = Script.write(Script.pay2wpkh(pub))

// valid chain
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script)), Block.TestnetGenesisBlock.hash) == Script.pay2sh(script))
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script)), Block.RegtestGenesisBlock.hash) == Script.pay2sh(script))
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script)), Block.SignetGenesisBlock.hash) == Script.pay2sh(script))
assert(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script)), Block.LivenetGenesisBlock.hash) == Script.pay2sh(script))
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))) == Right(Script.pay2sh(script)))
assert(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))) == Right(Script.pay2sh(script)))
assert(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))) == Right(Script.pay2sh(script)))
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))) == Right(Script.pay2sh(script)))

// wrong chain
assert(Try(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script)), Block.LivenetGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script)), Block.TestnetGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script)), Block.RegtestGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script)), Block.SignetGenesisBlock.hash)).isFailure)
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))).isLeft)
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).isLeft)
assert(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).isLeft)
assert(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).isLeft)
}

test("decode bech32 addresses") {
val priv = PrivateKey(ByteVector32(ByteVector.fill(32)(1)))
val pub = priv.publicKey

// p2wpkh
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("bc", 0, pub.hash160), Block.LivenetGenesisBlock.hash) == Script.pay2wpkh(pub))
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("tb", 0, pub.hash160), Block.TestnetGenesisBlock.hash) == Script.pay2wpkh(pub))
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("bcrt", 0, pub.hash160), Block.RegtestGenesisBlock.hash) == Script.pay2wpkh(pub))
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("tb", 0, pub.hash160), Block.SignetGenesisBlock.hash) == Script.pay2wpkh(pub))
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, pub.hash160)) == Right(Script.pay2wpkh(pub)))
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160)) == Right(Script.pay2wpkh(pub)))
assert(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Bech32.encodeWitnessAddress("bcrt", 0, pub.hash160)) == Right(Script.pay2wpkh(pub)))
assert(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160)) == Right(Script.pay2wpkh(pub)))

// wrong chain
assert(Try(addressToPublicKeyScript(Bech32.encodeWitnessAddress("bc", 0, pub.hash160), Block.TestnetGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Bech32.encodeWitnessAddress("tb", 0, pub.hash160), Block.LivenetGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Bech32.encodeWitnessAddress("bcrt", 0, pub.hash160), Block.LivenetGenesisBlock.hash)).isFailure)
assert(Try(addressToPublicKeyScript(Bech32.encodeWitnessAddress("tb", 0, pub.hash160), Block.LivenetGenesisBlock.hash)).isFailure)
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, pub.hash160)).isLeft)
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160)).isLeft)
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("bcrt", 0, pub.hash160)).isLeft)
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160)).isLeft)

val script = Script.write(Script.pay2wpkh(pub))
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("bc", 0, Crypto.sha256(script)), Block.LivenetGenesisBlock.hash) == Script.pay2wsh(script))
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script)), Block.TestnetGenesisBlock.hash) == Script.pay2wsh(script))
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("bcrt", 0, Crypto.sha256(script)), Block.RegtestGenesisBlock.hash) == Script.pay2wsh(script))
assert(addressToPublicKeyScript(Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script)), Block.SignetGenesisBlock.hash) == Script.pay2wsh(script))
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, Crypto.sha256(script))) == Right(Script.pay2wsh(script)))
assert(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script))) == Right(Script.pay2wsh(script)))
assert(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Bech32.encodeWitnessAddress("bcrt", 0, Crypto.sha256(script))) == Right(Script.pay2wsh(script)))
assert(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script))) == Right(Script.pay2wsh(script)))
}

test("fail to decode invalid addresses") {
val e = intercept[RuntimeException] {
addressToPublicKeyScript("1Qbbbbb", Block.LivenetGenesisBlock.hash)
}
assert(e.getMessage.contains("is neither a valid Base58 address") && e.getMessage.contains("nor a valid Bech32 address"))
assert(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, "1Qbbbbb").isLeft)
//assert(e.getMessage.contains("is neither a valid Base58 address") && e.getMessage.contains("nor a valid Bech32 address"))
}

test("compare short channel ids as unsigned longs") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import akka.pattern.pipe
import akka.testkit.TestProbe
import fr.acinq.bitcoin
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
import fr.acinq.bitcoin.scalacompat.{Block, Btc, BtcDouble, ByteVector32, Crypto, MilliBtcDouble, OP_DROP, OP_PUSHDATA, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut, computeP2PkhAddress, computeP2WpkhAddress}
import fr.acinq.bitcoin.scalacompat.{addressToPublicKeyScript, Block, Btc, BtcDouble, ByteVector32, Crypto, MilliBtcDouble, OP_DROP, OP_PUSHDATA, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut, computeP2PkhAddress, computeP2WpkhAddress}
import fr.acinq.bitcoin.{Bech32, SigHash, SigVersion}
import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, MakeFundingTxResponse, OnChainBalance, SignTransactionResponse}
import fr.acinq.eclair.blockchain.WatcherSpec.{createSpendManyP2WPKH, createSpendP2WPKH}
Expand All @@ -31,7 +31,7 @@ import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinJsonRPCAuthMethod.UserPass
import fr.acinq.eclair.blockchain.bitcoind.rpc.{BasicBitcoinJsonRPCClient, BitcoinCoreClient, JsonRPCError}
import fr.acinq.eclair.blockchain.fee.{FeeratePerByte, FeeratePerKw}
import fr.acinq.eclair.transactions.{Scripts, Transactions}
import fr.acinq.eclair.{BlockHeight, TestConstants, TestKitBaseClass, addressToPublicKeyScript, randomBytes32, randomKey}
import fr.acinq.eclair.{BlockHeight, TestConstants, TestKitBaseClass, randomBytes32, randomKey}
import grizzled.slf4j.Logging
import org.json4s.JsonAST._
import org.json4s.{DefaultFormats, Formats}
Expand Down Expand Up @@ -316,7 +316,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A

bitcoinClient.getReceiveAddress().pipeTo(sender.ref)
val address = sender.expectMsgType[String]
assert(Try(addressToPublicKeyScript(address, Block.RegtestGenesisBlock.hash)).isSuccess)
assert(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, address).isRight)

val fundingTxs = for (_ <- 0 to 3) yield {
val pubkeyScript = Script.write(Script.pay2wsh(Scripts.multiSig2of2(randomKey().publicKey, randomKey().publicKey)))
Expand Down Expand Up @@ -380,7 +380,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A

bitcoinClient.getReceiveAddress().pipeTo(sender.ref)
val address = sender.expectMsgType[String]
assert(Try(addressToPublicKeyScript(address, Block.RegtestGenesisBlock.hash)).isSuccess)
assert(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, address).isRight)

bitcoinClient.listLockedOutpoints().pipeTo(sender.ref)
sender.expectMsg(Set.empty[OutPoint])
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
<akka.version>2.6.20</akka.version>
<akka.http.version>10.2.7</akka.http.version>
<sttp.version>3.8.16</sttp.version>
<bitcoinlib.version>0.28</bitcoinlib.version>
<bitcoinlib.version>0.29</bitcoinlib.version>
<guava.version>32.1.1-jre</guava.version>
<kamon.version>2.6.3</kamon.version>
</properties>
Expand Down

0 comments on commit 3547f87

Please sign in to comment.