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

Correct explanation of partialFee #221

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

maltekliemann
Copy link
Contributor

According to https://wiki.polkadot.network/docs/build-node-interaction#fetching-a-block, partialFee contains the weight and length fee, not just the weight fee.

According to https://wiki.polkadot.network/docs/build-node-interaction#fetching-a-block, `partialFee` contains the weight and length fee, not just the weight fee.
@shawntabrizi
Copy link
Member

We should look to the code for real behavior, not just wiki: https://github.com/paritytech/substrate/blob/master/frame/transaction-payment/src/lib.rs#L506

impl<Balance: AtLeast32BitUnsigned + Copy> FeeDetails<Balance> {
	/// Returns the final fee.
	///
	/// ```ignore
	/// final_fee = inclusion_fee + tip;
	/// ```
	pub fn final_fee(&self) -> Balance {
		self.inclusion_fee
			.as_ref()
			.map(|i| i.inclusion_fee())
			.unwrap_or_else(|| Zero::zero())
			.saturating_add(self.tip)
	}
}

So it does include tip

@maltekliemann
Copy link
Contributor Author

maltekliemann commented Dec 14, 2021

@shawntabrizi I believe you're looking at the wrong function. Isn't the payment info populated by query_info?

I mean... the transaction info cannot contain any information about the tip before signing, right?

@shawntabrizi
Copy link
Member

I believe the tip information is included in the same extrinsic payload that is signed and submitted to chain. Pretty sure I am looking at the right function, as I am not aware of the term "partialFee" being used elsewhere.

@maltekliemann
Copy link
Contributor Author

@shawntabrizi Thank you for helping again, Shawn. I'm fairly clueless about javascript/typescript, so I'm not sure exactly how the code of polkadot.js works. But I think we may not be talking about the same thing. Apologies for the long comment, I'll try to explain.

First of all, I understand that the tip is part of the payload that is submitted to the chain. The question is which types of fee are included in the partialFee field of the objects returned by tx.paymentInfo and api.rpc.payment.queryInfo. For both cases, I've created an example to demonstrate behavior:

  1. For tx.paymentInfo, I use the following code:

    const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api");
    
    ALICE = "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5";
    ALICE_KEY = "//ALICE";
    BOB = "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3";
    
    BASE = 1000000000000;
    MILLI = BASE / 1000;
    
    async function main() {
      const provider = new WsProvider("ws://127.0.0.1:9944");
      const api = await ApiPromise.create({ provider });
    
      const keyring = new Keyring({ type: "sr25519" });
      alice = keyring.addFromUri(ALICE_KEY);
    
      const tx = api.tx.balances.transfer(BOB, 10 * MILLI);
      const paymentInfo = await tx.paymentInfo(alice);
      const paymentInfoWithTip = await tx.paymentInfo(alice, { tip: 100 * BASE });
      console.log(`Partial fee (no tip): ${paymentInfo.partialFee.toNumber()}`);
      console.log(`Partial fee (w/ tip): ${paymentInfoWithTip.partialFee.toNumber()}`);
      process.exit();
    }
    
    main()
      .catch(console.error);

    The idea here is that, according to the docs:

    A wrapper for this is available on the tx itself, taking exactly the same parameters as you would pass to a normal .signAndSend operation, specifically .paymentInfo(sender, <any options>).

    Nevertheless, the fees are almost identical, despite the generous tip:

    Partial fee (no tip): 171485576
    Partial fee (w/ tip): 177485576
    

    The difference between the tips is due to the length of the payload, I guess?

  2. For api.rpc.payment.queryInfo, check the following transaction: https://westend.subscan.io/extrinsic/0x3a6f9eb77a9a75201b60b1aed65e4d63b9b4772ab5acfd469bc604833b06c49e with fee 0.01610000137 WND (+0.1 WND tips). Run the following code:

    const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api");
    
    async function main() {
      const provider = new WsProvider("ws://127.0.0.1:9944");
      const api = await ApiPromise.create({ provider });
    
      let blockHash = await api.rpc.chain.getBlockHash(8685417);
      let block = await api.rpc.chain.getBlock(blockHash.toString());
      let extrinsic = block.block.extrinsics.filter((extrinsic) => { return extrinsic.hash.toHex() == 0x3a6f9eb77a9a75201b60b1aed65e4d63b9b4772ab5acfd469bc604833b06c49e} )[0];
      const queryInfo = await api.rpc.payment.queryInfo(extrinsic.toHex(), blockHash);
      console.log(queryInfo.partialFee.toNumber());
      process.exit();
    }
    
    main().catch(console.error);

    This prints 16100001370, so the tip is not included.

Regarding the underlying Rust code, I'm not sure I understand what you're saying either. The term partial fee appears only in the code of query_info, which, I presume, is used to populate the return value of tx.paymentInfo and api.rpc.payment.queryInfo. You write:

Pretty sure I am looking at the right function, as I am not aware of the term "partialFee" being used elsewhere.

I don't see any relation between partial_fee/partialFee and compute_fee_raw or FeeDetails, other than that query_info calls compute_free_raw, but it's called with a tip parameter of zero, so it doesn't really matter. Am I missing something important here?

So, long story short, I'm not sure I understand where you're going with the pieces of code you posted, but I'm fairly convinced that the behavior of polkadot.js and the polkadot-wiki are correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants