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 }