owned this note
owned this note
Published
Linked with GitHub
# Statemint HRMP Channel Postmortem & Fix
Referendum 62 ([Polkassembly](https://polkadot.polkassembly.io/referendum/62), [Subscan](https://polkadot.subscan.io/referenda/62)) 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:
![](https://i.imgur.com/6PPbRyo.png)
([Stage One Dispatch block 10,557,894](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc.polkadot.io#/explorer/query/0xeb4e4bbafe563b0cb1dc503328327a8e2ca5f0529b8bf53144dc37182c6ba11b))
Stage two also worked as expected. Statemint received the message and sent one back:
![](https://i.imgur.com/2lsqxVm.png)
([Stage Two Dispatch block 1,405,859](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fstatemint-rpc.polkadot.io#/explorer/query/0xb50f5578e7cb5102f5db60658168de0025eef50b054280d4c78138ec943d755c))
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).
![](https://i.imgur.com/iltMHqo.png)
Second, because the call wasn't executed, some of the fee assets (about 1.953 DOT) got _trapped_.
![](https://i.imgur.com/GzVqpNN.png)
([Stage Three Dispatch block 10,557,896](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc.polkadot.io#/explorer/query/0x20314baf2c9b31a063d0639451569b5977bf03da6ad0b421a3d0459dafddb3ae))
## 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:
```python=
>>> # 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
- [Call sent](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestmint-rpc.polkadot.io#/extrinsics/decode/0x1f00010100020c0004000000000b00204aa9d10113000000000b00204aa9d101000600821a06002d01040200fe747dadf0f62c7d1bac6988a156fdd41cf2d14ccfdc15e289512a7073bbf2660070617261e80300000000000000000000000000000000000000000000000000000b00407a10f35a)
- [Westend Block Sent](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestend-rpc.polkadot.io#/explorer/query/0xf262e7fb07eb91c12d2cec3da078235e0f5182b63f56603a2987dc4a1d33b2e8)
- [Westmint Block Received/Sent](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestmint-rpc.polkadot.io#/explorer/query/0x10d071619b7aded9009c5e80a2b1cec2f6e4f9ca25772706e6e9fa4e77c0a11b)
- [Westend Block Received](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestend-rpc.polkadot.io#/explorer/query/0x7dde59327cfa539c73e39330ec8971ae831aeeaa88fb6123a3ae386893124bff)
Trap ID: `0x46fd62c0e972be9ab4376439b81e255eeb84f9beae8c9f74972b89c37f7962d5`
Trap Amount: `1997805887113`
![image](https://user-images.githubusercontent.com/25483142/172878291-f19cf633-c6ed-4b92-b625-f9c80bc64f9c.png)
### Step 2: Claim Assets and Execute Call
- [Call to send to Westmint](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestmint-rpc.polkadot.io#/extrinsics/decode/0x1f0001010002141804000000000b899e8226d101000013000000000b899e8226d1010006000700e40b54025800084c6d79206e616d6520697320776573746d696e74140d01010000000004000101001299557001f55815d3fcb53c74463acb0cf6d14d4639b340982c60877f384609) (just a `remark_with_event` with an absurdly high weight, refunding the extra to an account).
- [Westend Block Sent](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestend-rpc.polkadot.io#/explorer/query/0xfc1598cd78f0c1f4173d62960681e6c6ccfd783bb5d70eee47775441ff1e0c1e)
- [Westmint Block Received](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestmint-rpc.polkadot.io#/explorer/query/0xe8fcb339fe6d4469bb21d28926e92022a931140f083752424bbe6d48434bba27)
- [Westend Block Received](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fwestend-rpc.polkadot.io#/explorer/query/0x92e9a757c100f5bb125b2aba61e65b572f4e7c2a7e64e04800fe3383fa0ac843)
### Results
It worked :tada:
![image](https://user-images.githubusercontent.com/25483142/172879532-23d08ae2-7e02-4b54-9209-3a8937f22903.png)
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](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc.polkadot.io#/extrinsics/decode/0x1a04283c01d00700003c00d0070000e8030000009001003c01d40700003c00d4070000e8030000009001003c01d60700003c00d6070000e8030000009001003c01db0700003c00db070000e8030000009001003c01dc0700003c00dc070000e803000000900100) has a hash of `0xa729c49f3f2482d68e82420782f2b8bbd51643ef3794458914f81990377c599e`.
![](https://i.imgur.com/behUCnC.png)
![](https://i.imgur.com/pAzLDFl.png)
### 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](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fstatemint-rpc.polkadot.io#/extrinsics/decode/0x1f00010100021418040000000007140a1d8c040000130000000007140a1d8c040006000700e40b54029d011a04283c01d00700003c00d0070000e8030000009001003c01d40700003c00d4070000e8030000009001003c01d60700003c00d6070000e8030000009001003c01db0700003c00db070000e8030000009001003c01dc0700003c00dc070000e803000000900100140d01010000000004000101006d6f646c70792f74727372790000000000000000000000000000000000000000) has a hash of `0x8555b29914baea2c198cb543f87ec53f751b158bbe75de48239bc817ad81ed8a`.
Of course, we are sending back to the Relay Chain:
![](https://i.imgur.com/xWdwly0.png)
Then we claim the trapped assets and buy execution with them:
![](https://i.imgur.com/F3dxYiA.png)
Transact: Where the fun happens:
![](https://i.imgur.com/MnMM8E5.png)
And finally we refund the leftover DOT to the Treasury:
![](https://i.imgur.com/NgOCqfo.png)
### Send it from Polkadot
This is all pretty standard stuff by now. We just send the above instructions to Statemint.
[This call](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc.polkadot.io#/extrinsics/decode/0x630001000100a10f0204060202286beefd021f00010100021418040000000007140a1d8c040000130000000007140a1d8c040006000700e40b54029d011a04283c01d00700003c00d0070000e8030000009001003c01d40700003c00d4070000e8030000009001003c01d60700003c00d6070000e8030000009001003c01db0700003c00db070000e8030000009001003c01dc0700003c00dc070000e803000000900100140d01010000000004000101006d6f646c70792f74727372790000000000000000000000000000000000000000) has a hash of `0xed77d6a7344d9ddf889de96927c89880ffb3ab766b5ede2cc7f5a08167791bb3` and **should be the hash of the proposal for referendum**.
![](https://i.imgur.com/5otpvl7.png)