Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: TxOut::minimal_non_dust and Script::dust_value #2255

Merged
merged 1 commit into from
Dec 11, 2023

Conversation

junderw
Copy link
Contributor

@junderw junderw commented Dec 6, 2023

Fixes #2192

TxOut::minimal_non_dust has 3 problems.

  1. There is an invisible dependency on Bitcoin Core's default minrelaytxfee value. It has been made explicit.
  2. There is an off by one error. The dust limit comparison uses < and therefore + 1 was not needed. It has been fixed.
  3. It was not returning 0 amount for OP_RETURN outputs.

Script::dust_value has 2 problems.

  1. The dust amount depends on minrelaytxfee which is configurable in Bitcoin Core. This method was not configurable.
  2. The division operation was done before multiplying the byte amount, which can cause small differences when using uncommon scripts and minrelaytxfee values.

@apoelstra
Copy link
Member

concept ACK. I am ambivalent about taking the minrelayfee as an argument. Maybe we should promote it to a constant, take it as an arg to minimal_non_dust, and show example code that passes the constant as the arg?

@yancyribbens
Copy link
Contributor

A test or two would be nice :P

apoelstra
apoelstra previously approved these changes Dec 6, 2023
Copy link
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK b4f1bbb

@tcharding
Copy link
Member

Perhaps this is cleaner?

    pub fn minimal_non_dust(script_pubkey: ScriptBuf) -> Self {
        // This is the default -minrelaytxfee (0.00001 BTC/kvB) in satoshis.
        const MIN_RELAY_TX_FEE: u64 = 1000; // sat/kvB
        const DUST_FEE_RATE: u64 3;

        let len = size_from_script_pubkey(&script_pubkey);
        let len = len
            + if script_pubkey.is_witness_program() {
                32 + 4 + 1 + (107 / 4) + 4
            } else {
                32 + 4 + 1 + 107 + 4
            };

        let limit = (len as u64) * DUST_FEE_RATE * (MIN_RELAY_TX_FEE / 1000);

        TxOut {
            value: Amount::from_sat(limit),
            script_pubkey,
        }
    }

IMO no tests needed for this code change.

@yancyribbens
Copy link
Contributor

IMO no tests needed for this code change.

yeah no tests to begin with so.

@junderw
Copy link
Contributor Author

junderw commented Dec 7, 2023

Discovery: We had duplicate code in TxOut and Script.

I consolidated it to Script and changed stuff around.

@junderw
Copy link
Contributor Author

junderw commented Dec 7, 2023

The commit message needs changing heh.

@Kixunil
Copy link
Collaborator

Kixunil commented Dec 7, 2023

I'm not convinced we should take the parameter since it's hard-coded in Core. As I understand it if Core changes it a lot of applications break so it won't happen.

Also if we're going to add it I'd prefer two method, the second one with _custom suffix instead of Option.

@junderw
Copy link
Contributor Author

junderw commented Dec 7, 2023

I'm not convinced we should take the parameter since it's hard-coded in Core. As I understand it if Core changes it a lot of applications break so it won't happen.

Also if we're going to add it I'd prefer two method, the second one with _custom suffix instead of Option.

The -minrelaytxfee arg for bitcoind will change the value for your node.

If we assume no one changes it, sure, a constant is fine. But Bitcoin Core allows users to change it on startup, so I think we should too.

@junderw junderw changed the title Fix: TxOut::minimal_non_dust Fix: TxOut::minimal_non_dust and Script::dust_value Dec 7, 2023
@junderw
Copy link
Contributor Author

junderw commented Dec 7, 2023

I split things up into a _custom and normal function.

@Kixunil
Copy link
Collaborator

Kixunil commented Dec 7, 2023

-minrelaytxfee is not related to the dust value. It's the total fee rate of a transaction. Dust value only applies to the outputs and as you can see the parameter is not used in Core.

So turns out I either misremembered it or the code changed since when I first read it. This is a dangerous situation - some contracts rely on the value being something specific. E.g. if enough people raised the value LN anchors would break. I don't think it should be easily configurable in Core (but of course we have to allow it in our code).

@apoelstra
Copy link
Member

So turns out I either misremembered it or the code changed since when I first read it. This is a dangerous situation - some contracts rely on the value being something specific. E.g. if enough people raised the value LN anchors would break. I don't think it should be easily configurable in Core (but of course we have to allow it in our code).

If this is true then LN anchors are just broken. The minrelayfee effectively is increased whenever Core nodes' mempools exceed 300Kb (with default settings).

