From 8f0374b950bfffc73f0a8700d3614102386f1f51 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 10 Oct 2023 12:52:13 -0700 Subject: [PATCH] Show etching and inscription on /rune page (#2512) --- src/index.rs | 11 + src/index/entry.rs | 63 +++++- src/index/updater/rune_updater.rs | 11 +- src/runes.rs | 341 ++++++++++++++++++++---------- src/subcommand/server.rs | 40 +++- src/templates/rune.rs | 17 +- templates/rune.html | 6 + 7 files changed, 352 insertions(+), 137 deletions(-) diff --git a/src/index.rs b/src/index.rs index c5b62389ff..04b382d4ba 100644 --- a/src/index.rs +++ b/src/index.rs @@ -848,6 +848,17 @@ impl Index { })) } + pub(crate) fn inscription_exists(&self, inscription_id: InscriptionId) -> Result { + Ok( + self + .database + .begin_read()? + .open_table(INSCRIPTION_ID_TO_SATPOINT)? + .get(&inscription_id.store())? + .is_some(), + ) + } + pub(crate) fn get_inscriptions_on_output_with_satpoints( &self, outpoint: OutPoint, diff --git a/src/index/entry.rs b/src/index/entry.rs index 8f724185e1..b9c853ec96 100644 --- a/src/index/entry.rs +++ b/src/index/entry.rs @@ -26,20 +26,31 @@ impl Entry for BlockHash { pub(crate) struct RuneEntry { pub(crate) burned: u128, pub(crate) divisibility: u8, + pub(crate) etching: Txid, pub(crate) rarity: Rarity, pub(crate) rune: Rune, pub(crate) supply: u128, } -pub(super) type RuneEntryValue = (u128, u8, u8, u128, u128); +pub(super) type RuneEntryValue = (u128, u8, (u128, u128), u8, u128, u128); impl Entry for RuneEntry { type Value = RuneEntryValue; - fn load((burned, divisibility, rarity, rune, supply): RuneEntryValue) -> Self { + fn load((burned, divisibility, etching, rarity, rune, supply): RuneEntryValue) -> Self { Self { burned, divisibility, + etching: { + let low = etching.0.to_le_bytes(); + let high = etching.1.to_le_bytes(); + Txid::from_byte_array([ + low[0], low[1], low[2], low[3], low[4], low[5], low[6], low[7], low[8], low[9], low[10], + low[11], low[12], low[13], low[14], low[15], high[0], high[1], high[2], high[3], high[4], + high[5], high[6], high[7], high[8], high[9], high[10], high[11], high[12], high[13], + high[14], high[15], + ]) + }, rarity: Rarity::try_from(rarity).unwrap(), rune: Rune(rune), supply, @@ -50,6 +61,19 @@ impl Entry for RuneEntry { ( self.burned, self.divisibility, + { + let bytes = self.etching.to_byte_array(); + ( + u128::from_le_bytes([ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], + ]), + u128::from_le_bytes([ + bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23], + bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31], + ]), + ) + }, self.rarity.into(), self.rune.0, self.supply, @@ -372,14 +396,45 @@ mod tests { let rune_entry = RuneEntry { burned: 1, divisibility: 2, + 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, + ]), rarity: Rarity::Epic, rune: Rune(4), supply: 5, }; - assert_eq!(rune_entry.store(), (1, 2, 3, 4, 5)); + assert_eq!( + rune_entry.store(), + ( + 1, + 2, + ( + 0x0F0E0D0C0B0A09080706050403020100, + 0x1F1E1D1C1B1A19181716151413121110 + ), + 3, + 4, + 5, + ) + ); - assert_eq!(RuneEntry::load((1, 2, 3, 4, 5)), rune_entry); + assert_eq!( + RuneEntry::load(( + 1, + 2, + ( + 0x0F0E0D0C0B0A09080706050403020100, + 0x1F1E1D1C1B1A19181716151413121110 + ), + 3, + 4, + 5, + )), + rune_entry + ); } #[test] diff --git a/src/index/updater/rune_updater.rs b/src/index/updater/rune_updater.rs index 946efb7f7a..f0921bbead 100644 --- a/src/index/updater/rune_updater.rs +++ b/src/index/updater/rune_updater.rs @@ -80,10 +80,10 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> { // ignored. match u16::try_from(index) { Ok(index) => Some(Allocation { - id: u128::from(self.height) << 16 | u128::from(index), balance: u128::max_value(), - rune: etching.rune, divisibility: etching.divisibility, + id: u128::from(self.height) << 16 | u128::from(index), + rune: etching.rune, }), Err(_) => None, } @@ -128,10 +128,10 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> { } if let Some(Allocation { - id, balance, - rune, divisibility, + id, + rune, }) = allocation { // Calculate the allocated supply @@ -145,6 +145,8 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> { id.store(), RuneEntry { burned: 0, + divisibility, + etching: txid, rarity: if self.count == 0 { self.rarity } else { @@ -152,7 +154,6 @@ impl<'a, 'db, 'tx> RuneUpdater<'a, 'db, 'tx> { }, rune, supply, - divisibility, } .store(), )?; diff --git a/src/runes.rs b/src/runes.rs index 0be43e5fb5..71de9b5e66 100644 --- a/src/runes.rs +++ b/src/runes.rs @@ -145,10 +145,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -234,6 +235,7 @@ mod tests { RuneEntry { burned: 0, divisibility: 0, + etching: txid, rune: Rune(u128::from(Sat::SUPPLY - 150 * COIN_VALUE)), supply: u128::max_value(), rarity: Rarity::Uncommon, @@ -289,6 +291,7 @@ mod tests { RuneEntry { burned: 0, rune: Rune(RUNE), + etching: txid, divisibility: 1, supply: u128::max_value(), rarity: Rarity::Uncommon, @@ -349,10 +352,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -410,10 +414,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -464,10 +469,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: 100, + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: 100, } )] ); @@ -525,10 +531,11 @@ mod tests { id, RuneEntry { burned: 100, - rune: Rune(RUNE), divisibility: 0, - supply: 200, + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: 200, } )] ); @@ -589,10 +596,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: 100, + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: 100, } )] ); @@ -611,7 +619,7 @@ mod tests { context.mine_blocks(1); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid0 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(1, 0, 0, Witness::new())], op_return: Some( Runestone { @@ -643,20 +651,27 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid0, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid1 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(2, 1, 0, Witness::new())], op_return: Some( Runestone { @@ -680,17 +695,24 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid1, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); } @@ -702,7 +724,7 @@ mod tests { context.mine_blocks(1); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid0 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(1, 0, 0, Witness::new())], op_return: Some( Runestone { @@ -734,20 +756,27 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid0, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid1 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(2, 1, 0, Witness::new())], op_return: Some( Runestone { @@ -767,17 +796,24 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid1, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); } @@ -790,7 +826,7 @@ mod tests { context.mine_blocks(1); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid0 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(1, 0, 0, Witness::new())], op_return: Some( Runestone { @@ -822,20 +858,27 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid0, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid1 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(2, 1, 0, Witness::new())], op_return: None, ..Default::default() @@ -849,17 +892,24 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid1, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); } @@ -903,10 +953,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -943,10 +994,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -997,10 +1049,11 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -1049,20 +1102,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -1102,20 +1157,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -1173,10 +1230,11 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -1225,20 +1283,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -1278,20 +1338,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -1341,20 +1403,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -1424,10 +1488,11 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -1476,20 +1541,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -1547,20 +1614,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -1587,7 +1656,7 @@ mod tests { context.mine_blocks(1); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid0 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(1, 0, 0, Witness::new())], op_return: Some( Runestone { @@ -1619,17 +1688,24 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid0, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); let txid = context.rpc_server.broadcast_tx(TransactionTemplate { @@ -1651,10 +1727,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -1730,20 +1807,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Common, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ), ] @@ -1778,7 +1857,7 @@ mod tests { context.mine_blocks(1); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid0 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(1, 0, 0, Witness::new())], op_return: Some( Runestone { @@ -1810,20 +1889,27 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid0, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid1 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(2, 1, 0, Witness::new())], op_return: Some( Runestone { @@ -1854,17 +1940,24 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); assert_eq!( context.index.rune_balances(), - [(OutPoint { txid, vout: 0 }, vec![(id, u128::max_value())])] + [( + OutPoint { + txid: txid1, + vout: 0 + }, + vec![(id, u128::max_value())] + )] ); } @@ -1908,10 +2001,11 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -1960,20 +2054,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -2031,20 +2127,22 @@ mod tests { id0, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } ), ( id1, RuneEntry { burned: 0, - rune: Rune(RUNE + 1), divisibility: 0, - supply: u128::max_value(), + etching: txid1, rarity: Rarity::Uncommon, + rune: Rune(RUNE + 1), + supply: u128::max_value(), } ) ] @@ -2079,7 +2177,7 @@ mod tests { context.mine_blocks(1); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid0 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(1, 0, 0, Witness::new())], op_return: Some( Runestone { @@ -2111,10 +2209,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value() / 2, + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value() / 2, } )] ); @@ -2122,12 +2221,15 @@ mod tests { assert_eq!( context.index.rune_balances(), [( - OutPoint { txid, vout: 0 }, + OutPoint { + txid: txid0, + vout: 0 + }, vec![(id, u128::max_value() / 2)] )] ); - let txid = context.rpc_server.broadcast_tx(TransactionTemplate { + let txid1 = context.rpc_server.broadcast_tx(TransactionTemplate { inputs: &[(2, 1, 0, Witness::new())], op_return: Some( Runestone { @@ -2151,10 +2253,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value() / 2, + etching: txid0, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value() / 2, } )] ); @@ -2162,7 +2265,10 @@ mod tests { assert_eq!( context.index.rune_balances(), [( - OutPoint { txid, vout: 0 }, + OutPoint { + txid: txid1, + vout: 0 + }, vec![(id, u128::max_value() / 2)] )] ); @@ -2208,10 +2314,11 @@ mod tests { id, RuneEntry { burned: u128::max_value(), - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -2263,10 +2370,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); @@ -2325,10 +2433,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(RUNE), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(RUNE), + supply: u128::max_value(), } )] ); diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index ba0195d605..86b888c4a4 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -569,7 +569,23 @@ impl Server { ) })?; - Ok(RuneHtml { id, entry }.page(page_config, index.has_sat_index()?)) + let inscription = InscriptionId { + txid: entry.etching, + index: 0, + }; + + let inscription = index + .inscription_exists(inscription)? + .then_some(inscription); + + Ok( + RuneHtml { + id, + entry, + inscription, + } + .page(page_config, index.has_sat_index()?), + ) } async fn runes( @@ -3147,10 +3163,11 @@ mod tests { id, RuneEntry { burned: 0, - rune: Rune(u128::from(21_000_000 * COIN_VALUE)), divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune: Rune(u128::from(21_000_000 * COIN_VALUE)), + supply: u128::max_value(), } )] ); @@ -3182,7 +3199,7 @@ mod tests { server.assert_response_regex(format!("/rune/{rune}"), StatusCode::NOT_FOUND, ".*"); let txid = server.bitcoin_rpc_server.broadcast_tx(TransactionTemplate { - inputs: &[(1, 0, 0, Witness::new())], + inputs: &[(1, 0, 0, inscription("text/plain", "hello").to_witness())], op_return: Some( Runestone { edicts: vec![Edict { @@ -3213,10 +3230,11 @@ mod tests { id, RuneEntry { burned: 0, - rune, divisibility: 0, - supply: u128::max_value(), + etching: txid, rarity: Rarity::Uncommon, + rune, + supply: u128::max_value(), } )] ); @@ -3229,7 +3247,8 @@ mod tests { server.assert_response_regex( format!("/rune/{rune}"), StatusCode::OK, - ".*Rune NVTDIJZYIPU.* + format!( + ".*Rune NVTDIJZYIPU.*

Rune NVTDIJZYIPU

id
@@ -3242,8 +3261,13 @@ mod tests {
0
rarity
uncommon
+
etching
+
{txid}
+
inscription
+
{txid}i0
-.*", +.*" + ), ); } diff --git a/src/templates/rune.rs b/src/templates/rune.rs index abf97ffd6f..47aba70a81 100644 --- a/src/templates/rune.rs +++ b/src/templates/rune.rs @@ -4,6 +4,7 @@ use super::*; pub(crate) struct RuneHtml { pub(crate) entry: RuneEntry, pub(crate) id: RuneId, + pub(crate) inscription: Option, } impl PageContent for RuneHtml { @@ -17,8 +18,8 @@ mod tests { use {super::*, crate::runes::Rune}; #[test] - fn supply_is_displayed_using_divisibility() { - assert_eq!( + fn display() { + assert_regex_match!( RuneHtml { entry: RuneEntry { burned: 123456789123456789, @@ -26,13 +27,17 @@ mod tests { rarity: Rarity::Uncommon, rune: Rune(u128::max_value()), supply: 123456789123456789, + etching: Txid::all_zeros(), }, id: RuneId { height: 10, index: 9, }, - } - .to_string(), + inscription: Some(InscriptionId { + txid: Txid::all_zeros(), + index: 0, + }), + }, "

Rune BCGDENLQRQWDSLRUGSNLBTMFIJAV

id
@@ -45,6 +50,10 @@ mod tests {
9
rarity
uncommon
+
etching
+
0{64}
+
inscription
+
0{64}i0
" ); diff --git a/templates/rune.html b/templates/rune.html index 012c19aae9..0e232f1244 100644 --- a/templates/rune.html +++ b/templates/rune.html @@ -10,4 +10,10 @@

Rune {{ self.entry.rune }}

{{ self.entry.divisibility }}
rarity
{{ self.entry.rarity }}
+
etching
+
{{ self.entry.etching }}
+%% if let Some(inscription) = self.inscription { +
inscription
+
{{ inscription }}
+%% }