feat: generate genesis utxos from genesis file (#59)
Co-authored-by: rvcas <x@rvcas.dev> Co-authored-by: jmhrpr <harper.jme@gmail.com>
This commit is contained in:
parent
90b228492c
commit
a8df6dc666
10 changed files with 15080 additions and 42 deletions
24
pallas-configs/Cargo.toml
Normal file
24
pallas-configs/Cargo.toml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "pallas-configs"
|
||||
description = "Config structs and utilities matching the Haskell implementation"
|
||||
version = "0.19.0-alpha.2"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/txpipe/pallas"
|
||||
homepage = "https://github.com/txpipe/pallas"
|
||||
documentation = "https://docs.rs/pallas-configs"
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
authors = ["Santiago Carmuega <santiago@carmuega.me>"]
|
||||
|
||||
[dependencies]
|
||||
hex = "0.4.3"
|
||||
pallas-addresses = { version = "0.19.0-alpha.0", path = "../pallas-addresses" }
|
||||
pallas-crypto = { version = "0.19.0-alpha.0", path = "../pallas-crypto" }
|
||||
pallas-codec = { version = "0.19.0-alpha.0", path = "../pallas-codec" }
|
||||
serde = { version = "1.0.136", optional = true, features = ["derive"] }
|
||||
serde_json = { version = "1.0.79", optional = true }
|
||||
base64 = "0.21.2"
|
||||
|
||||
[features]
|
||||
json = ["serde", "serde_json"]
|
||||
default = ["json"]
|
||||
2
pallas-configs/README.md
Normal file
2
pallas-configs/README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Pallas Configs
|
||||
|
||||
218
pallas-configs/src/byron.rs
Normal file
218
pallas-configs/src/byron.rs
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
//! Parsing of Byron configuration data
|
||||
|
||||
use pallas_addresses::ByronAddress;
|
||||
use pallas_crypto::hash::Hash;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenesisFile {
|
||||
pub avvm_distr: HashMap<String, String>,
|
||||
pub block_version_data: BlockVersionData,
|
||||
pub fts_seed: Option<String>,
|
||||
pub protocol_consts: ProtocolConsts,
|
||||
pub start_time: u64,
|
||||
pub boot_stakeholders: HashMap<String, BootStakeWeight>,
|
||||
pub heavy_delegation: HashMap<String, HeavyDelegation>,
|
||||
pub non_avvm_balances: HashMap<String, String>,
|
||||
pub vss_certs: Option<HashMap<String, VssCert>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BlockVersionData {
|
||||
pub heavy_del_thd: String,
|
||||
pub max_block_size: String,
|
||||
pub max_header_size: String,
|
||||
pub max_proposal_size: String,
|
||||
pub max_tx_size: String,
|
||||
pub mpc_thd: String,
|
||||
pub script_version: u32,
|
||||
pub slot_duration: String,
|
||||
pub softfork_rule: SoftForkRule,
|
||||
pub tx_fee_policy: TxFeePolicy,
|
||||
pub unlock_stake_epoch: String,
|
||||
pub update_implicit: String,
|
||||
pub update_proposal_thd: String,
|
||||
pub update_vote_thd: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProtocolConsts {
|
||||
pub k: usize,
|
||||
pub protocol_magic: u32,
|
||||
#[serde(rename = "vssMaxTTL")]
|
||||
pub vss_max_ttl: Option<u32>,
|
||||
#[serde(rename = "vssMinTTL")]
|
||||
pub vss_min_ttl: Option<u32>,
|
||||
}
|
||||
|
||||
pub type BootStakeWeight = u16;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HeavyDelegation {
|
||||
pub issuer_pk: String,
|
||||
pub delegate_pk: String,
|
||||
pub cert: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct VssCert {
|
||||
pub vss_key: String,
|
||||
// TODO: is this size fine?
|
||||
pub expiry_epoch: u32,
|
||||
pub signature: String,
|
||||
pub signing_key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SoftForkRule {
|
||||
pub init_thd: String,
|
||||
pub min_thd: String,
|
||||
pub thd_decrement: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TxFeePolicy {
|
||||
pub multiplier: String,
|
||||
pub summand: String,
|
||||
}
|
||||
|
||||
pub fn from_file(path: &std::path::Path) -> Result<GenesisFile, std::io::Error> {
|
||||
let file = std::fs::File::open(path)?;
|
||||
let reader = std::io::BufReader::new(file);
|
||||
let parsed: GenesisFile = serde_json::from_reader(reader)?;
|
||||
|
||||
Ok(parsed)
|
||||
}
|
||||
|
||||
use base64::Engine;
|
||||
|
||||
pub type GenesisUtxo = (Hash<32>, ByronAddress, u64);
|
||||
|
||||
pub fn genesis_avvm_utxos(config: &GenesisFile) -> Vec<GenesisUtxo> {
|
||||
config
|
||||
.avvm_distr
|
||||
.iter()
|
||||
.map(|(pubkey, amount)| {
|
||||
let amount = amount.parse().unwrap();
|
||||
let pubkey = base64::engine::general_purpose::URL_SAFE
|
||||
.decode(pubkey)
|
||||
.unwrap();
|
||||
|
||||
let pubkey = pallas_crypto::key::ed25519::PublicKey::try_from(&pubkey[..]).unwrap();
|
||||
|
||||
// TODO: network tag
|
||||
//let network_tag = Some(config.protocol_consts.protocol_magic);
|
||||
let network_tag = None;
|
||||
|
||||
let addr = pallas_addresses::byron::AddressPayload::new_redeem(pubkey, network_tag);
|
||||
|
||||
let addr: pallas_addresses::ByronAddress = addr.into();
|
||||
|
||||
let txid = pallas_crypto::hash::Hasher::<256>::hash_cbor(&addr);
|
||||
|
||||
(txid, addr, amount)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn genesis_non_avvm_utxos(config: &GenesisFile) -> Vec<GenesisUtxo> {
|
||||
config
|
||||
.non_avvm_balances
|
||||
.iter()
|
||||
.map(|(addr, amount)| {
|
||||
let amount = amount.parse().unwrap();
|
||||
let addr = ByronAddress::from_base58(addr).unwrap();
|
||||
|
||||
let txid = pallas_crypto::hash::Hasher::<256>::hash_cbor(&addr);
|
||||
|
||||
(txid, addr, amount)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn load_test_data_config(network: &str) -> GenesisFile {
|
||||
let path = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
|
||||
.join("..")
|
||||
.join("test_data")
|
||||
.join(format!("{network}-byron-genesis.json"));
|
||||
|
||||
from_file(&path).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preview_json_loads() {
|
||||
load_test_data_config("preview");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mainnet_json_loads() {
|
||||
load_test_data_config("mainnet");
|
||||
}
|
||||
|
||||
fn utxo_exists(set: &[GenesisUtxo], expected: GenesisUtxo) -> bool {
|
||||
set.iter().any(|(hash, addr, amount)| {
|
||||
hash.eq(&expected.0) && addr.eq(&expected.1) && amount.eq(&expected.2)
|
||||
})
|
||||
}
|
||||
|
||||
fn genesis_utxo_from_raw(hash_hex: &str, addr_base58: &str, amount: u64) -> GenesisUtxo {
|
||||
(
|
||||
Hash::from_str(hash_hex).unwrap(),
|
||||
ByronAddress::from_base58(addr_base58).unwrap(),
|
||||
amount,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preview_non_avvm_utxos() {
|
||||
let f = load_test_data_config("preview");
|
||||
|
||||
let utxos = super::genesis_non_avvm_utxos(&f);
|
||||
assert_eq!(utxos.len(), 8);
|
||||
|
||||
// check known tx as seen: https://preview.cexplorer.io/tx/4843cf2e582b2f9ce37600e5ab4cc678991f988f8780fed05407f9537f7712bd
|
||||
let expected = genesis_utxo_from_raw(
|
||||
"4843cf2e582b2f9ce37600e5ab4cc678991f988f8780fed05407f9537f7712bd",
|
||||
"FHnt4NL7yPXvDWHa8bVs73UEUdJd64VxWXSFNqetECtYfTd9TtJguJ14Lu3feth",
|
||||
30_000_000_000_000_000,
|
||||
);
|
||||
|
||||
assert!(utxo_exists(&utxos, expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_mainnet_avvm_utxos() {
|
||||
let f = load_test_data_config("mainnet");
|
||||
|
||||
let utxos = super::genesis_non_avvm_utxos(&f);
|
||||
|
||||
// there aren't non-avvm utxos in mainnet
|
||||
assert!(utxos.is_empty());
|
||||
|
||||
let utxos = super::genesis_avvm_utxos(&f);
|
||||
|
||||
assert_eq!(utxos.len(), 14505);
|
||||
|
||||
// check known tx as seen: https://cexplorer.io/tx/0ae3da29711600e94a33fb7441d2e76876a9a1e98b5ebdefbf2e3bc535617616
|
||||
let expected = genesis_utxo_from_raw(
|
||||
"0ae3da29711600e94a33fb7441d2e76876a9a1e98b5ebdefbf2e3bc535617616",
|
||||
"Ae2tdPwUPEZKQuZh2UndEoTKEakMYHGNjJVYmNZgJk2qqgHouxDsA5oT83n",
|
||||
2_463_071_701_000_000,
|
||||
);
|
||||
|
||||
assert!(utxo_exists(&utxos, expected));
|
||||
}
|
||||
}
|
||||
3
pallas-configs/src/lib.rs
Normal file
3
pallas-configs/src/lib.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//! Genesis data structs and utilities
|
||||
|
||||
pub mod byron;
|
||||
Loading…
Add table
Add a link
Reference in a new issue