Skip to content

Commit 798ab18

Browse files
committed
Add calculation of elements AssetId
1 parent 19eb8fc commit 798ab18

3 files changed

Lines changed: 178 additions & 2 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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
1717
use std::io;
1818
use std::str::FromStr;
19-
2019
use crate::encode::{self, Encodable, Decodable};
2120
use crate::hashes::{self, hash_newtype, sha256, sha256d, Hash};
2221
use crate::fast_merkle_root::fast_merkle_root;
2322
use secp256k1_zkp::Tag;
23+
use crate::genesis::{commit_to_custom_network_parameters, NetworkParams};
2424
use crate::transaction::OutPoint;
25+
use crate::Txid;
2526

2627
/// The zero hash.
2728
const ZERO32: [u8; 32] = [
@@ -75,6 +76,14 @@ impl AssetId {
7576
0x3d, 0x1c, 0x04, 0xed, 0xe9, 0x79, 0x02, 0x6f,
7677
]));
7778

79+
/// The asset ID for L-BTC, Bitcoin on the Liquidtestnet network.
80+
pub const LIQUIDTESTNET_BTC: AssetId = AssetId(sha256::Midstate([
81+
0x49, 0x9a, 0x81, 0x85, 0x45, 0xf6, 0xba, 0xe3,
82+
0x9f, 0xc0, 0x3b, 0x63, 0x7f, 0x2a, 0x4e, 0x1e,
83+
0x64, 0xe5, 0x90, 0xca, 0xc1, 0xbc, 0x3a, 0x6f,
84+
0x6d, 0x71, 0xaa, 0x44, 0x43, 0x65, 0x4c, 0x14,
85+
]));
86+
7887
/// Create an [`AssetId`] from its inner type.
7988
pub const fn from_inner(midstate: sha256::Midstate) -> AssetId {
8089
AssetId(midstate)
@@ -146,6 +155,30 @@ impl AssetId {
146155
pub fn into_tag(self) -> Tag {
147156
self.0.to_byte_array().into()
148157
}
158+
159+
/// Pegged asset id for given network parameters
160+
pub fn pegged_asset_id_for_network_params(params: &NetworkParams) -> AssetId {
161+
match params.network_id.as_str() {
162+
"liquidv1" => Self::LIQUID_BTC,
163+
"liquidtestnet" => Self::LIQUIDTESTNET_BTC,
164+
_ => {
165+
// Else calculate the asset_id
166+
Self::pegged_asset_id_for_params_and_parent_chain_hash(
167+
params,
168+
bitcoin::Network::Regtest.chain_hash(),
169+
)
170+
}
171+
}
172+
}
173+
174+
/// Calculate the `AssetId` for the pegged asset for a given set of network parameters assuming
175+
/// a Regtest parent network
176+
fn pegged_asset_id_for_params_and_parent_chain_hash(params: &NetworkParams, parent_chainhash: bitcoin::blockdata::constants::ChainHash) -> AssetId {
177+
let commit = commit_to_custom_network_parameters(params);
178+
let asset_outpoint = OutPoint::new(Txid::from_slice(commit.as_slice()).expect("txid"), 0);
179+
let asset_entropy = AssetId::generate_asset_entropy(asset_outpoint, ContractHash::from_slice(parent_chainhash.to_bytes().as_slice()).unwrap());
180+
AssetId::from_entropy(asset_entropy)
181+
}
149182
}
150183

151184
impl ::std::fmt::Display for AssetId {
@@ -260,7 +293,7 @@ impl<'de> ::serde::Deserialize<'de> for AssetId {
260293
mod test {
261294
use super::*;
262295
use std::str::FromStr;
263-
296+
use bitcoin::constants::ChainHash;
264297
use crate::hashes::sha256;
265298

266299
#[test]
@@ -366,4 +399,52 @@ mod test {
366399
"6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d",
367400
);
368401
}
402+
403+
#[test]
404+
fn liquid_asset_ids() {
405+
// Testing the two most common Regtest networks using in Liquid and CLN codebases
406+
let network_params = NetworkParams::custom_network("elementsregtest".to_string(), None, None, None);
407+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
408+
&network_params,
409+
bitcoin::Network::Regtest.chain_hash(),
410+
);
411+
412+
let elementsregtest_asset_id = AssetId(sha256::Midstate([
413+
0x23, 0x0f, 0x4f, 0x5d, 0x4b, 0x7c, 0x6f, 0xa8, 0x45, 0x80, 0x6e, 0xe4,
414+
0xf6, 0x77, 0x13, 0x45, 0x9e, 0x1b, 0x69, 0xe8, 0xe6, 0x0f, 0xce, 0xe2,
415+
0xe4, 0x94, 0x0c, 0x7a, 0x0d, 0x5d, 0xe1, 0xb2,
416+
]));
417+
418+
assert_eq!(asset_id, elementsregtest_asset_id);
419+
420+
let network_params = NetworkParams::custom_network("liquid-regtest".to_string(), None, None, None);
421+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
422+
&network_params,
423+
bitcoin::Network::Regtest.chain_hash(),
424+
);
425+
426+
let liquid_regtest_assetid = AssetId(sha256::Midstate([
427+
0x5c, 0xe7, 0xb9, 0x63, 0xd3, 0x7f, 0x8f, 0x2d, 0x51, 0xca, 0xfb, 0xba,
428+
0x92, 0x8a, 0xaa, 0x9e, 0x22, 0x0b, 0x8b, 0xbc, 0x66, 0x05, 0x71, 0x49,
429+
0x9c, 0x03, 0x62, 0x8a, 0x38, 0x51, 0xb8, 0xce,
430+
]));
431+
432+
assert_eq!(asset_id, liquid_regtest_assetid);
433+
434+
let liquidv1_params = NetworkParams::liquidv1();
435+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
436+
&liquidv1_params,
437+
bitcoin::Network::Bitcoin.chain_hash(),
438+
);
439+
440+
assert_eq!(asset_id, AssetId::LIQUID_BTC);
441+
442+
let liquidtestnet_params = NetworkParams::liquidtestnet();
443+
let asset_id = AssetId::pegged_asset_id_for_params_and_parent_chain_hash(
444+
&liquidtestnet_params,
445+
ChainHash::from([0u8; 32]),
446+
);
447+
448+
assert_eq!(asset_id, AssetId::LIQUIDTESTNET_BTC);
449+
}
369450
}

src/lib.rs

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

0 commit comments

Comments
 (0)