Last TX enhanced state checking according to JJ comments.

This commit is contained in:
Hernán Di Pietro 2021-11-01 15:50:38 -03:00
parent 4fb463ed38
commit 1c920c7c92
1 changed files with 47 additions and 30 deletions

View File

@ -41,19 +41,20 @@ SLOT 255: number of guardians in set
""" """
from pyteal.ast import * from pyteal.ast import *
from pyteal.types import * from pyteal.types import *
from pyteal.compiler import * from pyteal.compiler import *
from pyteal.ir import * from pyteal.ir import *
from globals import MAX_SIGNATURES_PER_VERIFICATION_STEP, get_group_size from globals import MAX_SIGNATURES_PER_VERIFICATION_STEP, get_group_size, get_sig_count_in_step
METHOD = Txn.application_args[0] METHOD = Txn.application_args[0]
VERIFY_ARG_GUARDIAN_KEY_SUBSET = Txn.application_args[1] VERIFY_ARG_GUARDIAN_KEY_SUBSET = Txn.application_args[1]
VERIFY_ARG_GUARDIAN_SET_SIZE = Txn.application_args[2] VERIFY_ARG_GUARDIAN_SET_SIZE = Txn.application_args[2]
VERIFY_ARG_PAYLOAD = Txn.note() VERIFY_ARG_PAYLOAD = Txn.note()
SLOTID_TEMP_0 = 251 SLOTID_TEMP_0 = 251
SLOTID_VERIFIED_GUARDIAN_BITS = 254 SLOTID_VERIFIED_BIT = 254
SLOTID_GUARDIAN_COUNT = 255
STATELESS_LOGIC_HASH = App.globalGet(Bytes("vphash")) STATELESS_LOGIC_HASH = App.globalGet(Bytes("vphash"))
NUM_GUARDIANS = App.globalGet(Bytes("gscount")) NUM_GUARDIANS = App.globalGet(Bytes("gscount"))
SLOT_VERIFIED_BITFIELD = ScratchVar(TealType.uint64, SLOTID_VERIFIED_BIT)
SLOT_TEMP = ScratchVar(TealType.uint64, SLOTID_TEMP_0)
# defined chainId/contracts # defined chainId/contracts
@ -81,17 +82,6 @@ def bootstrap():
]) ])
@Subroutine(TealType.uint64)
def verify_from():
return Txn.group_index() * Int(MAX_SIGNATURES_PER_VERIFICATION_STEP)
@Subroutine(TealType.uint64)
def verify_to():
return min(VERIFY_ARG_GUARDIAN_SET_SIZE, verify_from +
(Int(MAX_SIGNATURES_PER_VERIFICATION_STEP) - Int(1)))
@Subroutine(TealType.uint64) @Subroutine(TealType.uint64)
def is_creator(): def is_creator():
return Txn.sender() == Global.creator_address() return Txn.sender() == Global.creator_address()
@ -102,11 +92,14 @@ def check_guardian_key_subset():
# Verify that the passed argument for guardian keys [i..j] match the # Verify that the passed argument for guardian keys [i..j] match the
# global state for the same keys. # global state for the same keys.
# #
i = ScratchVar(TealType.uint64, SLOTID_TEMP_0) i = SLOT_TEMP
return Seq([For(i.store(Int(0)), i.load() < Int(MAX_SIGNATURES_PER_VERIFICATION_STEP), i.store(i.load() + Int(1))).Do( return Seq([
If(App.globalGet(Itob(i.load())) != Extract(VERIFY_ARG_GUARDIAN_KEY_SUBSET, For(i.store(Int(0)),
i.load() * Int(64), Int(64))).Then(Return(Int(0))) # get and compare stored global key i.load() < get_sig_count_in_step(Txn.group_index(), NUM_GUARDIANS),
), i.store(i.load() + Int(1))).Do(
If(App.globalGet(Itob(i.load())) != Extract(VERIFY_ARG_GUARDIAN_KEY_SUBSET,
i.load() * Int(64), Int(64))).Then(Return(Int(0))) # get and compare stored global key
),
Return(Int(1)) Return(Int(1))
]) ])
@ -155,6 +148,21 @@ def commit_vaa():
]) ])
@Subroutine(TealType.uint64)
def check_final_verification_state():
i = SLOT_TEMP
return Seq([
For(i.store(Int(0)),
i.load() < Global.group_size(),
i.store(i.load() + Int(0))).Do(
Assert(
And(Gtxn[i.load()].application_id() == Txn.application_id(),
GetBit(ImportScratchValue(i.load(), SLOTID_VERIFIED_BIT), i.load()) == Int(1)))
),
Return(Int(1))
])
def setvphash(): def setvphash():
# #
# Sets the hash of the verification stateless program. # Sets the hash of the verification stateless program.
@ -173,21 +181,30 @@ def setvphash():
def verify(): def verify():
# * Sender must be stateless logic. # * Sender must be stateless logic.
# * Let N be the number of signatures per verification step, for the TX(i) in group, we verify signatures [j..k] where j = i*N, k = j+(N-1) # * Let N be the number of signatures per verification step, for the TX(i) in group, we verify signatures [j..k] where j = i*N, k = j+(N-1)
# * Argument 1 must contain guardian public keys for guardians [i..j] (read by stateless logic) # * Argument 1 must contain guardian public keys for guardians [i..j] (read by stateless logic).
# Public keys are 32 bytes long so expected argument length is 32 * (j - i + 1)
# * Argument 2 must contain current guardian set size (read by stateless logic) # * Argument 2 must contain current guardian set size (read by stateless logic)
# * Passed guardian public keys [i..j] must match the current global state. # * Passed guardian public keys [i..j] must match the current global state.
# * Note must contain VAA message-in-digest (header+payload) (up to 1KB) (read by stateless logic) # * Note must contain VAA message-in-digest (header+payload) (up to 1KB) (read by stateless logic)
# #
# Last TX in group will trigger VAA handling depending on payload. # Last TX in group will trigger VAA handling depending on payload. It is required that
# all previous transactions are app-calls for this AppId and all bitfields are set.
return Seq([Assert(And(Global.group_size() == get_group_size(NUM_GUARDIANS), return Seq([
Txn.application_args.length() == Int(3), SLOT_VERIFIED_BITFIELD.store(Int(0)),
Txn.sender() == STATELESS_LOGIC_HASH, Assert(And(Global.group_size() == get_group_size(NUM_GUARDIANS),
check_guardian_set_size(), Txn.application_args.length() == Int(3),
check_guardian_key_subset())), Txn.sender() == STATELESS_LOGIC_HASH,
If(Txn.group_index() == Global.group_size() - check_guardian_set_size(),
Int(1)).Then(Return(commit_vaa())), check_guardian_key_subset())),
Approve()]) SLOT_VERIFIED_BITFIELD.store(SetBit(SLOT_VERIFIED_BITFIELD.load(), Txn.group_index(), Int(1))),
If(Txn.group_index() == Global.group_size() -
Int(1)).Then(
Return(Seq([
Assert(check_final_verification_state()),
commit_vaa()
]))),
Approve()])
def vaa_processor_program(): def vaa_processor_program():