瀏覽代碼

Add new API `create_account` and `delete_account`

	Also, update an access key representation.
	Added an error option for it.
develop
Silvestr Predko 2 年之前
父節點
當前提交
69fb2f78c3
共有 3 個檔案被更改,包括 342 行新增29 行删除
  1. 81
    15
      near-client/src/client.rs
  2. 123
    6
      near-client/src/types/near.rs
  3. 138
    8
      near-client/tests/rpc.rs

+ 81
- 15
near-client/src/client.rs 查看文件

1
 use near_primitives::{
1
 use near_primitives::{
2
-    account::id::AccountId,
2
+    account::{id::AccountId, AccessKey, AccessKeyPermission},
3
     hash::CryptoHash,
3
     hash::CryptoHash,
4
     types::{Balance, Gas, Nonce},
4
     types::{Balance, Gas, Nonce},
5
 };
5
 };
7
 use crate::{
7
 use crate::{
8
     rpc::client::RpcClient,
8
     rpc::client::RpcClient,
9
     types::{
9
     types::{
10
-        crypto::{ED25519PublicKey, ED25519Signature, Keypair},
10
+        crypto::{ED25519PublicKey, ED25519SecretKey, ED25519Signature, Key, Keypair},
11
         near::{
11
         near::{
12
-            Action, Chunks, DeployContractAction, FinalExecutionOutcomeView, FinalExecutionStatus,
13
-            FunctionCallAction, SignedTransaction, Transaction, ViewAccessKeyResult, ViewResult,
12
+            Action, AddKeyAction, Chunks, CreateAccountAction, DeleteAccountAction,
13
+            DeployContractAction, FinalExecutionOutcomeView, FinalExecutionStatus,
14
+            FunctionCallAction, SignedTransaction, Transaction, TransferAction, ViewAccessKey,
15
+            ViewResult,
14
         },
16
         },
15
     },
17
     },
16
     Error,
18
     Error,
25
 pub struct Signer {
27
 pub struct Signer {
26
     keypair: Keypair,
28
     keypair: Keypair,
27
     signer_acc: AccountId,
29
     signer_acc: AccountId,
28
-    key_nonce: Nonce,
30
+    pub key_nonce: Nonce,
29
 }
31
 }
30
 
32
 
31
 impl Signer {
33
 impl Signer {
37
         })
39
         })
38
     }
40
     }
39
 
41
 
42
+    // Temporary implementation
43
+    // TODO: refactor [`Signer`]
44
+    pub fn new_v1(
45
+        secret_key: &ED25519SecretKey,
46
+        signer_acc: AccountId,
47
+        key_nonce: Nonce,
48
+    ) -> Result<Self> {
49
+        let sk = ED25519SecretKey::from_bytes(&secret_key.to_bytes())?;
50
+        Ok(Self {
51
+            keypair: Keypair::new(sk),
52
+            signer_acc,
53
+            key_nonce,
54
+        })
55
+    }
56
+
40
     pub fn sign(&self, data: &[u8]) -> ED25519Signature {
57
     pub fn sign(&self, data: &[u8]) -> ED25519Signature {
41
         self.keypair.sign(data)
58
         self.keypair.sign(data)
42
     }
59
     }
45
         self.keypair.public_key
62
         self.keypair.public_key
46
     }
63
     }
47
 
64
 
65
+    pub fn secret_key(&self) -> &ED25519SecretKey {
66
+        &self.keypair.secret_key
67
+    }
68
+
48
     pub fn account(&self) -> &AccountId {
69
     pub fn account(&self) -> &AccountId {
49
         &self.signer_acc
70
         &self.signer_acc
50
     }
71
     }
122
         &'a self,
143
         &'a self,
123
         account_id: &'a AccountId,
144
         account_id: &'a AccountId,
124
         public_key: &'a ED25519PublicKey,
145
         public_key: &'a ED25519PublicKey,
