mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-19 09:54:02 +01:00
fix closing tx fee
This commit is contained in:
parent
74130c66d5
commit
b465b17223
@ -13,6 +13,8 @@ eclair {
|
||||
rpcuser = "foo"
|
||||
rpcpassword = "bar"
|
||||
}
|
||||
commit-fee = 50000
|
||||
closing-fee = 10000
|
||||
}
|
||||
akka {
|
||||
loggers = ["akka.event.slf4j.Slf4jLogger"]
|
||||
|
@ -29,8 +29,8 @@ object Demo extends App {
|
||||
val bob_commit_priv = Base58Check.decode("cSUwLtdZ2tht9ZmHhdQue48pfe7tY2GT2TGWJDtjoZgo6FHrubGk")._2
|
||||
val bob_final_priv = Base58Check.decode("cPR7ZgXpUaDPA3GwGceMDS5pfnSm955yvks3yELf3wMJwegsdGTg")._2
|
||||
|
||||
val alice_params = OurChannelParams(locktime(Blocks(10)), alice_commit_priv, alice_final_priv, 1, 100000, "alice-seed".getBytes())
|
||||
val bob_params = OurChannelParams(locktime(Blocks(10)), bob_commit_priv, bob_final_priv, 2, 100000, "bob-seed".getBytes())
|
||||
val alice_params = OurChannelParams(locktime(Blocks(10)), alice_commit_priv, alice_final_priv, 1, 100000, "alice-seed".getBytes(), true)
|
||||
val bob_params = OurChannelParams(locktime(Blocks(10)), bob_commit_priv, bob_final_priv, 2, 100000, "bob-seed".getBytes(), false)
|
||||
|
||||
val mockCoreClient = new BitcoinJsonRPCClient("foo", "bar") {
|
||||
override def invoke(method: String, params: Any*): Future[JValue] = method match {
|
||||
|
@ -18,7 +18,8 @@ object Globals {
|
||||
|
||||
val default_locktime = locktime(Seconds(86400))
|
||||
val default_mindepth = 3
|
||||
val default_commitfee = 50000
|
||||
val commit_fee = config.getInt("eclair.commit-fee")
|
||||
val closing_fee = config.getInt("eclair.closing-fee")
|
||||
|
||||
val default_anchor_amount = 1000000
|
||||
|
||||
|
@ -156,7 +156,7 @@ final case class RES_GETINFO(name: String, state: State, data: Data)
|
||||
sealed trait Data
|
||||
case object Nothing extends Data
|
||||
final case class AnchorInput(amount: Long) extends Data
|
||||
final case class OurChannelParams(delay: locktime, commitPrivKey: BinaryData, finalPrivKey: BinaryData, minDepth: Int, commitmentFee: Long, shaSeed: BinaryData) {
|
||||
final case class OurChannelParams(delay: locktime, commitPrivKey: BinaryData, finalPrivKey: BinaryData, minDepth: Int, commitmentFee: Long, shaSeed: BinaryData, isFunder: Boolean) {
|
||||
val commitPubKey: BinaryData = Crypto.publicKeyFromPrivateKey(commitPrivKey)
|
||||
val finalPubKey: BinaryData = Crypto.publicKeyFromPrivateKey(finalPrivKey)
|
||||
}
|
||||
@ -732,7 +732,8 @@ class Channel(val blockchain: ActorRef, val params: OurChannelParams, val anchor
|
||||
|
||||
when(WAIT_FOR_CLOSE_COMPLETE) {
|
||||
case Event(close_channel_complete(theirSig), d: CurrentCommitment) =>
|
||||
val finalTx = makeFinalTx(d.commitment.tx.txIn, ourFinalPubKey, d.theirParams.finalPubKey, d.commitment.state)
|
||||
val closingState = d.commitment.state.adjust_fees(Globals.closing_fee * 1000, d.ourParams.isFunder)
|
||||
val finalTx = makeFinalTx(d.commitment.tx.txIn, ourFinalPubKey, d.theirParams.finalPubKey, closingState)
|
||||
val signedFinalTx = sign_our_commitment_tx(d.ourParams, d.theirParams, finalTx, theirSig)
|
||||
val ok = Try(Transaction.correctlySpends(signedFinalTx, Map(signedFinalTx.txIn(0).outPoint -> anchorPubkeyScript(ourCommitPubKey, d.theirParams.commitPubKey)), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)).isSuccess
|
||||
ok match {
|
||||
@ -933,9 +934,10 @@ class Channel(val blockchain: ActorRef, val params: OurChannelParams, val anchor
|
||||
|
||||
def handle_pkt_close(pkt: close_channel, ourParams: OurChannelParams, theirParams: TheirChannelParams, commitment: Commitment): (Transaction, close_channel_complete) = {
|
||||
// the only difference between their final tx and ours is the order of the outputs, because state is symmetric
|
||||
val theirFinalTx = makeFinalTx(commitment.tx.txIn, theirParams.finalPubKey, ourFinalPubKey, commitment.state.reverse)
|
||||
val closingState = commitment.state.adjust_fees(Globals.closing_fee * 1000, ourParams.isFunder)
|
||||
val theirFinalTx = makeFinalTx(commitment.tx.txIn, theirParams.finalPubKey, ourFinalPubKey, closingState.reverse)
|
||||
val ourSigForThem = bin2signature(Transaction.signInput(theirFinalTx, 0, multiSig2of2(ourCommitPubKey, theirParams.commitPubKey), SIGHASH_ALL, ourParams.commitPrivKey))
|
||||
val ourFinalTx = makeFinalTx(commitment.tx.txIn, ourFinalPubKey, theirParams.finalPubKey, commitment.state)
|
||||
val ourFinalTx = makeFinalTx(commitment.tx.txIn, ourFinalPubKey, theirParams.finalPubKey, closingState)
|
||||
val ourSig = Transaction.signInput(ourFinalTx, 0, multiSig2of2(ourCommitPubKey, theirParams.commitPubKey), SIGHASH_ALL, ourParams.commitPrivKey)
|
||||
val signedFinalTx = ourFinalTx.updateSigScript(0, sigScript2of2(pkt.sig, ourSig, theirParams.commitPubKey, ourCommitPubKey))
|
||||
blockchain ! WatchConfirmed(self, signedFinalTx.txid, ourParams.minDepth, BITCOIN_CLOSE_DONE)
|
||||
|
@ -7,7 +7,9 @@ import lightning.{sha256_hash, update_add_htlc}
|
||||
/**
|
||||
* Created by PM on 19/01/2016.
|
||||
*/
|
||||
case class ChannelOneSide(pay_msat: Long, fee_msat: Long, htlcs: Seq[update_add_htlc])
|
||||
case class ChannelOneSide(pay_msat: Long, fee_msat: Long, htlcs: Seq[update_add_htlc]) {
|
||||
val funds = pay_msat + fee_msat
|
||||
}
|
||||
|
||||
case class ChannelState(us: ChannelOneSide, them: ChannelOneSide) {
|
||||
/**
|
||||
@ -91,5 +93,23 @@ case class ChannelState(us: ChannelOneSide, them: ChannelOneSide) {
|
||||
} else throw new RuntimeException(s"could not find corresponding htlc (r=$r)")
|
||||
}
|
||||
|
||||
def adjust_fees(fee: Int, is_funder: Boolean) : ChannelState = {
|
||||
if (is_funder) {
|
||||
val (funder, nonfunder) = ChannelState.adjust_fees(this.us, this.them, fee)
|
||||
this.copy(us = funder, them = nonfunder)
|
||||
} else {
|
||||
val (funder, nonfunder) = ChannelState.adjust_fees(this.them, this.us, fee)
|
||||
this.copy(us = nonfunder, them = funder)
|
||||
}
|
||||
}
|
||||
|
||||
def prettyString(): String = s"pay_us=${us.pay_msat} htlcs_us=${us.htlcs.map(_.amountMsat).sum} pay_them=${them.pay_msat} htlcs_them=${them.htlcs.map(_.amountMsat).sum} total=${us.pay_msat + us.htlcs.map(_.amountMsat).sum + them.pay_msat + them.htlcs.map(_.amountMsat).sum}"
|
||||
}
|
||||
|
||||
object ChannelState {
|
||||
def adjust_fees(funder: ChannelOneSide, nonfunder: ChannelOneSide, fee: Int) : (ChannelOneSide, ChannelOneSide) = {
|
||||
val nonfunder_fee = Math.min(fee - fee / 2, nonfunder.funds)
|
||||
val funder_fee = fee - nonfunder_fee
|
||||
(funder.copy(pay_msat = funder.funds - funder_fee, fee_msat = funder_fee), nonfunder.copy(pay_msat = nonfunder.funds - nonfunder_fee, fee_msat = nonfunder_fee))
|
||||
}
|
||||
}
|
@ -140,8 +140,8 @@ object Scripts {
|
||||
* @return an unsigned "final" tx
|
||||
*/
|
||||
def makeFinalTx(inputs: Seq[TxIn], ourFinalKey: BinaryData, theirFinalKey: BinaryData, channelState: ChannelState): Transaction = {
|
||||
// TODO : is this the proper behaviour ?
|
||||
assert(channelState.them.htlcs.isEmpty && channelState.us.htlcs.isEmpty, s"cannot close a channel with pending htlcs (see rusty's state_types.h line 103)")
|
||||
|
||||
permuteOutputs(Transaction(
|
||||
version = 1,
|
||||
txIn = inputs,
|
||||
|
@ -75,7 +75,7 @@ class AuthHandler(them: ActorRef, blockchain: ActorRef, our_anchor: Boolean, amo
|
||||
Some(AnchorInput(amount))
|
||||
else
|
||||
None
|
||||
val channel_params = OurChannelParams(Globals.default_locktime, Globals.commit_priv, Globals.final_priv, Globals.default_mindepth, Globals.default_commitfee, "sha-seed".getBytes())
|
||||
val channel_params = OurChannelParams(Globals.default_locktime, Globals.commit_priv, Globals.final_priv, Globals.default_mindepth, Globals.commit_fee, "sha-seed".getBytes(), our_anchor)
|
||||
val channel = context.actorOf(Props(new Channel(blockchain, channel_params, anchorInput_opt)), name = "channel")
|
||||
channel ! INPUT_NONE
|
||||
goto(IO_NORMAL) using Normal(channel, s)
|
||||
|
@ -58,4 +58,12 @@ class ChannelStateSpec extends FunSuite {
|
||||
))
|
||||
}
|
||||
|
||||
test("adjust fees") {
|
||||
val state_0 = ChannelState(
|
||||
us = ChannelOneSide(pay_msat = 950000*1000, fee_msat = 49900*1000, htlcs = Seq()),
|
||||
them = ChannelOneSide(pay_msat = 0, fee_msat = 100*1000, htlcs = Seq())
|
||||
)
|
||||
val state_1 = state_0.adjust_fees(100000, true)
|
||||
println(state_1)
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,8 @@ abstract class TestHelper(_system: ActorSystem) extends TestKit(_system) with Im
|
||||
val bob_commit_priv = Base58Check.decode("cSUwLtdZ2tht9ZmHhdQue48pfe7tY2GT2TGWJDtjoZgo6FHrubGk")._2
|
||||
val bob_final_priv = Base58Check.decode("cPR7ZgXpUaDPA3GwGceMDS5pfnSm955yvks3yELf3wMJwegsdGTg")._2
|
||||
|
||||
val ourParams = OurChannelParams(locktime(Blocks(10)), our_commitkey_priv, our_finalkey_priv, 1, 100000, "alice-seed".getBytes())
|
||||
val bob_params = OurChannelParams(locktime(Blocks(10)), bob_commit_priv, bob_final_priv, 2, 100000, "bob-seed".getBytes())
|
||||
val ourParams = OurChannelParams(locktime(Blocks(10)), our_commitkey_priv, our_finalkey_priv, 1, 100000, "alice-seed".getBytes(), true)
|
||||
val bob_params = OurChannelParams(locktime(Blocks(10)), bob_commit_priv, bob_final_priv, 2, 100000, "bob-seed".getBytes(), false)
|
||||
|
||||
val ourCommitPubKey = bitcoin_pubkey(ByteString.copyFrom(Crypto.publicKeyFromPrivateKey(our_commitkey_priv.key.toByteArray)))
|
||||
val ourFinalPubKey = bitcoin_pubkey(ByteString.copyFrom(Crypto.publicKeyFromPrivateKey(our_finalkey_priv.key.toByteArray)))
|
||||
|
@ -1 +1 @@
|
||||
java -jar /home/fabrice/code/acinq/eclair/lightning-types/target/scalapb-tmp-1.0-SNAPSHOT.jar
|
||||
java -jar target/scalapb-tmp-1.0-SNAPSHOT.jar
|
||||
|
Loading…
Reference in New Issue
Block a user