1
- use codec:: Decode ;
2
- use frame_support:: { log:: error, pallet_prelude:: Weight } ;
1
+ use codec:: { Decode , Encode } ;
2
+ use environment:: Environment ;
3
+ use executor:: Executor ;
4
+ use frame_support:: { log:: error, weights:: Weight } ;
3
5
use pallet_contracts:: chain_extension:: {
4
- ChainExtension , Environment , Ext , InitState , RetVal , SysConfig ,
5
- } ;
6
- use pallet_snarcos:: {
7
- Config , Error , Pallet as Snarcos , ProvingSystem , VerificationKeyIdentifier , WeightInfo ,
6
+ ChainExtension , Environment as SubstrateEnvironment , Ext , InitState , RetVal , SysConfig ,
8
7
} ;
8
+ use pallet_snarcos:: { Config , Error , ProvingSystem , VerificationKeyIdentifier , WeightInfo } ;
9
9
use sp_core:: crypto:: UncheckedFrom ;
10
10
use sp_runtime:: DispatchError ;
11
11
use sp_std:: { mem:: size_of, vec:: Vec } ;
12
12
use Error :: * ;
13
13
14
14
use crate :: { MaximumVerificationKeyLength , Runtime } ;
15
+ mod environment;
16
+ mod executor;
17
+ #[ cfg( test) ]
18
+ mod tests;
15
19
16
20
pub const SNARCOS_STORE_KEY_FUNC_ID : u32 = 41 ;
17
21
pub const SNARCOS_VERIFY_FUNC_ID : u32 = 42 ;
18
22
19
23
// Return codes for `SNARCOS_STORE_KEY_FUNC_ID`.
20
24
pub const SNARCOS_STORE_KEY_OK : u32 = 10_000 ;
21
25
pub const SNARCOS_STORE_KEY_TOO_LONG_KEY : u32 = 10_001 ;
22
- pub const SNARCOS_STORE_KEY_IN_USE : u32 = 10_002 ;
26
+ pub const SNARCOS_STORE_KEY_IDENTIFIER_IN_USE : u32 = 10_002 ;
23
27
pub const SNARCOS_STORE_KEY_ERROR_UNKNOWN : u32 = 10_003 ;
24
28
25
29
// Return codes for `SNARCOS_VERIFY_FUNC_ID`.
@@ -35,13 +39,18 @@ pub const SNARCOS_VERIFY_ERROR_UNKNOWN: u32 = 11_007;
35
39
pub struct SnarcosChainExtension ;
36
40
37
41
impl ChainExtension < Runtime > for SnarcosChainExtension {
38
- fn call < E : Ext > ( func_id : u32 , env : Environment < E , InitState > ) -> Result < RetVal , DispatchError >
42
+ fn call < E : Ext > (
43
+ func_id : u32 ,
44
+ env : SubstrateEnvironment < E , InitState > ,
45
+ ) -> Result < RetVal , DispatchError >
39
46
where
40
47
<E :: T as SysConfig >:: AccountId : UncheckedFrom < <E :: T as SysConfig >:: Hash > + AsRef < [ u8 ] > ,
41
48
{
42
49
match func_id {
43
- SNARCOS_STORE_KEY_FUNC_ID => Self :: snarcos_store_key ( env) ,
44
- SNARCOS_VERIFY_FUNC_ID => Self :: snarcos_verify ( env) ,
50
+ SNARCOS_STORE_KEY_FUNC_ID => {
51
+ Self :: snarcos_store_key :: < _ , Runtime > ( env. buf_in_buf_out ( ) )
52
+ }
53
+ SNARCOS_VERIFY_FUNC_ID => Self :: snarcos_verify :: < _ , Runtime > ( env. buf_in_buf_out ( ) ) ,
45
54
_ => {
46
55
error ! ( "Called an unregistered `func_id`: {}" , func_id) ;
47
56
Err ( DispatchError :: Other ( "Unimplemented func_id" ) )
@@ -58,7 +67,7 @@ pub type ByteCount = u32;
58
67
/// the order of values is important.
59
68
///
60
69
/// It cannot be `MaxEncodedLen` due to `Vec<_>` and thus `Environment::read_as` cannot be used.
61
- #[ derive( Decode ) ]
70
+ #[ derive( Decode , Encode ) ]
62
71
struct StoreKeyArgs {
63
72
pub identifier : VerificationKeyIdentifier ,
64
73
pub key : Vec < u8 > ,
@@ -70,35 +79,53 @@ struct StoreKeyArgs {
70
79
/// the order of values is important.
71
80
///
72
81
/// It cannot be `MaxEncodedLen` due to `Vec<_>` and thus `Environment::read_as` cannot be used.
73
- #[ derive( Decode ) ]
82
+ #[ derive( Decode , Encode ) ]
74
83
struct VerifyArgs {
75
84
pub identifier : VerificationKeyIdentifier ,
76
85
pub proof : Vec < u8 > ,
77
86
pub input : Vec < u8 > ,
78
87
pub system : ProvingSystem ,
79
88
}
80
89
81
- impl SnarcosChainExtension {
82
- fn snarcos_store_key < E : Ext > ( env : Environment < E , InitState > ) -> Result < RetVal , DispatchError >
83
- where
84
- <E :: T as SysConfig >:: AccountId : UncheckedFrom < <E :: T as SysConfig >:: Hash > + AsRef < [ u8 ] > ,
85
- {
86
- // We need to read input as plain bytes (encoded args).
87
- let mut env = env. buf_in_buf_out ( ) ;
90
+ /// Provides a weight of `store_key` dispatchable.
91
+ fn weight_of_store_key ( key_length : ByteCount ) -> Weight {
92
+ <<Runtime as Config >:: WeightInfo as WeightInfo >:: store_key ( key_length)
93
+ }
94
+
95
+ /// Provides a weight of `verify` dispatchable depending on the `ProvingSystem`. In case no system
96
+ /// is passed, we return maximal amongst all the systems.
97
+ fn weight_of_verify ( system : Option < ProvingSystem > ) -> Weight {
98
+ match system {
99
+ Some ( ProvingSystem :: Groth16 ) => {
100
+ <<Runtime as Config >:: WeightInfo as WeightInfo >:: verify_groth16 ( )
101
+ }
102
+ Some ( ProvingSystem :: Gm17 ) => <<Runtime as Config >:: WeightInfo as WeightInfo >:: verify_gm17 ( ) ,
103
+ Some ( ProvingSystem :: Marlin ) => {
104
+ <<Runtime as Config >:: WeightInfo as WeightInfo >:: verify_marlin ( )
105
+ }
106
+ None => weight_of_verify ( Some ( ProvingSystem :: Groth16 ) )
107
+ . max ( weight_of_verify ( Some ( ProvingSystem :: Gm17 ) ) )
108
+ . max ( weight_of_verify ( Some ( ProvingSystem :: Marlin ) ) ) ,
109
+ }
110
+ }
88
111
89
- // Check if it makes sense to read and decode data.
90
- let key_length = env
112
+ impl SnarcosChainExtension {
113
+ fn snarcos_store_key < Env : Environment , Exc : Executor > (
114
+ mut env : Env ,
115
+ ) -> Result < RetVal , DispatchError > {
116
+ // Check if it makes sense to read and decode data. This is only an upperbound for the key
117
+ // length, because this bytes suffix contains (possibly compressed) info about actual key
118
+ // length (needed for decoding).
119
+ let approx_key_length = env
91
120
. in_len ( )
92
121
. saturating_sub ( size_of :: < VerificationKeyIdentifier > ( ) as ByteCount ) ;
93
- if key_length > MaximumVerificationKeyLength :: get ( ) {
122
+ if approx_key_length > MaximumVerificationKeyLength :: get ( ) {
94
123
return Ok ( RetVal :: Converging ( SNARCOS_STORE_KEY_TOO_LONG_KEY ) ) ;
95
124
}
96
125
97
126
// We charge now - even if decoding fails and we shouldn't touch storage, we have to incur
98
127
// fee for reading memory.
99
- env. charge_weight ( <<Runtime as Config >:: WeightInfo as WeightInfo >:: store_key (
100
- key_length,
101
- ) ) ?;
128
+ let pre_charged = env. charge_weight ( weight_of_store_key ( approx_key_length) ) ?;
102
129
103
130
// Parsing will have to be done here. This is due to the fact that methods
104
131
// `Environment<_,_,_,S: BufIn>::read*` don't move starting pointer and thus we can make
@@ -111,42 +138,27 @@ impl SnarcosChainExtension {
111
138
let args = StoreKeyArgs :: decode ( & mut & * bytes)
112
139
. map_err ( |_| DispatchError :: Other ( "Failed to decode arguments" ) ) ?;
113
140
114
- let return_status = match Snarcos :: < Runtime > :: bare_store_key ( args. identifier , args. key ) {
141
+ // Now we know the exact key length.
142
+ env. adjust_weight (
143
+ pre_charged,
144
+ weight_of_store_key ( args. key . len ( ) as ByteCount ) ,
145
+ ) ;
146
+
147
+ let return_status = match Exc :: store_key ( args. identifier , args. key ) {
115
148
Ok ( _) => SNARCOS_STORE_KEY_OK ,
116
149
// In case `DispatchResultWithPostInfo` was returned (or some simpler equivalent for
117
- // `bare_store_key`), we could adjust weight. However, for the storing key action it
118
- // doesn't make sense.
150
+ // `bare_store_key`), we could have adjusted weight. However, for the storing key action
151
+ // it doesn't make much sense.
119
152
Err ( VerificationKeyTooLong ) => SNARCOS_STORE_KEY_TOO_LONG_KEY ,
120
- Err ( IdentifierAlreadyInUse ) => SNARCOS_STORE_KEY_IN_USE ,
153
+ Err ( IdentifierAlreadyInUse ) => SNARCOS_STORE_KEY_IDENTIFIER_IN_USE ,
121
154
_ => SNARCOS_STORE_KEY_ERROR_UNKNOWN ,
122
155
} ;
123
156
Ok ( RetVal :: Converging ( return_status) )
124
157
}
125
158
126
- fn weight_of_verify ( system : Option < ProvingSystem > ) -> Weight {
127
- match system {
128
- Some ( ProvingSystem :: Groth16 ) => {
129
- <<Runtime as Config >:: WeightInfo as WeightInfo >:: verify_groth16 ( )
130
- }
131
- Some ( ProvingSystem :: Gm17 ) => {
132
- <<Runtime as Config >:: WeightInfo as WeightInfo >:: verify_gm17 ( )
133
- }
134
- Some ( ProvingSystem :: Marlin ) => {
135
- <<Runtime as Config >:: WeightInfo as WeightInfo >:: verify_marlin ( )
136
- }
137
- None => Self :: weight_of_verify ( Some ( ProvingSystem :: Groth16 ) )
138
- . max ( Self :: weight_of_verify ( Some ( ProvingSystem :: Gm17 ) ) )
139
- . max ( Self :: weight_of_verify ( Some ( ProvingSystem :: Marlin ) ) ) ,
140
- }
141
- }
142
-
143
- fn snarcos_verify < E : Ext > ( env : Environment < E , InitState > ) -> Result < RetVal , DispatchError >
144
- where
145
- <E :: T as SysConfig >:: AccountId : UncheckedFrom < <E :: T as SysConfig >:: Hash > + AsRef < [ u8 ] > ,
146
- {
147
- // We need to read input as plain bytes (encoded args).
148
- let mut env = env. buf_in_buf_out ( ) ;
149
-
159
+ fn snarcos_verify < Env : Environment , Exc : Executor > (
160
+ mut env : Env ,
161
+ ) -> Result < RetVal , DispatchError > {
150
162
// We charge optimistically, i.e. assuming that decoding succeeds and the verification
151
163
// key is present. However, since we don't know the system yet, we have to charge maximal
152
164
// possible fee. We will adjust it as soon as possible.
@@ -156,23 +168,23 @@ impl SnarcosChainExtension {
156
168
// `pallet_snarcos::WeightInfo::verify_decoding_failure`, we can both charge less here
157
169
// (with further `env.adjust_weight`) and in the pallet itself (returning
158
170
// `DispatchErrorWithPostInfo` reducing actual fee and the block weight).
159
- let pre_charge = env. charge_weight ( Self :: weight_of_verify ( None ) ) ?;
171
+ let pre_charge = env. charge_weight ( weight_of_verify ( None ) ) ?;
160
172
161
173
// Parsing is done here for similar reasons as in `Self::snarcos_store_key`.
162
174
let bytes = env. read ( env. in_len ( ) ) ?;
163
175
164
176
let args: VerifyArgs = VerifyArgs :: decode ( & mut & * bytes)
165
177
. map_err ( |_| DispatchError :: Other ( "Failed to decode arguments" ) ) ?;
166
178
167
- env. adjust_weight ( pre_charge, Self :: weight_of_verify ( Some ( args. system ) ) ) ;
179
+ // Now we know the proving system and we can charge appropriate amount of gas.
180
+ env. adjust_weight ( pre_charge, weight_of_verify ( Some ( args. system ) ) ) ;
168
181
169
- let result =
170
- Snarcos :: < Runtime > :: bare_verify ( args. identifier , args. proof , args. input , args. system ) ;
182
+ let result = Exc :: verify ( args. identifier , args. proof , args. input , args. system ) ;
171
183
172
184
let return_status = match result {
173
185
Ok ( _) => SNARCOS_VERIFY_OK ,
174
186
// In case `DispatchResultWithPostInfo` was returned (or some simpler equivalent for
175
- // `bare_store_key `), we could adjust weight. However, we don't support it yet.
187
+ // `bare_verify `), we could adjust weight. However, we don't support it yet.
176
188
Err ( DeserializingProofFailed ) => SNARCOS_VERIFY_DESERIALIZING_PROOF_FAIL ,
177
189
Err ( DeserializingPublicInputFailed ) => SNARCOS_VERIFY_DESERIALIZING_INPUT_FAIL ,
178
190
Err ( UnknownVerificationKeyIdentifier ) => SNARCOS_VERIFY_UNKNOWN_IDENTIFIER ,
0 commit comments