Handle VAA at last TX.

This commit is contained in:
Hernán Di Pietro 2021-10-28 12:56:38 -03:00
parent ff486b7711
commit a3d5ce05fc
1 changed files with 64 additions and 49 deletions

View File

@ -21,8 +21,8 @@ verify: Verify guardian signature subset i..j, works in tandem with stateless p
Arguments: #0 guardian public keys subset i..j (must match stored in global state)
#1 guardian signatures subset i..j
#2 payload to verify
commit: Commit verified VAA, processing it according to its payload. Must be last TX.
Last verification step (the last TX in group) triggers the VAA commiting stage,
where we decide what to do based on the payload.
------------------------------------------------------------------------------------------------
Global state:
@ -35,11 +35,11 @@ key N : address of guardian N
------------------------------------------------------------------------------------------------
Stores in scratch:
SLOT 254: uint64 with bit field of approved guardians (initial 0)
SLOT 255: number of guardians in set
================================================================================================
"""
from os import P_OVERLAY
from pyteal import (compileTeal, Int, Mode, Txn, OnComplete, Itob, Btoi,
Return, Cond, Bytes, Global, Not, Seq, Approve, App, Assert, For, And,
Extract)
@ -60,12 +60,28 @@ from globals import SIGNATURES_PER_VERIFICATION_STEP
METHOD = Txn.application_args[0]
VERIFY_ARG_GUARDIAN_KEY_SUBSET = Txn.application_args[1]
VERIFY_ARG_GUARDIAN_SET_SIZE = Txn.application_args[2]
VERIFY_ARG_PAYLOAD = Txn.note
VERIFY_ARG_PAYLOAD = Txn.note()
SLOTID_TEMP_0 = 251
SLOTID_VERIFIED_GUARDIAN_BITS = 254
SLOTID_GUARDIAN_COUNT = 255
STATELESS_LOGIC_HASH = App.globalGet(Bytes("vphash"))
# defined chainId/contracts
GOVERNANCE_CHAIN_ID_TEST = 3
GOVERNANCE_CONTRACT_ID_TEST = 4
PYTH2WORMHOLE_CHAIN_ID_TEST = 5
PYTH2WORMHOLE_CONTRACT_ID_TEST = 6
# VAA fields
VAA_RECORD_EMITTER_CHAIN_POS = 8
VAA_RECORD_EMITTER_CHAIN_LEN = 2
VAA_RECORD_EMITTER_ADDR_POS = 10
VAA_RECORD_EMITTER_ADDR_LEN = 32
# -------------------------------------------------------------------------------------------------
@Subroutine(TealType.uint64)
# Bootstrap with the initial list of guardians as application argument
@ -99,14 +115,14 @@ def min(a, b):
@Subroutine(TealType.uint64)
def is_proper_group_size():
# Let G be the guardian count, N number of signatures per verification step, group must have CEIL(G/N) + 1 transactions (last one is commit).
# Let G be the guardian count, N number of signatures per verification step, group must have CEIL(G/N) transactions.
gssize = App.globalGet(Bytes("gssize"))
q = gssize / Int(SIGNATURES_PER_VERIFICATION_STEP)
r = gssize % Int(SIGNATURES_PER_VERIFICATION_STEP)
return Seq([
If(r != Int(0)).Then(
Return(Global.group_size() == q + Int(2))
).Else(Return(Global.group_size() == q + Int(1)))
Return(Global.group_size() == q + Int(1))
).Else(Return(Global.group_size() == q))
])
@ -133,26 +149,39 @@ def check_guardian_set_size():
@Subroutine(TealType.uint64)
def check_txn_note_payload():
#
# Verify the digest-source section argument of a signed VAA,
# consisting of:
#
# bytes
# 4 timestamp
# 4 Nonce
# 2 emitterChainId
# 32 emitterAddress
# 8 sequence
# 1 consistencyLevel
# N payload
#
def handle_governance():
return Int(1)
# Should we validate the fields?
@Subroutine(TealType.uint64)
def handle_pyth_price_ticker():
return Int(1)
@Subroutine(TealType.uint64)
#
# Unpack the verified VAA payload and process it according to
# the source based by emitterChainId, emitterAddress.
#
def commit_vaa():
chainId = Btoi(Extract(VERIFY_ARG_PAYLOAD, Int(
VAA_RECORD_EMITTER_CHAIN_POS), Int(VAA_RECORD_EMITTER_CHAIN_LEN)))
contractId = Btoi(Extract(VERIFY_ARG_PAYLOAD, Int(
VAA_RECORD_EMITTER_ADDR_POS), Int(VAA_RECORD_EMITTER_ADDR_LEN)))
return Seq([
Assert(Extract(VERIFY_ARG_PAYLOAD, Int(0), Int(4))
If(And(
chainId == Int(GOVERNANCE_CHAIN_ID_TEST),
contractId == Int(GOVERNANCE_CONTRACT_ID_TEST))).Then(
Return(handle_governance()))
.ElseIf(And(
chainId == Int(PYTH2WORMHOLE_CHAIN_ID_TEST),
contractId == Int(GOVERNANCE_CONTRACT_ID_TEST)
)).Then(
Return(handle_pyth_price_ticker())
).Else(
Return(Int(0))
)
])
return VERIFY_ARG_PAYLOAD
def setvphash():
@ -161,7 +190,9 @@ def setvphash():
#
return Seq([
Assert(And(is_creator(), Len(Txn.application_args[1]) == Int(32))),
Assert(And(is_creator(),
Global.group_size() == Int(1),
Len(Txn.application_args[1]) == Int(32))),
App.globalPut(Bytes("vphash"), Txn.application_args[1]),
Approve()
])
@ -174,33 +205,18 @@ def verify():
# * Argument 2 must contain current guardian set size (read by stateless logic)
# * 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)
# * This call must be not the last in a group of minimum 2 (prepare, commit)
#
# Call will set validated bits to i..j in bitfield.
# Last TX in group will trigger VAA handling depending on payload.
return Seq([Assert(And(is_proper_group_size(),
Txn.group_index() < (Global.group_size() - Int(1)),
Txn.sender() == STATELESS_LOGIC_HASH,
check_guardian_set_size(),
check_guardian_key_subset(),
check_txn_note_payload())),
check_guardian_key_subset())),
If(Txn.group_index() == Global.group_size() -
Int(1)).Then(Return(commit_vaa())),
Approve()])
def commit():
# Sender must be owner
# This call must be last in a group of minimum 3 (prepare->verify->commit)
# Bitfield must indicate all guardians verified.
# all_verified = ScratchVar(TealType.uint64, SLOTID_VERIFIED_GUARDIAN_BITS).load() ==
return Seq([
Assert(And(is_proper_group_size(),
Txn.group_index() == (Global.group_size() - Int(1)),
)),
#handle_vaa(),
Approve()
])
def vaa_processor_program():
handle_create = Return(bootstrap())
handle_update = Return(is_creator())
@ -208,7 +224,6 @@ def vaa_processor_program():
handle_noop = Cond(
[METHOD == Bytes("setvphash"), setvphash()],
[METHOD == Bytes("verify"), verify()],
[METHOD == Bytes("commit"), commit()]
)
return Cond(
[Txn.application_id() == Int(0), handle_create],