125
-    ) -> Result<ViewAccessKeyResult> {
146
+    ) -> Result<ViewAccessKey> {
126
         let result = self
147
         let result = self
127
             .rpc_client
148
             .rpc_client
128
-            .request::<ViewAccessKeyResult>(
149
+            .request::<ViewAccessKey>(
129
                 "query",
150
                 "query",
130
                 Some(json!({
151
                 Some(json!({
131
                     "request_type": "view_access_key",
152
                     "request_type": "view_access_key",
163
 
184
 
164
         Call {
185
         Call {
165
             transaction_info,
186
             transaction_info,
166
-            action: Action::from(DeployContractAction { code: wasm }),
187
+            actions: vec![Action::from(DeployContractAction { code: wasm })],
188
+        }
189
+    }
190
+
191
+    pub fn create_account<'a>(
192
+        &'a self,
193
+        signer: &'a mut Signer,
194
+        new_account_id: &'a AccountId,
195
+        new_account_pk: ED25519PublicKey,
196
+        amount: Balance,
197
+    ) -> Call {
198
+        let transaction_info = TransactionInfo::new(self, signer, new_account_id);
199
+        let actions = vec![
200
+            CreateAccountAction {}.into(),
201
+            AddKeyAction {
202
+                public_key: new_account_pk,
203
+                access_key: AccessKey {
204
+                    nonce: 0,
205
+                    permission: AccessKeyPermission::FullAccess,
206
+                },
207
+            }
208
+            .into(),
209
+            TransferAction { deposit: amount }.into(),
210
+        ];
211
+
212
+        Call {
213
+            transaction_info,
214
+            actions,
215
+        }
216
+    }
217
+
218
+    pub fn delete_account<'a>(
219
+        &'a self,
220
+        signer: &'a mut Signer,
221
+        account_id: &'a AccountId,
222
+        beneficiary_acc_id: &'a AccountId,
223
+    ) -> Call {
224
+        let transaction_info = TransactionInfo::new(self, signer, account_id);
225
+        let actions = vec![DeleteAccountAction {
226
+            beneficiary_id: beneficiary_acc_id.clone(),
227
+        }
228
+        .into()];
229
+
230
+        Call {
231
+            transaction_info,
232
+            actions,
167
         }
233
         }
168
     }
234
     }
169
 }
235
 }
170
 
236
 
171
 pub struct Call<'a> {
237
 pub struct Call<'a> {
172
     transaction_info: TransactionInfo<'a>,
238
     transaction_info: TransactionInfo<'a>,
173
-    action: Action,
239
+    actions: Vec<Action>,
174
 }
240
 }
175
 
241
 
176
 impl<'a> Call<'a> {
242
 impl<'a> Call<'a> {
177
     pub async fn commit<T: DeserializeOwned>(self) -> Result<T> {
243
     pub async fn commit<T: DeserializeOwned>(self) -> Result<T> {
178
-        let transaction_bytes = serialize_transaction(&self.transaction_info, self.action).await?;
244
+        let transaction_bytes = serialize_transaction(&self.transaction_info, self.actions).await?;
179
 
245
 
180
         let execution_outcome = self
246
         let execution_outcome = self
181
             .transaction_info
247
             .transaction_info
206
     }
272
     }
207
 
273
 
208
     pub async fn commit_empty(self) -> Result<()> {
274
     pub async fn commit_empty(self) -> Result<()> {
209
-        let transaction_bytes = serialize_transaction(&self.transaction_info, self.action).await?;
275
+        let transaction_bytes = serialize_transaction(&self.transaction_info, self.actions).await?;
210
         let execution_outcome = self
276
         let execution_outcome = self
211
             .transaction_info
277
             .transaction_info
212
             .client
278
             .client
232
     }
298
     }
233
 
299
 
234
     pub async fn commit_async(self) -> Result<String> {
300
     pub async fn commit_async(self) -> Result<String> {
235
-        let transaction_bytes = serialize_transaction(&self.transaction_info, self.action).await?;
301
+        let transaction_bytes = serialize_transaction(&self.transaction_info, self.actions).await?;
236
         self.transaction_info
302
         self.transaction_info
237
             .client
303
             .client
238
             .rpc_client
304
             .rpc_client
265
 
331
 
266
 async fn serialize_transaction<'a>(
332
 async fn serialize_transaction<'a>(
267
     transaction_info: &'a TransactionInfo<'_>,
333
     transaction_info: &'a TransactionInfo<'_>,
268
-    action: Action,
334
+    actions: Vec<Action>,
269
 ) -> Result<Vec<u8>> {
335
 ) -> Result<Vec<u8>> {
270
     let block_hash = transaction_info.client.block().await?;
336
     let block_hash = transaction_info.client.block().await?;
271
 
337
 
275
         nonce: transaction_info.signer.nonce() + 1,
341
         nonce: transaction_info.signer.nonce() + 1,
276
         receiver_id: transaction_info.contract_id.clone(),
342
         receiver_id: transaction_info.contract_id.clone(),
277
         block_hash,
343
         block_hash,
278
-        actions: vec![action],
344
+        actions,
279
     };
345
     };
280
 
346
 
281
     let signed_transaction = sign_transaction(transaction_info.signer, transaction);
347
     let signed_transaction = sign_transaction(transaction_info.signer, transaction);
340
 
406
 
341
         Ok(Call {
407
         Ok(Call {
342
             transaction_info: self.transaction_info,
408
             transaction_info: self.transaction_info,
343
-            action,
409
+            actions: vec![action],
344
         })
410
         })
345
     }
411
     }
346
 }
