@@ -13,6 +13,7 @@ import fr.acinq.eclair.channel.fund.InteractiveTxBuilder.SharedTransaction
13
13
import fr .acinq .eclair .crypto .keymanager .ChannelKeyManager
14
14
import fr .acinq .eclair .crypto .{Generators , ShaChain }
15
15
import fr .acinq .eclair .payment .OutgoingPaymentPacket
16
+ import fr .acinq .eclair .transactions .Transactions .TxOwner .{Local , Remote }
16
17
import fr .acinq .eclair .transactions .Transactions ._
17
18
import fr .acinq .eclair .transactions ._
18
19
import fr .acinq .eclair .wire .protocol ._
@@ -229,7 +230,7 @@ case class LocalCommit(index: Long, spec: CommitmentSpec, commitTxAndRemoteSig:
229
230
object LocalCommit {
230
231
def fromCommitSig (keyManager : ChannelKeyManager , params : ChannelParams , fundingTxId : TxId ,
231
232
fundingTxIndex : Long , remoteFundingPubKey : PublicKey , commitInput : InputInfo ,
232
- commit : CommitSig , localCommitIndex : Long , spec : CommitmentSpec , localPerCommitmentPoint : PublicKey , localNonce_opt : Option [(SecretNonce , IndividualNonce )]): Either [ChannelException , LocalCommit ] = {
233
+ commit : CommitSig , localCommitIndex : Long , spec : CommitmentSpec , localPerCommitmentPoint : PublicKey , localNonce_opt : Option [(SecretNonce , IndividualNonce )])( implicit log : LoggingAdapter ) : Either [ChannelException , LocalCommit ] = {
233
234
val (localCommitTx, htlcTxs) = Commitment .makeLocalTxs(keyManager, params.channelConfig, params.channelFeatures, localCommitIndex, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, localPerCommitmentPoint, spec)
234
235
if (! localCommitTx.checkSig(commit, remoteFundingPubKey, TxOwner .Remote , params.commitmentFormat)) {
235
236
return Left (InvalidCommitmentSignature (params.channelId, fundingTxId, fundingTxIndex, localCommitTx.tx))
@@ -243,6 +244,10 @@ object LocalCommit {
243
244
val fundingPubkey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex).publicKey
244
245
val Some (localNonce) = localNonce_opt
245
246
if (! localCommitTx.checkPartialSignature(psig, fundingPubkey, localNonce._2, remoteFundingPubKey)) {
247
+ log.debug(s " fromCommitSig: invalid partial signature $psig fundingPubkey = $fundingPubkey, fundingTxIndex = $fundingTxIndex localCommitIndex = $localCommitIndex localNonce = $localNonce remoteFundingPubKey = $remoteFundingPubKey" )
248
+
249
+ val localNonce1 = keyManager.verificationNonce(params.localParams.fundingKeyPath, fundingTxIndex, keyManager.keyPath(params.localParams, params.channelConfig), localCommitIndex)
250
+ log.debug(s " with $localNonce1 ${localCommitTx.checkPartialSignature(psig, fundingPubkey, localNonce1._2, remoteFundingPubKey)}" )
246
251
return Left (InvalidCommitmentSignature (params.channelId, fundingTxId, fundingTxIndex, localCommitTx.tx))
247
252
}
248
253
}
@@ -267,9 +272,10 @@ case class RemoteCommit(index: Long, spec: CommitmentSpec, txid: TxId, remotePer
267
272
def sign (keyManager : ChannelKeyManager , params : ChannelParams , fundingTxIndex : Long , remoteFundingPubKey : PublicKey , commitInput : InputInfo , remoteNonce_opt : Option [IndividualNonce ])(implicit log : LoggingAdapter ): CommitSig = {
268
273
val (remoteCommitTx, htlcTxs) = Commitment .makeRemoteTxs(keyManager, params.channelConfig, params.channelFeatures, index, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, remotePerCommitmentPoint, spec)
269
274
val (sig, tlvStream) = if (params.commitmentFormat.useTaproot) {
270
- val localNonce = keyManager.verificationNonce (params.localParams.fundingKeyPath, fundingTxIndex, keyManager.keyPath(params.localParams, params.channelConfig), index )
275
+ val localNonce = keyManager.signingNonce (params.localParams.fundingKeyPath, fundingTxIndex)
271
276
val Some (remoteNonce) = remoteNonce_opt
272
277
val Right (localPartialSigOfRemoteTx) = keyManager.partialSign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), remoteFundingPubKey, TxOwner .Remote , localNonce, remoteNonce)
278
+ log.debug(s " RemoteCommit.sign localPartialSigOfRemoteTx = $localPartialSigOfRemoteTx fundingTxIndex = $fundingTxIndex remote commit index = $index remote nonce = $remoteNonce" )
273
279
val tlvStream : TlvStream [CommitSigTlv ] = TlvStream (CommitSigTlv .PartialSignatureWithNonceTlv (PartialSignatureWithNonce (localPartialSigOfRemoteTx, localNonce._2)))
274
280
(ByteVector64 .Zeroes , tlvStream)
275
281
} else {
@@ -661,7 +667,7 @@ case class Commitment(fundingTxIndex: Long,
661
667
val localNonce = keyManager.signingNonce(params.localParams.fundingKeyPath, fundingTxIndex)
662
668
val Some (remoteNonce) = nextRemoteNonce_opt
663
669
val Right (psig) = keyManager.partialSign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), remoteFundingPubKey, TxOwner .Remote , localNonce, remoteNonce)
664
- log.debug(s " sendCommit: creating partial sig $psig for remote commit tx ${remoteCommitTx.tx.txid} with remote nonce $remoteNonce and remoteNextPerCommitmentPoint = $remoteNextPerCommitmentPoint" )
670
+ log.debug(s " sendCommit: creating partial sig $psig for remote commit tx ${remoteCommitTx.tx.txid} with fundingTxIndex = $fundingTxIndex remoteCommit.index (should add +1) = ${remoteCommit.index} remote nonce $remoteNonce and remoteNextPerCommitmentPoint = $remoteNextPerCommitmentPoint" )
665
671
Set (CommitSigTlv .PartialSignatureWithNonceTlv (PartialSignatureWithNonce (psig, localNonce._2)))
666
672
} else {
667
673
Set .empty
@@ -1080,6 +1086,10 @@ case class Commitments(params: ChannelParams,
1080
1086
}
1081
1087
val channelKeyPath = keyManager.keyPath(params.localParams, params.channelConfig)
1082
1088
val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, localCommitIndex + 1 )
1089
+
1090
+ val fundingIndexes = active.map(_.fundingTxIndex).toSet
1091
+ if (fundingIndexes.size > 1 ) log.warning(s " more than 1 funding tx index " )
1092
+
1083
1093
// Signatures are sent in order (most recent first), calling `zip` will drop trailing sigs that are for deactivated/pruned commitments.
1084
1094
val active1 = active.zip(commits).map { case (commitment, commit) =>
1085
1095
val localNonce_opt = if (params.commitmentFormat.useTaproot) {
@@ -1228,9 +1238,31 @@ case class Commitments(params: ChannelParams,
1228
1238
}
1229
1239
1230
1240
/** This function should be used to ignore a commit_sig that we've already received. */
1231
- def ignoreRetransmittedCommitSig (commitSig : CommitSig ): Boolean = {
1232
- val latestRemoteSig = latest.localCommit.commitTxAndRemoteSig.remoteSig
1233
- params.channelFeatures.hasFeature(Features .DualFunding ) && commitSig.batchSize == 1 && latestRemoteSig == commitSig.sigOrPartialSig
1241
+ def ignoreRetransmittedCommitSig (commitSig : CommitSig , keyManager : ChannelKeyManager ): Boolean = commitSig.sigOrPartialSig match {
1242
+ case _ if ! params.channelFeatures.hasFeature(Features .DualFunding ) => false
1243
+ case _ if commitSig.batchSize != 1 => false
1244
+ case Left (_) =>
1245
+ commitSig.sigOrPartialSig == latest.localCommit.commitTxAndRemoteSig.remoteSig
1246
+ case Right (psig) if active.size > 1 =>
1247
+ // we cannot compare partial signatures directly as they are not deterministic (a new signing nonce is used every time a signature is computed)
1248
+ // => instead we simply check that the provided partial signature is valid for our latest commit tx
1249
+ val localFundingKey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, latest.fundingTxIndex).publicKey
1250
+ val Some (localNonce) = generateLocalNonce(keyManager, latest.fundingTxIndex, latest.localCommit.index)
1251
+ val Right (oldPsig) = latest.localCommit.commitTxAndRemoteSig.remoteSig
1252
+ val currentcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(psig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1253
+ val oldcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(oldPsig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1254
+ require(oldcheck)
1255
+ currentcheck
1256
+ case Right (psig) =>
1257
+ // we cannot compare partial signatures directly as they are not deterministic (a new signing nonce is used every time a signature is computed)
1258
+ // => instead we simply check that the provided partial signature is valid for our latest commit tx
1259
+ val localFundingKey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, latest.fundingTxIndex).publicKey
1260
+ val Some (localNonce) = generateLocalNonce(keyManager, latest.fundingTxIndex, latest.localCommit.index)
1261
+ val Right (oldPsig) = latest.localCommit.commitTxAndRemoteSig.remoteSig
1262
+ val currentcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(psig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1263
+ val oldcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(oldPsig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1264
+ require(oldcheck)
1265
+ currentcheck
1234
1266
}
1235
1267
1236
1268
def localFundingSigs (fundingTxId : TxId ): Option [TxSignatures ] = {
@@ -1350,30 +1382,33 @@ case class Commitments(params: ChannelParams,
1350
1382
}
1351
1383
1352
1384
/**
1353
- * Create local verification nonces for the next funding tx
1354
- * @param keyManager key manager that will generate actual nonces
1355
- * @return a list of 2 verification nonces for the next funding tx: one for the current commitment index, one for the next commitment index
1385
+ * Generate local verification nonces for a specific funding tx index and commit tx index
1386
+ *
1387
+ * @param keyManager key manager that will generate actual nonces
1388
+ * @param fundingIndex funding tx index
1389
+ * @param commitIndex commit tx index
1390
+ * @return a public nonce for thr provided fundint tx index and commit tx index if taproot is used, None otherwise
1356
1391
*/
1357
- def generateLocalNonces (keyManager : ChannelKeyManager , fundingIndex : Long ): List [IndividualNonce ] = {
1392
+ def generateLocalNonce (keyManager : ChannelKeyManager , fundingIndex : Long , commitIndex : Long ): Option [IndividualNonce ] = {
1358
1393
if (latest.params.commitmentFormat.useTaproot) {
1359
-
1360
- def localNonce (commitIndex : Long ) = {
1361
- val (_, nonce) = keyManager.verificationNonce(params.localParams.fundingKeyPath, fundingIndex, keyManager.keyPath(params.localParams, params.channelConfig), commitIndex)
1362
- nonce
1363
- }
1364
-
1365
- List (localNonce(localCommitIndex), localNonce(localCommitIndex + 1 ))
1394
+ Some (keyManager.verificationNonce(params.localParams.fundingKeyPath, fundingIndex, keyManager.keyPath(params.localParams, params.channelConfig), commitIndex)._2)
1366
1395
} else {
1367
- List .empty
1396
+ None
1368
1397
}
1369
1398
}
1370
1399
1371
1400
/**
1372
- * Create local verification nonces for the next funding tx
1401
+ * Create local verification nonces a specific funding tx index and a range of commit tx indexes
1402
+ *
1373
1403
* @param keyManager key manager that will generate actual nonces
1374
- * @return a list of 2 verification nonces for the next funding tx: one for the current commitment index, one for the next commitment index
1404
+ * @param fundingIndex funding tx index
1405
+ * @param commitIndexes range of commit tx indexes
1406
+ * @return a list of nonces if raproot is used, or an empty list
1375
1407
*/
1376
- def generateLocalNonces (keyManager : ChannelKeyManager ): List [IndividualNonce ] = generateLocalNonces(keyManager, latest.commitment.fundingTxIndex + 1 )
1408
+ def generateLocalNonces (keyManager : ChannelKeyManager , fundingIndex : Long , commitIndexes : Long * ): List [IndividualNonce ] = {
1409
+ commitIndexes.toList.flatMap(commitIndex => generateLocalNonce(keyManager, fundingIndex, commitIndex))
1410
+ }
1411
+
1377
1412
}
1378
1413
1379
1414
object Commitments {
0 commit comments