Skip to content

Commit

Permalink
Implement open etchings
Browse files Browse the repository at this point in the history
  • Loading branch information
casey committed Oct 26, 2023
1 parent 7a87696 commit 8d85473
Show file tree
Hide file tree
Showing 6 changed files with 480 additions and 24 deletions.
47 changes: 32 additions & 15 deletions src/index/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,26 @@ impl Entry for BlockHash {
pub(crate) struct RuneEntry {
pub(crate) burned: u128,
pub(crate) divisibility: u8,
pub(crate) end: Option<u64>,
pub(crate) etching: Txid,
pub(crate) limit: Option<u128>,
pub(crate) number: u64,
pub(crate) rune: Rune,
pub(crate) supply: u128,
pub(crate) symbol: Option<char>,
pub(crate) timestamp: u32,
}

pub(super) type RuneEntryValue = (u128, u8, (u128, u128), u64, u128, u128, u32, u32);
pub(super) type RuneEntryValue = (u128, u8, u64, (u128, u128), u128, u64, u128, u128, u32, u32);

impl Default for RuneEntry {
fn default() -> Self {
Self {
burned: 0,
divisibility: 0,
end: None,
etching: Txid::all_zeros(),
limit: None,
number: 0,
rune: Rune(0),
supply: 0,
Expand All @@ -55,11 +59,12 @@ impl Entry for RuneEntry {
type Value = RuneEntryValue;

fn load(
(burned, divisibility, etching, number, rune, supply, symbol, timestamp): RuneEntryValue,
(burned, divisibility, end, etching, limit, number, rune, supply, symbol, timestamp): RuneEntryValue,
) -> Self {
Self {
burned,
divisibility,
end: (end != u64::max_value()).then_some(end),
etching: {
let low = etching.0.to_le_bytes();
let high = etching.1.to_le_bytes();
Expand All @@ -70,6 +75,7 @@ impl Entry for RuneEntry {
high[14], high[15],
])
},
limit: (limit != u128::max_value()).then_some(limit),
number,
rune: Rune(rune),
supply,
Expand All @@ -82,6 +88,7 @@ impl Entry for RuneEntry {
(
self.burned,
self.divisibility,
self.end.unwrap_or(u64::max_value()),
{
let bytes = self.etching.to_byte_array();
(
Expand All @@ -95,13 +102,11 @@ impl Entry for RuneEntry {
]),
)
},
self.limit.unwrap_or(u128::max_value()),
self.number,
self.rune.0,
self.supply,
match self.symbol {
Some(symbol) => symbol.into(),
None => u32::max_value(),
},
self.symbol.map(u32::from).unwrap_or(u32::max_value()),
self.timestamp,
)
}
Expand Down Expand Up @@ -422,14 +427,16 @@ mod tests {
let rune_entry = RuneEntry {
burned: 1,
divisibility: 2,
end: Some(3),
etching: Txid::from_byte_array([
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
0x1E, 0x1F,
]),
number: 3,
rune: Rune(4),
supply: 5,
limit: Some(4),
number: 5,
rune: Rune(6),
supply: 7,
symbol: Some('a'),
timestamp: 6,
};
Expand All @@ -439,13 +446,15 @@ mod tests {
(
1,
2,
3,
(
0x0F0E0D0C0B0A09080706050403020100,
0x1F1E1D1C1B1A19181716151413121110
),
3,
4,
5,
6,
7,
u32::from('a'),
6,
)
Expand All @@ -455,13 +464,15 @@ mod tests {
RuneEntry::load((
1,
2,
3,
(
0x0F0E0D0C0B0A09080706050403020100,
0x1F1E1D1C1B1A19181716151413121110
),
3,
4,
5,
6,
7,
u32::from('a'),
6,
)),
Expand All @@ -470,6 +481,8 @@ mod tests {

let rune_entry = RuneEntry {
symbol: None,
limit: None,
end: None,
..rune_entry
};

Expand All @@ -478,13 +491,15 @@ mod tests {
(
1,
2,
u64::max_value(),
(
0x0F0E0D0C0B0A09080706050403020100,
0x1F1E1D1C1B1A19181716151413121110
),
3,
4,
u128::max_value(),
5,
6,
7,
u32::max_value(),
6,
)
Expand All @@ -494,13 +509,15 @@ mod tests {
RuneEntry::load((
1,
2,
u64::max_value(),
(
0x0F0E0D0C0B0A09080706050403020100,
0x1F1E1D1C1B1A19181716151413121110
),
3,
4,
u128::max_value(),
5,
6,
7,
u32::max_value(),
6,
)),
Expand Down
75 changes: 73 additions & 2 deletions src/index/updater/rune_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ use {
crate::runes::{varint, Edict, Runestone},
};

fn claim(id: u128) -> Option<u128> {
id.checked_sub(1 << 48)
}

struct Allocation {
balance: u128,
divisibility: u8,
end: Option<u64>,
id: u128,
limit: Option<u128>,
rune: Rune,
symbol: Option<char>,
}
Expand Down Expand Up @@ -109,11 +115,21 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> {
// ignored.
match u16::try_from(index) {
Ok(index) => Some(Allocation {
balance: u128::max_value(),
balance: if let Some(limit) = etching.limit {
if etching.term == Some(0) {
0
} else {
limit
}
} else {
u128::max_value()
},
limit: etching.limit,
divisibility: etching.divisibility,
id: u128::from(self.height) << 16 | u128::from(index),
rune: etching.rune,
symbol: etching.symbol,
end: etching.term.map(|term| term + self.height),
}),
Err(_) => None,
}
Expand All @@ -123,6 +139,33 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> {
};

if !burn {
let mut mintable: HashMap<u128, u128> = HashMap::new();

let mut claims = runestone
.edicts
.iter()
.filter_map(|edict| claim(edict.id))
.collect::<Vec<u128>>();
claims.sort();
claims.dedup();
for id in claims {
if let Ok(key) = RuneId::try_from(id) {
if let Some(entry) = self.id_to_entry.get(&key.store())? {
let entry = RuneEntry::load(entry.value());
if let Some(limit) = entry.limit {
if let Some(end) = entry.end {
if self.height >= end {
continue;
}
}
mintable.insert(id, limit);
}
}
}
}

let limits = mintable.clone();

for Edict { id, amount, output } in runestone.edicts {
let Ok(output) = usize::try_from(output) else {
continue;
Expand All @@ -142,6 +185,11 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> {
Some(Allocation { balance, id, .. }) => (balance, *id),
None => continue,
}
} else if let Some(claim) = claim(id) {
match mintable.get_mut(&claim) {
Some(balance) => (balance, claim),
None => continue,
}
} else {
// Get the unallocated balance of the given ID
match unallocated.get_mut(&id) {
Expand Down Expand Up @@ -192,6 +240,17 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> {
allocate(balance, amount, output);
}
}

// increment entries with minted runes
for (id, amount) in mintable {
let minted = limits[&id] - amount;
if minted > 0 {
let id = RuneId::try_from(id).unwrap().store();
let mut entry = RuneEntry::load(self.id_to_entry.get(id)?.unwrap().value());
entry.supply += minted;
self.id_to_entry.insert(id, entry.store())?;
}
}
}

if let Some(Allocation {
Expand All @@ -200,6 +259,8 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> {
id,
rune,
symbol,
limit,
end,
}) = allocation
{
let id = RuneId::try_from(id).unwrap();
Expand All @@ -218,8 +279,18 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> {
etching: txid,
number,
rune,
supply: u128::max_value() - balance,
supply: if let Some(limit) = limit {
if end == Some(self.height) {
0
} else {
limit
}
} else {
u128::max_value()
} - balance,
end,
symbol,
limit,
timestamp: self.timestamp,
}
.store(),
Expand Down
Loading

0 comments on commit 8d85473

Please sign in to comment.