412
 }

+ 123
- 6
near-client/src/types/near.rs 查看文件

4
 use near_account_id::AccountId;
4
 use near_account_id::AccountId;
5
 
5
 
6
 use near_primitives::{
6
 use near_primitives::{
7
-    account::AccessKey,
7
+    account::{AccessKey, AccessKeyPermission},
8
     hash::{hash, CryptoHash},
8
     hash::{hash, CryptoHash},
9
     logging,
9
     logging,
10
     serialize::{base64_format, u128_dec_format_compatible},
10
     serialize::{base64_format, u128_dec_format_compatible},
11
-    types::{Balance, Gas, Nonce},
11
+    types::{Balance, BlockHeight, Gas, Nonce},
12
+};
13
+use serde::{
14
+    de::{self, Visitor},
15
+    Deserialize, Serialize,
12
 };
16
 };
13
-use serde::{Deserialize, Serialize};
14
 use serde_json::Value;
17
 use serde_json::Value;
15
 use std::{
18
 use std::{
16
     borrow::Borrow,
19
     borrow::Borrow,
460
     pub logs: Vec<String>,
463
     pub logs: Vec<String>,
461
 }
464
 }
462
 
465
 
463
-#[derive(Debug, Clone, Serialize, Deserialize)]
464
-pub struct ViewAccessKeyResult {
465
-    pub nonce: u64,
466
+#[derive(Debug, Clone)]
467
+pub struct ViewAccessKey {
468
+    pub block_hash: CryptoHash,
469
+    pub block_height: BlockHeight,
470
+    pub result: ViewAccessKeyResult,
471
+}
472
+
473
+#[derive(Debug, Clone)]
474
+pub enum ViewAccessKeyResult {
475
+    Ok {
476
+        nonce: Nonce,
477
+        permission: AccessKeyPermissionView,
478
+    },
479
+    Err {
480
+        error: String,
481
+        logs: Vec<String>,
482
+    },
483
+}
484
+
485
+impl From<ViewAccessKey> for Result<Nonce, String> {
486
+    fn from(view: ViewAccessKey) -> Self {
487
+        match view.result {
488
+            ViewAccessKeyResult::Ok { nonce, .. } => Ok(nonce),
489
+            ViewAccessKeyResult::Err { error, .. } => Err(error),
490
+        }
491
+    }
492
+}
493
+
494
+impl<'de> Deserialize<'de> for ViewAccessKey {
495
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
496
+    where
497
+        D: serde::Deserializer<'de>,
498
+    {
499
+        struct Visit;
500
+
501
+        impl<'de> Visitor<'de> for Visit {
502
+            type Value = ViewAccessKey;
503
+
504
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
505
+                write!(formatter, "Expecting an key-value map")
506
+            }
507
+
508
+            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
509
+            where
510
+                A: serde::de::MapAccess<'de>,
511
+            {
512
+                let block_hash = map
513
+                    .next_entry::<String, CryptoHash>()?
514
+                    .ok_or_else(|| de::Error::missing_field("block_hash"))
515
+                    .and_then(|(key, block_hash)| {
516
+                        if key != "block_hash" {
517
+                            Err(serde::de::Error::unknown_field(&key, &["block_hash"]))
518
+                        } else {
519
+                            Ok(block_hash)
520
+                        }
521
+                    })?;
522
+
523
+                let block_height = map
524
+                    .next_entry::<String, BlockHeight>()?
525
+                    .ok_or_else(|| de::Error::missing_field("block_height"))
526
+                    .and_then(|(key, block_hash)| {
527
+                        if key != "block_height" {
528
+                            Err(serde::de::Error::unknown_field(&key, &["block_height"]))
529
+                        } else {
530
+                            Ok(block_hash)
531
+                        }
532
+                    })?;
533
+
534
+                let next_key = map.next_key::<String>()?;
535
+
536
+                match next_key.as_deref() {
537
+                    Some("nonce") => {
538
+                        let nonce = map.next_value::<Nonce>()?;
539
+                        let permission = map
540
+                            .next_entry::<String, AccessKeyPermissionView>()?
541
+                            .ok_or_else(|| de::Error::missing_field("permission"))
542
+                            .and_then(|(key, permission)| {
543
+                                if key != "permission" {
544
+                                    Err(serde::de::Error::unknown_field(&key, &["permission"]))
545
+                                } else {
546
+                                    Ok(permission)
547
+                                }
548
+                            })?;
549
+
550
+                        Ok(ViewAccessKey {
551
+                            block_hash,
552
+                            block_height,
553
+                            result: ViewAccessKeyResult::Ok { nonce, permission },
554
+                        })
555
+                    }
556
+                    Some("error") => {
557
+                        let error = map.next_value::<String>()?;
558
+                        let logs = map
559
+                            .next_entry::<String, Vec<String>>()?
560
+                            .ok_or_else(|| serde::de::Error::missing_field("logs"))
561
+                            .and_then(|(key, logs)| {
562
+                                if key != "logs" {
563
+                                    Err(serde::de::Error::unknown_field(&key, &["logs"]))
564
+                                } else {
565
+                                    Ok(logs)
566
+                                }
567
+                            })?;
568
+
569
+                        Ok(ViewAccessKey {
570
+                            block_hash,
571
+                            block_height,
572
+                            result: ViewAccessKeyResult::Err { error, logs },
573
+                        })
574
+                    }
575
+                    Some(field) => Err(serde::de::Error::unknown_field(field, &["nonce", "error"])),
576
+                    None => Err(serde::de::Error::missing_field("nonce or error")),
577
+                }
578
+            }
579
+        }
580
+
581
+        deserializer.deserialize_map(Visit)
582
+    }
466
 }
