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

@ -17,12 +17,12 @@ setvphash: Set verify program hash.
Must be part of group: Must be part of group:
verify: Verify guardian signature subset i..j, works in tandem with stateless program. verify: Verify guardian signature subset i..j, works in tandem with stateless program.
Arguments: #0 guardian public keys subset i..j (must match stored in global state) Arguments: #0 guardian public keys subset i..j (must match stored in global state)
#1 guardian signatures subset i..j #1 guardian signatures subset i..j
#2 payload to verify #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: Global state:
@ -35,11 +35,11 @@ key N : address of guardian N
------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------
Stores in scratch: Stores in scratch:
SLOT 254: uint64 with bit field of approved guardians (initial 0)
SLOT 255: number of guardians in set SLOT 255: number of guardians in set
================================================================================================ ================================================================================================
""" """
from os import P_OVERLAY
from pyteal import (compileTeal, Int, Mode, Txn, OnComplete, Itob, Btoi, from pyteal import (compileTeal, Int, Mode, Txn, OnComplete, Itob, Btoi,
Return, Cond, Bytes, Global, Not, Seq, Approve, App, Assert, For, And, Return, Cond, Bytes, Global, Not, Seq, Approve, App, Assert, For, And,
Extract) Extract)
@ -60,12 +60,28 @@ from globals import SIGNATURES_PER_VERIFICATION_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_GUARDIAN_BITS = 254
SLOTID_GUARDIAN_COUNT = 255 SLOTID_GUARDIAN_COUNT = 255
STATELESS_LOGIC_HASH = App.globalGet(Bytes("vphash")) 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) @Subroutine(TealType.uint64)
# Bootstrap with the initial list of guardians as application argument # Bootstrap with the initial list of guardians as application argument
@ -99,14 +115,14 @@ def min(a, b):
@Subroutine(TealType.uint64) @Subroutine(TealType.uint64)
def is_proper_group_size(): 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")) gssize = App.globalGet(Bytes("gssize"))
q = gssize / Int(SIGNATURES_PER_VERIFICATION_STEP) q = gssize / Int(SIGNATURES_PER_VERIFICATION_STEP)
r = gssize % Int(SIGNATURES_PER_VERIFICATION_STEP) r = gssize % Int(SIGNATURES_PER_VERIFICATION_STEP)
return Seq([ return Seq([
If(r != Int(0)).Then( If(r != Int(0)).Then(
Return(Global.group_size() == q + Int(2)) Return(Global.group_size() == q + Int(1))
).Else(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) @Subroutine(TealType.uint64)
def check_txn_note_payload(): def handle_governance():
# return Int(1)
# 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
#
# 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([ 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(): def setvphash():
@ -161,7 +190,9 @@ def setvphash():
# #
return Seq([ 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]), App.globalPut(Bytes("vphash"), Txn.application_args[1]),
Approve() Approve()
]) ])
@ -174,33 +205,18 @@ def verify():
# * 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)
# * 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(), return Seq([Assert(And(is_proper_group_size(),
Txn.group_index() < (Global.group_size() - Int(1)),
Txn.sender() == STATELESS_LOGIC_HASH, Txn.sender() == STATELESS_LOGIC_HASH,
check_guardian_set_size(), check_guardian_set_size(),
check_guardian_key_subset(), check_guardian_key_subset())),
check_txn_note_payload())), If(Txn.group_index() == Global.group_size() -
Int(1)).Then(Return(commit_vaa())),
Approve()]) 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(): def vaa_processor_program():
handle_create = Return(bootstrap()) handle_create = Return(bootstrap())
handle_update = Return(is_creator()) handle_update = Return(is_creator())
@ -208,7 +224,6 @@ def vaa_processor_program():
handle_noop = Cond( handle_noop = Cond(
[METHOD == Bytes("setvphash"), setvphash()], [METHOD == Bytes("setvphash"), setvphash()],
[METHOD == Bytes("verify"), verify()], [METHOD == Bytes("verify"), verify()],
[METHOD == Bytes("commit"), commit()]
) )
return Cond( return Cond(
[Txn.application_id() == Int(0), handle_create], [Txn.application_id() == Int(0), handle_create],