Atomic transfer
The purpose of the atomic transfer protocol is to enable two (or more) coin transfers to be completed in a way that they all complete or none of them do. This effectively means that the transfer-receiver function and key update is only completed if both receivers have the correct information to proceed. Once each receiver has verified that the transfer message they have received is valid, then the other parties can be allowed to complete transfer-receiver.
To enable this there needs to be a mechanism to prevent the transfer-receiver being completed before the other parties have verified and confirmed their transfer messages. If all parties verify, then transfer-receiver can proceed, otherwise the key shares are not updated and ownership of the coins remains with the inital owner.
The process is performed by each party in the atomic transfer supplying a batch_id
in the transfer-sender message. The use of this (as opposed to leaving this null) is that the statecoin is put into a special locked state for a configured timeout period after the first batch_id
is submitted. During this locked status two things are prevented 1) The sender cannot perform another /transfer/sender
operation on the same coin (i.e. to send to a different address) and 2) /transfer/receiver
cannot be performed until all coins with the same batch_id
are unlocked by all the owners unlocking the coins with a new /transfer/unlock
function. At the end of the timeout (if all coins with a specified batch_id
have not been unlocked), the /transfer/receiver
function will still be blocked (i.e. return error) but the original owner can repeat /transfer/sender
again with a null batch_id
to regain control of the coin.
Protocol
The statechain_transfer
DB table can have 3 additional columns: batch_id
(string), batch-time
(integer) and locked
(boolen). By default batch_id
, batch-time
are null and locked
is false
. The server is configured with batch-timeout
parameter in seconds (in practice this will be some number of minutes). This is set in the server Settings.
The atomic transfer will then proceed as follows:
- The two or more parties that want to engage in an atomic transfer cooperate and share a
batch_id
(this is just a random UUID generated by one of the participants and shared with the other). One party can generate it and share with the others. - The parties each generate a
ml1
address that they want the coin they will recieve paid to and send to the sender. - Each party performs
/transfer/sender {statechain_id, batch_id, auth_sig, new_user_auth_key}
with thebatch_id
paying to the receiving partynew_user_auth_key
and then create and upload the transfer message. - If the
batch_id
is set in a/transfer/sender
call (and not null) the server adds this to thebatch_id
DB column for the specifiedstatechain_id
and updates thelocked
status totrue
. - The server then checks all other statecoins to see if the same
batch_id
is used for any other coin in the table. - If there are no other coins with this
batch_id
, then it adds the current time (unix epoch time in seconds) to thebatch-time
column. - If there are any other coin(s) with this same
batch_id
then thebatch-time
of those coin(s) is copied to the specified coinbatch-time
column.
This means that all coins where
/transfer/sender
have the samebatch_id
will have the samebatch-time
set.
With this logic, it does not mater which order the coins call
/transfer/sender
, the first call with a specificbatch_id
will set the initialbatch-time
for the atomic transfer.
When /transfer/sender
is called for any coin, if batch-time
+ batch-timeout
(as read from the DB table) is greater than or equal to the current time (i.e. the coin is still within the timeout period) then it will return an error (ERROR: statecoin batch locked
).
When /transfer/sender
is called for any coin, if batch-time
+ batch-timeout
(as read from the DB table) is less the current time (i.e. the timeout period has ended) the server will check the DB table for any other coins have the same batch_id
. For each coin that shares the samebatch_id
, if all locked
values are false, then the transfer-sender returns with an error (ERROR: batch transfer completed
) (in this case all participants have verified the transfer message and the atomic transfer must complete - all parties must perform transfer-receiver).
If all locked
values are NOT false /transfer/sender
can be called again with a null or different batch_id
. If called with null batch_id
then batch-time
is set to null and locked
to false.
-
Each participant in the atomic transfer then polls
/transfer/get_msg_addr
with their receive address within the timeout period. If they receive a transfer message, they fully verify as usual. If the verification passes, then the participant calls a function/transfer/unlock {statechain_id, auth_sig}
which changes thelocked
status of the coin (statechain_id
) in the DB table tofalse
. If thebatch-time
+batch-timeout
is less than the current time, then the/transfer/unlock
function should not unlock and instead return an error. -
Each participant then calls
transfer-reciever
. If/transfer/receiver
is called on any coin andbatch_id
andbatch-time
are set (not null) andlocked
is false, then the server checks if any other coins in the DB table have the samebatch_id
. For alls coin that share the samebatch_id
, if alllocked
are false, then the function proceeds with the key update, otherwise it returns with an error (ERROR: coin in locked state
). If/transfer/receiver
is called on any coin andbatch_id
andbatch-time
are set (not null) andlocked
is true, then this function should return an error.
The outcomes of this protocol:
Any coins where /transfer/sender
is called with a specific batch-id
within the batch-time
of the first one to call, will be added to the batch transfer.
Then, if all parties coins progress to call /transfer/unlock
within the batch-time
then /transfer/receiver
can be performed for all coins by each party.
If any single participant doesn't call /transfer/unlock
within the batch-time
then no-one can call /transfer/receiver
but after the batch-time
expiry each owner can call /transfer/sender
again to recover the coin (i.e. send to to their own address with null batch_id
and then calling transfer-receiver).