Skip to content

Commit bfc831e

Browse files
committed
Add calculation of elements AssetId
1 parent 0699935 commit bfc831e

3 files changed

Lines changed: 178 additions & 0 deletions

File tree

src/genesis.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Rust Elements Library
2+
// Written by
3+
// The Elements developers
4+
//
5+
// To the extent possible under law, the author(s) have dedicated all
6+
// copyright and related and neighboring rights to this software to
7+
// the public domain worldwide. This software is distributed without
8+
// any warranty.
9+
//
10+
// You should have received a copy of the CC0 Public Domain Dedication
11+
// along with this software.
12+
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
//
14+
15+
//! Helpers to calculate the genesis block for a given network.
16+
17+
use crate::hashes::{sha256, Hash, HashEngine};
18+
use crate::opcodes::OP_TRUE;
19+
use crate::pset::serialize::Serialize;
20+
use crate::{script, Script};
21+
22+
/// Parameters that influence chain consensus. The contents of the genesis block for a given network
23+
/// are defined by these values.
24+
#[derive(Clone, Debug)]
25+
pub struct NetworkParams {
26+
/// The network identifier string that elementsd accepts as the `chain` config argument
27+
pub network_id: String,
28+
/// This network's Fedpeg script
29+
pub fedpeg_script: Script,
30+
/// This network's `sign_block_script`
31+
pub sign_block_script: Script,
32+
/// How many free coins are present in this network
33+
pub initial_free_coins: u64,
34+
}
35+
36+
impl NetworkParams {
37+
/// New custom network params
38+
pub fn new(
39+
network_id: String,
40+
fedpeg_script: Script,
41+
sign_block_script: Script,
42+
initial_free_coins: u64,
43+
) -> NetworkParams {
44+
NetworkParams {
45+
network_id,
46+
fedpeg_script,
47+
sign_block_script,
48+
initial_free_coins,
49+
}
50+
}
51+
52+
/// Network params for Liquid mainnet
53+
pub fn liquidv1() -> Self {
54+
NetworkParams {
55+
network_id: "liquidv1".to_string(),
56+
// Can be verified at https://github.com/ElementsProject/elements/blob/27c2fb6b7de404908f9ef2eb5c98c9989d1ab8e4/src/chainparams.cpp#L1243
57+
fedpeg_script: Script::from_hex_no_prefix("745c87635b21020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b678172612102675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af992102896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d4821029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c2102a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc40102102f8a00b269f8c5e59c67d36db3cdc11b11b21f64b4bffb2815e9100d9aa8daf072103079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b2103111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2210318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa08401742103230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de121035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a62103bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c2103cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d175462103d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d4248282103ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a5f6702c00fb275522103aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79210291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807210386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb5368ae").expect("constant fedpeg script parse"),
58+
// Can be verified at https://github.com/ElementsProject/elements/blob/27c2fb6b7de404908f9ef2eb5c98c9989d1ab8e4/src/chainparams.cpp#L1193
59+
sign_block_script: Script::from_hex_no_prefix("5b21026a2a106ec32c8a1e8052e5d02a7b0a150423dbd9b116fc48d46630ff6e6a05b92102791646a8b49c2740352b4495c118d876347bf47d0551c01c4332fdc2df526f1a2102888bda53a424466b0451627df22090143bbf7c060e9eacb1e38426f6b07f2ae12102aee8967150dee220f613de3b239320355a498808084a93eaf39a34dcd62024852102d46e9259d0a0bb2bcbc461a3e68f34adca27b8d08fbe985853992b4b104e27412102e9944e35e5750ab621e098145b8e6cf373c273b7c04747d1aa020be0af40ccd62102f9a9d4b10a6d6c56d8c955c547330c589bb45e774551d46d415e51cd9ad5116321033b421566c124dfde4db9defe4084b7aa4e7f36744758d92806b8f72c2e943309210353dcc6b4cf6ad28aceb7f7b2db92a4bf07ac42d357adf756f3eca790664314b621037f55980af0455e4fb55aad9b85a55068bb6dc4740ea87276dc693f4598db45fa210384001daa88dabd23db878dbb1ce5b4c2a5fa72c3113e3514bf602325d0c37b8e21039056d089f2fe72dbc0a14780b4635b0dc8a1b40b7a59106325dd1bc45cc70493210397ab8ea7b0bf85bc7fc56bb27bf85e75502e94e76a6781c409f3f2ec3d1122192103b00e3b5b77884bf3cae204c4b4eac003601da75f96982ffcb3dcb29c5ee419b92103c1f3c0874cfe34b8131af34699589aacec4093399739ae352e8a46f80a6f68375fae").expect("constant sign_block_script parse"),
60+
initial_free_coins: 0,
61+
}
62+
}
63+
64+
/// Network params for Liquid testnet
65+
pub fn liquidtestnet() -> Self {
66+
NetworkParams {
67+
network_id: "liquidtestnet".to_string(),
68+
fedpeg_script: script::Builder::new().push_opcode(OP_TRUE).into_script(),
69+
// Can be verified at https://github.com/ElementsProject/elements/blob/27c2fb6b7de404908f9ef2eb5c98c9989d1ab8e4/src/chainparams.cpp#L1108
70+
sign_block_script: Script::from_hex_no_prefix("51210217e403ddb181872c32a0cd468c710040b2f53d8cac69f18dad07985ee37e9a7151ae").expect("constant sign_block_script parse"),
71+
initial_free_coins: 2_100_000_000_000_000,
72+
}
73+
}
74+
75+
/// Network params for a custom Elements network with defaults
76+
pub fn custom_network(network_id: String, fedpeg_script: Option<Script>, sign_block_script: Option<Script>, initial_free_coins: Option<u64>) -> Self {
77+
NetworkParams {
78+
network_id,
79+
fedpeg_script: fedpeg_script.unwrap_or_else(|| script::Builder::new().push_opcode(OP_TRUE).into_script()),
80+
sign_block_script: sign_block_script.unwrap_or_else(|| script::Builder::new().push_opcode(OP_TRUE).into_script()),
81+
initial_free_coins: initial_free_coins.unwrap_or(0),
82+
}
83+
}
84+
}
85+
86+
/// Hash commitment of network parameters for a given Network
87+
pub fn commit_to_custom_network_parameters(params: &NetworkParams) -> Vec<u8> {
88+
let mut eng = sha256::Hash::engine();
89+
eng.input(params.network_id.clone().as_bytes());
90+
eng.input(format!("{:x}", params.fedpeg_script).as_bytes());
91+
eng.input(format!("{:x}", params.sign_block_script).as_bytes());
92+
sha256::Hash::from_engine(eng).serialize()
93+
}

src/issuance.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use crate::encode::{self, Encodable, Decodable};
2020
use crate::hashes::{hash_newtype, sha256, sha256d, Hash};
2121
use crate::fast_merkle_root::fast_merkle_root;
2222
use secp256k1_zkp::Tag;
23+
use crate::genesis::{commit_to_custom_network_parameters, NetworkParams};
2324
use crate::transaction::OutPoint;
25+
use crate::Txid;
2426

2527
/// The zero hash.
2628
const ZERO32: [u8; 32] = [
@@ -81,6 +83,14 @@ impl AssetId {
8183
0x3d, 0x1c, 0x04, 0xed, 0xe9, 0x79, 0x02, 0x6f,
8284
]);
8385

86+
/// The asset ID for L-BTC, Bitcoin on the Liquidtestnet network.
87+
pub const LIQUIDTESTNET_BTC: AssetId = AssetId([
88+
0x49, 0x9a, 0x81, 0x85, 0x45, 0xf6, 0xba, 0xe3,
89+
0x9f, 0xc0, 0x3b, 0x63, 0x7f, 0x2a, 0x4e, 0x1e,
90+
0x64, 0xe5, 0x90, 0xca, 0xc1, 0xbc, 0x3a, 0x6f,
91+
0x6d, 0x71, 0xaa, 0x44, 0x43, 0x65, 0x4c, 0x14,
92+
]);
93+
8494
/// Generate the asset entropy from the issuance prevout and the contract hash.
8595
pub fn generate_asset_entropy(
8696
prevout: OutPoint,
@@ -137,6 +147,30 @@ impl AssetId {
137147
pub fn into_tag(self) -> Tag {
138148
self.0.into()
139149
}
150+
151+
/// Pegged asset id for given network parameters
152+
pub fn pegged_asset_id_for_network_params(params: &NetworkParams) -> AssetId {
153+
match params.network_id.as_str() {
154+
"liquidv1" => Self::LIQUID_BTC,
155+
"liquidtestnet" => Self::LIQUIDTESTNET_BTC,
156+
_ => {
157+
// Else calculate the asset_id
158+
Self::pegged_asset_id_for_params_and_parent_chain_hash(
159+
params,
160+
bitcoin::Network::Regtest.chain_hash(),
161+
)
162+
}
163+
}
164+
}
165+
166+
/// Calculate the `AssetId` for the pegged asset for a given set of network parameters assuming
167+
/// a Regtest parent network
168+
fn pegged_asset_id_for_params_and_parent_chain_hash(params: &NetworkParams, parent_chainhash: bitcoin::blockdata::constants::ChainHash) -> AssetId {
169+
let commit = commit_to_custom_network_parameters(params);
170+
let asset_outpoint = OutPoint::new(Txid::from_slice(commit.as_slice()).expect("txid"), 0);
171+
let asset_entropy = AssetId::generate_asset_entropy(asset_outpoint, ContractHash::from_slice(parent_chainhash.to_bytes().as_slice()).unwrap());
172+
AssetId::from_entropy(asset_entropy)
173+
}
140174
}
141175

142176
impl Encodable for AssetId {
@@ -155,6 +189,7 @@ impl Decodable for AssetId {
155189
mod test {
156190
use super::*;
157191
use std::str::FromStr;
192+
use bitcoin::constants::ChainHash;
158193

159194
#[test]
160195
fn example_elements_core() {
@@ -259,4 +294,52 @@ mod test {
259294
"6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
260295
);
261296
}
297+
298+
#[test]
299+
fn liquid_asset_ids() {
300+
// Testing the two most common Regtest networks using in Liquid and CLN codebases
301+
let network_params = NetworkParams::custom_network("elementsregtest".to_string(), None, None, None);
302+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
303+
&network_params,
304+
bitcoin::Network::Regtest.chain_hash(),
305+
);
306+
307+
let elementsregtest_asset_id = AssetId([
308+
0x23, 0x0f, 0x4f, 0x5d, 0x4b, 0x7c, 0x6f, 0xa8, 0x45, 0x80, 0x6e, 0xe4,
309+
0xf6, 0x77, 0x13, 0x45, 0x9e, 0x1b, 0x69, 0xe8, 0xe6, 0x0f, 0xce, 0xe2,
310+
0xe4, 0x94, 0x0c, 0x7a, 0x0d, 0x5d, 0xe1, 0xb2,
311+
]);
312+
313+
assert_eq!(asset_id, elementsregtest_asset_id);
314+
315+
let network_params = NetworkParams::custom_network("liquid-regtest".to_string(), None, None, None);
316+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
317+
&network_params,
318+
bitcoin::Network::Regtest.chain_hash(),
319+
);
320+
321+
let liquid_regtest_assetid = AssetId([
322+
0x5c, 0xe7, 0xb9, 0x63, 0xd3, 0x7f, 0x8f, 0x2d, 0x51, 0xca, 0xfb, 0xba,
323+
0x92, 0x8a, 0xaa, 0x9e, 0x22, 0x0b, 0x8b, 0xbc, 0x66, 0x05, 0x71, 0x49,
324+
0x9c, 0x03, 0x62, 0x8a, 0x38, 0x51, 0xb8, 0xce,
325+
]);
326+
327+
assert_eq!(asset_id, liquid_regtest_assetid);
328+
329+
let liquidv1_params = NetworkParams::liquidv1();
330+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
331+
&liquidv1_params,
332+
bitcoin::Network::Bitcoin.chain_hash(),
333+
);
334+
335+
assert_eq!(asset_id, AssetId::LIQUID_BTC);
336+
337+
let liquidtestnet_params = NetworkParams::liquidtestnet();
338+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
339+
&liquidtestnet_params,
340+
ChainHash::from([0u8; 32]),
341+
);
342+
343+
assert_eq!(asset_id, AssetId::LIQUIDTESTNET_BTC);
344+
}
262345
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub mod taproot;
7272
mod transaction;
7373
// consider making upstream public
7474
mod endian;
75+
pub mod genesis;
76+
7577
// re-export bitcoin deps which we re-use
7678
pub use bitcoin::hashes;
7779
// export everything at the top level so it can be used as `elements::Transaction` etc.

0 commit comments

Comments
 (0)