Skip to content

Commit 9b0e695

Browse files
committed
Implement genesis block calculations
1 parent 798ab18 commit 9b0e695

1 file changed

Lines changed: 164 additions & 2 deletions

File tree

src/genesis.rs

Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@
1414

1515
//! Helpers to calculate the genesis block for a given network.
1616
17-
use crate::hashes::{sha256, Hash, HashEngine};
17+
use bitcoin::secp256k1::impl_array_newtype;
18+
use secp256k1_zkp::Tweak;
19+
use crate::hashes::{sha256, sha256d, Hash, HashEngine};
20+
use crate::opcodes::all::OP_RETURN;
1821
use crate::opcodes::OP_TRUE;
1922
use crate::pset::serialize::Serialize;
20-
use crate::{script, Script};
23+
use crate::{confidential, script, AssetId, Block, BlockExtData, BlockHash, BlockHeader, LockTime, Script, Sequence, Transaction, TxIn, TxInWitness, TxOut, TxOutWitness};
24+
use crate::{AssetIssuance, ContractHash, OutPoint, Txid};
25+
use crate::confidential::Nonce;
2126

2227
/// Parameters that influence chain consensus. The contents of the genesis block for a given network
2328
/// are defined by these values.
@@ -91,3 +96,160 @@ pub fn commit_to_custom_network_parameters(params: &NetworkParams) -> Vec<u8> {
9196
eng.input(format!("{:x}", params.sign_block_script).as_bytes());
9297
sha256::Hash::from_engine(eng).serialize()
9398
}
99+
100+
/// Produce the genesis transaction for a given elements Network
101+
fn liquid_genesis_tx(network_params: &NetworkParams) -> Transaction {
102+
let commit = commit_to_custom_network_parameters(network_params);
103+
104+
let input = TxIn {
105+
previous_output: OutPoint::default(),
106+
is_pegin: false,
107+
script_sig: script::Builder::new()
108+
.push_slice(commit.as_slice())
109+
.into_script(),
110+
sequence: Sequence::default(),
111+
asset_issuance: AssetIssuance::default(),
112+
witness: TxInWitness::default(),
113+
};
114+
115+
let output = TxOut {
116+
asset: confidential::Asset::Explicit(AssetId::default()),
117+
value: confidential::Value::Explicit(0),
118+
nonce: Nonce::default(),
119+
script_pubkey: script::Builder::new().push_opcode(OP_RETURN).into_script(),
120+
witness: TxOutWitness::default(),
121+
};
122+
123+
Transaction {
124+
version: 1,
125+
lock_time: LockTime::ZERO,
126+
input: vec![input],
127+
output: vec![output],
128+
}
129+
}
130+
131+
/// Create the confidential asset transaction for the genesis block if required by the specified Network
132+
fn liquid_genesis_asset_tx(network_params: &NetworkParams) -> Option<Transaction> {
133+
let commit = commit_to_custom_network_parameters(network_params);
134+
let asset_amount = network_params.initial_free_coins;
135+
if asset_amount == 0 {
136+
return None;
137+
}
138+
let asset_outpoint = OutPoint::new(Txid::from_slice(commit.as_slice()).expect("txid"), 0);
139+
let contract_hash = ContractHash::from_byte_array([0u8; 32]);
140+
let asset_entropy = AssetId::generate_asset_entropy(asset_outpoint, contract_hash);
141+
let asset_id = AssetId::from_entropy(asset_entropy);
142+
143+
let asset_issuance = AssetIssuance {
144+
asset_blinding_nonce: Tweak::default(),
145+
asset_entropy: [0u8; 32],
146+
amount: confidential::Value::Explicit(asset_amount),
147+
inflation_keys: confidential::Value::Explicit(0),
148+
};
149+
150+
let input = TxIn {
151+
previous_output: asset_outpoint,
152+
is_pegin: false,
153+
script_sig: Script::new(),
154+
sequence: Sequence::default(),
155+
asset_issuance,
156+
witness: TxInWitness::default(),
157+
};
158+
159+
let output = TxOut {
160+
asset: confidential::Asset::Explicit(asset_id),
161+
value: confidential::Value::Explicit(asset_amount),
162+
nonce: Nonce::default(),
163+
script_pubkey: script::Builder::new().push_opcode(OP_TRUE).into_script(),
164+
witness: TxOutWitness::default(),
165+
};
166+
167+
let ret = Transaction {
168+
version: 1,
169+
lock_time: LockTime::ZERO,
170+
input: vec![input],
171+
output: vec![output],
172+
};
173+
Some(ret)
174+
}
175+
176+
/// Constructs and returns the Liquid genesis blocks assuming default consensus parameters
177+
/// Does not return upstream bitcoin network blocks as they are a different format and can be
178+
/// acquired from the `rust-bitcoin` library
179+
pub fn genesis_block(params: &NetworkParams) -> Block {
180+
let tx = liquid_genesis_tx(params);
181+
let mut txdata = vec![tx.clone()];
182+
183+
let merkle_root: sha256d::Hash =
184+
if let Some(asset_tx) = liquid_genesis_asset_tx(params) {
185+
txdata.push(asset_tx.clone());
186+
let tx_hashes = vec![tx.txid().to_raw_hash(), asset_tx.txid().to_raw_hash()];
187+
bitcoin::merkle_tree::calculate_root(tx_hashes.into_iter())
188+
.expect("merkle root")
189+
} else {
190+
tx.txid().to_raw_hash()
191+
};
192+
193+
Block {
194+
header: BlockHeader {
195+
version: 1,
196+
prev_blockhash: BlockHash::all_zeros(),
197+
merkle_root: merkle_root.into(),
198+
time: 1_296_688_602,
199+
height: 0,
200+
ext: BlockExtData::Proof {
201+
challenge: params.sign_block_script.clone(),
202+
solution: Script::default(),
203+
},
204+
},
205+
txdata,
206+
}
207+
}
208+
/// The uniquely identifying hash of the target blockchain.
209+
/// Liquid networks assume default consensus constants, Elements allows for modification of fedpeg and signblock scripts
210+
/// via configuration argument which will cause these values to differ so these are only for default parameters
211+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
212+
pub struct ChainHash([u8; 32]);
213+
impl_array_newtype!(ChainHash, u8, 32);
214+
215+
impl ChainHash {
216+
/// `ChainHash` for Liquid v1 mainnet.
217+
pub const LIQUIDV1: Self = Self([
218+
3, 96, 32, 138, 136, 150, 146, 55, 44, 141, 104, 176, 132, 166, 46, 253, 246, 14, 161, 163,
219+
89, 160, 76, 148, 178, 13, 34, 54, 88, 39, 102, 20,
220+
]);
221+
/// `ChainHash` for Liquid testnet.
222+
pub const LIQUIDTESTNET: Self = Self([
223+
193, 177, 106, 226, 79, 36, 35, 174, 162, 234, 52, 85, 34, 146, 121, 59, 91, 94, 130, 153,
224+
154, 30, 237, 129, 213, 106, 238, 82, 142, 218, 113, 167,
225+
]);
226+
227+
/// Calculates the chainhash for a set of network parameters
228+
pub fn for_params(params: &NetworkParams) -> Self {
229+
let genesis_block = genesis_block(params);
230+
ChainHash(genesis_block.block_hash().to_byte_array())
231+
}
232+
}
233+
234+
#[cfg(test)]
235+
mod test {
236+
use crate::genesis::{genesis_block, ChainHash, NetworkParams};
237+
use crate::hashes::Hash;
238+
239+
#[test]
240+
fn genesis_block_hash() {
241+
let genesis_block = genesis_block(&NetworkParams::liquidv1());
242+
assert_eq!(
243+
genesis_block.block_hash().to_byte_array(),
244+
ChainHash::LIQUIDV1.0
245+
);
246+
247+
let genesis_block =
248+
crate::genesis::genesis_block(&NetworkParams::liquidtestnet());
249+
250+
assert_eq!(
251+
genesis_block.block_hash().to_byte_array(),
252+
ChainHash::LIQUIDTESTNET.0
253+
);
254+
}
255+
}

0 commit comments

Comments
 (0)