1
0
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:
sstone 2016-02-08 16:52:22 +01:00
parent 74130c66d5
commit b465b17223
10 changed files with 46 additions and 13 deletions

View File

@ -13,6 +13,8 @@ eclair {
rpcuser = "foo"
rpcpassword = "bar"
}
commit-fee = 50000
closing-fee = 10000
}
akka {
loggers = ["akka.event.slf4j.Slf4jLogger"]

View File

@ -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 {

View File

@ -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

View File

@ -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)

View File

@ -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))
}
}

View File

@ -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,

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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)))

View File

@ -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