forked from Vero-protocol/vero-core-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzk_hooks.rs
More file actions
143 lines (122 loc) · 4.25 KB
/
Copy pathzk_hooks.rs
File metadata and controls
143 lines (122 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Stable ZK proof attestation hook for the control plane.
//!
//! The audit module validates state-transition commitments. This module anchors
//! proof hashes against those committed state roots, creating a small and stable
//! ABI for off-chain ZK workers and indexers.
use soroban_sdk::{
contracterror, contracttype, panic_with_error, symbol_short, Address, Bytes, BytesN, Env, Map,
Symbol,
};
use crate::audit;
use crate::event_struct::{ACT_COMMIT, MOD_AUDIT};
use crate::event_utils::publish_event;
const KEY_PROOF_COUNT: Symbol = symbol_short!("ZK_COUNT");
const MAX_METADATA_ENTRIES: u32 = 16;
const MAX_METADATA_VALUE_BYTES: u32 = 256;
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ZkProofKey {
Proof(BytesN<32>),
Attestation(BytesN<32>),
}
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ProofAttestation {
pub state_root: BytesN<32>,
pub proof_hash: BytesN<32>,
pub block_seq: u32,
pub registered_at_ledger: u32,
pub metadata: Map<Symbol, Bytes>,
}
#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum ZkHookError {
Unauthorized = 1,
StateRootMismatch = 2,
InvalidProofHash = 3,
MetadataTooLarge = 4,
NotInitialized = 5,
ArithmeticOverflow = 6,
}
/// Register or update the proof hash associated with the latest committed state root.
pub fn register_proof(
env: &Env,
caller: &Address,
state_root: BytesN<32>,
proof_hash: BytesN<32>,
block_seq: u32,
metadata: Map<Symbol, Bytes>,
) {
require_control_plane_admin(env, caller);
validate_current_state_root(env, &state_root);
validate_proof_hash(env, &proof_hash);
validate_metadata(env, &metadata);
let attestation = ProofAttestation {
state_root: state_root.clone(),
proof_hash: proof_hash.clone(),
block_seq,
registered_at_ledger: env.ledger().sequence(),
metadata,
};
env.storage()
.instance()
.set(&ZkProofKey::Proof(state_root.clone()), &proof_hash);
env.storage()
.instance()
.set(&ZkProofKey::Attestation(state_root.clone()), &attestation);
increment_proof_count(env);
publish_event(env, MOD_AUDIT | ACT_COMMIT, block_seq as u64, proof_hash);
}
pub fn get_proof(env: &Env, state_root: BytesN<32>) -> Option<BytesN<32>> {
env.storage().instance().get(&ZkProofKey::Proof(state_root))
}
pub fn get_attestation(env: &Env, state_root: BytesN<32>) -> Option<ProofAttestation> {
env.storage()
.instance()
.get(&ZkProofKey::Attestation(state_root))
}
pub fn proof_count(env: &Env) -> u64 {
env.storage().instance().get(&KEY_PROOF_COUNT).unwrap_or(0)
}
fn require_control_plane_admin(env: &Env, caller: &Address) {
// Keep this in sync with control_plane::KEY_ADMIN without exposing the raw
// key publicly. Storage is shared because zk_hooks is invoked inside the
// same contract instance.
const KEY_ADMIN: Symbol = symbol_short!("ADMIN");
caller.require_auth();
let admin: Address = env
.storage()
.instance()
.get(&KEY_ADMIN)
.unwrap_or_else(|| panic_with_error!(env, ZkHookError::NotInitialized));
if caller != &admin {
panic_with_error!(env, ZkHookError::Unauthorized);
}
}
fn validate_current_state_root(env: &Env, state_root: &BytesN<32>) {
if audit::get_last_sequence(env) == 0 || audit::get_state_hash(env) != *state_root {
panic_with_error!(env, ZkHookError::StateRootMismatch);
}
}
fn validate_proof_hash(env: &Env, proof_hash: &BytesN<32>) {
if proof_hash.to_array() == [0u8; 32] {
panic_with_error!(env, ZkHookError::InvalidProofHash);
}
}
fn validate_metadata(env: &Env, metadata: &Map<Symbol, Bytes>) {
if metadata.len() > MAX_METADATA_ENTRIES {
panic_with_error!(env, ZkHookError::MetadataTooLarge);
}
for (_, value) in metadata.iter() {
if value.len() > MAX_METADATA_VALUE_BYTES {
panic_with_error!(env, ZkHookError::MetadataTooLarge);
}
}
}
fn increment_proof_count(env: &Env) {
let count = proof_count(env);
let next = count
.checked_add(1)
.unwrap_or_else(|| panic_with_error!(env, ZkHookError::ArithmeticOverflow));
env.storage().instance().set(&KEY_PROOF_COUNT, &next);
}