Arbitrary state access is a read or write to a storage slot specified by another storage slot.
This example is a loose approximation of an auction contract. Each new highest bidder locks in Ether as their bid, and the previous bidder is refunded.
refund_addr: address
refund_amount: wei_value
@public
@payable
def bid(new_refund_addr: address):
assert msg.value > self.refund_amount
send(self.refund_addr, self.refund_amount)
self.refund_addr = new_refund_addr
self.refund_amount = msg.valueTo show how this is DSA, imagine a scenario given the two following transactions {and their witnesses}:
bid('0xB', 4){refund_addr == 0xA && refund_amount == 3 && (0xA).balance == 2}bid('0xC', 5){refund_addr == 0xA && refund_amount == 3 && (0xA).balance == 2}
If bid('0xB', 4) is included in the block first, the witnesses included by bid('0xC', 5) will be missing the state at 0xB.
A branched state access is a read or write to a storage slot selected from a list known ahead of time.
troz: int128
poit: int128
narf: int128
@public
def add_value(value: int128):
if self.troz < 5:
self.troz = self.poit + value
else:
self.troz = self.narf + valueTo show how this is DSA, imagine a scenario given the two following transactions {and their witnesses}:
add_value(2){troz == 3 && poit == 5}add_value(3){troz == 3 && poit == 5}
If add_value(2) is included in the block first, the witnesses included by add_value(3) will be missing the state for narf.
Unlike Arbitrary State Access, it is possible to create a witness that is guaranteed to be sufficient by unconditionally adding poit and narf:
add_value(2){troz == 3 && poit == 5 && narf == 11}add_value(3){troz == 3 && poit == 5 && narf == 11}
previous_addr: address
@public
@payable
def dweep():
send(self.previous_addr, msg.value)
self.previous_addr = msg.senderWhile dweep contains DSA, a transaction cannot be invalidated by a preceding transaction in the same block.
Regardless of whether dweep()[value=11,sender=0xB] is included before dweep()[value=23,sender=0xC] or vise versa, every state access will have a value (provided by the preceding transaction.)
Explanation
Consider these transactions {and their witnesses}:
dweep()[value=11,sender=0xB]{previous_addr = 0xA && (0xB).balance = 13}dweep()[value=23,sender=0xC]{previous_addr = 0xA && (0xC).balance = 29}
If dweep()[value=11,sender=0xB] is included first, the state accesses for dweep()[value=23,sender=0xC] look like:
(0xC).balance == 29is included indweep()[value=23,sender=0xC]'s witness.previous_addr == 0xBis known afterdweep()[value=11,sender=0xB]is executed.(0xB).balance == 2is known afterdweep()[value=11,sender=0xB]is executed.
On the other hand, if dweep(23) is included first, the state accesses for dweep(11) look like:
(0xB).balance == 13is included indweep()[value=11,sender=0xB]'s witness.previous_addr == 0xCis known afterdweep()[value=23,sender=0xC]is executed.(0xC).balance == 6is known afterdweep()[value=23,sender=0xC]is executed.