github.com/decred/dcrlnd@v0.7.6/lnwallet/transactions.go (about)

     1  package lnwallet
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  
     7  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     8  	"github.com/decred/dcrd/dcrutil/v4"
     9  	"github.com/decred/dcrd/wire"
    10  	"github.com/decred/dcrlnd/channeldb"
    11  	"github.com/decred/dcrlnd/input"
    12  )
    13  
    14  const (
    15  	// StateHintSize is the total number of bytes used between the sequence
    16  	// number and locktime of the commitment transaction use to encode a hint
    17  	// to the state number of a particular commitment transaction.
    18  	StateHintSize = 6
    19  
    20  	// maxStateHint is the maximum state number we're able to encode using
    21  	// StateHintSize bytes amongst the sequence number and locktime fields
    22  	// of the commitment transaction.
    23  	maxStateHint uint64 = (1 << 48) - 1
    24  )
    25  
    26  var (
    27  	// TimelockShift is used to make sure the commitment transaction is
    28  	// spendable by setting the locktime with it so that it is larger than
    29  	// 500,000,000, thus interpreting it as Unix epoch timestamp and not a
    30  	// block height. It is also smaller than the current timestamp which
    31  	// has bit (1 << 30) set, so there is no risk of having the commitment
    32  	// transaction be rejected. This way we can safely use the lower 24
    33  	// bits of the locktime field for part of the obscured commitment
    34  	// transaction number.
    35  	TimelockShift = uint32(1 << 29)
    36  )
    37  
    38  // CreateHtlcSuccessTx creates a transaction that spends the output on the
    39  // commitment transaction of the peer that receives an HTLC. This transaction
    40  // essentially acts as an off-chain covenant as it's only permitted to spend
    41  // the designated HTLC output, and also that spend can _only_ be used as a
    42  // state transition to create another output which actually allows redemption
    43  // or revocation of an HTLC.
    44  //
    45  // In order to spend the HTLC output, the witness for the passed transaction
    46  // should be:
    47  //   - <sender sig> <recvr sig> <preimage>
    48  func CreateHtlcSuccessTx(chanType channeldb.ChannelType, initiator bool,
    49  	htlcOutput wire.OutPoint, htlcAmt dcrutil.Amount, csvDelay,
    50  	leaseExpiry uint32, revocationKey, delayKey *secp256k1.PublicKey) (
    51  	*wire.MsgTx, error) {
    52  
    53  	// Create a version two transaction (as the success version of this
    54  	// spends an output with a CSV timeout).
    55  	successTx := wire.NewMsgTx()
    56  	successTx.Version = input.LNTxVersion
    57  
    58  	// The input to the transaction is the outpoint that creates the
    59  	// original HTLC on the sender's commitment transaction. Set the
    60  	// sequence number based on the channel type.
    61  	txin := &wire.TxIn{
    62  		PreviousOutPoint: htlcOutput,
    63  		Sequence:         HtlcSecondLevelInputSequence(chanType),
    64  	}
    65  	successTx.AddTxIn(txin)
    66  
    67  	// Next, we'll generate the script used as the output for all second
    68  	// level HTLC which forces a covenant w.r.t what can be done with all
    69  	// HTLC outputs.
    70  	script, err := SecondLevelHtlcScript(
    71  		chanType, initiator, revocationKey, delayKey, csvDelay,
    72  		leaseExpiry,
    73  	)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	// Finally, the output is simply the amount of the HTLC (minus the
    79  	// required fees), paying to the timeout script.
    80  	successTx.AddTxOut(&wire.TxOut{
    81  		Value:    int64(htlcAmt),
    82  		PkScript: script.PkScript,
    83  	})
    84  
    85  	return successTx, nil
    86  }
    87  
    88  // CreateHtlcTimeoutTx creates a transaction that spends the HTLC output on the
    89  // commitment transaction of the peer that created an HTLC (the sender). This
    90  // transaction essentially acts as an off-chain covenant as it spends a 2-of-2
    91  // multi-sig output. This output requires a signature from both the sender and
    92  // receiver of the HTLC. By using a distinct transaction, we're able to
    93  // uncouple the timeout and delay clauses of the HTLC contract. This
    94  // transaction is locked with an absolute lock-time so the sender can only
    95  // attempt to claim the output using it after the lock time has passed.
    96  //
    97  // In order to spend the HTLC output, the witness for the passed transaction
    98  // should be:
    99  // * <sender sig> <receiver sig> <0>
   100  //
   101  // NOTE: The passed amount for the HTLC should take into account the required
   102  // fee rate at the time the HTLC was created. The fee should be able to
   103  // entirely pay for this (tiny: 1-in 1-out) transaction.
   104  func CreateHtlcTimeoutTx(chanType channeldb.ChannelType, initiator bool,
   105  	htlcOutput wire.OutPoint, htlcAmt dcrutil.Amount,
   106  	cltvExpiry, csvDelay, leaseExpiry uint32,
   107  	revocationKey, delayKey *secp256k1.PublicKey) (*wire.MsgTx, error) {
   108  
   109  	// Create a version two transaction (as the success version of this
   110  	// spends an output with a CSV timeout), and set the lock-time to the
   111  	// specified absolute lock-time in blocks.
   112  	timeoutTx := wire.NewMsgTx()
   113  	timeoutTx.Version = input.LNTxVersion
   114  	timeoutTx.LockTime = cltvExpiry
   115  
   116  	// The input to the transaction is the outpoint that creates the
   117  	// original HTLC on the sender's commitment transaction. Set the
   118  	// sequence number based on the channel type.
   119  	txin := &wire.TxIn{
   120  		PreviousOutPoint: htlcOutput,
   121  		SignatureScript:  []byte{},
   122  		Sequence:         HtlcSecondLevelInputSequence(chanType),
   123  	}
   124  	timeoutTx.AddTxIn(txin)
   125  
   126  	// Next, we'll generate the script used as the output for all second
   127  	// level HTLC which forces a covenant w.r.t what can be done with all
   128  	// HTLC outputs.
   129  	script, err := SecondLevelHtlcScript(
   130  		chanType, initiator, revocationKey, delayKey, csvDelay,
   131  		leaseExpiry,
   132  	)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	// Finally, the output is simply the amount of the HTLC (minus the
   138  	// required fees), paying to the regular second level HTLC script.
   139  	timeoutTx.AddTxOut(&wire.TxOut{
   140  		Value:    int64(htlcAmt),
   141  		PkScript: script.PkScript,
   142  	})
   143  
   144  	return timeoutTx, nil
   145  }
   146  
   147  // SetStateNumHint encodes the current state number within the passed
   148  // commitment transaction by re-purposing the locktime and sequence fields in
   149  // the commitment transaction to encode the obfuscated state number.  The state
   150  // number is encoded using 48 bits. The lower 24 bits of the lock time are the
   151  // lower 24 bits of the obfuscated state number and the lower 24 bits of the
   152  // sequence field are the higher 24 bits. Finally before encoding, the
   153  // obfuscator is XOR'd against the state number in order to hide the exact
   154  // state number from the PoV of outside parties.
   155  func SetStateNumHint(commitTx *wire.MsgTx, stateNum uint64,
   156  	obfuscator [StateHintSize]byte) error {
   157  
   158  	// With the current schema we are only able to encode state num
   159  	// hints up to 2^48. Therefore if the passed height is greater than our
   160  	// state hint ceiling, then exit early.
   161  	if stateNum > maxStateHint {
   162  		return fmt.Errorf("unable to encode state, %v is greater "+
   163  			"state num that max of %v", stateNum, maxStateHint)
   164  	}
   165  
   166  	if len(commitTx.TxIn) != 1 {
   167  		return fmt.Errorf("commitment tx must have exactly 1 input, "+
   168  			"instead has %v", len(commitTx.TxIn))
   169  	}
   170  
   171  	// Convert the obfuscator into a uint64, then XOR that against the
   172  	// targeted height in order to obfuscate the state number of the
   173  	// commitment transaction in the case that either commitment
   174  	// transaction is broadcast directly on chain.
   175  	var obfs [8]byte
   176  	copy(obfs[2:], obfuscator[:])
   177  	xorInt := binary.BigEndian.Uint64(obfs[:])
   178  
   179  	stateNum ^= xorInt
   180  
   181  	// Set the height bit of the sequence number in order to disable any
   182  	// sequence locks semantics.
   183  	commitTx.TxIn[0].Sequence = uint32(stateNum>>24) | wire.SequenceLockTimeDisabled
   184  	commitTx.LockTime = uint32(stateNum&0xFFFFFF) | TimelockShift
   185  
   186  	return nil
   187  }
   188  
   189  // GetStateNumHint recovers the current state number given a commitment
   190  // transaction which has previously had the state number encoded within it via
   191  // setStateNumHint and a shared obfuscator.
   192  //
   193  // See setStateNumHint for further details w.r.t exactly how the state-hints
   194  // are encoded.
   195  func GetStateNumHint(commitTx *wire.MsgTx, obfuscator [StateHintSize]byte) uint64 {
   196  	// Convert the obfuscator into a uint64, this will be used to
   197  	// de-obfuscate the final recovered state number.
   198  	var obfs [8]byte
   199  	copy(obfs[2:], obfuscator[:])
   200  	xorInt := binary.BigEndian.Uint64(obfs[:])
   201  
   202  	// Retrieve the state hint from the sequence number and locktime
   203  	// of the transaction.
   204  	stateNumXor := uint64(commitTx.TxIn[0].Sequence&0xFFFFFF) << 24
   205  	stateNumXor |= uint64(commitTx.LockTime & 0xFFFFFF)
   206  
   207  	// Finally, to obtain the final state number, we XOR by the obfuscator
   208  	// value to de-obfuscate the state number.
   209  	return stateNumXor ^ xorInt
   210  }