Question about protocol and race conditions


#1

Hello everyone, I’m looking through the protocol code at the moment (there is a lot of it) and I have a question about the specifics of how pre-orders work.

So I understand the process works something like this at the moment:

  1. Commit to the name you want to register: hash(NS_suffix, script_pub, name_you_are_registering)
  2. Then reveal the pre-image to register the name to prevent passive attackers stealing a name during the registration process.

Now what would happen if an attacker committed to a bunch of probable domains by going through step 1 and then waiting until a client does step 2 (indicating their interest) to hijack the name?

How do you decide who wins then? For example, you now have two competing transactions to try claim a registration operation for the same address. Now how does the client handle that? If its random and based on whoever confirms first then you have a race condition. If the consensus layer awards the registration to the earliest person to commit then you can still be attacked via squatters.

In any case, the client needs to be able to detect this change during the consensus phase between step 1 -> step 2. So if this isn’t being anticipated the client can receive unexpected results. If anyone can tell me more about this I’d appreciate it. I am still looking through the code myself.


#2

I think I’ve found the answer to my question in the code. This is surprisingly well documented code, by the way.

So in file: https://github.com/blockstack/blockstack-core/blob/master/blockstack/lib/operations/namespacereveal.py#L113 Line, 113

It seems to indicate that the first virtual chain operation to reveal a name is the one that wins. So this prevents the first attack I mentioned because it masks the name, however the race condition still occurs prior to confirm for a reveal so that the first transaction to be confirmed in a block (as determined by luck or whatever) is the one that “wins.”

This isn’t really an attack. My concern was that there wasn’t checks in place for multiple pre-registrations for the same address but the code here clearly indicates that this is checked for and it means that if someone wants to squat names they still obviously have to pay the protocol costs for a pre-registration.

(It might still be economically viable to squat a bunch of names in theory like this and only have to pay potential registration costs when there is demand for it. But the fact that there is a fee at all at least discourages that from happening and obviously the client is well-formed so the user always gets consistent notification if a pre-registration fails based on consensus.)

I was trying to determine if any steps in the process could be hijacked by an attacker but so far I’ve only found edge cases that are already noted in other documentation.

Edit: I should also say that it seems that pre-orders are considered invalid after a certain number of blocks (it seems to be 130 at the current time) So an attacker would have a 22 or so hour window to do the attack I described which really prevents much organization for wide-scale hijacking. This is a very good idea for the protocol. The code for that is here: https://github.com/blockstack/blockstack-cli/blob/bbda7c95c411d8fc0f1eb20715e28a35243e4fb7/blockstack_client/backend/queue.py#L334


#3

I think I’ve found the answer to my question in the code. This is surprisingly well documented code, by the way.

:smiley:

Edit: I should also say that it seems that pre-orders are considered invalid after a certain number of blocks (it seems to be 130 at the current time) So an attacker would have a 22 or so hour window to do the attack I described which really prevents much organization for wide-scale hijacking.

You may also want to see the code here: https://github.com/blockstack/blockstack-core/blob/master/blockstack/lib/nameset/db.py#L2409. This method gets an outstanding, unexpired preorder.

It gets used by Blockstack’s virtualchain state engine implementation here: https://github.com/blockstack/blockstack-core/blob/master/blockstack/lib/nameset/namedb.py#L937, which is made available to the code that processes NAME_REGISTRATION opcodes. That way, a NAME_REGISTRATION fails trivially since a query to the name database will not find a matching preorder (i.e. this line returns None for the existing preorder: https://github.com/blockstack/blockstack-core/blob/master/blockstack/lib/operations/register.py#L208).