583
 }

+ 138
- 8
near-client/tests/rpc.rs 查看文件

1
 use git2::{Cred, RemoteCallbacks};
1
 use git2::{Cred, RemoteCallbacks};
2
 use itertools::Itertools;
2
 use itertools::Itertools;
3
-use near_account_id::AccountId;
4
 use near_client::{
3
 use near_client::{
5
     client::{NearClient, Signer},
4
     client::{NearClient, Signer},
6
-    types::crypto::{ED25519PublicKey, ED25519SecretKey, Key},
5
+    types::{
6
+        crypto::{ED25519PublicKey, ED25519SecretKey, Key},
7
+        near::{ViewAccessKey, ViewAccessKeyResult},
8
+    },
7
 };
9
 };
8
 use rand::{RngCore, SeedableRng};
10
 use rand::{RngCore, SeedableRng};
9
 use rand_chacha::ChaChaRng;
11
 use rand_chacha::ChaChaRng;
14
     path::Path,
16
     path::Path,
15
     str::FromStr,
17
     str::FromStr,
16
 };
18
 };
17
-use workspaces::{network::Sandbox, types::SecretKey, Worker};
19
+use workspaces::{network::Sandbox, types::SecretKey, AccountId, Worker};
18
 
20
 
19
 // auxiliary structs and methods
21
 // auxiliary structs and methods
20
 fn near_client(worker: &Worker<Sandbox>) -> anyhow::Result<NearClient> {
22
 fn near_client(worker: &Worker<Sandbox>) -> anyhow::Result<NearClient> {
34
     let ws_sk = SecretKey::from_str(&ws_secret_key_str)?;
36
     let ws_sk = SecretKey::from_str(&ws_secret_key_str)?;
35
     let _ = worker.create_tla(signer_acc_id.clone(), ws_sk).await?;
37
     let _ = worker.create_tla(signer_acc_id.clone(), ws_sk).await?;
36
 
38
 
37
-    let access_key_nonce = client.view_access_key(signer_acc_id, &pk).await?.nonce;
38
-
39
-    let signer_acc = Signer::new(&ws_secret_key_str, signer_acc_id.clone(), access_key_nonce)?;
40
-
41
-    Ok(signer_acc)
39
+    client
40
+        .view_access_key(signer_acc_id, &pk)
41
+        .await
42
+        .map(|access_key_view| match access_key_view.result {
43
+            ViewAccessKeyResult::Ok { nonce, .. } => {
44
+                let signer_acc = Signer::new(&ws_secret_key_str, signer_acc_id.clone(), nonce)?;
45
+                Ok(signer_acc)
46
+            }
47
+            ViewAccessKeyResult::Err { error, .. } => Err(anyhow::anyhow!(error)),
48
+        })?
42
 }
49
 }
