Currently in State circuit it's speced here as:
if value_prev == 0 and value == 0:
mpt_lookup(NonExistingStorageProof, key)
else:
mpt_lookup(StorageMod, key, value_prev, value)
Where the StorageMod
supports insertion and deletion as said in this mpt-proof.md.
It seems to cover all the cases here, I'm curious why do we need to check the non-existing again in EVM circuit like that described in #259?
NonExisting
should also be reversible valueIf we still need the NonExisting
check in EVM circuit, it seems that we need to update its value to false
when we insert any non-zero value into the key (of account or storage), and need to revert it as well, otherwise a prover could do NonExisting
lookup even after it's no longer non-existing, but I didn't see that mentioned in #259.
My naive thought is that we don't need to have NonExisting
as account field in State circuit, we could just check in the very similar way as we check storage like:
if value_prev == 0 and value == 0 and is_other_field_also_empty:
mpt_lookup(NonExistingAccountProof, key)
else:
mpt_lookup({NonceMod,BalanceMod,CodeHashMod}, key, value_prev, value)
Where is_other_field_also_empty
is additionally witnessed by prover, and shouldn't be manipulated to pass the MPT circuit (if it's not empty the NonExisting
should not pass, if it's empty the *Mod
should not pass).
AccountDeleteMod
In my above approach, it's not complete since using {NonceMod,BalanceMod,CodeHashMod}
to delete an account is not supported, instead we need to use another API AccountDeleteMod
. And since SELFDESTRUCT
(which is the only one that could delete an account) could also be reverted, we might need to track another tag for it and set it order after other account field tag and storage tag, to ensure after there is no more unexpected modification after account deletion.
However, since we haven't had plan for SELFDESTRUCT
, perhaps we could lower its priority and implement that when we are really sure that we are going to support SELFDESTRUCT
.
These opcodes have the following behaviours when account doesn't exist:
How to prove a non-existing account in the EVM circuit?
EVM execution trace
Sorted in Rw Table
R0
MPT lookups:
(We assume no selfdestruct)
Sorted in Rw Table
MPT lookups:
MPT lookups:
Address | ProofType | Key | ValuePrev | Value | RootPrev | Root |
---|---|---|---|---|---|---|
$addr | NonceMod | 0 | $noncePrev | $nonceCur | $rootPrev | $root |
$addr | BalanceMod | 0 | $balancePrev | $balanceCur | $rootPrev | $root |
$addr | CodeHashMod | 0 | $codeHashPrev | $codeHashCur | $rootPrev | $root |
$addr | NonExistingAccountProof | 0 | 0 | 0 | $root | $root |
$addr | AccountDeleteMod | 0 | 0 | 0 | $rootPrev | $root |
$addr | StorageMod | $key | $valuePrev | $value | $rootPrev | $root |
$addr | NonExistingStorageProof | $key | 0 | 0 | $root | $root |
if value_prev == 0 and value == 0 and key == CodeHash:
mpt_lookup(NonExistingAccountProof, key)
else:
mpt_lookup({NonceMod,BalanceMod,CodeHashMod}, key, value_prev, value)
def extcodehash():
code_hash = lookup(addr, codeHash)
if code_hash == 0: # doesn't exist
return 0
else
return code_hash
RwTable
MptLookups
LeafA = 0
SSTORE LeafA = 77
SLOAD LeafA
SSTORE 0 LeafA
RwTable
MptLookups:
State circuit specs: apply line 150-153
Circuits: update from specs
specs table: remove Account-NonExisting from RwTable
BALANCE, EXTCODEHASH, EXTCODECOPY, EXTCODESIZE, CALLCODE, DELEGATECALL, STATICCALL
NonExisting
tag by lookup to CodeHash
with IsZero
check.NonExisting
, needs to be changed)CALL
CodeHash
with IsZero
check.Circuits: