Skip to content

Instantly share code, notes, and snippets.

@tymm

tymm/merging.md Secret

Last active December 30, 2019 22:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tymm/c98acf4f91b1fca8cbd48c02c21e3472 to your computer and use it in GitHub Desktop.
Save tymm/c98acf4f91b1fca8cbd48c02c21e3472 to your computer and use it in GitHub Desktop.
Merging multiple transfers to the same RevVault

Problem: Two or more RevVault transfers to the same RevVault are conflicting. This is a problem in general and in particular for the PoS contract since on every user deploy we want to make transfers to the same PoS vault.

The root cause of why two or more transfers to the same vault are conflicting, lies in NonNegativeNumber.rho:

contract this(@"add", @x, success) = {
  if (x >= 0) {
    for(@v <- valueStore){
      if (v + x >= v) {
        valueStore!(v + x) | success!(true)
      } else {
        //overflow
        valueStore!(v) | success!(false)
      }
    }
  } else {
    success!(false)
  }
} 

According to the C! C! rule in the Mergeable Google Sheet, the add contract conflicts because two different blocks that execute the add contract would fight over consuming the value at valueStore. This leads to different post states depending on which linear consume comes first.

Proposed solution: It is easy to see from the add contract that the C! C! rule can be too strict. There is no reason for the add contract having to conflict since after each for(@v <- valueStore) a send on valueStore happens and addition is commutative.

However I am unsure how big the changes are that are required to detect the add contract as non-conflicting.

  • Comm events would need to have some knowledge about Rholang syntax so that conflict detection can for example differentiate between:

    1. for (@v <- valueStore) { valueStore!(...) } (commutes with itself)
    2. for (@v <- valueStore) { Nil } | valueStore!(42) (does not commute with itself)
  • Since the overflow case in the add contract does not commute, there needs to be a way to differentiate between the non-overflow produce (valueStore!(v + x)) and the overflow produce (valueStore!(v)). One way to do that would be to check if the underlying value increased. If it was increased, we had no overflow. If it stayed the same, there was an overflow and a conflict needs to be raised.

@lukasz-golebiewski
Copy link

In the second bullet point the overflow could be made less conflict prone by leveraging peek syntax:

for(@v <<- valueStore){
  if (v + x >= v) {
    for(@v <- valueStore){
      valueStore!(v + x) | success!(true)
    } 
  else {
    //overflow
   success!(false)
  }
}

@lukasz-golebiewski
Copy link

lukasz-golebiewski commented Sep 25, 2019

There is no reason for the add contract having to conflict since after each for(@v <- valueStore) a send on valueStore happens and addition is commutative.

We strive to keep merging as fast as possible, and the long term goal is to be able to do it without replaying - just by merging the non-conflicting tuplespaces. What you propose however would require re-playing both operations in order to get the summed value (and the Par random part), so I guess this is not a sensible approach.

@tymm
Copy link
Author

tymm commented Sep 25, 2019

In the second bullet point the overflow could be made less conflict prone by leveraging peek syntax:

for(@v <<- valueStore){
  if (v + x >= v) {
    for(@v <- valueStore){
      valueStore!(v + x) | success!(true)
    } 
  else {
    //overflow
   success!(false)
  }
}

Unfortunately this would not help. A conflict still has to be raised here if there is an overflow.

@ArturGajowy
Copy link

ArturGajowy commented Sep 25, 2019

addition is commutative.

it's not commutative when we prohibit negative balances

@tymm
Copy link
Author

tymm commented Sep 25, 2019

addition is commutative.

it's not when we prohibit negative balances

With "prohibit negative balances" you are referring to the else-part of the add contract where we prohibit the overflow or something else?

@ArturGajowy
Copy link

purse underneath the revvault is based on a non-negative integer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment