My name is Eli Guenzburger I am researching with Prof. Cesar Sanchez at the IMDEA Software Institute.
Due to BFS calling pattern in Tezos (discussed Concurrency, BFS vs DFS (and a proposal)), Balance
is awkward and vulnerable. There are two key factors that contribute to unexpected values of Balance.
-
Outgoing Transfers earlier in the queue
Let Contract B be initialized with a balance of 200tz and have a request entrypoint. B would like to never allow its balance to go below aMin_balance
of 100tz but will transfer any amount that does not bring its balance below this amount. Suppose Contract A generates 20 requests for a transfer of 10tz from Contract B. We might naively expect the execution of A to fail given given that 200tz - (20 * 10tz) = 0tz < 100tz =Min_balance
. However, Balance is only updated upon execution of the transfers from B to A, which occur after all 20 requests from A to B are executed. B naively enforcing thatBalance - TransferRequestAmount >= Min_Balance
does not guarantee thatBalance
is not brought belowMin_balance
. In fact, upon termination of the procedure described above, the balance of B will be brought to 0 and the balance of A will increase by 200tz. The point is thatBalance
does not reflectOutgoing
funds earlier invocations of B (as well as the current invocation of B) have already promised to send away in transactions in the operation queue that have not been executed yet. Contracts should be able to reason about theseOutgoing
funds. -
Incoming Transfers later in the queue
Let Contract A be initialized with a balance of 1tz and contract B be initialized with a balance of 99tz and have a request entrypoint. Suppose in a single execution, A generates 2 operations: Op1 requests 100tz from B and Op2 transfers 1tz to B. B would like to always transfer the amount requested by A when it can theoretically transfer that amount, and execute a failure procedure if this is not possible. In this example, Op1 will result in the failure procedure since B will have balance 99tz so it reasons that it cannot send the 100tz requested. Strangely, the optimal behavior of B on execution of Op1 in this example would be to just generate the transfer of 100tz to A (call this Op3) without checking balance. Due to BFS calling nature, Op2 is executed before Op3, bringing the balance of B to 100tz. Therefore, Op3 will execute successfully and A would finish with a balance of 100tz. A contract should be able to reason about theIncoming
funds it will be receiving from subsequent operations in the queue so as to anticipate its balance at the time of the execution of its external operations.
It would be better if contracts referenced a new variable EffectiveBalance
instead of the unsafe Balance
.
If we can successfully maintain variables Outgoing
and Incoming
we can calculate EffectiveBalance
by referencing Balance
, Outgoing
, and Incoming
.