Skip to content

Commit 526a189

Browse files
author
Conor Okus
committed
Adds FundingGenerationReady Event Handling section
1 parent 5aa2dc9 commit 526a189

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

docs/tutorials/building-a-node-with-ldk/opening-a-channel.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,129 @@ val createChannelResult = channelManager.create_channel(
6767
</template>
6868
</CodeSwitcher>
6969

70+
# FundingGenerationReady Event Handling
71+
72+
At this point, an outbound channel has been initiated with your peer and it will appear in `ChannelManager::list_channels`. However, the channel is not yet funded. Once your peer accepts the channel, you will be notified with a `FundingGenerationReady` event. It's then your responsibility to construct the funding transaction and pass it to ChannelManager, which will broadcast it once it receives your channel counterparty's signature.
73+
74+
75+
<CodeSwitcher :languages="{rust:'Rust', java:'Java', kotlin:'Kotlin'}">
76+
<template v-slot:rust>
77+
78+
```rust
79+
// In the event handler passed to BackgroundProcessor::start
80+
match event {
81+
Event::FundingGenerationReady {
82+
temporary_channel_id,
83+
channel_value_satoshis,
84+
output_script,
85+
user_channel_id,
86+
} => {
87+
// This is the same channel created earler.
88+
assert_eq!(event.user_channel_id, 42);
89+
90+
// Construct the raw transaction with one output, that is paid the amount of the
91+
// channel.
92+
let network = bitcoin_bech32::constants::Network::Testnet;
93+
let address = WitnessProgram::from_scriptpubkey(&output_script[..], network)
94+
.unwrap().to_address;
95+
let mut outputs = vec![HashMap::with_capacity(1)];
96+
outputs[0].insert(address, channel_value_satoshis as f64 / 100_000_000.0);
97+
let raw_tx = bitcoind_client.create_raw_transaction(outputs).await;
98+
99+
// Have your wallet put the inputs into the transaction such that the output is
100+
// satisfied.
101+
let funded_tx = bitcoind_client.fund_raw_transaction(raw_tx).await;
102+
assert!(funded_tx.changepos == 0 || funded_tx.changepos == 1);
103+
104+
// Sign the funding transaction and give it to ChannelManager to broadcast.
105+
let signed_tx = bitcoind_client.sign_raw_transaction_with_wallet(funded_tx.hex).await;
106+
assert_eq!(signed_tx.complete, true);
107+
let final_tx: Transaction =
108+
encode::deserialize(&hex_utils::to_vec(&signed_tx.hex).unwrap()).unwrap();
109+
channel_manager.funding_transaction_generated(&temporary_channel_id, final_tx).unwrap();
110+
}
111+
// ...
112+
}
113+
```
114+
115+
</template>
116+
117+
<template v-slot:java>
118+
119+
```java
120+
// After the peer responds with an `accept_channel` message, an
121+
// Event.FundingGenerationReady event will be generated.
122+
123+
// In the `handle_event` method of ChannelManagerPersister implementation
124+
if (e instanceof Event.FundingGenerationReady) {
125+
Event.FundingGenerationReady event = (Event.FundingGenerationReady) e;
126+
byte[] funding_scriptpubkey = event.output_script;
127+
long output_value = event.channel_value_satoshis;
128+
129+
// This is the same channel created earler
130+
assert event.user_channel_id == 42;
131+
132+
// The output is always a P2WSH:
133+
assert funding_scriptpubkey.length == 34 && funding_scriptpubkey[0] == 0 &&
134+
funding_scriptpubkey[1] == 32;
135+
136+
// Generate the funding transaction for the channel based on the channel amount
137+
// The following uses the bitcoinj library to do so, but you can use any
138+
// standard Bitcoin library for on-chain logic.
139+
NetworkParameters bitcoinj_net =
140+
NetworkParameters.fromID(NetworkParameters.ID_MAINNET);
141+
Transaction funding_tx = new Transaction(bitcoinj_net);
142+
funding_tx.addInput(new TransactionInput(bitcoinj_net, funding, new byte[0]));
143+
// Note that all inputs in the funding transaction MUST spend SegWit outputs
144+
// (and have witnesses)
145+
funding_tx.getInputs().get(0).setWitness(new TransactionWitness(2));
146+
funding_tx.getInput(0).getWitness().setPush(0, new byte[]{0x1});
147+
funding_tx.addOutput(Coin.SATOSHI.multiply(output_value),
148+
new Script(funding_scriptpubkey));
149+
150+
// Give the funding transaction back to the ChannelManager.
151+
Result_NoneAPIErrorZ funding_res = channel_manager.funding_transaction_generated(
152+
event.temporary_channel_id, funding_tx.bitcoinSerialize());
153+
// funding_transaction_generated should only generate an error if the
154+
// transaction didn't meet the required format (or the counterparty already
155+
// closed the channel on us):
156+
assert funding_res instanceof Result_NoneAPIErrorZ.Result_NoneAPIErrorZ_OK;
157+
}
158+
```
159+
160+
</template>
161+
162+
<template v-slot:kotlin>
163+
164+
```kotlin
165+
// After the peer responds with an `accept_channel` message, an
166+
// Event.FundingGenerationReady event will be generated.
167+
168+
if (event is Event.FundingGenerationReady) {
169+
val funding_spk = event.output_script
170+
171+
if (funding_spk.size == 34 && funding_spk[0].toInt() == 0 && funding_spk[1].toInt() == 32) {
172+
// Generate the funding transaction for the channel based on the channel amount
173+
// The following uses BDK for on-chain logic
174+
val rawTx = OnchainWallet.buildFundingTx(event.channel_value_satoshis, event.output_script)
175+
176+
channelManager.funding_transaction_generated(
177+
event.temporary_channel_id,
178+
event.counterparty_node_id,
179+
rawTx
180+
)
181+
}
182+
}
183+
```
184+
185+
</template>
186+
187+
188+
189+
190+
</CodeSwitcher>
191+
192+
70193

71194

72195

0 commit comments

Comments
 (0)