Handle VAA at last TX.
This commit is contained in:
parent
ff486b7711
commit
a3d5ce05fc
|
@ -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],
|
||||||
|
|
Loading…
Reference in New Issue