Skip to content

Commit

Permalink
Derive reserved rune names from rune ID (ordinals#3412)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey authored Mar 29, 2024
1 parent 8381cb1 commit 5de81cf
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 21 deletions.
19 changes: 12 additions & 7 deletions crates/ordinals/src/rune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ impl Rune {
self.0 >= Self::RESERVED
}

pub fn reserved(n: u128) -> Option<Self> {
Some(Rune(Self::RESERVED.checked_add(n)?))
pub fn reserved(block: u64, tx: u32) -> Self {
Self(
Self::RESERVED
.checked_add(u128::from(block) << 32 | u128::from(tx))
.unwrap(),
)
}

pub fn commitment(self) -> Vec<u8> {
Expand Down Expand Up @@ -360,13 +364,14 @@ mod tests {
"AAAAAAAAAAAAAAAAAAAAAAAAAAA".parse::<Rune>().unwrap().0,
);

assert_eq!(Rune::reserved(0), Some(Rune(Rune::RESERVED)));
assert_eq!(Rune::reserved(1), Some(Rune(Rune::RESERVED + 1)));
assert_eq!(Rune::reserved(0, 0), Rune(Rune::RESERVED));
assert_eq!(Rune::reserved(0, 1), Rune(Rune::RESERVED + 1));
assert_eq!(Rune::reserved(1, 0), Rune(Rune::RESERVED + (1 << 32)));
assert_eq!(Rune::reserved(1, 1), Rune(Rune::RESERVED + (1 << 32) + 1));
assert_eq!(
Rune::reserved(u128::MAX - Rune::RESERVED),
Some(Rune(u128::MAX))
Rune::reserved(u64::MAX, u32::MAX),
Rune(Rune::RESERVED + (u128::from(u64::MAX) << 32 | u128::from(u32::MAX))),
);
assert_eq!(Rune::reserved(u128::MAX - Rune::RESERVED + 1), None);
}

#[test]
Expand Down
20 changes: 15 additions & 5 deletions docs/src/runes/specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,8 @@ runestone is a cenotaph.
##### Rune

The `Rune` field contains the name of the rune being etched. If the `Etching`
flag is set, but the `Rune` field is omitted, a reserved rune name is
allocated, starting with `AAAAAAAAAAAAAAAAAAAAAAAAAAA` and increasing by one
with each such reserved rune allocated.
flag is set but the `Rune` field is omitted, a reserved rune name is
allocated.

##### Premine

Expand Down Expand Up @@ -428,8 +427,19 @@ And so on and so on.

Rune names `AAAAAAAAAAAAAAAAAAAAAAAAAAA` and above are reserved.

`rune` may be omitted, in which case the first unallocated rune name, starting
at `AAAAAAAAAAAAAAAAAAAAAAAAAAA` and increasing by one each time, is etched.
If `rune` is omitted a reserved rune name is allocated as follows:

```rust
fn reserve(block: u64, tx: u32) -> Rune {
Rune(
6402364363415443603228541259936211926
+ (u128::from(block) << 32 | u128::from(tx))
)
}
```

`6402364363415443603228541259936211926` corresponds to the rune name
`AAAAAAAAAAAAAAAAAAAAAAAAAAA`.

If `rune` is present, it must be unlocked as of the block in which the etching
appears.
Expand Down
2 changes: 1 addition & 1 deletion src/index/updater/rune_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ impl<'a, 'tx, 'client> RuneUpdater<'a, 'tx, 'client> {
.statistic_to_count
.insert(&Statistic::ReservedRunes.into(), reserved_runes + 1)?;

Rune::reserved(reserved_runes.into()).unwrap()
Rune::reserved(self.height.into(), tx_index)
};

Ok(Some(Etched {
Expand Down
14 changes: 7 additions & 7 deletions src/runes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ mod tests {
output: 0,
}],
etching: Some(Etching {
rune: Some(Rune::reserved(0).unwrap()),
rune: Some(Rune::reserved(0, 0)),
..default()
}),
..default()
Expand All @@ -252,7 +252,7 @@ mod tests {
output: 0,
}],
etching: Some(Etching {
rune: Some(Rune(Rune::reserved(0).unwrap().n() - 1)),
rune: Some(Rune(Rune::reserved(0, 0).n() - 1)),
premine: Some(u128::MAX),
..default()
}),
Expand All @@ -268,7 +268,7 @@ mod tests {
block: id.block,
etching: txid,
spaced_rune: SpacedRune {
rune: Rune(Rune::reserved(0).unwrap().n() - 1),
rune: Rune(Rune::reserved(0, 0).n() - 1),
spacers: 0,
},
premine: u128::MAX,
Expand Down Expand Up @@ -320,7 +320,7 @@ mod tests {
block: id0.block,
etching: txid0,
spaced_rune: SpacedRune {
rune: Rune::reserved(0).unwrap(),
rune: Rune::reserved(id0.block, id0.tx),
spacers: 0,
},
premine: u128::MAX,
Expand Down Expand Up @@ -372,7 +372,7 @@ mod tests {
block: id0.block,
etching: txid0,
spaced_rune: SpacedRune {
rune: Rune::reserved(0).unwrap(),
rune: Rune::reserved(id0.block, id0.tx),
spacers: 0,
},
premine: u128::MAX,
Expand All @@ -386,7 +386,7 @@ mod tests {
block: id1.block,
etching: txid1,
spaced_rune: SpacedRune {
rune: Rune::reserved(1).unwrap(),
rune: Rune::reserved(id1.block, id0.tx),
spacers: 0,
},
premine: u128::MAX,
Expand Down Expand Up @@ -907,7 +907,7 @@ mod tests {
block: id.block,
etching: txid0,
spaced_rune: SpacedRune {
rune: Rune::reserved(0).unwrap(),
rune: Rune::reserved(2, 1),
spacers: 0,
},
timestamp: id.block,
Expand Down
2 changes: 1 addition & 1 deletion tests/wallet/batch_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1707,7 +1707,7 @@ fn etch_reserved_rune_error() {
etching: Some(batch::Etching {
divisibility: 0,
rune: SpacedRune {
rune: Rune::reserved(0).unwrap(),
rune: Rune::reserved(0, 0),
spacers: 0,
},
premine: "1000".parse().unwrap(),
Expand Down

0 comments on commit 5de81cf

Please sign in to comment.