In any case, minrelayfee is purely a policy thing set by individual nodes. It absolutely should be configurable (it is impossible for the network to enforce any relay policy at all, including policy about minimum fees, so it is always "configurable" for somebody willing to do the work).

Whether we want to support different values, for purposes of defining a "dust limit" (another Core policy which nodes are free to implement differently), I don't know. These days it's usually a true assumption that nodes will enforce a dust limit at the default Core limit. In future, when we have consistent mempool backlog exceeding the default mempool size, it usually won't be. In future, plausibly Core will boost the value. Or drop it entirely and depend on the mempool eviction logic to drop low-fee transactions. Or something else entirely.

@junderw
Copy link
Contributor Author

junderw commented Dec 7, 2023

If this is true then LN anchors are just broken. The minrelayfee effectively is increased whenever Core nodes' mempools exceed 300Kb (with default settings).

It should be noted that the dust limit is not tied to the ejection rate (which is dynamic based on the mempool size) but just the runtime parameter.

@apoelstra
Copy link
Member

@junderw oops, you're right. So txes above the minrelayfee will be relayed, they just might be immediately forgotten. This may be an important distinction.

I'm unsure how CPFP interacts with this. If it's possible to CPFP a too-low-fee transaction but not possible to CPFP a below-minrelayfee transaction, then that's a serious difference.

(All assuming that the vast majority of the network is using the default Core policy ofc)

@junderw
Copy link
Contributor Author

junderw commented Dec 7, 2023

Upon looking into the Core code to gather links to the areas where values are parsed and used... I noticed an error on my part.

I made a mistake: it was -dustrelayfee not -minrelaytxfee... but it is still configurable on startup.

sanket1729
sanket1729 previously approved these changes Dec 7, 2023
Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 09664c0

Copy link
Collaborator

@Kixunil Kixunil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking but I would prefer my comments to be addressed.

bitcoin/src/blockdata/script/borrowed.rs Outdated Show resolved Hide resolved
bitcoin/src/blockdata/script/borrowed.rs Outdated Show resolved Hide resolved
bitcoin/src/blockdata/script/borrowed.rs Outdated Show resolved Hide resolved
bitcoin/src/blockdata/script/borrowed.rs Outdated Show resolved Hide resolved
TxOut::minimal_non_dust has 3 problems.

1. There is an invisible dependency on Bitcoin Core's default minrelaytxfee value. It has been made explicit.
2. There is an off by one error. The dust limit comparison uses < and therefore `+ 1` was not needed. It has been fixed.
3. It was not returning 0 amount for OP_RETURN outputs.

Script::dust_value has 2 problems.

1. The dust amount depends on minrelaytxfee which is configurable in Bitcoin Core. This method was not configurable.
2. The division operation was done before multiplying the byte amount, which can cause small differences when using uncommon scripts and minrelaytxfee values.
Copy link
Collaborator

@Kixunil Kixunil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 1b23220

Copy link
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 1b23220

@junderw
Copy link
Contributor Author

junderw commented Dec 10, 2023

Aaaahhh! Just realized the commit message still mistakenly refers to minrelaytxfee...... (On Mobile RN)

@Kixunil
Copy link
Collaborator

Kixunil commented Dec 11, 2023

I can tolerate sligthly wrong commit message here.

@apoelstra apoelstra merged commit c534027 into rust-bitcoin:master Dec 11, 2023
29 checks passed
@tcharding
Copy link
Member

Was there a reason we didn't deprecate dust_value?

This change is hinders the upgrade path for upcoming 0.32.0 release.

@apoelstra
Copy link
Member

I think we just forgot. Should we put it back before release?

apoelstra added a commit that referenced this pull request Mar 24, 2024
c17db32 Pub back in deprecated dust_value (Tobin C. Harding)

Pull request description:

  When we renamed `dust_value` to `minimal_non_dust` we forgot to keep the original and deprecated it, doing so assists with the upgrade path.

  Put back in deprecated `dust_value`, linking to the rename.

  Renamed in #2255, found while testing upgrade of downstream software.

ACKs for top commit:
  tcharding:
    > ACK [c17db32](c17db32) I _think_ this matches the behavior of the old version
  apoelstra:
    ACK c17db32 I *think* this matches the behavior of the old version
  sanket1729:
    ACK c17db32

Tree-SHA512: 28e1bd2e1a0fd13c78c70ad2667b72b3bf649c293201b79c86c00f09d0126389ebaeb430b8dd32aeeec3d60cbd8761ae949f5784a5ea7756b1b9ae77ec96ce61
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Script::dust_value method name disagrees with the documentation
6 participants