owned this note changed 3 years ago
Linked with GitHub

Statemint HRMP Channel Postmortem & Fix

Referendum 62 (Polkassembly, Subscan) was supposed to create bi-directional HRMP channels with five other parachains. It failed due to not enough weight being used. Here's a rundown of what was correct, what needs fixing, and how to do better in the future.

Stage one worked as expected and sent a message to Statemint:


(Stage One Dispatch block 10,557,894)

Stage two also worked as expected. Statemint received the message and sent one back:


(Stage Two Dispatch block 1,405,859)

Stage 3 is where the problems came up. First, the instructions to open the HRMP channels failed because I grossly underestimated the weight required (more on that later).

Second, because the call wasn't executed, some of the fee assets (about 1.953 DOT) got trapped.


(Stage Three Dispatch block 10,557,896)

Fixing Stuff

A new proposal should claim the assets and re-do the HRMP channels with sufficient weight. I confess to a bit of laziness here; I always used 1 billion weight for other calls and it was normally an over-estimate (authorize_upgrade e.g. is about 1 million).

First, let's do a more rigorous job of calculating weight:

>>> # Some constants >>> WEIGHT_PER_SECOND = 1_000_000_000_000 >>> WEIGHT_PER_NANOS = WEIGHT_PER_SECOND / 1000 / 1000 / 1000 >>> # Database read/write costs >>> reads = 20_499 * WEIGHT_PER_NANOS >>> writes = 83_471 * WEIGHT_PER_NANOS >>> # Weight for initiating a channel: >>> init_channel = 54_952_000 + 10 * reads + 5 * writes >>> # Weight for accepting a channel: >>> accept_channel = 47_965_000 + 7 * reads + 4 * writes >>> # We are doing 5 of them: >>> total = 5 * (init_channel + accept_channel) >>> print(total) 6013195000

That's slightly over 6 billion. My 1 billion estimate was pitiful.

Confirming this estimate with Sidecar (what I should have done first) I get:

{
	"weight": "6173973000",
	"class": "Normal",
	"partialFee": "217000724"
}

So also a little over 6 billion (this is overly conservative as there is a "fake" signature on the call to access the transaction fee info and validating that adds a little bit of weight).

Now we can construct the call. We have 1.935 DOT in the trap, and the estimated fee is 0.0217 DOT, so we shouldn't need any more from the Treasury. We can just claim them, then buy all the execution we need, and still return the leftovers to the Treasury.

Verifying on Westend

Westend and Polkadot aren't exactly the same, notably in the WeightToFee conversion, but we should really have plenty of DOT to buy execution with, given that 0.047 DOT bought 4 billion weight, 1.935 should easily buy 10 (overestimating the 6, just for some safety).

I tested out a fix on Westend by trapping some assets and then claiming them and executing some follow-on instructions. They weren't establishing HRMP channel instructions, but that shouldn't matter.

Step 1: Trap Assets Again

Trap ID: 0x46fd62c0e972be9ab4376439b81e255eeb84f9beae8c9f74972b89c37f7962d5
Trap Amount: 1997805887113

image

Step 2: Claim Assets and Execute Call

Results

It worked

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

image

Now we'll just change "TESTNET-ACCOUNT" to "the Treasury".

Polkadot

Let's reconstruct the needed calls.

Call to Execute on Polkadot

One thing to note is that I've taken advantage of the new force_batch call. This will attempt each call, continuing to the end even if one fails. If one team were to remove their channel request, this will still allow the other channels to open.

This call has a hash of 0xa729c49f3f2482d68e82420782f2b8bbd51643ef3794458914f81990377c599e.


Call to Execute on Statemint

This is where things get different from previous HRMP channel openings because we need to claim the assets from the trap first.

This call has a hash of 0x8555b29914baea2c198cb543f87ec53f751b158bbe75de48239bc817ad81ed8a.

Of course, we are sending back to the Relay Chain:

Then we claim the trapped assets and buy execution with them:

Transact: Where the fun happens:

And finally we refund the leftover DOT to the Treasury:

Send it from Polkadot

This is all pretty standard stuff by now. We just send the above instructions to Statemint.

This call has a hash of 0xed77d6a7344d9ddf889de96927c89880ffb3ab766b5ede2cc7f5a08167791bb3 and should be the hash of the proposal for referendum.

Select a repo