Saturday morning, 8:12 am. Awake. Kids screaming. Weekend. Coffee. What’s happening in the world… Laptop. Checking some messages. Chain fully online again? nice.
Wait, what?!
>>> import bittensor as bt
>>> st = bt.subtensor(network='local')
>>> st.query_module('SubtensorModule','NetworkLastLockCost').value/1e9
100.0
But that means… [digging through subtensor code] https://github.com/opentensor/subtensor/blob/main/pallets/subtensor/src/root.rs#L1229 less than 200 Tao to register the next network!
🤯 This is my chance. All those ideas, all those rants about things I would do differently… at a 90% discount. Calling my miner friend. Two minutes later, we decide to give it a shot. How long do we have?
>>> st.block - st.query_module('SubtensorModule','NetworkLastRegistered').value
3021
>>> st.query_module('SubtensorModule','NetworkRateLimit').value
7200
>>> (7200-3021)*12/3600
13.93
Okay, 14 hours left to figure out how we get our register_subnet
extrinsic to be processed first, in the right block. Can we actually see extrinsics as they accumulate somewhere in the chain?
$ cd /opt/conda/lib/python3.10/site-packages/substrateinterface/
$ rgrep extrinsics
...
base.py: def retrieve_pending_extrinsics(self) -> list:
base.py: Retrieves and decodes pending extrinsics from the node's transaction pool
...
Sounds good?
>>> st.substrate.retrieve_pending_extrinsics()
Okay, this could work…
>>> [e.value['call']['call_function'] for e in st.substrate.retrieve_pending_extrinsics()]
This works. But we are a bit late to the party, people are already trying to register or sharpening their tools. Time left? 13 hours. Ohh that’s right, cinema with kids – Despicable Me, part 4 in 3D – only 8 hours left now. Picking up another kid from a party. Dinner. 5 hours left…
Let’s monitor this properly, in a loop.
>>> def print_exts(filter_func):
... ext = st.substrate.retrieve_pending_extrinsics()
... for i,e in enumerate(ext):
... if e.value['call']['call_function'] != filter_func:
... continue
... addr = e.value['address']
... func = e.value['call']['call_function']
... print(f"{subtensor.block}-{i}: {func} {addr}")
...
>>> print_exts('register_subnet')
3378312-1: register_subnet 5H...
3378312-19: register_subnet 5G...
3378312-20: register_subnet 5G...
3378312-24: register_subnet 5F...
Nice. Now loop this thing, add timestamps etc. (Full code: https://github.com/coldint/tools/bt_scan_extrinsics.py)
So where would our calls land if we were to script the registration, and loop btcli
? One registration per 36 seconds at position 15 or higher – this will never win us the subnet. Let’s optimize… Still not on top. Let’s optimize some more. Why not sign the extrinsic before waiting for the next block? What is the bare minimum alternative to substrate.block
in our waiting loop?
block = st.block
ws = st.substrate.websocket
payload = {
"jsonrpc": "2.0", "method": "chain_getHeader", "params": [None], "id": 0
}
get_block_ws_data = json.dumps(payload)
while True:
ws.send(get_block_ws_data)
response = json.loads(ws.recv())
b = int(response["result"]["number"],0)
if b != block: break
So we cut out bittensor
and substrateinterface
, but does this even work?! Apparently it does, because our coldkey is now consistently at the top position. It should all work out now. Fingers crossed and just wait for block 3378782
. Less than one hour left, but well before the deadline.
Countdown starts while I watch the extrinsics, flooding my screen. Even more players emerge. Is the chain slowing down or is my brain accelerating?
3378778…
3378779…
3379780…
3378781…
3378782…
🚀
>>> [(k.value,v.value) for k,v in st.query_map_subtensor('SubnetOwner') if v.value.startswith('5HHHHH')]
[(29, '5HHHHHzgLnYRvnKkHd45cRUDMHXTSwx7MjUzxBrKbY4JfZWn')]
We’ve got it! SN29 is officially ours… and now what?
0 Comments