In our last post Problems with Balance, we described problems with the way Balance
is calculated due to the BFS calling pattern in Tezos. Balance
does not take into account a contract’s expected Incoming
funds from operations later in the operation queue than the currently executing operation, and it does not take into account Outgoing
funds already promised by the currently executing contract in operations in the queue that have not yet been executed. Here, we will propose a solution to this problem along with the minimum changes to the Tezos architecture the solution requires.
Solution
-
Each contract will get a new storage variable:
Outgoing
. This does not require changes to Tezos architecture, just changes to the way Contracts are written. Tezos will maintain a global mapIncoming : Contract –> Tez
as it doesBalance
(this requires changes to Tezos architecture). -
Everytime a contract adds a transfer operation to its operation queue, it will also add the amount transferred in that operation to its storage variable
Outgoing
. -
Suppose Contract A invokes Contract B m times and each for invocation i of Contract B, B generates n transactions ti1, …, tin (where operation tij transfers A(tij) to T(tij)). Then, Tezos will make the following changes to how these n*m transactions are executed.
- Before any of these n*m transactions are executed, for all i,j Tezos will execute II(tij) (or Increase Incoming) which will add A (tij) to Incoming(T(tij)).
- For all i,j, for a given tij Tezos will generate another operation DI(tij) (or Decrease Incoming). DI(tij) will subtract A (tij) from Incoming(T(tij)). DI(tij) will execute immediately after tij executes.
- For all i,j, for a given tij Tezos will generate another operation DO(tij) (or Decrease Outcoming). DO(tij) is a self call that will subtract A(tij) from its own
Outgoing
storage variable. DO(tij) will execute immediately after DI(ij) executes.
NOTE: For simplicity, points 1 and 2 in the list above are written to look like we are adding new operations to the operation queue. In reality these ‘operations’ just indicate a change in the way Tezos processes operation queues. Point 3 in the above list is indeed a new operation added to the operation list that could be implemented by contracts without changes to the tezos architecture. However, since 1 and 2 require changes to Tezos code, we suggest that point 3 is implemented by Tezos as well.
-
Each contract can now get a new storage variable
EffectiveBalance := Balance + Incoming - *Outgoing - Transferred
(where we derefence a pointer to Outgoing so that changes to it in that contract’s code will be reflected in EffectiveBalance.Transferred
refers to what is currently returned byAMOUNT
opcode and is subtracted from calculation to correct for double counting ofTransferred
inBalance
andIncoming
.
Required Changes to Tezos Architecture
- Creation and maintenance of external map
Incoming : Contract –> Tez
, similar to existing oneBalance.
NOTE: In contrast toIncoming,
a given contract’sOutcoming
balance can be maintained as a storage variable in that contract, and does not require changes to Tezos architecture. However, that contract cannot know the amount being sent to it by another contract and we cannot rely on/trust external callers to accurately report the total amount they are sending to another contract across all operations. Therefore,Incoming
must be maintained by Tezos. - A new Opcode
INCOMING
which returns the calling contract’s expected incoming funds at time of execution. - Changes to the Tezos scheduler that implement the solution described in point 3 of the above section.