Skip to content

Commit 9164a3b

Browse files
authored
Add vanchor handler separately (#201)
1 parent edf1d40 commit 9164a3b

File tree

9 files changed

+1921
-0
lines changed

9 files changed

+1921
-0
lines changed

Cargo.lock

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ members = [
1616
"pallets/vanchor",
1717
"pallets/xanchor",
1818
"pallets/anchor-handler",
19+
"pallets/vanchor-handler",
1920
"pallets/token-wrapper",
2021
"pallets/token-wrapper-handler",
2122
"standalone/*",

pallets/vanchor-handler/Cargo.toml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
[package]
2+
authors = ["Webb Technologies Inc."]
3+
description = "FRAME pallet for Webb anchor-handler."
4+
edition = "2018"
5+
homepage = "https://substrate.dev"
6+
license = "Unlicense"
7+
name = "pallet-vanchor-handler"
8+
repository = "https://github.com/webb-tools/protocol-substrate"
9+
version = "1.0.0"
10+
11+
[package.metadata.docs.rs]
12+
targets = ["x86_64-unknown-linux-gnu"]
13+
14+
[dependencies]
15+
# third-party dependencies
16+
serde = { version = "1.0.101", optional = true }
17+
codec = { package = "parity-scale-codec", version = "2.3.0", default-features = false, features = ["derive", "max-encoded-len"] }
18+
19+
# frame dependencies
20+
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
21+
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
22+
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
23+
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
24+
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
25+
sp-io = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
26+
sp-core = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
27+
sp-arithmetic = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
28+
pallet-mt = { path = "../mt", default-features = false }
29+
pallet-linkable-tree = { path = "../linkable-tree", default-features = false }
30+
pallet-vanchor = { path = "../vanchor", default-features = false }
31+
pallet-bridge = { path = "../bridge", default-features = false }
32+
pallet-signature-bridge = { path = "../signature-bridge", default-features = false }
33+
orml-traits = { path = "../../open-runtime-module-library/traits", default-features = false }
34+
webb-primitives = { path = "../../primitives", default-features = false }
35+
pallet-asset-registry = { path = "../asset-registry", default-features = false }
36+
37+
frame-system-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17", optional = true }
38+
frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17", optional = true }
39+
40+
hex-literal = "0.3.4"
41+
42+
[dev-dependencies]
43+
serde = { version = "1.0.119" }
44+
sp-core = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
45+
sp-io = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
46+
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
47+
pallet-balances = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.17" }
48+
pallet-hasher = { path = "../hasher", default-features = false }
49+
pallet-mixer = { path = "../mixer", default-features = false }
50+
pallet-mt = { path = "../mt", default-features = false }
51+
pallet-linkable-tree = { path = "../linkable-tree", default-features = false }
52+
pallet-verifier = { path = "../verifier", default-features = false }
53+
webb-primitives = { path = "../../primitives", default-features = false }
54+
ark-crypto-primitives = { version = "^0.3.0", features = ["r1cs"], default-features = false }
55+
orml-tokens = { path = "../../open-runtime-module-library/tokens", default-features = false }
56+
orml-currencies = { path = "../../open-runtime-module-library/currencies", default-features = false }
57+
58+
ark-bn254 = {version = "^0.3.0", default-features = false, features = ["curve"]}
59+
arkworks-setups = { version = "1.0.0", features = ["r1cs"], default-features = false }
60+
61+
62+
[features]
63+
default = ["std"]
64+
std = [
65+
"codec/std",
66+
"serde",
67+
"sp-std/std",
68+
"sp-runtime/std",
69+
"sp-io/std",
70+
"sp-core/std",
71+
"sp-arithmetic/std",
72+
"frame-support/std",
73+
"frame-system/std",
74+
"pallet-mt/std",
75+
"pallet-vanchor/std",
76+
"pallet-bridge/std",
77+
"pallet-signature-bridge/std",
78+
"orml-traits/std",
79+
"webb-primitives/std",
80+
"pallet-asset-registry/std",
81+
]
82+
runtime-benchmarks = [
83+
"frame-benchmarking",
84+
"frame-system/runtime-benchmarks",
85+
"frame-support/runtime-benchmarks",
86+
]

pallets/vanchor-handler/src/lib.rs

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// This file is part of Webb.
2+
3+
// Copyright (C) 2021 Webb Technologies Inc.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
//! # Anchor Handler Module
19+
//!
20+
//! A module for executing the creation and modification of anchors.
21+
//!
22+
//! ## Overview
23+
//!
24+
//! The anchor-handler module provides functionality for the following:
25+
//!
26+
//! * The creation of anchors from proposals
27+
//! * Updating existing anchors from proposals
28+
//!
29+
//! ## Interface
30+
//!
31+
//! ### Permissioned Functions
32+
//!
33+
//! * `execute_vanchor_create_proposal`: Creates a vanchor from successfully voted on proposal. This
34+
//! method requires the `origin` to be [T::BridgeOrigin].
35+
//! * `execute_vanchor_update_proposal`: Adds/Updates a vanchor from successfully voted on proposal.
36+
//! This method requires the `origin` to be [T::BridgeOrigin].
37+
//!
38+
//! ## Related Modules
39+
//!
40+
//! * VAnchor pallet
41+
//! * Linkable-tree pallet
42+
43+
// Ensure we're `no_std` when compiling for Wasm.
44+
#![cfg_attr(not(feature = "std"), no_std)]
45+
46+
#[cfg(test)]
47+
pub mod mock_bridge;
48+
#[cfg(test)]
49+
mod tests_bridge;
50+
51+
#[cfg(test)]
52+
pub mod mock_signature_bridge;
53+
#[cfg(test)]
54+
mod tests_signature_bridge;
55+
56+
use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, traits::EnsureOrigin};
57+
use frame_system::pallet_prelude::OriginFor;
58+
use pallet_linkable_tree::types::EdgeMetadata;
59+
use pallet_vanchor::{BalanceOf as VAnchorBalanceOf, CurrencyIdOf as VAnchorCurrencyIdOf};
60+
use webb_primitives::{
61+
traits::vanchor::{VAnchorConfig, VAnchorInspector, VAnchorInterface},
62+
ResourceId,
63+
};
64+
pub mod types;
65+
use types::*;
66+
67+
pub use pallet::*;
68+
69+
#[frame_support::pallet]
70+
pub mod pallet {
71+
use super::*;
72+
use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*};
73+
use frame_system::pallet_prelude::*;
74+
use pallet_linkable_tree::types::EdgeMetadata;
75+
use pallet_vanchor::VAnchorConfigration;
76+
77+
#[pallet::pallet]
78+
#[pallet::generate_store(pub(super) trait Store)]
79+
#[pallet::without_storage_info]
80+
pub struct Pallet<T, I = ()>(_);
81+
82+
#[pallet::config]
83+
/// The module configuration trait.
84+
pub trait Config<I: 'static = ()>: frame_system::Config + pallet_vanchor::Config<I> {
85+
/// The overarching event type.
86+
type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;
87+
88+
type BridgeOrigin: EnsureOrigin<Self::Origin, Success = Self::AccountId>;
89+
90+
/// VAnchor Interface
91+
type VAnchor: VAnchorInterface<VAnchorConfigration<Self, I>>
92+
+ VAnchorInspector<VAnchorConfigration<Self, I>>;
93+
}
94+
95+
/// The map of trees to their anchor metadata
96+
#[pallet::storage]
97+
#[pallet::getter(fn anchor_list)]
98+
pub type AnchorList<T: Config<I>, I: 'static = ()> =
99+
StorageMap<_, Blake2_128Concat, ResourceId, T::TreeId, ValueQuery>;
100+
101+
#[pallet::storage]
102+
#[pallet::getter(fn update_records)]
103+
/// sourceChainID => nonce => Update Record
104+
pub type UpdateRecords<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
105+
_,
106+
Blake2_128Concat,
107+
T::ChainId,
108+
Blake2_128Concat,
109+
u64,
110+
UpdateRecord<T::TreeId, ResourceId, T::ChainId, T::Element, T::LeafIndex>,
111+
ValueQuery,
112+
>;
113+
114+
#[pallet::storage]
115+
#[pallet::getter(fn counts)]
116+
/// The number of updates
117+
pub(super) type Counts<T: Config<I>, I: 'static = ()> =
118+
StorageMap<_, Blake2_128Concat, T::ChainId, u64, ValueQuery>;
119+
120+
#[pallet::event]
121+
#[pallet::generate_deposit(pub(super) fn deposit_event)]
122+
pub enum Event<T: Config<I>, I: 'static = ()> {
123+
AnchorCreated,
124+
AnchorEdgeAdded,
125+
AnchorEdgeUpdated,
126+
}
127+
128+
#[pallet::error]
129+
pub enum Error<T, I = ()> {
130+
/// Access violation.
131+
InvalidPermissions,
132+
// Anchor handler already exists for specified resource Id.
133+
ResourceIsAlreadyAnchored,
134+
// Anchor handler doesn't exist for specified resoure Id.
135+
AnchorHandlerNotFound,
136+
// Source chain Id is not registered.
137+
SourceChainIdNotFound,
138+
/// Storage overflowed.
139+
StorageOverflow,
140+
}
141+
142+
#[pallet::hooks]
143+
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {}
144+
145+
#[pallet::call]
146+
impl<T: Config<I>, I: 'static> Pallet<T, I> {
147+
/// This will be called by bridge when proposal to create a
148+
/// vanchor has been successfully voted on.
149+
#[pallet::weight(195_000_000)]
150+
pub fn execute_vanchor_create_proposal(
151+
origin: OriginFor<T>,
152+
src_chain_id: T::ChainId,
153+
r_id: ResourceId,
154+
max_edges: u32,
155+
tree_depth: u8,
156+
asset: VAnchorCurrencyIdOf<T, I>,
157+
) -> DispatchResultWithPostInfo {
158+
T::BridgeOrigin::ensure_origin(origin)?;
159+
Self::create_vanchor(src_chain_id, r_id, max_edges, tree_depth, asset)
160+
}
161+
162+
/// This will be called by bridge when proposal to add/update edge of a
163+
/// vanchor has been successfully voted on.
164+
#[pallet::weight(195_000_000)]
165+
pub fn execute_vanchor_update_proposal(
166+
origin: OriginFor<T>,
167+
r_id: ResourceId,
168+
vanchor_metadata: EdgeMetadata<T::ChainId, T::Element, T::LeafIndex>,
169+
) -> DispatchResultWithPostInfo {
170+
T::BridgeOrigin::ensure_origin(origin)?;
171+
Self::update_vanchor(r_id, vanchor_metadata)
172+
}
173+
174+
// TODO: Add configurable limit proposal executors for VAnchors
175+
}
176+
}
177+
178+
impl<T: Config<I>, I: 'static> VAnchorConfig for Pallet<T, I> {
179+
type AccountId = T::AccountId;
180+
type Balance = VAnchorBalanceOf<T, I>;
181+
type Amount = i128;
182+
type ChainId = T::ChainId;
183+
type CurrencyId = VAnchorCurrencyIdOf<T, I>;
184+
type Element = T::Element;
185+
type LeafIndex = T::LeafIndex;
186+
type TreeId = T::TreeId;
187+
}
188+
189+
impl<T: Config<I>, I: 'static> Pallet<T, I> {
190+
fn create_vanchor(
191+
src_chain_id: T::ChainId,
192+
r_id: ResourceId,
193+
max_edges: u32,
194+
tree_depth: u8,
195+
asset: VAnchorCurrencyIdOf<T, I>,
196+
) -> DispatchResultWithPostInfo {
197+
ensure!(!AnchorList::<T, I>::contains_key(r_id), Error::<T, I>::ResourceIsAlreadyAnchored);
198+
let tree_id = T::VAnchor::create(None, tree_depth, max_edges, asset)?;
199+
AnchorList::<T, I>::insert(r_id, tree_id);
200+
Counts::<T, I>::insert(src_chain_id, 0);
201+
Self::deposit_event(Event::AnchorCreated);
202+
Ok(().into())
203+
}
204+
205+
fn update_vanchor(
206+
r_id: ResourceId,
207+
anchor_metadata: EdgeMetadata<T::ChainId, T::Element, T::LeafIndex>,
208+
) -> DispatchResultWithPostInfo {
209+
let tree_id =
210+
AnchorList::<T, I>::try_get(r_id).map_err(|_| Error::<T, I>::AnchorHandlerNotFound)?;
211+
let (src_chain_id, merkle_root, latest_leaf_index, target) = (
212+
anchor_metadata.src_chain_id,
213+
anchor_metadata.root,
214+
anchor_metadata.latest_leaf_index,
215+
anchor_metadata.target,
216+
);
217+
218+
if T::VAnchor::has_edge(tree_id, src_chain_id) {
219+
T::VAnchor::update_edge(tree_id, src_chain_id, merkle_root, latest_leaf_index, target)?;
220+
Self::deposit_event(Event::AnchorEdgeUpdated);
221+
} else {
222+
T::VAnchor::add_edge(tree_id, src_chain_id, merkle_root, latest_leaf_index, target)?;
223+
Self::deposit_event(Event::AnchorEdgeAdded);
224+
}
225+
let nonce = Counts::<T, I>::try_get(src_chain_id)
226+
.map_err(|_| Error::<T, I>::SourceChainIdNotFound)?;
227+
let record = UpdateRecord { tree_id, resource_id: r_id, edge_metadata: anchor_metadata };
228+
UpdateRecords::<T, I>::insert(src_chain_id, nonce, record);
229+
Counts::<T, I>::mutate(src_chain_id, |val| -> DispatchResultWithPostInfo {
230+
*val = val.checked_add(1).ok_or(Error::<T, I>::StorageOverflow)?;
231+
Ok(().into())
232+
})
233+
}
234+
}

0 commit comments

Comments
 (0)