43
 
50
 
44
 async fn download_contract() -> anyhow::Result<Vec<u8>> {
51
 async fn download_contract() -> anyhow::Result<Vec<u8>> {
262
 
269
 
263
     Ok(())
270
     Ok(())
264
 }
271
 }
272
+
273
+#[tokio::test]
274
+async fn view_access_key_success() -> anyhow::Result<()> {
275
+    let worker = workspaces::sandbox().await?;
276
+    let client = near_client(&worker)?;
277
+    let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
278
+    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
279
+
280
+    let new_acc = AccountId::from_str("one.alice.test.near")?;
281
+    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
282
+    let pk = ED25519PublicKey::from(&secret_key);
283
+
284
+    let _ = client
285
+        .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
286
+        .commit::<serde_json::Value>()
287
+        .await?;
288
+
289
+    let access_key = client.view_access_key(&new_acc, &pk).await?;
290
+    assert!(matches!(
291
+        access_key,
292
+        ViewAccessKey {
293
+            result: ViewAccessKeyResult::Ok { .. },
294
+            ..
295
+        }
296
+    ));
297
+
298
+    Ok(())
299
+}
300
+
301
+#[tokio::test]
302
+async fn view_access_key_failure() -> anyhow::Result<()> {
303
+    let worker = workspaces::sandbox().await?;
304
+    let client = near_client(&worker)?;
305
+
306
+    let new_acc = AccountId::from_str("one.alice.test.near")?;
307
+    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
308
+    let pk = ED25519PublicKey::from(&secret_key);
309
+
310
+    let access_key = client.view_access_key(&new_acc, &pk).await?;
311
+    assert!(matches!(
312
+        access_key,
313
+        ViewAccessKey {
314
+            result: ViewAccessKeyResult::Err { .. },
315
+            ..
316
+        }
317
+    ));
318
+
319
+    Ok(())
320
+}
321
+
322
+#[tokio::test]
323
+async fn create_account() -> anyhow::Result<()> {
324
+    let worker = workspaces::sandbox().await?;
325
+    let client = near_client(&worker)?;
326
+    let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
327
+    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
328
+
329
+    let new_acc = AccountId::from_str("one.alice.test.near")?;
330
+    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
331
+    let pk = ED25519PublicKey::from(&secret_key);
332
+
333
+    let _ = client
334
+        .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
335
+        .commit::<serde_json::Value>()
336
+        .await?;
337
+
338
+    let access_key = client.view_access_key(&new_acc, &pk).await?;
339
+    assert!(matches!(
340
+        access_key,
341
+        ViewAccessKey {
342
+            result: ViewAccessKeyResult::Ok { .. },
343
+            ..
344
+        }
345
+    ));
346
+
347
+    Ok(())
348
+}
349
+
350
+#[tokio::test]
351
+async fn delete_account() -> anyhow::Result<()> {
352
+    let worker = workspaces::sandbox().await?;
353
+    let client = near_client(&worker)?;
354
+    let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
355
+    let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
356
+
357
+    let new_acc = AccountId::from_str("one.alice.test.near")?;
358
+    let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
359
+    let pk = ED25519PublicKey::from(&secret_key);
360
+
361
+    client
362
+        .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
363
+        .commit_empty()
364
+        .await?;
365
+
366
+    let access_key = client.view_access_key(&new_acc, &pk).await?;
367
+
368
+    let nonce = if let ViewAccessKey {
369
+        result: ViewAccessKeyResult::Ok { nonce, .. },
370
+        ..
371
+    } = access_key
372
+    {
373
+        nonce
374
+    } else {
375
+        panic!("Can't view access key for just created account")
376
+    };
377
+
378
+    let mut acc_signer = Signer::new(&secret_key.to_string(), new_acc.clone(), nonce)?;
379
+    client
380
+        .delete_account(&mut acc_signer, &new_acc, &signer_account_id)
381
+        .commit_empty()
382
+        .await?;
383
+
384
+    let access_key = client.view_access_key(&new_acc, &pk).await?;
385
+    assert!(matches!(
386
+        access_key,
387
+        ViewAccessKey {
388
+            result: ViewAccessKeyResult::Err { .. },
389
+            ..
390
+        }
391
+    ));
392
+
393
+    Ok(())
394
+}

Loading…
取消
儲存