Skip to content

Commit

Permalink
Working on fixing how send-many works with reinscriptions.
Browse files Browse the repository at this point in the history
  • Loading branch information
gmart7t2 committed Nov 19, 2023
1 parent 663aaa6 commit a1d3a1e
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 26 deletions.
12 changes: 11 additions & 1 deletion src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1222,9 +1222,19 @@ impl Index {
&self,
utxos: &BTreeMap<OutPoint, Amount>,
) -> Result<BTreeMap<SatPoint, InscriptionId>> {
let mut result = BTreeMap::new();

result.extend(self.get_inscriptions_vector(utxos)?.into_iter());
Ok(result)
}

pub(crate) fn get_inscriptions_vector(
&self,
utxos: &BTreeMap<OutPoint, Amount>,
) -> Result<Vec<(SatPoint, InscriptionId)>> {
let rtx = self.database.begin_read()?;

let mut result = BTreeMap::new();
let mut result = Vec::new();

let table = rtx.open_multimap_table(SATPOINT_TO_INSCRIPTION_ID)?;
for utxo in utxos.keys() {
Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/wallet/inscriptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub(crate) fn run(options: Options) -> SubcommandResult {
index.update()?;

let unspent_outputs = index.get_unspent_outputs(Wallet::load(&options)?)?;
let inscriptions = index.get_inscriptions(&unspent_outputs)?;
let inscriptions = index.get_inscriptions_vector(&unspent_outputs)?;

let explorer = match options.chain() {
Chain::Mainnet => "https://ordinals.com/inscription/",
Expand Down
81 changes: 57 additions & 24 deletions src/subcommand/wallet/sendmany.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,50 +82,86 @@ impl SendMany {
// we get a tree <SatPoint, InscriptionId>, and turn it into
// a tree <InscriptionId, SatPoint>
let mut inscriptions = BTreeMap::new();
for (satpoint, inscriptionid) in index.get_inscriptions(&unspent_outputs)? {
for (satpoint, inscriptionid) in index.get_inscriptions_vector(&unspent_outputs)? {
inscriptions.insert(inscriptionid, satpoint);
}

let mut ordered_inscriptions = Vec::new();
let mut total_value = 0;
let mut inputs = Vec::new();
let mut outputs = Vec::new();

let mut requested_satpoints: BTreeMap<SatPoint, (InscriptionId, Address)> = BTreeMap::new();

// this loop checks that we own all the listed inscriptions, and that we aren't listing the same sat more than once
for (inscriptionid, address) in &requested {
if !inscriptions.contains_key(&inscriptionid) {
bail!("inscriptionid {} isn't in the wallet", inscriptionid.to_string());
}

let satpoint = inscriptions[&inscriptionid];
if requested_satpoints.contains_key(&satpoint) {
bail!("inscriptionid {} is on the same sat as {}, and both appear in the CSV file", inscriptionid.to_string(), requested_satpoints[&satpoint].0);
}
requested_satpoints.insert(satpoint, (inscriptionid.clone(), address.clone()));
}
/*
eprintln!("requested_satpoints:");
for (satpoint, (inscriptionid, address)) in &requested_satpoints {
eprintln!(" {} {} {}", satpoint.to_string(), inscriptionid.to_string(), address);
}
eprintln!("\n");
*/
// this loop handles the inscriptions in order of offset in each utxo
while !requested.is_empty() {
let mut inscriptions_on_outpoint = Vec::new();
// pick the first remaining inscriptionid from the list
for (inscriptionid, _address) in &requested {
if !inscriptions.contains_key(&inscriptionid) {
bail!("inscriptionid {} isn't in the wallet", inscriptionid.to_string());
}

let satpoint = inscriptions[inscriptionid];
let outpoint = satpoint.outpoint;
// look up which utxo it's in
let outpoint = inscriptions[inscriptionid].outpoint;
// get a list of the inscriptions in that utxo
inscriptions_on_outpoint = index.get_inscriptions_on_output_with_satpoints(outpoint)?;
// sort it by offset
inscriptions_on_outpoint.sort_by_key(|(s, _)| s.offset);
for (_satpoint, outpoint_inscriptionid) in &inscriptions_on_outpoint {
if !requested.contains_key(&outpoint_inscriptionid) {
// make sure that they are all in the csv file
for (satpoint, outpoint_inscriptionid) in &inscriptions_on_outpoint {
if !requested_satpoints.contains_key(&satpoint) {
bail!("inscriptionid {} is in the same output as {} but wasn't in the CSV file", outpoint_inscriptionid.to_string(), inscriptionid.to_string());
}
}
break;
}

// create an input for the first inscription of each utxo
let (first_satpoint, _first_inscription) = inscriptions_on_outpoint[0];
let first_offset = first_satpoint.offset;
let first_outpoint = first_satpoint.outpoint;
let utxo_value = unspent_outputs[&first_outpoint].to_sat();

if first_offset != 0 {
bail!("the first inscription in {} is at non-zero offset {}", first_outpoint, first_offset);
}

eprintln!("\noutput {}, worth {}:", first_outpoint, utxo_value);
total_value += utxo_value;

inputs.push(first_outpoint);

/*
eprintln!("before:");
for (satpoint, inscriptionid) in &inscriptions_on_outpoint {
eprintln!(" inscriptions_on_outpoint has {} {}", satpoint.to_string(), inscriptionid.to_string());
}
*/
// filter out the inscriptions that aren't in our list - these are inscriptions that are on the same sat as the ones we listed
// we want to remove just the ones where the satpoint is requested but the inscriptionid isn't
// ie. keep the ones where the satpoint isn't requested or the inscriptionid is
inscriptions_on_outpoint = inscriptions_on_outpoint.into_iter().filter(
|(satpoint, inscriptionid)| !requested_satpoints.contains_key(&satpoint) || requested.contains_key(&inscriptionid)
).collect();
/*
eprintln!("after:");
for (satpoint, inscriptionid) in &inscriptions_on_outpoint {
eprintln!(" inscriptions_on_outpoint has {} {}", satpoint.to_string(), inscriptionid.to_string());
}
*/
// create an output for each inscription in this utxo
for (i, (satpoint, inscriptionid)) in inscriptions_on_outpoint.iter().enumerate() {
let destination = &requested[inscriptionid];
// eprintln!("looking for satpoint {}", satpoint.to_string());
let destination = &requested_satpoints[&satpoint].1;
let offset = satpoint.offset;
let value = if i == inscriptions_on_outpoint.len() - 1 {
utxo_value - offset
Expand All @@ -138,14 +174,15 @@ impl SendMany {
bail!("inscription {} at {} is only followed by {} sats, less than dust limit {} for address {}",
inscriptionid, satpoint.to_string(), value, dust_limit, destination);
}

eprintln!(" {} : offset: {}, value: {}\n id: {}\n dest: {}", i, offset, value, inscriptionid, destination);
outputs.push(TxOut{script_pubkey, value});

// remove each inscription in this utxo from the list
requested.remove(&inscriptionid);
}
ordered_inscriptions.extend(inscriptions_on_outpoint);
}

// get a list of available unlocked cardinals
let cardinals = Self::get_cardinals(unspent_outputs, locked_outputs, inscriptions);

if cardinals.is_empty() {
Expand All @@ -156,10 +193,6 @@ impl SendMany {
let (cardinal_outpoint, cardinal_value) = cardinals[0];
eprintln!("\ncardinal:\n {}, worth {}", cardinal_outpoint.to_string(), cardinal_value);

eprintln!("\ninputs without cardinal: {}", total_value);
total_value += cardinal_value;
eprintln!("inputs with cardinal: {}", total_value);

inputs.push(cardinal_outpoint);

let change_address = get_change_address(&client, chain)?;
Expand All @@ -176,7 +209,7 @@ impl SendMany {
bail!("cardinal ({}) is too small: we need enough for fee {} plus dust limit {} = {}", cardinal_value, fee, dust_limit, needed);
}
let value = cardinal_value - fee;
eprintln!("vsize: {}, fee: {}, change: {}\n", vsize, fee, value);
eprintln!("vsize: {}, fee: {}, change: {}", vsize, fee, value);
let last = outputs.len() - 1;
outputs[last] = TxOut{script_pubkey, value};

Expand Down

0 comments on commit a1d3a1e

Please sign in to comment.