-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
744 lines (389 loc) · 233 KB
/
atom.xml
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>人话翻译机</title>
<subtitle>有限的时间,先限的可能</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://liukai.net/"/>
<updated>2023-11-20T15:46:16.396Z</updated>
<id>https://liukai.net/</id>
<author>
<name>潇洒</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>ETH-EIP-4337</title>
<link href="https://liukai.net/posts/752261e8.html"/>
<id>https://liukai.net/posts/752261e8.html</id>
<published>2023-11-20T15:40:48.000Z</published>
<updated>2023-11-20T15:46:16.396Z</updated>
<content type="html"><![CDATA[<h1 id="EIP-4337"><a href="#EIP-4337" class="headerlink" title="EIP-4337"></a>EIP-4337</h1><p>首先声明以下几点:</p><ol><li>用户钱包都采用 <strong>contract</strong> 实现,每个用户对应一个合约地址</li><li>用户初次发起交易时,会<strong>自动创建合约</strong></li><li>用户可以指定一个 payment 合约地址,用该地址中的余额支付手续费</li></ol><h3 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a>整体架构</h3><p><img src="/posts/752261e8/%E6%95%B4%E4%BD%93%E6%9E%B6%E6%9E%84.png" alt="image"></p><p>ERC-4337 定义了一个基于 ETH 的账户抽象标准,以下为简单介绍。</p><ul><li>UserOperation:类比原生交易,不过为另一种格式的交易,比如支持携带自定义签名、交易的基础信息(gas、sender、limit等)</li><li>UserOperation mempool:专门的一些节点搭建的P2P网络构成的交易缓存池,用于接受UserOperation</li><li>Bundler:负责收集、校验、打包UserOperation,并将打包好的交易发送给产块人,交易上链的费用由Bundler支付,但是Bundler会从UserOperation中获取用户的手续费作为奖励。</li></ul><p>Note:本质上是启动了一个独立于主链的P2P网络,用于接收抽象账户的交易并打包上链。</p><p><a href="https://github.com/ethereum/EIPs/blob/3fd65b1a782912bfc18cb975c62c55f733c7c96e/EIPS/eip-4337.md">https://github.com/ethereum/EIPs/blob/3fd65b1a782912bfc18cb975c62c55f733c7c96e/EIPS/eip-4337.md</a></p>]]></content>
<summary type="html">
<h1 id="EIP-4337"><a href="#EIP-4337" class="headerlink" title="EIP-4337"></a>EIP-4337</h1><p>首先声明以下几点:</p>
<ol>
<li>用户钱包都采用 <strong>contrac
</summary>
<category term="blockchain" scheme="https://liukai.net/categories/blockchain/"/>
<category term="ethereum" scheme="https://liukai.net/categories/ethereum/"/>
<category term="eth" scheme="https://liukai.net/categories/eth/"/>
<category term="4337" scheme="https://liukai.net/categories/eth/4337/"/>
<category term="eip" scheme="https://liukai.net/categories/ethereum/eip/"/>
<category term="eth" scheme="https://liukai.net/categories/blockchain/eth/"/>
<category term="blockchain" scheme="https://liukai.net/tags/blockchain/"/>
<category term="eth" scheme="https://liukai.net/tags/eth/"/>
<category term="eip" scheme="https://liukai.net/tags/eip/"/>
<category term="4337" scheme="https://liukai.net/tags/4337/"/>
</entry>
<entry>
<title>Cosmos 普通交易手续费调研</title>
<link href="https://liukai.net/posts/819a1e2d.html"/>
<id>https://liukai.net/posts/819a1e2d.html</id>
<published>2023-09-18T09:19:26.000Z</published>
<updated>2023-11-20T15:36:38.470Z</updated>
<content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>分析 cosmos 的交易手续费的实现细节,以了解其实现手续费模型用于实现参考。<br>在 cosmos 中,<code>gas</code> 用于跟踪执行期间的资源消耗。<strong>普通交易</strong>消耗的也是 <code>gas</code>。<br><code>gas</code> 通常在对<strong>存储</strong>进行<strong>读取</strong>和<strong>写入</strong>时使用,但如果需要执行昂贵的<strong>计算</strong>,也可以使用。</p><p>重点关注的两件事情:</p><ol><li>如果计算、校验,即交易做了哪些操作,是否合法</li><li>每个操作的收费是如何定价的,包括:读取、存储、计算。</li></ol><p>tx 会产生所有状态读取/写入、签名验证以及与 tx 大小成比例的成本的 gas 成本。运营商在启动节点时会设定最低 gas 价格。</p><h2 id="需要消耗-gas的交易类型"><a href="#需要消耗-gas的交易类型" class="headerlink" title="需要消耗 gas的交易类型"></a>需要消耗 gas的交易类型</h2><p><strong>每个交易</strong>在执行过程中都会消耗一定数量的Gas,该Gas用于跟踪执行过程中的资源消耗。<br>在Cosmos SDK应用程序中,交易可以是发送消息(Message)的操作,例如</p><ol><li>发送代币</li><li>执行智能合约</li></ol><p>当执行这些消息时,相关的Gas会被消耗,并且可能会生成相应的费用(Fees)。</p><p>请注意,<strong>Gas的消耗和费用的生成通常由应用程序开发者定义和管理</strong>,可以根据具体的应用逻辑和需求进行设置。</p><p>Cosmos SDK提供了<strong>Gas计量器(GasMeter)(主要就是通过个是来记录gas消耗)</strong>和相关的方法来追踪Gas的消耗和管理费用的生成。开发者可以在交易的执行逻辑中使用Gas计量器来测量Gas的消耗,并根据消耗的Gas数量来计算相应的费用。</p><p>因此,Gas的消耗和费用的生成是与交易(Transaction)密切相关的,并由应用程序开发者根据具体需求进行定义和管理。</p><h2 id="交易收费"><a href="#交易收费" class="headerlink" title="交易收费"></a>交易收费</h2><p>收费公式:<code>fees = gas * gas-prices</code>,交易费用按共识计算的确切gas价格收取。</p><p>收费有两个主要目的:</p><ol><li>确保块不会消耗太多资源</li><li>防止用户发起垃圾交易</li></ol><h3 id="普通交易的gas是如何计算的"><a href="#普通交易的gas是如何计算的" class="headerlink" title="普通交易的gas是如何计算的"></a>普通交易的gas是如何计算的</h3><p>通过对交易的长度进行计算,最终确认这笔交易所需要gas。而当发送到节点的交易低于全节点本地设置的 <code>min-gas-prices</code> ,交易将直接被丢弃,这可确保 mempool 不会被垃圾交易塞满。</p><p>对于数据读、写的操作,可以通过根据需要设置每个gas的消耗,以下是Cosmos官方的默认设定:</p><table><thead><tr><th><strong>操作</strong></th><th><strong>作用</strong></th><th><strong>gas</strong></th></tr></thead><tbody><tr><td>HasCost</td><td>检查是否存在kay的 Gas 消耗</td><td>1000</td></tr><tr><td>DeleteCost</td><td>删除kay的 Gas 消耗</td><td>1000</td></tr><tr><td>ReadCostFlat</td><td>读取操作的固定 Gas 消耗</td><td>1000</td></tr><tr><td>ReadCostPerByte</td><td>每字节读取操作的额外 Gas 消耗</td><td>3</td></tr><tr><td>WriteCostFlat</td><td>写入操作的固定 Gas 消耗</td><td>2000</td></tr><tr><td>WriteCostPerByte</td><td>每字节写入操作的额外 Gas 消耗</td><td>30</td></tr><tr><td>IterNextCostFlat</td><td>迭代器的下一个操作的固定 Gas 消耗</td><td>30</td></tr></tbody></table><h3 id="1-写入收费"><a href="#1-写入收费" class="headerlink" title="1.写入收费"></a>1.写入收费</h3><p>对数据写入的gas消耗需要计算 key 和 value 的大小,如下:</p><p>总消耗 = keyGas + valueGas</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">key = WriteCostPerByte * len(key)</span><br><span class="line">value = WriteCostPerByte * len(value)</span><br></pre></td></tr></table></figure><h3 id="2-签名收费"><a href="#2-签名收费" class="headerlink" title="2.签名收费"></a>2.签名收费</h3><p>普通交易按照<strong>签名</strong>后的字节长度进行计费,每笔交易的gas有上限。</p><p>计算公式:</p><p><code>总消耗</code> = <code>原始交易byte大小</code> + <code>签名数据大小</code> * <code>每个字节的 Gas 消耗值</code><br><code>ConsumeGas</code> = <code>byte</code> + <code>TxSizeCostPerByte</code> * <code>cost</code><br><code>params.TxSizeCostPerByte</code> 就是用来定义每个字节的额外 Gas 消耗值。通过将交易的大小乘以该值,可以得到交易大小对应的额外 Gas 消耗。</p><h3 id="3-读取收费"><a href="#3-读取收费" class="headerlink" title="3.读取收费"></a>3.读取收费</h3><p>对数据读取的gas消耗需要计算 key 和 value 的大小,如下:</p><p>总消耗 = keyGas + valueGas</p><figure class="highlight plain"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">keyGas = ReadCostPerByte * len(key)</span><br><span class="line">valueGas = ReadCostPerByte * len(value)</span><br></pre></td></tr></table></figure><h3 id="4-gas-price"><a href="#4-gas-price" class="headerlink" title="4.gas price"></a>4.gas price</h3><p>gas price 是动态的变动的,有三种方式:</p><ol><li>提案进行修改,很少情况会通过这种方式修改</li><li>前一个区块负载进行调整</li><li>前一个区块负载以更高的速度进行调整</li></ol><h2 id="实现部分分析"><a href="#实现部分分析" class="headerlink" title="实现部分分析"></a>实现部分分析</h2><p>gas 的消耗有两个功能跟踪:</p><ol><li>Main Gas Meter 主gas表<br>作用:用于跟踪每一笔交易的执行消耗。</li><li>Block Gas Meter<br>作用:用于跟踪每一个区块的gas消耗。</li></ol><p>Cosmos 通过抽像 Meter 数据结构,对gas的消耗进行跟踪。</p><h3 id="1-Main-Gas-Meter-交易gas跟踪"><a href="#1-Main-Gas-Meter-交易gas跟踪" class="headerlink" title="1.Main Gas Meter 交易gas跟踪"></a>1.Main Gas Meter 交易gas跟踪</h3><p>作用:用于跟踪每一笔交易的执行消耗。</p><p>在 Cosmos SDK 中,<code>gas</code>是简单的别名,由名为<code>GasMeter</code> 结构的一个字段<code>uint64</code></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// GasMeter interface to track gas consumption</span></span><br><span class="line"> <span class="keyword">type</span> GasMeter <span class="keyword">interface</span> {</span><br><span class="line"> GasConsumed() Gas</span><br><span class="line"> GasConsumedToLimit() Gas</span><br><span class="line"> GasRemaining() Gas</span><br><span class="line"> Limit() Gas</span><br><span class="line"> ConsumeGas(amount Gas, descriptor <span class="keyword">string</span>)</span><br><span class="line"> RefundGas(amount Gas, descriptor <span class="keyword">string</span>)</span><br><span class="line"> IsPastLimit() <span class="keyword">bool</span></span><br><span class="line"> IsOutOfGas() <span class="keyword">bool</span></span><br><span class="line"> String() <span class="keyword">string</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><code>GasConsumed()</code> 返回 gas meter实例消耗的gas量。</li><li><code>GasConsumedToLimit()</code> 返回 gas meter 实例消耗的gas量或达到限制(如果达到限制)。</li><li><code>GasRemaining()</code> 返回 gas mete 中剩余的gas。</li><li><code>Limit()</code> 返回gas meter实例的限制。 <code>0</code> 如果燃气表是无限大的。</li><li><code>ConsumeGas(amount Gas, descriptor string)</code> 消耗提供的数量 <code>gas</code> 。<br>如果溢出, <code>gas</code> 它会对 <code>descriptor</code> 消息感到恐慌(panics)。<br>如果燃气表不是无限的,消耗超过限制,它会 <code>gas</code> 恐慌(panics)。</li><li><code>RefundGas()</code> 从消耗的gas中扣除给定的量。此功能可以将gas退还到交易或区块 gas 池,以便EVM兼容链可以完全支持go-ethereum <code>StateDB</code>接口。</li><li><code>IsPastLimit()</code> 如果gas meter实例消耗的 gas 量严格高于限制, <code>false</code> 则返回 <code>true</code> 。</li><li><code>IsOutOfGas()</code> 如果燃气表实例消耗的 gas 量高于或等于限制, <code>false</code> 则返回,否则返回 <code>true</code> 。</li></ul><h3 id="2-读-写-操作的gas消耗跟踪"><a href="#2-读-写-操作的gas消耗跟踪" class="headerlink" title="2.读/写 操作的gas消耗跟踪"></a>2.读/写 操作的gas消耗跟踪</h3><p>Cosmos 中对读 和 写的操作,记录到 gasMeter 中,先操作后,再进行记录,每一笔交易的gas 都有上限,实现逻辑如下</p><ol><li>进行数据库读写</li><li>计算所需要的gas值</li><li>注意 <code>gs.gasConfig.ReadCostPerByte</code> 是一个常量值,见上文</li><li><code>key</code> 和 <code>value</code> 都需要计算 gas</li></ol><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Implements KVStore.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(gs *Store)</span> <span class="title">Get</span><span class="params">(key []<span class="keyword">byte</span>)</span> <span class="params">(value []<span class="keyword">byte</span>)</span></span> {</span><br><span class="line"> gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostFlat, types.GasReadCostFlatDesc)</span><br><span class="line"> <span class="comment">// parent 是 types.KVStore,即数据库接口</span></span><br><span class="line"> value = gs.parent.Get(key)</span><br><span class="line"></span><br><span class="line"> <span class="comment">// TODO overflow-safe math?</span></span><br><span class="line"> <span class="comment">// 对读的操作,记录到 gasMeter 中</span></span><br><span class="line"> gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(<span class="built_in">len</span>(key)), types.GasReadPerByteDesc)</span><br><span class="line"> gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(<span class="built_in">len</span>(value)), types.GasReadPerByteDesc)</span><br><span class="line"> <span class="keyword">return</span> value</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">// Implements KVStore.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(gs *Store)</span> <span class="title">Set</span><span class="params">(key, value []<span class="keyword">byte</span>)</span></span> {</span><br><span class="line"> types.AssertValidKey(key)</span><br><span class="line"> types.AssertValidValue(value)</span><br><span class="line"> gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostFlat, types.GasWriteCostFlatDesc)</span><br><span class="line"></span><br><span class="line"> <span class="comment">// TODO overflow-safe math?</span></span><br><span class="line"> gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(<span class="built_in">len</span>(key)), types.GasWritePerByteDesc)</span><br><span class="line"> gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(<span class="built_in">len</span>(value)), types.GasWritePerByteDesc)</span><br><span class="line"> gs.parent.Set(key, value) </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="3-签名gas消耗"><a href="#3-签名gas消耗" class="headerlink" title="3.签名gas消耗"></a>3.签名gas消耗</h3><p>对于签名部分,也是需要计算gas的消耗,<code>总消耗</code> = <code>原始交易byte大小</code> + <code>签名数据大小</code> * <code>每个字节的 Gas 消耗值</code></p><p>x/auth/ante/basic.go</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(cgts ConsumeTxSizeGasDecorator)</span> <span class="title">AnteHandle</span><span class="params">(ctx sdk.Context, tx sdk.Tx, simulate <span class="keyword">bool</span>, next sdk.AnteHandler)</span> <span class="params">(sdk.Context, error)</span></span> {</span><br><span class="line"> sigTx, ok := tx.(authsigning.SigVerifiableTx)</span><br><span class="line"> <span class="keyword">if</span> !ok {</span><br><span class="line"> <span class="keyword">return</span> ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, <span class="string">"invalid tx type"</span>)</span><br><span class="line"> }</span><br><span class="line"> params := cgts.ak.GetParams(ctx)</span><br><span class="line"> <span class="comment">// 计算交易长度</span></span><br><span class="line"> <span class="comment">// ctx: transaction 交易上下文</span></span><br><span class="line"> <span class="comment">// 注意,此处跟踪原始交易 byte 长度</span></span><br><span class="line"> ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*storetypes.Gas(<span class="built_in">len</span>(ctx.TxBytes())), <span class="string">"txSize"</span>)</span><br><span class="line"> <span class="comment">// simulate gas cost for signatures in simulate mode</span></span><br><span class="line"> <span class="comment">// 在模拟模式下模拟签名的gas成本</span></span><br><span class="line"> <span class="keyword">if</span> simulate {</span><br><span class="line"> <span class="comment">// in simulate mode, each element should be a nil signature</span></span><br><span class="line"> <span class="comment">// 在模拟模式下,每个元素都应是 nil 签名 </span></span><br><span class="line"> sigs, err := sigTx.GetSignaturesV2()</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> <span class="keyword">return</span> ctx, err</span><br><span class="line"> } n := <span class="built_in">len</span>(sigs) signers, err := sigTx.GetSigners() <span class="keyword">if</span> err != <span class="literal">nil</span> { <span class="keyword">return</span> sdk.Context{}, err }</span><br><span class="line"> <span class="keyword">for</span> i, signer := <span class="keyword">range</span> signers {</span><br><span class="line"> <span class="comment">// if signature is already filled in, no need to simulate gas cost</span></span><br><span class="line"> <span class="comment">// 如果签名已填写,则无需模拟gas成本</span></span><br><span class="line"> <span class="keyword">if</span> i < n && !isIncompleteSignature(sigs[i].Data) {</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">var</span> pubkey cryptotypes.PubKey</span><br><span class="line"> acc := cgts.ak.GetAccount(ctx, signer)</span><br><span class="line"></span><br><span class="line"> <span class="comment">// use placeholder simSecp256k1Pubkey</span></span><br><span class="line"> <span class="keyword">if</span> sig is <span class="literal">nil</span> <span class="keyword">if</span> acc == <span class="literal">nil</span> || acc.GetPubKey() == <span class="literal">nil</span> {</span><br><span class="line"> pubkey = simSecp256k1Pubkey </span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> pubkey = acc.GetPubKey()</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// use stdsignature to mock the size of a full signature</span></span><br><span class="line"> <span class="comment">// 使用 stdsignature 模拟完整签名的大小</span></span><br><span class="line"> simSig := legacytx.StdSignature{ <span class="comment">//nolint:staticcheck // SA1019: legacytx.StdSignature is deprecated </span></span><br><span class="line"> Signature: simSecp256k1Sig[:],</span><br><span class="line"> PubKey: pubkey,</span><br><span class="line"> }</span><br><span class="line"> sigBz := legacy.Cdc.MustMarshal(simSig)</span><br><span class="line"> <span class="comment">// cost 为签名长度</span></span><br><span class="line"> cost := storetypes.Gas(<span class="built_in">len</span>(sigBz) + <span class="number">6</span>)</span><br><span class="line"> <span class="comment">// If the pubkey is a multi-signature pubkey, then we estimate for the maximum</span></span><br><span class="line"> <span class="comment">// number of signers. </span></span><br><span class="line"> <span class="comment">// 如果公开密钥是多签名公开密钥,那么我们将估计最大的签名者数量。 </span></span><br><span class="line"> <span class="keyword">if</span> _, ok := pubkey.(*multisig.LegacyAminoPubKey); ok {</span><br><span class="line"> cost *= params.TxSigLimit</span><br><span class="line"> } </span><br><span class="line"> <span class="comment">// 此处记录 签名后的 gas 消耗</span></span><br><span class="line"> ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*cost, <span class="string">"txSize"</span>) </span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> next(ctx, tx, simulate)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Cosmos 对普通交易的处理,基于对交易长度 * 预设gas 的方式进行计算,其中的实现方式以抽出 Meter 记录表的方式,在每一步关键操作位置计算并记录gas消息,可以考虑借鉴Cosmos。</p><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p>transaction 生命周期:<a href="https://docs.cosmos.network/main/basics/tx-lifecycle">Transaction Lifecycle | Cosmos SDK</a><br>gas fee介绍:<a href="https://docs.cosmos.network/main/basics/gas-fees">Gas and Fees | Cosmos SDK</a><br>Gas & Fees:<a href="https://docs.cosmos.network/v0.47/modules/auth#gas--fees">x/auth | Cosmos SDK</a><br>GasKVStore:<a href="https://docs.cosmos.network/main/core/store.html#gaskv-store">Store | Cosmos SDK</a></p>]]></content>
<summary type="html">
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>分析 cosmos 的交易手续费的实现细节,以了解其实现手续费模型用于实现参考。<br>在 cosmos 中,<code>gas</code
</summary>
<category term="blockchain" scheme="https://liukai.net/categories/blockchain/"/>
<category term="cosmos" scheme="https://liukai.net/categories/blockchain/cosmos/"/>
<category term="cosmos" scheme="https://liukai.net/categories/cosmos/"/>
<category term="cosmos" scheme="https://liukai.net/tags/cosmos/"/>
<category term="gas" scheme="https://liukai.net/tags/gas/"/>
<category term="fee" scheme="https://liukai.net/tags/fee/"/>
<category term="base_fee" scheme="https://liukai.net/tags/base-fee/"/>
<category term="gas_fee" scheme="https://liukai.net/tags/gas-fee/"/>
</entry>
<entry>
<title>EIP-4844-blob 简单说明</title>
<link href="https://liukai.net/posts/82ae354b.html"/>
<id>https://liukai.net/posts/82ae354b.html</id>
<published>2023-06-20T15:01:09.000Z</published>
<updated>2023-11-20T15:35:04.495Z</updated>
<content type="html"><![CDATA[<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>Blob交易是专门为Rollups而设计的特殊交易。<br>它从 EVM 执行环境中分离出来,并以状态最小化的方式,来促进rollup机制原生嵌入以太坊网络中的实施(包括 optimistic 和 zk)的方式大幅增加交易吞吐量。<br>大白话就是,为了省钱(手续费)专门设计的一种交易类型。</p><h2 id="第一阶段"><a href="#第一阶段" class="headerlink" title="第一阶段"></a>第一阶段</h2><p>EIP4844 主要即为第一个阶段所要完成的工作。主要包括:</p><p>1.新增一种交易类型,该交易类型新增了一种字段:blob,为该字段设置单独的gas收费标准,且收费较低,rollup 可采用该字段存储数据</p><p>2.新增blob会增大区块数据量,新增历史数据清理功能,超过30天的blob数据可以从节点移除,或迁移至第三方去中心化存储</p><p>3.blob与 tx 存储分离,并通过一个 commitment 来进行关联,commitment采用 KZG 算法来实现,KZG 算法可以看做类似 merkle 树的证明算法</p><p>4.KZG 在 sharding 中扮演着重要的角色,Rollup 校验中除了 KZG,采用别的验证算法都无法达到很好的效果。</p><h2 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h2><p><img src="/posts/82ae354b/image-20230313-081509.png" alt="BLOB Transaction"></p><h3 id="1-消息与签名"><a href="#1-消息与签名" class="headerlink" title="1.消息与签名"></a>1.消息与签名</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">class SignedBlobTransaction(Container):</span><br><span class="line"> message: BlobTransaction</span><br><span class="line"> signature: ECDSASignature</span><br><span class="line"> </span><br><span class="line">class BlobTransaction(Container):</span><br><span class="line"> chain_id: uint256</span><br><span class="line"> nonce: uint64</span><br><span class="line"> max_priority_fee_per_gas: uint256</span><br><span class="line"> max_fee_per_gas: uint256</span><br><span class="line"> gas: uint64</span><br><span class="line"> to: Union[None, Address] # Address = Bytes20</span><br><span class="line"> value: uint256</span><br><span class="line"> data: ByteList[MAX_CALLDATA_SIZE]</span><br><span class="line"> access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE]</span><br><span class="line"> max_fee_per_data_gas: uint256</span><br><span class="line"> blob_versioned_hashes: List[VersionedHash, MAX_OBJECT_LIST_SIZE]</span><br></pre></td></tr></table></figure><p>从上面可以看出,BlobTransaction除了新增了<code>blob_versioned_hashes</code>字段和<code>max_fee_per_data_gas</code>字段外,其余字段基本与eip1559里面交易类型是一样的。<br><code>blob_versioned_hashes</code>:首先 将blob数据转化为kzg多项式点。然后将kzg多项式电转换为versioned hash。之所以使用VersionedHash 而不是 KZG 是为了向前兼容,以后可以方便更换为STARK。</p><h3 id="2-增加了一种新的OPCODE"><a href="#2-增加了一种新的OPCODE" class="headerlink" title="2.增加了一种新的OPCODE"></a>2.增加了一种新的OPCODE</h3><p>这个<code>opcode</code>为<code>DATA_HASH</code>,其对应的值为<code>HASH_OPCODE_BYTE</code>。表示这个<code>opcode</code>的gas成本。</p><h2 id="一些问题"><a href="#一些问题" class="headerlink" title="一些问题"></a>一些问题</h2><p>1.blob存储和数据结构<br>Blob数据持久化到共识层,而不是在执行层。<br>2.blob数据内容是什么<br>Blob的数据是 L2 里的交易集合或者状态变更,由 Rollup 决定。<br>3.blob如何和合约交互,<br>在 L1 的 EVM 里不能访问Blob数据。<br>但是可以通过versioned hash获取Blob,然后校验kzg,以及versioned hash。<br>4.blob交易中proof存储在哪<br>5.blob在共识层和应用层的作用</p><p><a href="https://dankradfeist.de/ethereum/2021/10/13/kate-polynomial-commitments-mandarin.html">KZG多项式承诺</a><br><a href="https://www.eip4844.com/#support">EIP4844</a></p>]]></content>
<summary type="html">
<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>Blob交易是专门为Rollups而设计的特殊交易。<br>它从 EVM 执行环境中分离出来,并以状态最小化的方式,来促进rollup机制原
</summary>
<category term="blockchain" scheme="https://liukai.net/categories/blockchain/"/>
<category term="ethereum" scheme="https://liukai.net/categories/ethereum/"/>
<category term="eth" scheme="https://liukai.net/categories/eth/"/>
<category term="4844" scheme="https://liukai.net/categories/eth/4844/"/>
<category term="eip" scheme="https://liukai.net/categories/ethereum/eip/"/>
<category term="eth" scheme="https://liukai.net/categories/blockchain/eth/"/>
<category term="eth" scheme="https://liukai.net/tags/eth/"/>
<category term="blob" scheme="https://liukai.net/tags/blob/"/>
<category term="4844" scheme="https://liukai.net/tags/4844/"/>
</entry>
<entry>
<title>rust 继承、封装、多态</title>
<link href="https://liukai.net/posts/4cbcc746.html"/>
<id>https://liukai.net/posts/4cbcc746.html</id>
<published>2023-06-01T12:00:03.000Z</published>
<updated>2023-09-04T10:18:40.374Z</updated>
<content type="html"><![CDATA[<h2 id="封装(encapsulation)"><a href="#封装(encapsulation)" class="headerlink" title="封装(encapsulation)"></a>封装(encapsulation)</h2><p>rust 的封装是基于结构体,而不是对象,结构体就是 rust 的对象,这个和go一样。<br>默认情况下,结构体只有字段。<br>注意,结构体自身被标记为 pub,这样其他代码就可以使用这个结构体,但是在结构体内部的字段仍然是私有的!!!!<br>可以通过实现结构体,来为结构体添加方法,也是和go一样的特性!!</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">pub</span> <span class="class"><span class="keyword">struct</span> <span class="title">AveragedCollection</span></span> {</span><br><span class="line"> list: <span class="built_in">Vec</span><<span class="built_in">i32</span>>,</span><br><span class="line"> average: <span class="built_in">f64</span>,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> AveragedCollection {</span><br><span class="line"> <span class="comment">// 这个 self 是不是有熟悉的感觉,python 中大量使用 self</span></span><br><span class="line"> <span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">add</span></span>(&<span class="keyword">mut</span> <span class="keyword">self</span>, value: <span class="built_in">i32</span>) {</span><br><span class="line"> <span class="keyword">self</span>.list.push(value);</span><br><span class="line"> <span class="keyword">self</span>.update_average();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">remove</span></span>(&<span class="keyword">mut</span> <span class="keyword">self</span>) -> <span class="built_in">Option</span><<span class="built_in">i32</span>> {</span><br><span class="line"> <span class="keyword">let</span> result = <span class="keyword">self</span>.list.pop();</span><br><span class="line"> <span class="keyword">match</span> result {</span><br><span class="line"> <span class="literal">Some</span>(value) => {</span><br><span class="line"> <span class="keyword">self</span>.update_average();</span><br><span class="line"> <span class="literal">Some</span>(value)</span><br><span class="line"> }</span><br><span class="line"> <span class="literal">None</span> => <span class="literal">None</span>,</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">average</span></span>(&<span class="keyword">self</span>) -> <span class="built_in">f64</span> {</span><br><span class="line"> <span class="keyword">self</span>.average</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">update_average</span></span>(&<span class="keyword">mut</span> <span class="keyword">self</span>) {</span><br><span class="line"> <span class="keyword">let</span> total: <span class="built_in">i32</span> = <span class="keyword">self</span>.list.iter().sum();</span><br><span class="line"> <span class="keyword">self</span>.average = total <span class="keyword">as</span> <span class="built_in">f64</span> / <span class="keyword">self</span>.list.len() <span class="keyword">as</span> <span class="built_in">f64</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> <span class="keyword">mut</span> average = AveragedCollection {</span><br><span class="line"> list: <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>],</span><br><span class="line"> average: <span class="number">3.0</span>,</span><br><span class="line"> };</span><br><span class="line"> <span class="comment">// 注意看,这个里用 . 而不是 ::,在rust中对象使用是. 进行调用</span></span><br><span class="line"> average.add(<span class="number">3</span>);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="继承(Inheritance)-rust-没有继续机制!!"><a href="#继承(Inheritance)-rust-没有继续机制!!" class="headerlink" title="继承(Inheritance)--rust 没有继续机制!!"></a>继承(Inheritance)--rust 没有继续机制!!</h2><p>是一个很多编程语言都提供的机制,一个对象可以定义为继承另一个对象定义中的元素,这使其可以获得父对象的数据和行为,而无需重新定义。<br>如果一个语言必须有继承才能被称为面向对象语言的话,那么 Rust 就不是面向对象的。因为没有宏则无法定义一个结构体继承父结构体的成员和方法。<br>其实 go 也是这么干的,这两哥们都不愿意使用继承,而都是通过组合的形式。</p><p><strong>rust 如何实现代码复用?</strong><br>Rust 代码中可以使用默认 trait 方法实现来进行有限的共享。 </p><h2 id="多态(Polymorphism)"><a href="#多态(Polymorphism)" class="headerlink" title="多态(Polymorphism)"></a>多态(Polymorphism)</h2><p>Rust 则通过泛型来对不同的可能类型进行抽象,并通过 <strong>trait bounds</strong> 对这些类型所必须提供的内容施加约束。<br>这有时被称为 bounded parametric polymorphism。<br>Rust 选择了一个不同的途径,使用 trait 对象而不是继承。<br>其实 trait 就是类似于其它语言的接口(Interface),然后以这种形式实现多态。</p><p>举个例子:</p><p>定义一下<code>Shape</code>的Trait,其中包含一个<code>area</code>方法。<br>然后,分别为<code>Circle</code>和<code>Rectangle</code>结构体实现了Shape Trait。<br>最后,编写了一个<code>print_area</code>函数,它接受一个实现了Shape Trait的参数,并打印出其面积。</p><p>通过Trait和动态分发,可以在运行时选择不同的实现,并实现多态的效果。</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">Shape</span></span> {</span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">area</span></span>(&<span class="keyword">self</span>) -> <span class="built_in">f64</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Circle</span></span> {</span><br><span class="line"> radius: <span class="built_in">f64</span>,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> Shape <span class="keyword">for</span> Circle {</span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">area</span></span>(&<span class="keyword">self</span>) -> <span class="built_in">f64</span> {</span><br><span class="line"> std::<span class="built_in">f64</span>::consts::PI * <span class="keyword">self</span>.radius * <span class="keyword">self</span>.radius</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Rectangle</span></span> {</span><br><span class="line"> width: <span class="built_in">f64</span>,</span><br><span class="line"> height: <span class="built_in">f64</span>,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> Shape <span class="keyword">for</span> Rectangle {</span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">area</span></span>(&<span class="keyword">self</span>) -> <span class="built_in">f64</span> {</span><br><span class="line"> <span class="keyword">self</span>.width * <span class="keyword">self</span>.height</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">print_area</span></span>(shape: &<span class="keyword">dyn</span> Shape) {</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"Area: {}"</span>, shape.area());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> circle = Circle { radius: <span class="number">1.0</span> };</span><br><span class="line"> <span class="keyword">let</span> rectangle = Rectangle { width: <span class="number">2.0</span>, height: <span class="number">3.0</span> };</span><br><span class="line"></span><br><span class="line"> print_area(&circle);</span><br><span class="line"> print_area(&rectangle);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这个其实和go实现多态的方式是一样的,也是基于实现接口的方式。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Rust 和 go 这两哥们都不支持基于继承的面向对象,都是基于组合的形式,主要是因为rust的设计理念不同。<br>Rust选择不使用继承来实现多态,而是使用trait和泛型来实现多态性。这是因为Rust的设计目标之一是提供内存安全和无运行时开销的抽象机制。<br>使用继承来实现多态性的语言,如C++和Java,通常需要在运行时进行动态分派,这需要额外的运行时开销。此外,继承关系还引入了对象的大小和布局的问题。<br>Rust通过trait和泛型的组合提供了一种更安全、更灵活的多态性实现方式。trait是一种抽象机制,允许定义一组方法的契约,并让类型来实现这些方法。泛型允许在编写代码时引入抽象的类型参数,以便代码可以适用于不同的具体类型。这种静态的泛型多态性在编译时进行类型检查,并且没有运行时开销。<br>使用trait和泛型实现多态性的优势包括:</p><ol><li>零运行时开销:Rust的trait和泛型在编译时进行静态分派,不需要额外的运行时开销。</li><li>内存安全:Rust的trait和泛型机制保证了类型安全和内存安全,避免了继承层次带来的一些问题,如对象切片的大小和布局问题。</li><li>更灵活的抽象:使用trait和泛型,可以根据需要定义和使用不同的行为集合,而不受固定的继承关系的限制。</li></ol><p>综上,Rust选择使用trait和泛型来实现多态性,以提供更安全、更高效、更灵活的抽象机制,并符合Rust的设计目标和哲学。</p>]]></content>
<summary type="html">
<h2 id="封装(encapsulation)"><a href="#封装(encapsulation)" class="headerlink" title="封装(encapsulation)"></a>封装(encapsulation)</h2><p>rust 的封装是基
</summary>
<category term="rust" scheme="https://liukai.net/categories/rust/"/>
<category term="rust" scheme="https://liukai.net/tags/rust/"/>
<category term="面像对象" scheme="https://liukai.net/tags/%E9%9D%A2%E5%83%8F%E5%AF%B9%E8%B1%A1/"/>
<category term="继承" scheme="https://liukai.net/tags/%E7%BB%A7%E6%89%BF/"/>
<category term="封装" scheme="https://liukai.net/tags/%E5%B0%81%E8%A3%85/"/>
<category term="多态" scheme="https://liukai.net/tags/%E5%A4%9A%E6%80%81/"/>
</entry>
<entry>
<title>以太坊 EIP-4844 简述</title>
<link href="https://liukai.net/posts/e5fa7f4c.html"/>
<id>https://liukai.net/posts/e5fa7f4c.html</id>
<published>2023-05-23T17:17:21.000Z</published>
<updated>2023-07-15T15:25:46.993Z</updated>
<content type="html"><![CDATA[<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>是由Vitalik Buterin和其他来自以太坊生态系统的程序员共同创建的,它关注的是分片技术。</p><h2 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h2><p>EIP-4844的主要目的是在不牺牲去中心化的情况下,降低网络上的gas费用,特别是对rollup解决方案。<br><strong>Arbitrum</strong>和<strong>Optimism</strong>等rollup解决方案可以将gas费用降低100到1000倍。</p><p>EIP-4844 提案是作为以太坊2.0更新完成之前的<strong>临时</strong>解决方案。该提案解释了一种新方法,以帮助划分交易中所需的信息,如验证规则和交易格式,而无需实际实现任何分片。</p><p><strong>这是一个很大的EIP,细分下来,需要用很多篇文章才能讲完整个EIP的细节经及EIP-4844要做的事</strong>。</p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>每个区块 12 秒的出块时间 TPS 大概为 13~30 笔交易左右,但根据目前已知以太坊的 TPS 最高可以达到每秒 45 笔交易。<br>以太坊做为最主流的区块链,这个TPS就非常拉夸,还要号称世界计算机。</p><p>所以想要成为 “世界计算机” 的以太坊每秒最多处理 45 笔交易的性能实在是太弱了。所以以太坊迫切需要扩容来解决性能问题。</p><p>以太坊由于智能合约的存在,每个交易的内容各不相同,所以每个区块可以处理多少笔交易(TPS)取决于一个区块中包含的交易的数据量大小,每个交易的数据量大小都是根据实时需求决定的。<br>下图为以太坊交易TPS表:</p><h3 id="区块链不可能三角"><a href="#区块链不可能三角" class="headerlink" title="区块链不可能三角"></a>区块链不可能三角</h3><p>"区块链不可能三角" 指的是一个公共区块链无法同时满足三个特性:</p><ul><li>去中心化</li><li>安全性</li><li>可扩展性</li></ul><p>去中心化:指的是节点的去中心化程度,节点越多越分散越去中心化<br>安全性:指的是整个区块链网络的安全,攻击成本越高越安全<br>可扩展性:指的是区块链的处理交易性能,每秒可处理交易越多越具备可扩展性</p><p>从这三点的重要性来看的话,会发现去中心化和安全性是权重最高的。<br>以太坊的愿景是在去中心化并且安全的前提下实现可扩展性。</p><h2 id="技术方向"><a href="#技术方向" class="headerlink" title="技术方向"></a>技术方向</h2><p>针对以上三个问题,以太坊也进行了各种偿试,目前大方向就是<strong>扩容</strong>,扩容方案有以下几种:<br>以太坊主流扩容方案</p><ol><li>rollup</li><li>分片</li><li>sharding<ol><li>sharding 1.0</li><li>sharding 2.0</li></ol></li></ol><h3 id="rollup"><a href="#rollup" class="headerlink" title="rollup"></a>rollup</h3><p>Rollup 原理是将数百笔交易在链下像摊煎饼一样打包成一笔交易发送给以太坊来实现扩容,这样每个人平摊下来上传以太坊的费用就会很便宜,同时还可以继承以太坊的安全性。</p><p>Rollup 目前分为两种类型:</p><ul><li>Optimism Rollup(乐观 Rollup)</li><li>ZK Rollup(零知识证明 Rollup)</li></ul><p>Optimism Rollup: 假设所有交易都是诚实可信的,把许多笔交易压缩成一笔交易提交给以太坊,在提交后会有一段时间窗口(挑战期-目前是一周),任何人都可以质疑发起挑战来验证交易的真实性,但用户如果要将 OP Rollup 上的 ETH 转到以太坊上则需要等待挑战期结束后才可以得到最终确认。</p><p>ZK Rollup: 则是通过生成一个零知识证明来证明所有交易都是有效的,并将所有交易执行后的最终状态变化上传至以太坊。</p><p>相比 Optimism Rollup 来说 ZK Rollup 更有前景,ZK Rollup 不需要像 Optimism Rollup 那样上传压缩后的所有交易细节,只需要上传一个零知识证明和最终的状态变化的数据即可,意味着在可扩展性上可以比 OP Rollup 压缩更多的数据,并且也不需要像 OP Rollup 那样等待长达一周的挑战期,但 ZK Rollup 最大的缺点就是开发难度极大。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md">eip-4844.md</a></p>]]></content>
<summary type="html">
<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>是由Vitalik Buterin和其他来自以太坊生态系统的程序员共同创建的,它关注的是分片技术。</p>
<h2 id="目的"><a h
</summary>
<category term="blockchain" scheme="https://liukai.net/categories/blockchain/"/>
<category term="ethereum" scheme="https://liukai.net/categories/ethereum/"/>
<category term="eth" scheme="https://liukai.net/categories/eth/"/>
<category term="ethereum" scheme="https://liukai.net/categories/blockchain/ethereum/"/>
<category term="eip" scheme="https://liukai.net/categories/ethereum/eip/"/>
<category term="eth" scheme="https://liukai.net/categories/blockchain/eth/"/>
<category term="eip" scheme="https://liukai.net/categories/eth/eip/"/>
<category term="eip" scheme="https://liukai.net/categories/eip/"/>
<category term="4844" scheme="https://liukai.net/categories/eip/4844/"/>
<category term="blockchain" scheme="https://liukai.net/tags/blockchain/"/>
<category term="ethereum" scheme="https://liukai.net/tags/ethereum/"/>
<category term="eth" scheme="https://liukai.net/tags/eth/"/>
<category term="以太坊" scheme="https://liukai.net/tags/%E4%BB%A5%E5%A4%AA%E5%9D%8A/"/>
<category term="eip" scheme="https://liukai.net/tags/eip/"/>
<category term="eip4844" scheme="https://liukai.net/tags/eip4844/"/>
</entry>
<entry>
<title>使用IDEA开发rust提示file is not included in module tree</title>
<link href="https://liukai.net/posts/750b0a4e.html"/>
<id>https://liukai.net/posts/750b0a4e.html</id>
<published>2023-04-18T18:08:57.000Z</published>
<updated>2023-07-18T18:24:15.880Z</updated>
<content type="html"><![CDATA[<h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>用了很长一段时间nvim写rust,还没有用IDEA这样的IDE来写rust。就准备用一下,一用发现,还不太会在IDEA上用rust。<br>碰到的第一个问题就是 IDEA 提示:</p><blockquote><p>file is not included in module tree, analysis is not available</p></blockquote><p>fn main 也没有可以运行的按钮,但是命令行使用 cargo run 正常。这个说明应该是IDEA的配置的问题。</p><h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><p>IDEA 用 rust 我也不熟,猜测应该是跟项目构建有关,就类似IDEA 使用 maven 的构建,也需要对应的设置一样。</p><p>右键一下 Cargo.toml看一下,还真有一个Attach Cargo Project这一项,然后只要把项目添加到 IDEA 中就可以:</p><p>右键--> Cargo.toml-->Attach Cargo Project</p><p><img src="/posts/750b0a4e/n3zLjlSsji8AQJvDZNCH2nnVGI-l4gytOOh4TWGsexA.png" alt="image"></p><p>之后运行就正常了,记录一下,虽然是个小问题,但是可能也会帮助到同样出现这个问题的小伙伴。</p><p><img src="/posts/750b0a4e/0vP5KwFuq-jRdsn4IJ4EgCwOiKRBLnVF2BGeI54heu0.png" alt="image"></p>]]></content>
<summary type="html">
<h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>用了很长一段时间nvim写rust,还没有用IDEA这样的IDE来写rust。就准备用一下,一用发现,还不太会在IDEA上用rust。<br
</summary>
<category term="rust" scheme="https://liukai.net/categories/rust/"/>
<category term="rust" scheme="https://liukai.net/tags/rust/"/>
<category term="idea" scheme="https://liukai.net/tags/idea/"/>
</entry>
<entry>
<title>rust-生命周期</title>
<link href="https://liukai.net/posts/49b9d1d2.html"/>
<id>https://liukai.net/posts/49b9d1d2.html</id>
<published>2023-03-06T14:06:13.000Z</published>
<updated>2023-06-19T16:45:15.859Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>先说大白话,rust 的生命周期标注,是为了明确多个变量的生命周期是否一致,仅此而已,因为如果rust不知道多个变量的生命周期是否一致,它无法确的知道这个变量是否已经被释放。这个下面再细说,先说有什么用。</p><p>rust当中,的两个重要概念:<strong>借用</strong>和<strong>生命周期</strong>分别代是在:</p><ol><li>栈变量,需要关注【所有权】</li><li>引用(指针),需要关注【生命周期】</li></ol><p>Rust 的每个引用都有自己的生命周期,生命周期指的是引用保持有效的作用域。<br>大多数情况下,引用是隐式的、可以被推断出来的,但当引用可能以不同的方式互相关联时,则需要手动标注生命周期。<br>这里重点就是<strong>以不同的方式互相关联时</strong>。</p><p>大多数情况下,rust 可以自己推断出引用的生拿周期,也就是只有在一些rust无法自行推断的情况下,才需要手动<strong>标注</strong>生命周期。</p><h2 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h2><p>Rust 中的每一个引用都有其<strong>生命周期(lifetime)</strong>,也就是引用保持有效的作用域。<br>大部分时候生命周期是隐含并可以推断的,正如大部分时候类型也是可以推断的一样。<br>类似于当因为有多种可能类型的时候必须注明类型,也会出现引用的生命周期以一些不同方式相关联的情况,所以 Rust 需要我们使用泛型生命周期参数来注明他们的关系,这样就能确保运行时实际使用的引用绝对是有效的。</p><p>这里还有一个需要关注的点就是<strong>关系</strong>,也就多个引用之前的关系,才是导致rust无法明确推断出引用生命周期的最根本原因。</p><h2 id="反例"><a href="#反例" class="headerlink" title="反例"></a>反例</h2><p>这段代码看着很正常,但是实际上,编译会报错,类为这里调用<code>longest</code>时,<code>longest</code>无法确认<code>x</code>、<code>y</code>的生命周期。<br>为什么无法确认?<br>因为<code>longest</code>是被调用的方法,它肯定没法知道,这两个传入在<code>main</code>方法的中的生命周期。<br>好比,你写一个接口给外部调用,你也无法知道调你的服务,传入的两个变量,在那个服务中的生命周期。<br>但是在rust中,又非常强调安全性,它必须清楚每个引用的明确的生命周期。<br>所以这个活,就落在了开发者身上,必须明确告诉rust,每个引用的生命周期。</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> string1 = <span class="built_in">String</span>::from(<span class="string">"abcd"</span>);</span><br><span class="line"> <span class="keyword">let</span> string2 = <span class="string">"xyz"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> result = longest(string1.as_str(), string2);</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"The longest string is {}"</span>, result);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// longest函数 无法确认 x、y 在 mian 函数中的生命周期</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">longest</span></span>(x: &<span class="built_in">str</span>, y: &<span class="built_in">str</span>) -> &<span class="built_in">str</span> {</span><br><span class="line"> <span class="keyword">if</span> x.len() > y.len() {</span><br><span class="line"> x</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> y</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>报错如下:missing lifetime specifier</p><figure class="highlight console"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">error[E0106]: missing lifetime specifier</span><br><span class="line"><span class="meta"> --></span><span class="bash"> src/main.rs:9:33</span></span><br><span class="line"> |</span><br><span class="line">9 | fn longest(x: &str, y: &str) -> &str {</span><br><span class="line"> | ---- ---- ^ expected named lifetime parameter</span><br><span class="line"> |</span><br><span class="line"> = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`</span><br><span class="line">help: consider introducing a named lifetime parameter</span><br><span class="line"> |</span><br><span class="line">9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {</span><br><span class="line"> | ++++ ++ ++ ++</span><br><span class="line"></span><br><span class="line">For more information about this error, try `rustc --explain E0106`.</span><br><span class="line">error: could not compile `playground` due to previous error</span><br></pre></td></tr></table></figure><p>上面看着很正常呀,哪里有问题?</p><h2 id="生命周期标注"><a href="#生命周期标注" class="headerlink" title="生命周期标注"></a>生命周期标注</h2><p>即然<code>rust</code>不智能,那只能开发者辛苦一点,手动来标注了。<br><code>rust</code>的生命周期标注语法,只能表示引用的生命周期,而不能、不会改会引用的生命周期。</p><p>命名规则:</p><ol><li><code>'a</code> 以 ' 开头</li><li>全小写</li></ol><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&<span class="built_in">i32</span> <span class="comment">// 引用</span></span><br><span class="line">&<span class="symbol">'a</span> <span class="built_in">i32</span> <span class="comment">// 带有显式生命周期的引用</span></span><br><span class="line">&<span class="symbol">'a</span> <span class="keyword">mut</span> <span class="built_in">i32</span> <span class="comment">// 带有显式生命周期的可变引用</span></span><br></pre></td></tr></table></figure><p>单个的生命周期注解本身没有多少意义,因为生命周期注解告诉 Rust 多个引用的泛型生命周期参数如何相互联系的。</p><h2 id="函数签名中的生命周期注解"><a href="#函数签名中的生命周期注解" class="headerlink" title="函数签名中的生命周期注解"></a>函数签名中的生命周期注解</h2><p>描述了 x、y 之间的关系。<br>longest 函数定义指定了签名中所有的引用必须有相同的生命周期<code>'a</code></p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> string1 = <span class="built_in">String</span>::from(<span class="string">"abcd"</span>);</span><br><span class="line"> <span class="keyword">let</span> string2 = <span class="string">"xyz"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> result = longest(string1.as_str(), string2);</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"The longest string is {}"</span>, result);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">longest</span></span><<span class="symbol">'a</span>>(x: &<span class="symbol">'a</span> <span class="built_in">str</span>, y: &<span class="symbol">'a</span> <span class="built_in">str</span>) -> &<span class="symbol">'a</span> <span class="built_in">str</span> {</span><br><span class="line"> <span class="keyword">if</span> x.len() > y.len() {</span><br><span class="line"> x</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> y</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="只有一个参数,要不要标注"><a href="#只有一个参数,要不要标注" class="headerlink" title="只有一个参数,要不要标注"></a>只有一个参数,要不要标注</h2><p>那当然是不要啦!!<br>生命周期注解告诉编译器引用参数的有效范围,以便编译器可以检查代码是否合法。<br>但是,在某些情况下,编译器可以自动推断出引用参数的生命周期,因此不需要显式注解。</p><p>当一个函数或方法需要<strong>一个</strong>借用参数时,如果该参数的生命周期与函数或方法的生命周期相同,则可以省略生命周期注解。例如:<br>这个例子,标不标注都是成立的。</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">foo</span></span><<span class="symbol">'a</span>>(x: &<span class="symbol">'a</span> <span class="built_in">i32</span>) -> &<span class="symbol">'a</span> <span class="built_in">i32</span> {</span><br><span class="line"> x</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> x = <span class="number">5</span>;</span><br><span class="line"> <span class="keyword">let</span> y = foo(&x);</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"{}"</span>, y);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>但是,如果函数或方法需要一个借用参数,并且该参数的生命周期与函数或方法的生命周期不同,则必须显式注解参数的生命周期。</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Foo</span></span><<span class="symbol">'a</span>> {</span><br><span class="line"> x: &<span class="symbol">'a</span> <span class="built_in">i32</span>,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span><<span class="symbol">'a</span>> Foo<<span class="symbol">'a</span>> {</span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">bar</span></span>(&<span class="keyword">self</span>, y: &<span class="symbol">'a</span> <span class="built_in">i32</span>) -> &<span class="symbol">'a</span> <span class="built_in">i32</span> {</span><br><span class="line"> <span class="keyword">if</span> *y > <span class="number">0</span> {</span><br><span class="line"> y</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">self</span>.x</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> x = <span class="number">5</span>;</span><br><span class="line"> <span class="keyword">let</span> y = <span class="number">6</span>;</span><br><span class="line"> <span class="keyword">let</span> foo = Foo { x: &x };</span><br><span class="line"> <span class="keyword">let</span> z = foo.bar(&y);</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"{}"</span>, z);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在这个例子中,方法 bar 的第二个参数 y 的生命周期不同于 Foo 结构体中的引用 x 的生命周期,所以嘛必须显式注解参数的生命周期。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>人多了,就容易产生纠分,变量形参多了,也是这样,所以才需要标注,分个明白。</p>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>先说大白话,rust 的生命周期标注,是为了明确多个变量的生命周期是否一致,仅此而已,因为如果rust不知道多个变量的生命周期是否一致,它无
</summary>
<category term="rust" scheme="https://liukai.net/categories/rust/"/>
<category term="rust" scheme="https://liukai.net/tags/rust/"/>
<category term="生命周期" scheme="https://liukai.net/tags/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/"/>
</entry>
<entry>
<title>rust-vim 整合基于vimspector的debug调试环境</title>
<link href="https://liukai.net/posts/3e7235c0.html"/>
<id>https://liukai.net/posts/3e7235c0.html</id>
<published>2023-02-27T15:17:08.000Z</published>
<updated>2023-03-08T09:29:03.543Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>前面配置好<code>rust</code>开发环境后,还需要一个调试功能就能用了。<br>不清楚的可以回看我的<a href="https://liukai.net/posts/69325553.html">rust-vim安装记录</a><br>调试器,找了几款,最后还是觉得还是使用<code>vimspector</code>这个用的习惯,捣鼓两个整合了一下基于<code>vimspector</code>的调试环境,快捷键不用重新再配置。</p><p>效果图:</p><p><img src="/posts/3e7235c0/rust-vimspector-debug%E6%95%88%E6%9E%9C%E5%9B%BE.jpg" alt="rust-vimspector-debug效果图.jpg"></p><p>这几天换了mac M2,把功能都迁移过来,完可用,这图就是M2上载图的。<br>另外补全相关的配置,需要coc的一些额外配置。<br><a href="https://liukai.net/posts/1ca1b354.html">vim CocConfig参数设置说明</a></p><h2 id="流程"><a href="#流程" class="headerlink" title="流程"></a>流程</h2><ul><li>安装<strong>vimspector插件</strong>: <code>puremourning/vimspector</code></li><li>添加配置文件:<ul><li><code>lldb-vscode.json</code></li><li><code>.vimspector.json</code></li></ul></li></ul><h2 id="安装vimspector插件"><a href="#安装vimspector插件" class="headerlink" title="安装vimspector插件"></a>安装vimspector插件</h2><p>添加插件,然后执行<code>PlugInstall</code>,路径:</p><blockquote><p>~/.config/nvim/init.vim</p></blockquote><p><code>--enable-rust</code> 表示要启用的语言支持,可以从官网查看支持的语言。</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Plug <span class="string">'puremourning/vimspector'</span>, {<span class="string">'do'</span>: <span class="string">'./install_gadget.py --enable-rust'</span>}</span><br></pre></td></tr></table></figure><p>在vim中执行:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:PlugInstall</span><br></pre></td></tr></table></figure><p>添加配置到<code>init.vim</code>中</p><blockquote><p>~/.config/nvim/init.vim</p></blockquote><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">"==============================================================================</span></span><br><span class="line"><span class="comment">" rust</span></span><br><span class="line"><span class="comment">"==============================================================================</span></span><br><span class="line"><span class="keyword">nnoremap</span> <span class="symbol"><leader></span>rr :CocCommand rust-analyzer.run<span class="symbol"><CR></span></span><br><span class="line"></span><br><span class="line"><span class="comment">"==============================================================================</span></span><br><span class="line"><span class="comment">" vimspector 调式配置</span></span><br><span class="line"><span class="comment">"==============================================================================</span></span><br><span class="line"># 指定快捷键影射为 HUMAN 模式,还有 VISUAL_STUDIO 模式</span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:vimspector_enable_mappings</span> = <span class="string">'HUMAN'</span></span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><leader></span>dd :<span class="keyword">call</span> vimspector#Launch()<span class="symbol"><CR></span></span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><leader></span>dx :VimspectorReset<span class="symbol"><CR></span></span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><leader></span>de :VimspectorEval</span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><leader></span>dw :VimspectorWatch</span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><leader></span><span class="keyword">do</span> :VimspectorShowOutput</span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:vimspector_install_gadgets</span> = [ <span class="string">'debugpy'</span>, <span class="string">'vscode-go'</span>, <span class="string">'CodeLLDB'</span> ]</span><br></pre></td></tr></table></figure><p>其它建议的配置项:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">" mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">" for normal mode - the word under the cursor</span></span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><Leader></span><span class="keyword">di</span> <span class="symbol"><Plug></span>VimspectorBalloonEval</span><br><span class="line"><span class="comment">" for visual mode, the visually selected text</span></span><br><span class="line"><span class="keyword">xmap</span> <span class="symbol"><Leader></span><span class="keyword">di</span> <span class="symbol"><Plug></span>VimspectorBalloonEval</span><br></pre></td></tr></table></figure><p>您可能还希望添加用于向上/向下导航堆栈、切换断点窗口和显示反汇编的映射,例如:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">nmap</span> <span class="symbol"><LocalLeader></span><span class="symbol"><F11></span> <span class="symbol"><Plug></span>VimspectorUpFrame</span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><LocalLeader></span><span class="symbol"><F12></span> <span class="symbol"><Plug></span>VimspectorDownFrame</span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><LocalLeader></span>B <span class="symbol"><Plug></span>VimspectorBreakpoints</span><br><span class="line"><span class="comment">" 反汇编的映射</span></span><br><span class="line"><span class="keyword">nmap</span> <span class="symbol"><LocalLeader></span>D <span class="symbol"><Plug></span>VimspectorDisassemble</span><br></pre></td></tr></table></figure><h2 id="vimspector-配置"><a href="#vimspector-配置" class="headerlink" title="vimspector 配置"></a>vimspector 配置</h2><p>需要添加两个配置文件:</p><ol><li><code>lldb-vscode.json</code></li><li><code>.vimspector.json</code></li></ol><h3 id="1-添加-lldb-vscode-json"><a href="#1-添加-lldb-vscode-json" class="headerlink" title="1.添加 lldb-vscode.json"></a>1.添加 lldb-vscode.json</h3><p><code>lldb-vscode.json</code>文件所以在这个路径,如果没有<code>.gadgets.d</code>需要创建一个,我的 路径:<br><code>~/.vim/plugged/vimspector/gadgets/macos/.gadgets.d/lldb-vscode.json</code><br>这里说明一个,这个路径是<code>.vim</code>,我用的是<code>nvim</code>没错,只是我把插件路径都统一到了<code>.vim</code>这个目录下了。<br>最开还没有使用<code>nvim</code>,用的是<code>vim</code>。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"adapters"</span>: {</span><br><span class="line"> <span class="attr">"lldb-vscode"</span>: {</span><br><span class="line"> <span class="attr">"variables"</span>: {</span><br><span class="line"> <span class="attr">"LLVM"</span>: {</span><br><span class="line"> <span class="attr">"shell"</span>: <span class="string">"brew --prefix llvm"</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"attach"</span>: {</span><br><span class="line"> <span class="attr">"pidProperty"</span>: <span class="string">"pid"</span>,</span><br><span class="line"> <span class="attr">"pidSelect"</span>: <span class="string">"none"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"command"</span>: [</span><br><span class="line"> <span class="string">"${LLVM}/bin/lldb-vscode"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"env"</span>: {</span><br><span class="line"> <span class="attr">"LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY"</span>: <span class="string">"YES"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"lldb"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-添加-vimspector-文件"><a href="#2-添加-vimspector-文件" class="headerlink" title="2.添加 .vimspector 文件"></a>2.添加 .vimspector 文件</h3><p>这个文件添加到子项目下,比如下面是我的项目结构,<br>添加到 <code>vector_test</code> 这个项目下,偿试在<code>rust-learning</code>上添加,子项无法启动<code>vimspector</code>。</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">rust-learning/</span><br><span class="line">\--src/</span><br><span class="line">\--target/</span><br><span class="line">\--string_test/</span><br><span class="line">\--struct_test/</span><br><span class="line">\--vector_test/</span><br><span class="line"> \--.vimspector</span><br></pre></td></tr></table></figure><h2 id="调试操作"><a href="#调试操作" class="headerlink" title="调试操作"></a>调试操作</h2><p>对应<code>HUMAN</code>模式的快捷键:</p><table><thead><tr><th>按键</th><th>映射</th><th>功能</th></tr></thead><tbody><tr><td><code>F5</code></td><td><code><Plug>VimspectorContinue</code></td><td>开始调试、下一个断点</td></tr><tr><td><code>F3</code></td><td><code><Plug>VimspectorStop</code></td><td>停止调试</td></tr><tr><td><code>F4</code></td><td><code><Plug>VimspectorRestart</code></td><td>使用相同的配置,重启debug</td></tr><tr><td><code>F6</code></td><td><code><Plug>VimspectorPause</code></td><td>暂停调试对象</td></tr><tr><td><code>F9</code></td><td><code><Plug>VimspectorToggleBreakpoint</code></td><td>添加、取消断点</td></tr><tr><td><code><leader>F9</code></td><td><code><Plug>VimspectorToggleConditionalBreakpoint</code></td><td>添加条件断点或日志点</td></tr><tr><td><code>F8</code></td><td><code><Plug>VimspectorAddFunctionBreakpoint</code></td><td>为光标下的表达式添加函数断点</td></tr><tr><td><code><leader>F8</code></td><td><code><Plug>VimspectorRunToCursor</code></td><td>运行到光标处</td></tr><tr><td><code>F10</code></td><td><code><Plug>VimspectorStepOver</code></td><td>单步跳过</td></tr><tr><td><code>F11</code></td><td><code><Plug>VimspectorStepInto</code></td><td>单步进入</td></tr><tr><td><code>F12</code></td><td><code><Plug>VimspectorStepOut</code></td><td>单步跳出</td></tr></tbody></table><p>如果跑完一圈断点要重开,就按<code>F4</code>,其它的跟常用IDE差不多。<br>还有就是各个窗口,也和IDE差不多的功能,线程栈可以跳对应的线程和执行的代码位置。<br>变量监视窗口支持表达式,到窗口按<code>i</code>,就可以输入表达式如:<code>i==50</code>。</p><p><img src="/posts/3e7235c0/rust-vimspector-debug%E7%AA%97%E5%8F%A3%E8%AF%B4%E6%98%8E.jpg" alt="rust-vimspector-debug窗口说明.jpg"></p><p>差不多就能用了,有问题留言。</p><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="https://github.com/puremourning/vimspector">https://github.com/puremourning/vimspector</a></p>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>前面配置好<code>rust</code>开发环境后,还需要一个调试功能就能用了。<br>不清楚的可以回看我的<a href="https
</summary>
<category term="rust" scheme="https://liukai.net/categories/rust/"/>
<category term="vim" scheme="https://liukai.net/categories/vim/"/>
<category term="ide" scheme="https://liukai.net/categories/vim/ide/"/>
<category term="ide" scheme="https://liukai.net/categories/rust/ide/"/>
<category term="rust" scheme="https://liukai.net/categories/vim/rust/"/>
<category term="rust" scheme="https://liukai.net/tags/rust/"/>
<category term="ide" scheme="https://liukai.net/tags/ide/"/>
<category term="vim" scheme="https://liukai.net/tags/vim/"/>
<category term="debug" scheme="https://liukai.net/tags/debug/"/>
<category term="vim-ide" scheme="https://liukai.net/tags/vim-ide/"/>
<category term="vimspector" scheme="https://liukai.net/tags/vimspector/"/>
</entry>
<entry>
<title>coc-java无法启动和lombok报错解决</title>
<link href="https://liukai.net/posts/2fd8d4c0.html"/>
<id>https://liukai.net/posts/2fd8d4c0.html</id>
<published>2023-02-21T17:33:35.000Z</published>
<updated>2023-03-04T06:43:49.645Z</updated>
<content type="html"><![CDATA[<h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>一问时间不写java,这两天写java程序发现<code>vim-java</code>相关配置失效了,症状就是:</p><ol><li>语法提示服务<code>jdt</code>不启动</li><li>lombok 失效</li></ol><p>排查了一圈发现启动后官方的插件配置名都变了,改用合结<code>vs-code</code>的配置,又折腾了好一会。</p><h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><h3 id="更新jdt"><a href="#更新jdt" class="headerlink" title="更新jdt"></a>更新jdt</h3><p>从官方jdt下载一个新包:<a href="https://github.com/eclipse/eclipse.jdt.ls">https://github.com/eclipse/eclipse.jdt.ls</a><br>备分:~/.config/coc/extensions/coc-java-data/server/ 目录,把下载的新包,内容放到 server下。</p><h3 id="解决-lombok-报错问题"><a href="#解决-lombok-报错问题" class="headerlink" title="解决 lombok 报错问题"></a>解决 lombok 报错问题</h3><p>还没完,启动后发现<code>lombok</code>报错,首先<code>coc-java-lombok</code>必须安装,没装的可以装一下</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CocInstall coc-java-lombok</span><br></pre></td></tr></table></figure><p>然后安装<code>OpenJDK</code>,这个已验证必须使用<code>OpenJDK</code>才能解决这个问题。<br>最后清理一下项目,很多人发现改完也没有效果,就是因为没有清理:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CocCommand java.clean.workspace</span><br></pre></td></tr></table></figure><p><img src="/posts/2fd8d4c0/coc-java%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C.jpg" alt=" coc-java最终效果"></p>]]></content>
<summary type="html">
<h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>一问时间不写java,这两天写java程序发现<code>vim-java</code>相关配置失效了,症状就是:</p>
<ol>
<li
</summary>
<category term="java" scheme="https://liukai.net/categories/java/"/>
<category term="vim" scheme="https://liukai.net/categories/vim/"/>
<category term="java" scheme="https://liukai.net/categories/vim/java/"/>
<category term="java" scheme="https://liukai.net/tags/java/"/>
<category term="vim" scheme="https://liukai.net/tags/vim/"/>
<category term="coc" scheme="https://liukai.net/tags/coc/"/>
<category term="coc-java" scheme="https://liukai.net/tags/coc-java/"/>
<category term="lombok" scheme="https://liukai.net/tags/lombok/"/>
<category term="coc-java-lombok" scheme="https://liukai.net/tags/coc-java-lombok/"/>
<category term="问題解决" scheme="https://liukai.net/tags/%E9%97%AE%E9%A1%8C%E8%A7%A3%E5%86%B3/"/>
</entry>
<entry>
<title>rust-泛型generics</title>
<link href="https://liukai.net/posts/4fcae1e5.html"/>
<id>https://liukai.net/posts/4fcae1e5.html</id>
<published>2023-02-12T06:49:53.000Z</published>
<updated>2023-04-02T11:05:28.072Z</updated>
<content type="html"><![CDATA[<h2 id="泛型(generics"><a href="#泛型(generics" class="headerlink" title="泛型(generics)"></a>泛型(generics)</h2><p>rust 也有泛型,这种最早出现1970年代的<code>Ada</code>语言中,后来被许多基于对象和面向对象的语言所采用,包括BETA、 C++、java。<br>rust 也借鉴了这一特性。<br>这种特性让程序有更好的通用性。</p><h3 id="1-简单示例-结构体泛型"><a href="#1-简单示例-结构体泛型" class="headerlink" title="1.简单示例-结构体泛型"></a>1.简单示例-结构体泛型</h3><p>给结构体 <code>Point</code> 定义一个泛型 <code>T</code></p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span><T> {</span><br><span class="line"> x: T,</span><br><span class="line"> y: T,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> integer = Point { x: <span class="number">5</span>, y: <span class="number">10</span> };</span><br><span class="line"> <span class="keyword">let</span> float = Point { x: <span class="number">1.0</span>, y: <span class="number">4.0</span> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>不同类型泛型</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span><T, U> {</span><br><span class="line"> x: T,</span><br><span class="line"> y: U,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> both_integer = Point { x: <span class="number">5</span>, y: <span class="number">10</span> };</span><br><span class="line"> <span class="keyword">let</span> both_float = Point { x: <span class="number">1.0</span>, y: <span class="number">4.0</span> };</span><br><span class="line"> <span class="keyword">let</span> integer_and_float = Point { x: <span class="number">5</span>, y: <span class="number">4.0</span> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-函数泛型-同方法泛型"><a href="#2-函数泛型-同方法泛型" class="headerlink" title="2.函数泛型-同方法泛型"></a>2.函数泛型-同方法泛型</h3><p>传入什么,就返回什么类型</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">largest</span></span><T>(list: &[T]) -> T {</span><br></pre></td></tr></table></figure><p>那会不会跟java一样,可以类泛型作用到方法。<br>rust 结构体泛型作用到 函数?</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">largest</span></span><T>(list: &[T]) -> &T {</span><br><span class="line"> <span class="keyword">let</span> <span class="keyword">mut</span> largest = &list[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> item <span class="keyword">in</span> list {</span><br><span class="line"> <span class="keyword">if</span> item > largest {</span><br><span class="line"> largest = item;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> largest</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> number_list = <span class="built_in">vec!</span>[<span class="number">34</span>, <span class="number">50</span>, <span class="number">25</span>, <span class="number">100</span>, <span class="number">65</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> result = largest(&number_list);</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"The largest number is {}"</span>, result);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> char_list = <span class="built_in">vec!</span>[<span class="string">'y'</span>, <span class="string">'m'</span>, <span class="string">'a'</span>, <span class="string">'q'</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> result = largest(&char_list);</span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"The largest char is {}"</span>, result);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="3-方法泛型"><a href="#3-方法泛型" class="headerlink" title="3.方法泛型"></a>3.方法泛型</h3><p>真有这个。</p><p>用法和定义同java一样。<br>实现一个Point 的方法,类型为T。</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span><T> {</span><br><span class="line"> x: T,</span><br><span class="line"> y: T,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span><T> Point<T> {</span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">x</span></span>(&<span class="keyword">self</span>) -> &T {</span><br><span class="line"> &<span class="keyword">self</span>.x</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> p = Point { x: <span class="number">5</span>, y: <span class="number">10</span> };</span><br><span class="line"></span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"p.x = {}"</span>, p.x());</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>泛型指定限制(constraint)<br>这个例子,也是实现Point,但是类型为具体类型 f32</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">impl</span> Point<<span class="built_in">f32</span>> {</span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">distance_from_origin</span></span>(&<span class="keyword">self</span>) -> <span class="built_in">f32</span> {</span><br><span class="line"> (<span class="keyword">self</span>.x.powi(<span class="number">2</span>) + <span class="keyword">self</span>.y.powi(<span class="number">2</span>)).sqrt()</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结合 self 使用<br>注意 x 返回的是 self.x 所以是调用者 p1 自己的x</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span><X1, Y1> {</span><br><span class="line"> x: X1,</span><br><span class="line"> y: Y1,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span><X1, Y1> Point<X1, Y1> {</span><br><span class="line"> <span class="function"><span class="keyword">fn</span> <span class="title">mixup</span></span><X2, Y2>(<span class="keyword">self</span>, other: Point<X2, Y2>) -> Point<X1, Y2> {</span><br><span class="line"> Point {</span><br><span class="line"> x: <span class="keyword">self</span>.x,</span><br><span class="line"> y: other.y,</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> p1 = Point { x: <span class="number">5</span>, y: <span class="number">10.4</span> };</span><br><span class="line"> <span class="keyword">let</span> p2 = Point { x: <span class="string">"Hello"</span>, y: <span class="string">'c'</span> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> p3 = p1.mixup(p2);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"p3.x = {}, p3.y = {}"</span>, p3.x, p3.y);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果:</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">p3.x = <span class="number">5</span>, p3.y = c</span><br></pre></td></tr></table></figure><h3 id="泛型代码的性能"><a href="#泛型代码的性能" class="headerlink" title="泛型代码的性能"></a>泛型代码的性能</h3><p>Rust 通过在编译时进行泛型代码的 <code>单态化(monomorphization)</code>来保证效率。<br>单态化是一个通过填充<strong>编译时</strong>使用的具体类型,将通用代码转换为特定代码的过程。</p><p>java也是一样的方式,通过泛型擦除来实现,就是<br>泛型信息只存在于代码编译阶段,在java的运行期(已经生成字节码文件后)与泛型相关的信息会被擦除掉。<br>所以其实也是在编译期做文章。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>rust 的很多方面,都借鉴了java的总分特性,不是指泛型,而是指后面还明更多的部分,比如<strong>迭代器</strong>,用起来很丝滑。<br>还有如<code>golang</code>部份的特性,在<code>channel</code>部分,用起来,就是像<code>golang</code>。</p>]]></content>
<summary type="html">
<h2 id="泛型(generics"><a href="#泛型(generics" class="headerlink" title="泛型(generics)"></a>泛型(generics)</h2><p>rust 也有泛型,这种最早出现1970年代的<code>Ada
</summary>
<category term="rust" scheme="https://liukai.net/categories/rust/"/>
<category term="rust" scheme="https://liukai.net/tags/rust/"/>
<category term="泛型" scheme="https://liukai.net/tags/%E6%B3%9B%E5%9E%8B/"/>
<category term="generics" scheme="https://liukai.net/tags/generics/"/>
</entry>
<entry>
<title>tron-节点-witness加载过程</title>
<link href="https://liukai.net/posts/fe400015.html"/>
<id>https://liukai.net/posts/fe400015.html</id>
<published>2023-02-04T01:43:01.000Z</published>
<updated>2023-06-19T15:08:07.452Z</updated>
<content type="html"><![CDATA[<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>witness 即在tron链中就是产块节点的代名词,一般称为<code>SR</code>。<br>一般节点不产块,要配置成witness,需要启动时指定私钥,并使用<code>--witness</code>或<code>-w</code>指定成为产块节点。</p><h2 id="witness-加载过程"><a href="#witness-加载过程" class="headerlink" title="witness 加载过程"></a>witness 加载过程</h2><p>有两种加载方式:</p><ol><li>参数或配置文件</li><li>指定<code>localwitness</code>启动</li></ol><h3 id="参数或配置文件"><a href="#参数或配置文件" class="headerlink" title="参数或配置文件"></a>参数或配置文件</h3><p>通过参数指定为witness节点,但是私钥建议写在配置文件中,否则<code>ps</code>查看一下进程就能看到启动参数,就全暴露了,但是如果有人能上机器,也能查看配置文件。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar FullNode.jar --witness -p xxxxxxxxxxxxxxxxxx</span><br></pre></td></tr></table></figure><p>输入上面的命令后,节点就会以<code>SR</code>类型启动,具体是如何加载的,调用栈如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">FullNode.main()</span><br><span class="line">\--Args.setParam(args, Constant.TESTNET_CONF); //381</span><br><span class="line"> \--PARAMETER.privateKey //优先加载 参数</span><br><span class="line"> \--Constant.LOCAL_WITNESS //或加载 配置文件</span><br><span class="line"> \--LocalWitnesses.setPrivateKeys //或从 keystore 中加载</span><br><span class="line">FullNode.startup()</span><br><span class="line">\--ConsensusService.start() // 加载localwitness</span><br></pre></td></tr></table></figure><h3 id="Args-setParam-加载过程"><a href="#Args-setParam-加载过程" class="headerlink" title="Args.setParam 加载过程"></a>Args.setParam 加载过程</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j(topic = "app")</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Args</span> <span class="keyword">extends</span> <span class="title">CommonParameter</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Getter</span></span><br><span class="line"> <span class="meta">@Setter</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> LocalWitnesses localWitnesses = <span class="keyword">new</span> LocalWitnesses();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setParam</span><span class="params">(<span class="keyword">final</span> String[] args, <span class="keyword">final</span> String confFileName)</span> </span>{</span><br><span class="line"> <span class="comment">// 省略部分代码</span></span><br><span class="line"> ...</span><br><span class="line"> <span class="comment">// PARAMETER.privateKey 即 -p 或 --private-key 参数</span></span><br><span class="line"> <span class="keyword">if</span> (StringUtils.isNoneBlank(PARAMETER.privateKey)) {</span><br><span class="line"> localWitnesses = (<span class="keyword">new</span> LocalWitnesses(PARAMETER.privateKey));</span><br><span class="line"> <span class="keyword">if</span> (StringUtils.isNoneBlank(PARAMETER.witnessAddress)) {</span><br><span class="line"> <span class="keyword">byte</span>[] bytes = Commons.decodeFromBase58Check(PARAMETER.witnessAddress);</span><br><span class="line"> <span class="keyword">if</span> (bytes != <span class="keyword">null</span>) {</span><br><span class="line"> localWitnesses.setWitnessAccountAddress(bytes);</span><br><span class="line"> logger.debug(<span class="string">"Got localWitnessAccountAddress from cmd"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> PARAMETER.witnessAddress = <span class="string">""</span>;</span><br><span class="line"> logger.warn(IGNORE_WRONG_WITNESS_ADDRESS_FORMAT);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 初始化 witness</span></span><br><span class="line"> localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine());</span><br><span class="line"> logger.debug(<span class="string">"Got privateKey from cmd"</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (config.hasPath(Constant.LOCAL_WITNESS)) {</span><br><span class="line"> <span class="comment">// Constant.LOCAL_WITNESS 即,配置文件中的 localwitness 这个配置项,可以配置多个</span></span><br><span class="line"> <span class="comment">// 作用就是一个 java-tron 服务,配置多个witness产块,这样做的话,要约成本,一台机器就可以配置多个</span></span><br><span class="line"> localWitnesses = <span class="keyword">new</span> LocalWitnesses();</span><br><span class="line"> List<String> localwitness = config.getStringList(Constant.LOCAL_WITNESS);</span><br><span class="line"> localWitnesses.setPrivateKeys(localwitness);</span><br><span class="line"> witnessAddressCheck(config);</span><br><span class="line"> localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine());</span><br><span class="line"> logger.debug(<span class="string">"Got privateKey from config.conf"</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (config.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)) {</span><br><span class="line"> <span class="comment">// 通过 keystore 加载</span></span><br><span class="line"> localWitnesses = <span class="keyword">new</span> LocalWitnesses();</span><br><span class="line"> List<String> privateKeys = <span class="keyword">new</span> ArrayList<String>();</span><br><span class="line"> <span class="keyword">if</span> (PARAMETER.isWitness()) {</span><br><span class="line"> List<String> localwitness = config.getStringList(Constant.LOCAL_WITNESS_KEYSTORE);</span><br><span class="line"> <span class="keyword">if</span> (localwitness.size() > <span class="number">0</span>) {</span><br><span class="line"> String fileName = System.getProperty(<span class="string">"user.dir"</span>) + <span class="string">"/"</span> + localwitness.get(<span class="number">0</span>);</span><br><span class="line"> String password;</span><br><span class="line"> <span class="keyword">if</span> (StringUtils.isEmpty(PARAMETER.password)) {</span><br><span class="line"> System.out.println(<span class="string">"Please input your password."</span>);</span><br><span class="line"> password = WalletUtils.inputPassword();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> password = PARAMETER.password;</span><br><span class="line"> PARAMETER.password = <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Credentials credentials = WalletUtils</span><br><span class="line"> .loadCredentials(password, <span class="keyword">new</span> File(fileName));</span><br><span class="line"> SignInterface sign = credentials.getSignInterface();</span><br><span class="line"> String prikey = ByteArray.toHexString(sign.getPrivateKey());</span><br><span class="line"> privateKeys.add(prikey);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException | CipherException e) {</span><br><span class="line"> logger.error(e.getMessage());</span><br><span class="line"> logger.error(<span class="string">"Witness node start failed!"</span>);</span><br><span class="line"> exit(-<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> localWitnesses.setPrivateKeys(privateKeys);</span><br><span class="line"> witnessAddressCheck(config);</span><br><span class="line"> localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine());</span><br><span class="line"> logger.debug(<span class="string">"Got privateKey from keystore"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 省略部分代码</span></span><br><span class="line"> ...</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="共识阶段加载"><a href="#共识阶段加载" class="headerlink" title="共识阶段加载"></a>共识阶段加载</h2><p><code>ConsensusService</code> 主要控制共识相关,在启动时。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ConsensusService.start</span><br><span class="line">\--Consensus.start</span><br><span class="line"> \--DposService.start <span class="comment">// 对共抽的抽象,设计上方便切换共识</span></span><br></pre></td></tr></table></figure><p>几个关注的点:</p><ol><li>设置成<code>witness</code>节点</li><li>加载前面的私钥</li><li>启动共识</li><li>更新updateWitness</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">start</span><span class="params">()</span> </span>{</span><br><span class="line"> Param param = Param.getInstance();</span><br><span class="line"> <span class="comment">// 设置成 witness 节点</span></span><br><span class="line"> param.setEnable(parameter.isWitness());</span><br><span class="line"> param.setGenesisBlock(parameter.getGenesisBlock());</span><br><span class="line"> param.setMinParticipationRate(parameter.getMinParticipationRate());</span><br><span class="line"> param.setBlockProduceTimeoutPercent(Args.getInstance().getBlockProducedTimeOut());</span><br><span class="line"> param.setNeedSyncCheck(parameter.isNeedSyncCheck());</span><br><span class="line"> param.setAgreeNodeCount(parameter.getAgreeNodeCount());</span><br><span class="line"> List<Miner> miners = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"> <span class="comment">// 拿到私钥列表</span></span><br><span class="line"> List<String> privateKeys = Args.getLocalWitnesses().getPrivateKeys();</span><br><span class="line"> <span class="keyword">if</span> (privateKeys.size() > <span class="number">1</span>) {</span><br><span class="line"> <span class="comment">// 前面说了,可以配置多个 私钥,所以这里遍历</span></span><br><span class="line"> <span class="keyword">for</span> (String key : privateKeys) {</span><br><span class="line"> <span class="keyword">byte</span>[] privateKey = fromHexString(key);</span><br><span class="line"> <span class="keyword">byte</span>[] privateKeyAddress = SignUtils</span><br><span class="line"> .fromPrivate(privateKey, Args.getInstance().isECKeyCryptoEngine()).getAddress();</span><br><span class="line"> WitnessCapsule witnessCapsule = witnessStore.get(privateKeyAddress);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">null</span> == witnessCapsule) {</span><br><span class="line"> logger.warn(<span class="string">"Witness {} is not in witnessStore."</span>, Hex.toHexString(privateKeyAddress));</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 封装到 Miner 中,在产块时私钥相关校验</span></span><br><span class="line"> Miner miner = param.<span class="function">new <span class="title">Miner</span><span class="params">(privateKey, ByteString.copyFrom(privateKeyAddress)</span>,</span></span><br><span class="line"><span class="function"> ByteString.<span class="title">copyFrom</span><span class="params">(privateKeyAddress)</span>)</span>;</span><br><span class="line"> miners.add(miner);</span><br><span class="line"> logger.info(<span class="string">"Add witness: {}, size: {}"</span>,</span><br><span class="line"> Hex.toHexString(privateKeyAddress), miners.size());</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">byte</span>[] privateKey =</span><br><span class="line"> fromHexString(Args.getLocalWitnesses().getPrivateKey());</span><br><span class="line"> <span class="keyword">byte</span>[] privateKeyAddress = SignUtils.fromPrivate(privateKey,</span><br><span class="line"> Args.getInstance().isECKeyCryptoEngine()).getAddress();</span><br><span class="line"> <span class="keyword">byte</span>[] witnessAddress = Args.getLocalWitnesses().getWitnessAccountAddress(</span><br><span class="line"> Args.getInstance().isECKeyCryptoEngine());</span><br><span class="line"> WitnessCapsule witnessCapsule = witnessStore.get(witnessAddress);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">null</span> == witnessCapsule) {</span><br><span class="line"> logger.warn(<span class="string">"Witness {} is not in witnessStore."</span>, Hex.toHexString(witnessAddress));</span><br><span class="line"> }</span><br><span class="line"> Miner miner = param.n<span class="function">ew <span class="title">Miner</span><span class="params">(privateKey, ByteString.copyFrom(privateKeyAddress)</span>,</span></span><br><span class="line"><span class="function"> ByteString.<span class="title">copyFrom</span><span class="params">(witnessAddress)</span>)</span>;</span><br><span class="line"> miners.add(miner);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> param.setMiners(miners);</span><br><span class="line"> param.setBlockHandle(blockHandle);</span><br><span class="line"> param.setPbftInterface(pbftBaseImpl);</span><br><span class="line"> <span class="comment">// 启动共识</span></span><br><span class="line"> consensus.start(param);</span><br><span class="line"> logger.info(<span class="string">"consensus service start success"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Dpos-中加载"><a href="#Dpos-中加载" class="headerlink" title="Dpos 中加载"></a>Dpos 中加载</h2><p>//TODO</p>]]></content>
<summary type="html">
<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>witness 即在tron链中就是产块节点的代名词,一般称为<code>SR</code>。<br>一般节点不产块,要配置成witness
</summary>
<category term="tron" scheme="https://liukai.net/categories/tron/"/>
<category term="blockchain" scheme="https://liukai.net/categories/blockchain/"/>
<category term="tron" scheme="https://liukai.net/categories/blockchain/tron/"/>
<category term="witness" scheme="https://liukai.net/categories/tron/witness/"/>
<category term="blockchain" scheme="https://liukai.net/tags/blockchain/"/>
<category term="tron" scheme="https://liukai.net/tags/tron/"/>
<category term="波场" scheme="https://liukai.net/tags/%E6%B3%A2%E5%9C%BA/"/>
<category term="witness" scheme="https://liukai.net/tags/witness/"/>
<category term="加载" scheme="https://liukai.net/tags/%E5%8A%A0%E8%BD%BD/"/>
</entry>
<entry>
<title>go结合Slash Commands使用</title>
<link href="https://liukai.net/posts/3c62c672.html"/>
<id>https://liukai.net/posts/3c62c672.html</id>
<published>2023-01-09T09:01:35.000Z</published>
<updated>2023-03-04T06:43:49.642Z</updated>
<content type="html"><![CDATA[<h2 id="需求"><a href="#需求" class="headerlink" title="需求"></a>需求</h2><p>通过 <code>Slack</code> 命令模式,调用操作远程服务器。<br>服务端需要跟一个<code>http</code>服务来解析<code>slash</code>调过来的命令。</p><h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2><p>准备以下步骤:</p><ol><li>创建Slash conmand</li><li>开发服务端应用</li></ol><h2 id="添加-Slash-Conmand"><a href="#添加-Slash-Conmand" class="headerlink" title="添加 Slash Conmand"></a>添加 Slash Conmand</h2><h3 id="添加App"><a href="#添加App" class="headerlink" title="添加App"></a>添加App</h3><p>先到官网地址:<a href="https://api.slack.com/">https://api.slack.com/</a> 创建一个<code>App</code></p><p><img src="/posts/3c62c672/%E5%AE%98%E7%BD%91.png" alt="官网"></p><p><img src="/posts/3c62c672/createApp.png" alt="createApp"></p><p>选<code>Slash Conmand</code></p><p><img src="/posts/3c62c672/slashCommand.png" alt="slashCommand"></p><p><img src="/posts/3c62c672/createCommand.png" alt="createCommand"></p><p>输出一个自定义命令</p><p><img src="/posts/3c62c672/createNewCommand.png" alt="createNewCommand"></p><p>到这就创建完成了,接下来开发服务端。</p><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>创建 go 项目<code>slacktool</code>,添加:</p><ol><li>main.go 文件</li><li>go.mod 文件</li><li>environment.env 文件</li></ol><p>项目结构</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">slacktool</span><br><span class="line">|---main.go</span><br><span class="line">|---go.mod</span><br><span class="line">|---environment.env</span><br></pre></td></tr></table></figure><h3 id="添加-go-mod-依赖"><a href="#添加-go-mod-依赖" class="headerlink" title="添加 go.mod 依赖"></a>添加 go.mod 依赖</h3><p>添加两个依赖:<br><code>godotenv</code> 和 <code>slack</code>。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">module github.com/forfreeday/slacktool</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> <span class="number">1.17</span></span><br><span class="line"></span><br><span class="line">require (</span><br><span class="line"> github.com/joho/godotenv v1<span class="number">.4</span><span class="number">.0</span></span><br><span class="line"> github.com/nlopes/slack v0<span class="number">.6</span><span class="number">.0</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>添加后执行:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go mod tidy</span><br></pre></td></tr></table></figure><h3 id="编辑-main-go"><a href="#编辑-main-go" class="headerlink" title="编辑 main.go"></a>编辑 main.go</h3><p>下面的功能包括:</p><ol><li>运行一个http服务端</li><li>runConmand 运行逻辑</li><li>exec 执行shell命令</li></ol><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line"><span class="string">"log"</span></span><br><span class="line"><span class="string">"net/http"</span></span><br><span class="line"><span class="string">"os"</span></span><br><span class="line"><span class="string">"os/exec"</span></span><br><span class="line"></span><br><span class="line"><span class="string">"github.com/joho/godotenv"</span></span><br><span class="line"><span class="string">"github.com/nlopes/slack"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> <span class="comment">// 读取环境变量配置</span></span><br><span class="line">err := godotenv.Load(<span class="string">"environment.env"</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line">log.Fatal(<span class="string">"Error loading .env file"</span>)</span><br><span class="line">}</span><br><span class="line"> <span class="comment">// 具体处理逻辑</span></span><br><span class="line">http.HandleFunc(<span class="string">"/deploy-test"</span>, slashCommandHandler)</span><br><span class="line">fmt.Println(<span class="string">"[INFO] Server listening"</span>)</span><br><span class="line"> <span class="comment">// 启动 http</span></span><br><span class="line">http.ListenAndServe(<span class="string">":10001"</span>, <span class="literal">nil</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">slashCommandHandler</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> {</span><br><span class="line">s, err := slack.SlashCommandParse(r)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line">w.WriteHeader(http.StatusInternalServerError)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">fmt.Println(<span class="string">"for test: invoke msg"</span>)</span><br><span class="line"><span class="keyword">if</span> !s.ValidateToken(os.Getenv(<span class="string">"SLACK_VERIFICATION_TOKEN"</span>)) {</span><br><span class="line">w.WriteHeader(http.StatusUnauthorized)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">switch</span> s.Command {</span><br><span class="line"><span class="keyword">case</span> <span class="string">"/deploy-test"</span>:</span><br><span class="line">params := &slack.Msg{Text: s.Text}</span><br><span class="line">response := fmt.Sprintf(<span class="string">"Command params : %v"</span>, params.Text)</span><br><span class="line"> <span class="comment">// 开启协程,否则如果执行太久,slack端会返回 timeout</span></span><br><span class="line"><span class="keyword">go</span> runConmand(params, w)</span><br><span class="line">w.Write([]<span class="keyword">byte</span>(response))</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">w.WriteHeader(http.StatusInternalServerError)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 执行命令</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">runConmand</span><span class="params">(param *slack.Msg, w http.ResponseWriter)</span></span> {</span><br><span class="line"><span class="keyword">switch</span> param.Text {</span><br><span class="line"><span class="keyword">case</span> <span class="string">"--restartAll"</span>:</span><br><span class="line">fmt.Println(<span class="string">"restart All node"</span>)</span><br><span class="line">cmd := exec.Command(<span class="string">"deploy-test"</span>, param.Text)</span><br><span class="line">_, err := cmd.CombinedOutput()</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line">log.Fatalf(<span class="string">"cmd.Run() failed with %s\n"</span>, err)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">case</span> <span class="string">"--develop"</span>:</span><br><span class="line">fmt.Println(<span class="string">"develop code"</span>)</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">w.WriteHeader(http.StatusInternalServerError)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>服务端行一下,服务端可以多加一些日志,查看效果。</p><p><img src="/posts/3c62c672/slash%E6%89%A7%E8%A1%8C%E6%95%88%E6%9E%9C.jpg" alt="slash执行效果"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>比较简单,上面的代码最终调了一个系统命令<code>deploy-test</code>,这个实际写的另一个命令,写文章举个例子。</p>]]></content>
<summary type="html">
<h2 id="需求"><a href="#需求" class="headerlink" title="需求"></a>需求</h2><p>通过 <code>Slack</code> 命令模式,调用操作远程服务器。<br>服务端需要跟一个<code>http</code>服务来解
</summary>
<category term="go" scheme="https://liukai.net/categories/go/"/>
<category term="slack" scheme="https://liukai.net/categories/slack/"/>
<category term="slash" scheme="https://liukai.net/categories/slack/slash/"/>
<category term="go" scheme="https://liukai.net/tags/go/"/>
<category term="slack" scheme="https://liukai.net/tags/slack/"/>
<category term="slash" scheme="https://liukai.net/tags/slash/"/>
<category term="conmand" scheme="https://liukai.net/tags/conmand/"/>
</entry>
<entry>
<title>rust-所有权</title>
<link href="https://liukai.net/posts/e28f62f.html"/>
<id>https://liukai.net/posts/e28f62f.html</id>
<published>2023-01-03T18:07:28.000Z</published>
<updated>2023-04-02T11:06:00.487Z</updated>
<content type="html"><![CDATA[<h2 id="所有权"><a href="#所有权" class="headerlink" title="所有权"></a>所有权</h2><p>所有权(系统)是 Rust 最为与众不同的特性。<br>它让 Rust 无需垃圾回收(garbage collector)即可保障内存安全。<br>所有权以及相关功能:借用(borrowing)、slice 以及 Rust 如何在内存中布局数据。</p><p>所有程序都必须管理其运行时使用计算机内存的方式。<br>一些语言中具有垃圾回收机制,如: java、python;<br>在另一些语言中,程序员必须亲自分配和释放内存,如:C/C++;</p><p>Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。</p><h2 id="内存与分配"><a href="#内存与分配" class="headerlink" title="内存与分配"></a>内存与分配</h2><p>Rust 的所有权围绕着内存分配进行,Rust 对内存管理通过其所有权展开。</p><h3 id="栈"><a href="#栈" class="headerlink" title="栈"></a>栈</h3><p>它是一种 <strong>后进先出</strong> 的机制,类似我们日常的落盘子,只能一个一个向上方,然后从最上面拿一个盘子。<br>一个变量要放到栈上,那么它的大小在编译时就要明确。<code>i32</code> 类型的变量,它就占用 <code>4</code> 个字节。Rust 中可以放到栈上的数据类型,他们的大小都是固定的。<br>如果是字符串,在运行时才会赋值的变量,在编译期的时候大小是未知或不确定的。所以字符串类型存储在<strong>堆上</strong>。</p><h3 id="堆"><a href="#堆" class="headerlink" title="堆"></a>堆</h3><p>用于编译时大小未知或不确定的,只有运行时才能确定的数据。在堆上存储一些动态类型的数据。堆是不受系统管理的,是用户自己管理的,也增加了内存溢出的风险。</p><h2 id="1-所有权规则"><a href="#1-所有权规则" class="headerlink" title="1.所有权规则"></a>1.所有权规则</h2><p>记住这三句话,整个所有权就是围绕这三句话,这三句话也直接概括了所有权。</p><ol><li>Rust 中的<strong>每一个值</strong>都有一个<strong>所有者(owner)</strong>。</li><li>值在<strong>任一时刻</strong>有且只有<strong>一个</strong>所有者。</li><li>当所有者(变量)离开作用域,这个值将被丢弃。</li></ol><h2 id="2-变量作用域"><a href="#2-变量作用域" class="headerlink" title="2.变量作用域"></a>2.变量作用域</h2><p>大部份编程语言都有 <strong>作用域(scope)</strong> 的概念,但是在rust中,这个概念被提到一个很重要的高度。<br>先看看rust一些变量的 <strong>作用域(scope)</strong>。<br>作用域是一个项(item)在程序中有效的范围。<br>下面这个例子,重点关注变量:<code>let s = "hello"</code></p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> { <span class="comment">// s 在这里无效, 它尚未声明</span></span><br><span class="line"> <span class="keyword">let</span> s = <span class="string">"hello"</span>; <span class="comment">// 从此处起,s 是有效的</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 使用 s</span></span><br><span class="line"> } <span class="comment">// 此作用域已结束,s 不再有效</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>当 <code>s</code> 进入作用域时,它就是有效的。<br>这一直持续到它 <strong>离开作用域</strong> 为止。</p><p>当 <code>s</code> 离开作用域的时候。当变量离开作用域,Rust 为我们调用一个特殊的函数。这个函数叫做 <code>drop</code>,在这里 String 的作者可以放置释放内存的代码。<br>Rust 在结尾的 <code>}</code> 处<strong>自动调用</strong> <code>drop</code>。</p><p><strong>Rust 采取了一个不同的策略:内存在拥有它的变量离开作用域后就被自动释放</strong>。<br>核心就一句话,变量出了<strong>作用域</strong>,rust帮你释放了!!</p><h2 id="3-移动"><a href="#3-移动" class="headerlink" title="3.移动"></a>3.移动</h2><p>在 rust 当中一个变量指向另一个变量,并不是地址或引用的copy,而是称之为:<strong>移动</strong>。<br>当 s2=s1 时,引用s1被移动到s2上,这和其它编程语言完全不同!!<br>下面这段代码,在其它编程语言上指针<code>s1</code>指向了指针<code>s1</code>,<code>s1</code>仍然有效,在rust当中,<code>s1</code>无效已经无效。<br>在rust中,这个操作被称为 <strong>移动(move)</strong>,而不是叫做浅拷贝。</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">"hello"</span>);</span><br><span class="line"> <span class="keyword">let</span> s2 = s1;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"{}, world!"</span>, s1);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行结果:</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">error[E0382]: borrow of moved value: `s1`</span><br><span class="line"> --> src/main.rs:<span class="number">5</span>:<span class="number">28</span></span><br><span class="line"> |</span><br><span class="line"><span class="number">2</span> | <span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">"hello"</span>);</span><br><span class="line"> | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait</span><br><span class="line"><span class="number">3</span> | <span class="keyword">let</span> s2 = s1;</span><br><span class="line"> | -- value moved here</span><br><span class="line"><span class="number">4</span> |</span><br><span class="line"><span class="number">5</span> | <span class="built_in">println!</span>(<span class="string">"{}, world!"</span>, s1); </span><br><span class="line"> | ^^ value borrowed here after <span class="keyword">move</span></span><br><span class="line"> |</span><br></pre></td></tr></table></figure><p>为什么要这么设计?<br>为了防止<strong>二次释放</strong>。<br>当 <code>s2</code> 和 <code>s1</code> 离开作用域,他们都会尝试释放相同的内存。<br>这是一个叫做 <strong>二次释放(double free)</strong>的错误,也是之前提到过的内存安全性 bug 之一。<br>两次释放(相同)内存会导致内存污染,它可能会导致潜在的安全漏洞。</p><h3 id="如何保证,即要、也要"><a href="#如何保证,即要、也要" class="headerlink" title="如何保证,即要、也要"></a>如何保证,即要、也要</h3><p>即要把<code>s2=s1</code>,也可保持<code>s1</code>可用,那就显示拷贝。</p><h2 id="4-引用和借用-reference-amp-borrowing"><a href="#4-引用和借用-reference-amp-borrowing" class="headerlink" title="4.引用和借用 reference & borrowing"></a>4.引用和借用 reference & borrowing</h2><h3 id="借用-borrowing"><a href="#借用-borrowing" class="headerlink" title="借用(borrowing)"></a>借用(borrowing)</h3><p>借用就是字面意思,借来的数据,你并不拥有它。<br>看个例子:</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">"hello"</span>);</span><br><span class="line"> <span class="comment">// len 借用 s1</span></span><br><span class="line"> <span class="keyword">let</span> len = calculate_length(&s1);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">println!</span>(<span class="string">"The length of '{}' is {}."</span>, s1, len);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">calculate_length</span></span>(s: &<span class="built_in">String</span>) -> <span class="built_in">usize</span> {</span><br><span class="line"> s.len()</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>s1</code> 移进了 <code>calculate_length</code>,但是所有权并没有转移,这里只是借用了<code>s1</code>。<br>也就是说:指向 值 <code>s1</code> 的引用,但是并不拥有它。<br>因为并不拥有这个值,所以当引用停止使用时,它所指向的值也不会被丢弃。</p><h3 id="借用默认不允许修改值"><a href="#借用默认不允许修改值" class="headerlink" title="借用默认不允许修改值"></a>借用默认不允许修改值</h3><p>这个是反例,当去改变一个借用的数据时,就会报错。</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() {</span><br><span class="line"> <span class="keyword">let</span> s = <span class="built_in">String</span>::from(<span class="string">"hello"</span>);</span><br><span class="line"></span><br><span class="line"> change(&s);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">change</span></span>(some_string: &<span class="built_in">String</span>) {</span><br><span class="line"> some_string.push_str(<span class="string">", world"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h2 id="所有权"><a href="#所有权" class="headerlink" title="所有权"></a>所有权</h2><p>所有权(系统)是 Rust 最为与众不同的特性。<br>它让 Rust 无需垃圾回收(garbage collector)即可保障内
</summary>
<category term="rust" scheme="https://liukai.net/categories/rust/"/>
<category term="rust" scheme="https://liukai.net/tags/rust/"/>
<category term="所有权" scheme="https://liukai.net/tags/%E6%89%80%E6%9C%89%E6%9D%83/"/>
</entry>
<entry>
<title>GnuPG-2子密钥使用</title>
<link href="https://liukai.net/posts/38f72231.html"/>
<id>https://liukai.net/posts/38f72231.html</id>
<published>2023-01-03T17:41:20.000Z</published>
<updated>2023-03-04T06:43:49.908Z</updated>
<content type="html"><![CDATA[<h2 id="子密钥"><a href="#子密钥" class="headerlink" title="子密钥"></a>子密钥</h2><p>主私钥有所有功能,但实际使用中仅用来生成子密钥,要保证主密钥的绝对安全。<br>所以一般只用来生成子密钥,使用子密钥参与工作。<br>即:<code>subkey</code>,可以看到子密钥拥有以下这些功能,除了没有<strong>认证</strong>功能</p><table><thead><tr><th align="center">类型</th><th align="center">认证 [C]</th><th align="center">签名 [S]</th><th align="center">身份验证 [A]</th><th align="center">加密 [E]</th></tr></thead><tbody><tr><td align="center">主私钥</td><td align="center">有</td><td align="center">有</td><td align="center">有</td><td align="center">有</td></tr><tr><td align="center">子私钥</td><td align="center">无</td><td align="center">有</td><td align="center">有</td><td align="center">有</td></tr></tbody></table><p>单一公钥机制对于服务端的验证特别友好,无论用户有多少个子密钥,服务器只需要一份证书(公钥)就够了,而不需要额外开销,去查询这份证书是哪个上级签发的。<br>什么叫单一公钥机制?<br>就是<strong>主密钥</strong>生成一个公钥,所有的子私钥都可以对这个公钥进行签名、身份验证、加密操作。</p><h2 id="生成子密钥"><a href="#生成子密钥" class="headerlink" title="生成子密钥"></a>生成子密钥</h2><p>子密钥可以指定上面的:[S]、[A]、[E] 的功能,可以全部拥有,也可以功能独立,取决于在添加时的指定。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --expert --edit-key [用户ID]</span><br></pre></td></tr></table></figure><p>参数说明:</p><p><code>--expert</code>:进入gpg命令模式<br><code>--edit-key</code>:操作用户ID</p><p>输入<code>addkey</code>,添加子密钥,选择一种加密模式,选 <code>4</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">gpg> addkey</span><br><span class="line">请选择您要使用的密钥类型:</span><br><span class="line"> (3) DSA(仅用于签名)</span><br><span class="line"> (4) RSA(仅用于签名)</span><br><span class="line"> (5) ElGamal(仅用于加密)</span><br><span class="line"> (6) RSA(仅用于加密)</span><br><span class="line"> (7) DSA(自定义用途)</span><br><span class="line"> (8) RSA(自定义用途)</span><br><span class="line"> (10) ECC(仅用于签名)</span><br><span class="line"> (11) ECC(自定义用途)</span><br><span class="line"> (12) ECC(仅用于加密)</span><br><span class="line"> (13) 现存的密钥</span><br><span class="line"> (14)卡中现有密钥</span><br></pre></td></tr></table></figure><p>选择长度</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">RSA 密钥的长度应在 1024 位与 4096 位之间。</span><br><span class="line">您想要使用的密钥长度?(3072)</span><br><span class="line">请求的密钥长度是 3072 位</span><br><span class="line">选择一个有效期:1y 表示一年</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">请设定这个密钥的有效期限。</span><br><span class="line"> 0 = 密钥永不过期</span><br><span class="line"> <n> = 密钥在 n 天后过期</span><br><span class="line"> <n>w = 密钥在 n 周后过期</span><br><span class="line"> <n>m = 密钥在 n 月后过期</span><br><span class="line"> <n>y = 密钥在 n 年后过期</span><br><span class="line">密钥的有效期限是?(0) 1y</span><br><span class="line">创建时间要大概几秒,成功后的输出:DAF9C7421FB1B533为子密钥</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">sec rsa3072/D66E46924A7A4475</span><br><span class="line"> 创建于:2023-01-03 有效至:2025-01-02 可用于:SC</span><br><span class="line"> 信任度:绝对 有效性:绝对</span><br><span class="line">ssb rsa3072/9FF7004AC3A0DB89</span><br><span class="line"> 创建于:2023-01-03 有效至:2025-01-02 可用于:E</span><br><span class="line">ssb rsa3072/DAF9C7421FB1B533</span><br><span class="line"> 创建于:2023-01-04 有效至:2024-01-04 可用于:S</span><br><span class="line">[ 绝对 ] (1). liukai <[email protected]></span><br><span class="line">最后输入save,保存后再退出当前模式。</span><br><span class="line">gpg > save</span><br></pre></td></tr></table></figure><h3 id="验证子密钥"><a href="#验证子密钥" class="headerlink" title="验证子密钥"></a>验证子密钥</h3><p>查看刚生成的子密钥:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">gpg -k DAF9C7421FB1B533</span><br><span class="line">输出:sub rsa3072为刚创建的子密钥</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">pub rsa3072 2023-01-03 [SC] [有效至:2025-01-02]</span><br><span class="line"> 79A86B57A0DA913F0D76B5ACD66E46924A7A4475</span><br><span class="line">uid [ 绝对 ] liukai <[email protected]></span><br><span class="line">sub rsa3072 2023-01-03 [E] [有效至:2025-01-02]</span><br><span class="line">sub rsa3072 2023-01-04 [S] [有效至:2024-01-04]</span><br></pre></td></tr></table></figure><h3 id="导出子密钥"><a href="#导出子密钥" class="headerlink" title="导出子密钥"></a>导出子密钥</h3><p>实际使用中,主密钥不会直接参与验证工作,而是生成多个子密钥去工作,这样做的好处是,子密钥如果泄露可以吊销,子密钥的功能也是有限的。</p><p>将生成的子密钥发送给服务端进行验证工作。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --armor --output private-key.txt --export-secret-subkey [用户ID]</span><br></pre></td></tr></table></figure><p>参数说明:</p><p><code>--armor</code>: 以ASCII形式显示,不推存,容易密钥暴露明文<br><code>--export-secret-subkey</code>:导出子密钥<br><code>--output</code>:子密钥文件名</p><h2 id="GPG-吊销证书"><a href="#GPG-吊销证书" class="headerlink" title="GPG 吊销证书"></a>GPG 吊销证书</h2><p>这个就是字面意思,吊销证书。场景就是如果私钥丢失了,那么原来的公钥也就不能信任了。<br>所以可以生成一个员销证书,来吊销原来的证书。</p><p>因此 GPG 多了一个“吊销证书”(revocation certificate),拿着这个证书你就能证明</p><ol><li>确认吊销者身份</li><li>把丢失当前这个密钥作废</li></ol>]]></content>
<summary type="html">
<h2 id="子密钥"><a href="#子密钥" class="headerlink" title="子密钥"></a>子密钥</h2><p>主私钥有所有功能,但实际使用中仅用来生成子密钥,要保证主密钥的绝对安全。<br>所以一般只用来生成子密钥,使用子密钥参与工作。<br
</summary>
<category term="safe" scheme="https://liukai.net/categories/safe/"/>
<category term="cryptography" scheme="https://liukai.net/categories/cryptography/"/>
<category term="rsa" scheme="https://liukai.net/categories/rsa/"/>
<category term="gnupg" scheme="https://liukai.net/tags/gnupg/"/>
</entry>
<entry>
<title>GnuPG-1主密钥使用</title>
<link href="https://liukai.net/posts/82be817.html"/>
<id>https://liukai.net/posts/82be817.html</id>
<published>2023-01-03T10:02:39.000Z</published>
<updated>2023-03-04T06:43:49.907Z</updated>
<content type="html"><![CDATA[<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>GnuPG,简称GPG,是一个密码学软件,用于加密、签名通信内容及管理非对称密码学的密钥。GnuPG 是自由软件,遵循 IETF 订定的 OpenPGP 技术标准设计,并与 <code>PGP</code> 保持兼容。</p><table><thead><tr><th align="center">功能</th><th align="center">能力</th><th align="center">说明</th></tr></thead><tbody><tr><td align="center">[C]</td><td align="center">Certificating</td><td align="center">认证 / 给其它证书签名</td></tr><tr><td align="center">[S]</td><td align="center">Signing</td><td align="center">签名</td></tr><tr><td align="center">[A]</td><td align="center">Authenticating</td><td align="center">身份验证</td></tr><tr><td align="center">[E]</td><td align="center">Encrypting</td><td align="center">加密</td></tr></tbody></table><p>GPG 密钥的能力中, [C]、[S]、[A] 均属于签名方案,只有 [E] 是加密方案。<br>一个主密钥,可以绑定若干个子密钥;这些子密钥有的具备加密功能,有的具备签名功能。<br>可以理解为,主私钥就是用来生成多个子密钥来使用,而子密钥丢失可以随时废弃,主密钥生成新的子密钥来使用。</p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>官方下载地址:<a href="https://www.gnupg.org/download/index.en.html">https://www.gnupg.org/download/index.en.html</a></p><h3 id="centOS"><a href="#centOS" class="headerlink" title="centOS"></a>centOS</h3><p>CentOS 默认已经安装了 gpg2</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --version</span><br></pre></td></tr></table></figure><p>如果需要手动安装,在<a href="http://rpmfind.net/">http://rpmfind.net/</a> 搜GPG下载:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">wget http://rpmfind.net/linux/centos/7.9.2009/os/x86_64/Packages/gnupg2-2.0.22-5.el7_5.x86_64.rpm</span><br><span class="line">rpm -ivh gnupg2-2.0.22-5.el7_5.x86_64.rpm</span><br></pre></td></tr></table></figure><h3 id="macOS"><a href="#macOS" class="headerlink" title="macOS"></a>macOS</h3><p>macOS 下安装,可以选择图形界面和命令行两种形式:</p><p>1.GPGTools 包含图形界面,下载地址:<a href="https://gpgtools.org/">https://gpgtools.org/</a></p><p>可以直接安装 GPGTools,就可以包含命令行工具,本例安装 GPGTools,但是使用它的命令行进行操作。</p><p><img src="/posts/82be817/macOS.jpg" alt="macOS"></p><p>2.命令行工具安装:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install gpg</span><br></pre></td></tr></table></figure><h2 id="生成私钥"><a href="#生成私钥" class="headerlink" title="生成私钥"></a>生成私钥</h2><p>安装后使用命令:<code>gpg</code>进行后续的操作,生成私钥使用命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --gen-key</span><br></pre></td></tr></table></figure><p>只需输入姓名、邮件即可生成,输出如下,私钥文件生成目录:/Users/{user_name}/.gnupg/openpgp-revocs.d/<br>需要关注<strong>用户ID</strong>,在操作时很多地方需要用到用户ID,我这里生成的测试用户ID:9F4B9BCF408B96C68E0645805BDF50B192200806</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">gpg (GnuPG/MacGPG2) 2.2.40; Copyright (C) 2022 g10 Code GmbH</span><br><span class="line">This is free software: you are free to change and redistribute it.</span><br><span class="line">There is NO WARRANTY, to the extent permitted by law.</span><br><span class="line"></span><br><span class="line">注意:使用 “gpg --full-generate-key” 以获得一个全功能的密钥生成对话框。</span><br><span class="line"></span><br><span class="line">GnuPG 需要构建用户标识以辨认您的密钥。</span><br><span class="line"></span><br><span class="line">真实姓名: liukaitest</span><br><span class="line">电子邮件地址: [email protected]</span><br><span class="line">您选定了此用户标识:</span><br><span class="line"> “liukaitest <[email protected]>”</span><br><span class="line"></span><br><span class="line">更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)? o</span><br><span class="line">我们需要生成大量的随机字节。在质数生成期间做些其他操作(敲打键盘</span><br><span class="line">、移动鼠标、读写硬盘之类的)将会是一个不错的主意;这会让随机数</span><br><span class="line">发生器有更好的机会获得足够的熵。</span><br><span class="line">我们需要生成大量的随机字节。在质数生成期间做些其他操作(敲打键盘</span><br><span class="line">、移动鼠标、读写硬盘之类的)将会是一个不错的主意;这会让随机数</span><br><span class="line">发生器有更好的机会获得足够的熵。</span><br><span class="line">gpg: 吊销证书已被存储为‘/Users/liukai/.gnupg/openpgp-revocs.d/9F4B9BCF408B96C68E0645805BDF50B192200806.rev’</span><br><span class="line">公钥和私钥已经生成并被签名。</span><br><span class="line"></span><br><span class="line">pub rsa3072 2023-01-03 [SC] [有效至:2025-01-02]</span><br><span class="line"> 9F4B9BCF408B96C68E0645805BDF50B192200806</span><br><span class="line">uid liukaitest <[email protected]></span><br><span class="line">sub rsa3072 2023-01-03 [E] [有效至:2025-01-02]</span><br></pre></td></tr></table></figure><h2 id="列出私链"><a href="#列出私链" class="headerlink" title="列出私链"></a>列出私链</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --list-secret-keys</span><br></pre></td></tr></table></figure><h2 id="输出公钥"><a href="#输出公钥" class="headerlink" title="输出公钥"></a>输出公钥</h2><p>项目应用中,需要将公钥输出给其它机器使用。公钥文件(.gnupg/pubring.gpg)以二进制形式储存。<br>执行命令,需要用到上面生成的用户ID</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --armor --output public-key.txt --export [用户ID]</span><br></pre></td></tr></table></figure><p><strong>参数说明</strong>:</p><p><code>--armor</code>:参数可以将其转换为ASCII码显示<br><code>--output</code>:参数指定输出文件名(public-key.txt)<br><code>--export:</code>:指定哪个用户的公钥</p><h2 id="导入、导出密钥"><a href="#导入、导出密钥" class="headerlink" title="导入、导出密钥"></a>导入、导出密钥</h2><h3 id="导出公钥"><a href="#导出公钥" class="headerlink" title="导出公钥"></a>导出公钥</h3><p>导出为公钥文件,--output 参数可以省略,默认文件名也是 public-key.txt</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --armor --output public-key.txt --export [用户ID]</span><br></pre></td></tr></table></figure><h3 id="导出私钥"><a href="#导出私钥" class="headerlink" title="导出私钥"></a>导出私钥</h3><p>导出需要输入密钥密码。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg -a -o private-file.key --export-secret-keys [用户ID]</span><br></pre></td></tr></table></figure><h3 id="导入公钥、私钥"><a href="#导入公钥、私钥" class="headerlink" title="导入公钥、私钥"></a>导入公钥、私钥</h3><p>有两种方式:</p><ol><li>从远GPG公钥服务器导入</li><li>从公钥文件导入</li></ol><p>从公钥文件导入,这种方式很简单,做开源项目,很多项目会在README中说明公钥HASH,就可以拿着HASH或uid从远程导入到本地。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --recv-keys <keyid/uid></span><br></pre></td></tr></table></figure><p>通过文件导入</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --import [密钥文件]</span><br></pre></td></tr></table></figure><hr><h2 id="签名"><a href="#签名" class="headerlink" title="签名"></a>签名</h2><p>签名的数据内容有两种形式:</p><ol><li>二进制</li><li>ASCII</li></ol><p>签名会生成签名文件或将签名和文件合并成一个文件。</p><h3 id="1-签名数据、生成新文件:原文件和签名生成在同一个文件中"><a href="#1-签名数据、生成新文件:原文件和签名生成在同一个文件中" class="headerlink" title="1.签名数据、生成新文件:原文件和签名生成在同一个文件中"></a>1.签名数据、生成新文件:原文件和签名生成在同一个文件中</h3><p>生成结果为二进制的签名文件:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --sign demo.txt</span><br></pre></td></tr></table></figure><p>生成新文件:<code>demo.txt.gpg</code>,内容为二进制。</p><p>生成 ASCII 内容的签名文件。文件名为xxxx.xxx.asc。签名信息添加在文件尾</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --clear-sign 123.txt.gpg</span><br></pre></td></tr></table></figure><p>结果</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">-----BEGIN PGP SIGNED MESSAGE-----</span><br><span class="line">Hash: SHA256</span><br><span class="line"></span><br><span class="line">123123</span><br><span class="line">1231231</span><br><span class="line">12</span><br><span class="line">3123</span><br><span class="line">12</span><br><span class="line">312323</span><br><span class="line">123123123</span><br><span class="line">12</span><br><span class="line">3</span><br><span class="line">-----BEGIN PGP SIGNATURE-----</span><br><span class="line"></span><br><span class="line">iQGzBAEBCAAdFiEEeahrV6DakT8NdrWs1m5Gkkp6RHUFAmOz+Y4ACgkQ1m5Gkkp6</span><br><span class="line">RHXWNQv/fbhBLdmuvw41nrtqK6exJ6MxX0Kso5NXOp5PleKc5baParHgjEvXEey8</span><br><span class="line">6/krmom2K0W9tQQ0cXQkagDqRIhpSNEr+QiG1OZb6tLRLbFPqYCEU9dugc426/xO</span><br><span class="line">4s9/gaLscYo5X8aoOkvO2cdlP/cYNPmI3CUGXJqy9KGVqmfvl8iTbg2LCEmAYqQu</span><br><span class="line">uQdS42XXH8qieEvjCaBj1aC06NVsLmydwlFu3Zah9HVGj2IQmBTXjboz+FrYJ4q+</span><br><span class="line">iVMuOH4b02dg7Il0h8u636EeUwNVkX+4jJB3+DPenQ37FOxp1vv/miKM4ace7SjX</span><br><span class="line">nmMi+oAJnB577dEaOrxnP6wOKcWEd6/GJMRvb1FcLElu46Bsz5UhoQwRmGyuCrNL</span><br><span class="line">2M6j2j4MHzNv4XBLaFv7Lo59TjZVZrghwblL3Y82zcDsak4kBu/GwZCS9/WANjSs</span><br><span class="line">sPFZSVpwe5bg6cFLN35GAcUB590UCbOtN2SMvdWLWeTw4bSeyqcA8wRi0GTU31Tc</span><br><span class="line">yrVpIRH4</span><br><span class="line">=oMT2</span><br><span class="line">-----END PGP SIGNATURE-----</span><br></pre></td></tr></table></figure><p>以上两个命令都是将签名添加到文件中。</p><h3 id="2-签名数据、生成新文件:sig、asc"><a href="#2-签名数据、生成新文件:sig、asc" class="headerlink" title="2.签名数据、生成新文件:sig、asc"></a>2.签名数据、生成新文件:sig、asc</h3><p>1.生成签名,基于二进制格式</p><p>如果想生成单独的签名文件,与文件内容分开存放,可以使用detach-sign参数。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --detach-sign demo.txt</span><br></pre></td></tr></table></figure><p>2.生成签名,基于 ASCII 格式</p><p>这个命令会在当前目录下生成 xxxx.xxx.sig 这是文件的签名。采用二进制储存。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --detach-sign --armor demo.txt</span><br></pre></td></tr></table></figure><p>这个命令会生成文件的ASCII签名: demo.txt.asc。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">-----BEGIN PGP SIGNATURE-----</span><br><span class="line"></span><br><span class="line">iQGzBAABCAAdFiEEeahrV6DakT8NdrWs1m5Gkkp6RHUFAmOz+vUACgkQ1m5Gkkp6</span><br><span class="line">RHVfKQv8CptzZlVqHoxq7TpGeg0kuB7WAtnG5yaHqRCWmGAI6RdMa6o6MI/RchtZ</span><br><span class="line">CvBZRZjm4U228cUmN1/pl/wwI91HL97tei/NZ65ke/KgcEnw+HrluY+5b8j7SLug</span><br><span class="line">XambZRlfFkdjTuwGM1zgaIhcBpTG4tX+pURGtdGRp5jTzNyWP6vVq80oXte85o/N</span><br><span class="line">aZV/GEa5UOgigPnEK09DP3yTsHxhw8y2Rc8kDS5P1AWeE37dxO3NU1NzkWOmct7P</span><br><span class="line">a4g+1cTxL2o3hXCt+TYCejqduKLXJjZLJRlU+Kie+nanEH868GN+qGeCOQN2eN3K</span><br><span class="line">5E/sZzR7A3XTNT9gLYrtr7uRlz7+iU4vYsL5SvyB18I84T7Fqa8qM5s9KMIh7wsL</span><br><span class="line">GlHcoE7H7zOkES3U0RyZWTYHrzJ/h8bCm6ErGy4meqWZRzQTgGMpWlAUvx9rU6iS</span><br><span class="line">ZgwWDgc2qLPIEi0PhD6rVl9Kx1Pr3Ai5XJCtbBn41VK5B5Y6tXqheKXoo6n6lEBj</span><br><span class="line">EmTuKvec</span><br><span class="line">=OduX</span><br><span class="line">-----END PGP SIGNATURE-----</span><br></pre></td></tr></table></figure><h3 id="3-验证签名-gpg-verify"><a href="#3-验证签名-gpg-verify" class="headerlink" title="3.验证签名 gpg --verify"></a>3.验证签名 gpg --verify</h3><p>新版本不需要 --output 参数,但是原文件必须在当前目录下</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gpg --verify demo.txt.gpg</span><br><span class="line">gpg --verify demo.txt.asc</span><br><span class="line">gpg --verify demo.txt.sig</span><br></pre></td></tr></table></figure><p>结果:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">gpg: 假定被签名的数据在‘demo.txt’</span><br><span class="line">gpg: 签名建立于 二 1/ 3 17:52:53 2023 CST</span><br><span class="line">gpg: 使用 RSA 密钥 79A86B57A0DA913F0D76B5ACD66E46924A7A4475</span><br><span class="line">gpg: 完好的签名,来自于 “liukai <[email protected]>” [绝对]</span><br></pre></td></tr></table></figure><h3 id="4-签名-加密"><a href="#4-签名-加密" class="headerlink" title="4.签名+加密"></a>4.签名+加密</h3><p>命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --local-user [发信者ID] --recipient [接收者ID] --armor --sign --encrypt demo.txt</span><br></pre></td></tr></table></figure><p>参数说明:</p><p><code>--local-user</code>:参数指定用发信者的私钥签名<br><code>--recipient</code>:参数指定用接收者的公钥加密<br><code>--armor</code>:参数表示采用ASCII码形式显示<br><code>--sign</code>:参数表示需要签名<br><code>--encrypt</code>:参数表示指定源文件</p><p>发信者ID、接收者ID形式:DF9B9C49EAA9298432589D76DA87E80D6294BE9B</p><p>5.验证签名</p><p>收到别人签名后的文件,需要用对方的公钥验证签名是否为真。verify参数用来验证。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --verify demo.txt.sig demo.txt</span><br></pre></td></tr></table></figure><h3 id="结果"><a href="#结果" class="headerlink" title="结果"></a>结果</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gpg: 签名建立于 二 1/ 3 16:32:41 2023 CST</span><br><span class="line">gpg: 使用 RSA 密钥 79A86B57A0DA913F0D76B5ACD66E46924A7A4475</span><br><span class="line">gpg: 完好的签名,来自于 “liukai <[email protected]>” [绝对]</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>主密钥拥有所有的功能,但是在使用上一般<strong>不直接使用</strong>主密钥,而是多个生成子密来使用。</p><h2 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h2><p><a href="https://gnupg.org/">https://gnupg.org/</a></p>]]></content>
<summary type="html">
<h2 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h2><p>GnuPG,简称GPG,是一个密码学软件,用于加密、签名通信内容及管理非对称密码学的密钥。GnuPG 是自由软件,遵循 IETF 订定的 O
</summary>
<category term="safe" scheme="https://liukai.net/categories/safe/"/>
<category term="cryptography" scheme="https://liukai.net/categories/cryptography/"/>
<category term="rsa" scheme="https://liukai.net/categories/rsa/"/>
<category term="gnupg" scheme="https://liukai.net/tags/gnupg/"/>
</entry>
<entry>
<title>随笔--2022-2023总结</title>
<link href="https://liukai.net/posts/9c4b5c1b.html"/>
<id>https://liukai.net/posts/9c4b5c1b.html</id>
<published>2022-12-25T09:00:47.000Z</published>
<updated>2023-02-02T18:13:16.000Z</updated>
<content type="html"><![CDATA[<h2 id="起点"><a href="#起点" class="headerlink" title="起点"></a>起点</h2><p>说是总结,其实是吐槽。<br>写了这么些博客,很少说跟技术无关的博客。<br>2022已经完结,这一篇过去了,2023年是一个新的起点,一切都会从新开始,我也一样。<br>在2022之前的不完整,都留在过去,在这一个新的起点,告别过往,重新开始,回归自己应有的状态。</p><h2 id="谷底"><a href="#谷底" class="headerlink" title="谷底"></a>谷底</h2><p><code>2023</code>之前的感想。<br><code>2020</code>年之前,是最好生活状态。每天能够边工作边学习边生活,即便是996也是一种很好的状态,每天都在进步,不论是工作、还是生活。<br>就像跟代码热恋,走到哪满脑子都是代码,就差跟代码生猴子。<br>每天处在一种打鸡血的状态,没事也要找点问题出来,大嗓门就怕大厦楼下保安不知道楼上有我这号人物。<br>在公司能搞定一切和不要脸。</p><p>直到这个过程被打破。</p><p>之后两年感觉像是,在一个泥潭中,越用力陷的越深,一点一点往下拖。</p><p><code>2020</code>年,人生中的一个大低谷,并不是因为疫情,而是人和事,我发现除了代码之外,很多事我控制不了。<br>疫情对我来说,除了担心身边的人之外,需要戴口罩这件麻烦事,其他的没有什么影响。<br>前半年的人与人之间折腾,让我身心俱疲,从生活漫延到工作,工作实在进行不下去,也没法工作,干脆给自己放个长假,在家躺了一段时间。<br>逃避虽然不能解决问题,但是有用,休息了一段时间后,算是放空身心,但总是要面对生活。<br>过完十一开始新的征程。</p><p><code>2020</code>下半年的开始</p><p>半推半就入职新公司,最大的想法是找回状态,好好去做。不管什么都留在前半年。</p><p>事实证明烦心事,如果不能彻底解决的话,工作还是没有办法好好进行。整个人都在暴发的边缘反复来回。新的征程怕是要中道崩殂了。</p><p>经历着一个让自己都感觉厌恶自己的阶段。<br>工作也迎来入行以来最大的低谷与被动,很多事情变得不再可控,处处被动。<br>事事都搞成我以往最看不起的样子,原来生活真的非常影响工作,整个人被巨大的负面情绪包围。</p><p>最难受的倒不是专业能力受到质疑,而是让对我有期望的人失望,这个让我更难受。人的精力有限,是个消耗品,如果在情绪中被消耗,那工作中就没有的消耗,就是没有油的车一样。</p><h2 id="山间"><a href="#山间" class="headerlink" title="山间"></a>山间</h2><p><code>2020</code>年,的另一个拐点,对生活有了另一种的思考,明确需要改变重心,考虑工作以外的事。在此之前的日子是除了工作很多事情与我无关。<br><code>2020</code>年,疫情让节凑换了一种调调,开始有时间考虑理想、生活、工作之间平衡。</p><p>做编程一直是我的理想,一直都是,甚至有时候会掐灭做其他工作的想法。这其实是一种逃避心态,坚定的信念是不惧挑战的。</p><p>为什么会去挑战自己的理想,才是重点。</p><p>不逃避,直面所有问题</p><p>是否忽视了对人的关心?<br>工作真是全部?<br>打工可以为荣?<br>工作的意义是人生价值,还是为老板奉献?<br>做喜欢的事是伟大还是自私?<br>时间有限,着眼当下,还是着眼不确定的未来?<br>那,是否该放弃理想,追求世俗意义的成功,还是理想的成功?</p><p>很多事不能追问,一追问就会发现以前觉得不错的是,很可能是过于主观。</p><p>而理想是是个自私的执念,</p><h2 id="捷径"><a href="#捷径" class="headerlink" title="捷径"></a>捷径</h2><p>这个理想其实相比较起来,其实并不怎么赚钱,当你有一条别人眼里的光明大道时,这个理想,显得没什么说服力。年纪小的时候有理由追求理想,但是,没有但是。</p><p>如果想让自己能够继续维持理想,那就需要有维持理想的资本。<br>然后开始各种偿试。</p><p>然后在不断的偿试中,自以为发现一条如同印钞机捷径,忽然感觉自己又行了,可以把控一切。再然后就翻车了。<br><code>2020</code>下半年接触币圈,以为看到维持理想的捷径,靠币圈赚到钱,可以边赚很多钱,可以边做自己想做的事,然后头脑发热两眼发光没日没夜的搞,真是没日没夜,觉都不睡。</p><p>事实证明这并不是一条捷径。<br>当一个人把时间花在自己事上,工作的时间事必须会被占用。我只想赚钱,又不想离开工作,于是就把自己慢慢边缘化。</p><p>我听过一句,只有自己才能把自己边缘化,我做到了,但是在这个阶段,我确并不在意。<br>我最应该感谢的是<code>lvs007</code>对我的包容,<code>lvs007</code>对我的期待很高。<br>我确因为自己做的事,没有精力照顾到工作上的事,忽略了很多工作上的事,有的时候刻意回避一些事,就怕别人知道我能干。<br><code>lvs007</code>的对由很高的期望变成失望。<br>这种让别人失望的感受,同时也让我很难受,我其实很怕让别人失望。<br>我说话从来避免出现找借口的字句和话语,很多私事又没法解释,只能自己叹气。</p><h2 id="山坡"><a href="#山坡" class="headerlink" title="山坡"></a>山坡</h2><p>这个时候的自己,就像在两条路的中间拔河,越努力越痛苦,无论哪一边用力,都会很痛苦。其实在把时间更多的占用工作时间时,就已经说明心态从理想和现实之间出现了拉扯,理想与现实难平衡。</p><p>理想是做自己一直想做的事,现实是必须认清现状,做可以让生活更好的事。<br>做开发是我的理想。赚更多的钱是现实。</p><p>理想和现实本来不冲突,在我刻意忽略现实问题,假装看不见的时候,都不是问题。但是经历事多了,成了一个大问题,已经到了不得不面对的时候。</p><p>当自己沉浸在自己世界里,不断的学习更新技术,不用去面对现实的时候,一切都是好的。投资自己,再通过技术获得更多的报酬。<br>但是直接这个问题,没有任何躲闪空间的时候,这个问题就打破了平衡。<br>一旦思想起来冲突,就像有两个小人天天在大脑里做辩论,都想说服对方:</p><ul><li>现实:明明可以赚到更多的钱,却耗在自己的理想上,真是很不负责</li><li>理想:这不是耗,是投资,理想也很重要,这是一直在追求的东西</li><li>现实:追求没错,然后呢,放弃更好的生活,只为你自己,那对其他人呢?</li><li>理想:你说没错,但是理想也可以让生活变的更好,虽然没有现实来的多</li><li>现实:那你做饭了吗,只要放弃理想,就可以赚钱到很多,满足所有人的期待,你在做无意义的坚持,你也明白这一点。</li><li>理想: ...</li><li>现实:...</li></ul><p>都明白更好的发展,才是最好的选择,光一句为了理想就可以放弃给身边的人未来的生活,就无法反驳。<br>然后,越努力越痛苦,陷处无限的自我内耗。<br>内耗最可怕的是磨灭状态,无论之前多好的状态,甚至换了一个人的性格和个性。</p><p>这两年发生的事情,只能对自己讲,没法对别人讲,甚至我自己对现在的自己都感觉很陌生。</p><p>忽然有一天想明白了一件事,<br>马化腾、雷军、谢吉·布林、拉里·佩奇、比尔·盖茨 也都是很牛X的程序员,不都不写代码了。<br>这么一想就不纠结了。<br>虽然我跟这些人比,啥也不是,但是本质是对职业生涯选择是一样的,那就是都在想办法搞更多钱。<br>这样一想就舒服多了。<br>如果想写代码,还跟以前一样,参与开源项目,一样可以过把瘾。还欠风轮一个天池比赛,也可以还了。<br>这个问题算是有解了。</p><h2 id="山脚"><a href="#山脚" class="headerlink" title="山脚"></a>山脚</h2><p>一个人需要走很多路,多个方向的路不应该是拔河,人生应该有很多偿试,不应该越走越窄,每一条路不过是前方的分叉路,最终都是朝着一个方向前进。多走几条路,才会体会到到达终点前,还有一不样的风景。</p><p>内耗了很久,还是妥协了。<br>理想和现实可以并行,只是存在的方式不同。</p><p>理想是一条路,现实也是一条路,把每一条走过的路,当成经验,认真对待每一次旅程,收获到经验后,走出一条更适合自己的路。带着每一段路的经验和收获继续一路向前。</p><p>停止逼迫自己,好好去做想做的事。</p><p>为了逼自己离开编程行业,故意让自己把事情搞砸,一旦有努力的心态,就会被负面的逻辑打压。<br>这种逼着自离开工作和想要努力工作的心态,反复的折磨自己,很痛苦。<br>本想着在币圈赚到钱的话,还可以一边写代码一边把生活安排好,结果自己成了韭菜。这个破功了。</p><p>在低谷想明白很多事,生活上的事,已经朝着好的方向前进。<br>工用上的事,尽量去做,然后做好才能说服自己没有遗憾。<br>这二者已经能做到平衡。</p><h2 id="原点"><a href="#原点" class="headerlink" title="原点"></a>原点</h2><p>坚定、明确和有序合理的安排才能消除内耗。<br>理想不需要放弃,在路上就一路前行。<br>现实需要直面,说再多不如大步迈向前方。</p><p>给自己设定一个时间,走完理想需要的路程。<br>走完了,也就去做该做的事。<br>有时候真希望自己是个自私的人,只想自己过的好就行了。<br>这把年纪了,想要自私也来不及了感觉。<br>人总是需要面对各种现实情况,做想做的事和该做什么事,有时候真的很难选。</p><p><code>2023</code>年开始给自己一个倒计时:<br>把暴脾气调整好,做一个谦和、平和的人,每一个人都值得尊重,不要再伤害到任何人。<br>解决掉所有事情,集中精力,认真工作。<br>明确生活和工作的边界,不再被某一方面事情主导,不内耗,好好去做每一件事,不要故意搞砸来逼自己,给自己的理想做一个美好的收尾,给所有人一个满意的答案。</p><p>找回之前的自己,恢复状态和境界。</p>]]></content>
<summary type="html">
<h2 id="起点"><a href="#起点" class="headerlink" title="起点"></a>起点</h2><p>说是总结,其实是吐槽。<br>写了这么些博客,很少说跟技术无关的博客。<br>2022已经完结,这一篇过去了,2023年是一个新的起点,一切
</summary>
<category term="随笔" scheme="https://liukai.net/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="随笔" scheme="https://liukai.net/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>rust-vim整合基于rust-analyzer</title>
<link href="https://liukai.net/posts/69325553.html"/>
<id>https://liukai.net/posts/69325553.html</id>
<published>2022-12-22T14:01:31.000Z</published>
<updated>2023-03-04T06:43:49.714Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在vim上配置并使用<code>rust</code>的vim开发环境,我个人比较习惯<code>coc.vim</code>这个平台的一系列插件,所以整个就接着在<code>coc.vim</code>上构建<code>rust-vim</code>,谁叫这东西确实牛逼。<br>依赖插件:</p><ul><li>coc.vim</li><li>coc-rls</li><li>coc-rust-analyzer</li></ul><p>rust官方有提供一个vim的插件,但是功能比较简单,本节要说插件,并不是官方提供的vim插件,而是比官方提供插件功能还要强一些。<br>而<code>coc-rust-analyzer</code>这个插件的是基于<code>rust-analyzer</code>这个插件,<code>coc.vim</code>将期进行<code>vim</code>化,记其可以工作在vim下,这个和<code>vim-go</code>插件的做法是一样的。</p><h2 id="安装-coc-rls"><a href="#安装-coc-rls" class="headerlink" title="安装 coc-rls"></a>安装 coc-rls</h2><p>需要提前安装好<a href="https://liukay.com/posts/db0a7b21.html">rustup</a>,这个工具其实在装<code>rust</code>的时候就已经安装好了。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 安装依赖组件</span></span><br><span class="line">rustup component add rls rust-analysis rust-src</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 安装 coc-rls</span></span><br><span class="line">:CocInstall coc-rls</span><br></pre></td></tr></table></figure><h2 id="安装coc-rust-analyzer"><a href="#安装coc-rust-analyzer" class="headerlink" title="安装coc-rust-analyzer"></a>安装coc-rust-analyzer</h2><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:CocInstall coc-rust-analyzer</span><br></pre></td></tr></table></figure><p><img src="/posts/69325553/%E5%AE%89%E8%A3%85coc-rust-analyzer.jpg" alt="安装coc-rust-analyzer"></p><p>初次打开,会有这样的提示,安装一下:</p><p><img src="/posts/69325553/%E5%88%9D%E6%AC%A1%E6%89%93%E5%BC%80.jpg" alt="初次打开"></p><h2 id="配置插件"><a href="#配置插件" class="headerlink" title="配置插件"></a>配置插件</h2><p>开启<code>coc-rust-analyzer</code>,在命令模式下输入:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:CocConfig</span><br></pre></td></tr></table></figure><p>这是个json格式,添加一行:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"rust-analyzer.enable"</span>: true</span><br></pre></td></tr></table></figure><p>看下代码提示,还有截图中的<code>i32</code>都是类似于<code>vscode</code>的类型提示功能。</p><p><img src="/posts/69325553/%E4%BB%A3%E7%A0%81%E6%8F%90%E7%A4%BA.jpg" alt="代码提示"></p><p>再看下函数跳转,直接跳转<code>println!</code>这个内置函数。<br>我之前配置的是<code>gd</code>,这里直接继续了配置,还是跟<code>coc</code>快捷有关。<br>后续专门说下coc相关的配置。</p><p><img src="/posts/69325553/%E8%B7%B3%E8%BD%AC%E5%87%BD%E6%95%B0.jpg" alt="跳转函数"></p><p>再按下<code>control+i</code>退回。</p><h2 id="运行-rust"><a href="#运行-rust" class="headerlink" title="运行 rust"></a>运行 rust</h2><p>装好了,代码提示也有了,怎么运行呢?<br>通过内置工具就可以运行<code>rust</code>,每安装一个插件,可运行的命令都在<code>CocCommand</code>中,输入查看一下:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:CocCommand</span><br></pre></td></tr></table></figure><p>在这个命令行下输入<code>rust</code>把所有的rust开头的命令过滤出来:</p><p><img src="/posts/69325553/CocCommand.jpg" alt="CocCommand"></p><p><img src="/posts/69325553/rust%E5%91%BD%E4%BB%A4.jpg" alt="rust命令"></p><p>运行一下</p><p><img src="/posts/69325553/%E8%BF%90%E8%A1%8C%E4%B8%80%E4%B8%8B.jpg" alt="运行一下"></p><p>结果:</p><p><img src="/posts/69325553/%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C.jpg" alt="运行结果"></p><h3 id="输入命令运行"><a href="#输入命令运行" class="headerlink" title="输入命令运行"></a>输入命令运行</h3><p>一般不会反复的输命令来执行,而是会通过快捷键不执行。</p><p><img src="/posts/69325553/%E7%9B%B4%E6%8E%A5%E8%BF%90%E8%A1%8C.jpg" alt="直接运行"></p><p>rust的内置命令很多,可以直接设置快捷键</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">nnoremap</span> <span class="symbol"><leader></span>rt :CocCommand rust-analyzer.run<span class="symbol"><CR></span></span><br></pre></td></tr></table></figure><p>通过<code>\rt</code>来运行。</p><h2 id="显示文档说明"><a href="#显示文档说明" class="headerlink" title="显示文档说明"></a>显示文档说明</h2><p>大写<code>K</code></p><p><img src="/posts/69325553/%E6%98%BE%E7%A4%BA%E6%96%87%E6%A1%A3%E8%AF%B4%E6%98%8E.jpg" alt="显示文档说明"></p><h2 id="完整配置如下"><a href="#完整配置如下" class="headerlink" title="完整配置如下"></a>完整配置如下</h2><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这个工具,如果是和我一样的<code>vim</code>患者可以捣鼓捣鼓,如果不是,建议还是直接IDEA的产品加个插件就可以开跑了。<br>rust我也是在学习的过程,语言虽然只是工具,但是在学习的过程中,也能学习到新的东西,拓宽一下边界,也能触类旁通。<br>下一步给<code>rust-vim</code>添加上debug功能。<br>已添加完成: <a href="https://liukai.net/posts/3e7235c0.html">rust-vim 整合基于vimspector的debug调试环境</a></p><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="https://github.com/neoclide/coc-rls">https://github.com/neoclide/coc-rls</a><br><a href="https://github.com/fannheyward/coc-rust-analyzer">https://github.com/fannheyward/coc-rust-analyzer</a></p>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在vim上配置并使用<code>rust</code>的vim开发环境,我个人比较习惯<code>coc.vim</code>这个平台的一系
</summary>
<category term="rust" scheme="https://liukai.net/categories/rust/"/>
<category term="vim" scheme="https://liukai.net/categories/vim/"/>
<category term="ide" scheme="https://liukai.net/categories/vim/ide/"/>
<category term="ide" scheme="https://liukai.net/categories/rust/ide/"/>
<category term="rust" scheme="https://liukai.net/categories/vim/rust/"/>
<category term="rust" scheme="https://liukai.net/tags/rust/"/>
<category term="ide" scheme="https://liukai.net/tags/ide/"/>
<category term="vim" scheme="https://liukai.net/tags/vim/"/>
<category term="rust-vim" scheme="https://liukai.net/tags/rust-vim/"/>
</entry>
<entry>
<title>Mac m2自动登陆跳板机脚本</title>
<link href="https://liukai.net/posts/95f16259.html"/>
<id>https://liukai.net/posts/95f16259.html</id>
<published>2022-12-15T12:27:13.000Z</published>
<updated>2023-08-29T09:25:37.069Z</updated>
<content type="html"><![CDATA[<h2 id="需求"><a href="#需求" class="headerlink" title="需求"></a>需求</h2><p>需求很简单,通过脚本自动登陆跳板机。<br>因为最近换的是mac M2,然后碰到了一堆问题。</p><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>从<strong>intel</strong>芯片换到<strong>m2</strong>出现很多问题。<br>首先mac m2 没有python2,默认是python3,所以脚本的命令要调整成python3相关的。<br>然后是 ssh 登陆,原来正常可以登陆方式也有问题,默认的ssh密钥失效,需要替换成新的密钥。<br>就导致原来的免密登陆也失效了,添加了公钥,依然需要输密码,下面的脚本,有一段是补偿输入密码的操作,<br>如果不需要,可以删了输密码的部份。</p><h2 id="自动登陆脚本"><a href="#自动登陆脚本" class="headerlink" title="自动登陆脚本"></a>自动登陆脚本</h2><p>需要准备两个脚本:</p><ol><li>login.sh, shell 脚本</li><li>jump.python, python3脚本</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">!/bin/sh</span></span><br><span class="line">expect -c "</span><br><span class="line">set pwd you_pass_word</span><br><span class="line">spawn ssh -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa [email protected]</span><br><span class="line">set timeout 2</span><br><span class="line">expect "*assword:*"</span><br><span class="line">send \"\$pwd\r\"</span><br><span class="line"></span><br><span class="line">set timeout 2</span><br><span class="line">expect \"\[MFA auth\]:\"</span><br><span class="line">set password \"`python3 ~/.ssh/jump.python`\"</span><br><span class="line">send \"\$password\r\"</span><br><span class="line">interact</span><br><span class="line">"</span><br></pre></td></tr></table></figure><h3 id="解释上面的脚本"><a href="#解释上面的脚本" class="headerlink" title="解释上面的脚本"></a>解释上面的脚本</h3><p>说明一下,新的 ssh 需要输入:</p><blockquote><p>ssh -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa</p></blockquote><p>原来 ssh 只需要:</p><blockquote><p>ssh <a href="mailto:username@10.10.10.10">username@10.10.10.10</a> 就可以登陆了</p></blockquote><h2 id="python3-部分"><a href="#python3-部分" class="headerlink" title="python3 部分"></a>python3 部分</h2><p>python3 脚本提取google验证码。</p><p><code>my_secret</code> 是谷歌的密钥。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python3</span></span><br><span class="line"><span class="keyword">import</span> onetimepass <span class="keyword">as</span> otp</span><br><span class="line"></span><br><span class="line">my_secret = <span class="string">'XXXXXXXXXXXXX'</span></span><br><span class="line">my_token = otp.get_totp(my_secret)</span><br><span class="line"><span class="keyword">print</span> (<span class="string">"%06d"</span> % my_token)</span><br></pre></td></tr></table></figure><h2 id="iterm2-配置"><a href="#iterm2-配置" class="headerlink" title="iterm2 配置"></a>iterm2 配置</h2><p>在 Open Profiles 中添加一下自动登陆脚本:</p><p><img src="/posts/95f16259/iterm2%E8%87%AA%E5%8A%A8%E7%99%BB%E9%99%86%E9%85%8D%E7%BD%AE.jpg" alt="iterm2自动登陆配置.jpg"></p><p>login shell 或 Command 都可以,用<code>sh</code>:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sh ~/.ssh/jump.sh</span><br></pre></td></tr></table></figure><p>不要使用 <code>expect</code> 开头:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">expect ~/.ssh/jump.sh</span><br></pre></td></tr></table></figure><p>这样就可以登陆成功了,即不需要输密码,也不需要验证码。<br>需要注意的是,如果需要使用<code>lrzsz</code> 这样的功能的话,不可以使用<code>expect</code>执行脚本,会失败,只能使用<code>sh</code>进行登陆。</p>]]></content>
<summary type="html">
<h2 id="需求"><a href="#需求" class="headerlink" title="需求"></a>需求</h2><p>需求很简单,通过脚本自动登陆跳板机。<br>因为最近换的是mac M2,然后碰到了一堆问题。</p>
<h2 id="问题"><a href
</summary>
<category term="linux" scheme="https://liukai.net/categories/linux/"/>
<category term="mac" scheme="https://liukai.net/categories/mac/"/>
<category term="shell" scheme="https://liukai.net/categories/linux/shell/"/>
<category term="iterm2" scheme="https://liukai.net/categories/mac/iterm2/"/>
<category term="linux" scheme="https://liukai.net/tags/linux/"/>
<category term="shell" scheme="https://liukai.net/tags/shell/"/>
<category term="mac" scheme="https://liukai.net/tags/mac/"/>
<category term="iterm2" scheme="https://liukai.net/tags/iterm2/"/>
<category term="m2" scheme="https://liukai.net/tags/m2/"/>
<category term="python3" scheme="https://liukai.net/tags/python3/"/>
<category term="跳板机" scheme="https://liukai.net/tags/%E8%B7%B3%E6%9D%BF%E6%9C%BA/"/>
</entry>
<entry>
<title>Merkle Tree、Merkle Patricia Tree</title>
<link href="https://liukai.net/posts/504d00cf.html"/>
<id>https://liukai.net/posts/504d00cf.html</id>
<published>2022-12-15T09:23:08.000Z</published>
<updated>2023-06-19T15:05:38.175Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>如果是接触区块链开发相关的话题,Merkle Tree 是一个必需要了解的话题。<br>BTC和ETH都使用这项技术,但是数据结构不同。<br>应用侧重点也不同。</p><h2 id="用意"><a href="#用意" class="headerlink" title="用意"></a>用意</h2><h2 id="Merkle-tree"><a href="#Merkle-tree" class="headerlink" title="Merkle tree"></a>Merkle tree</h2><p><img src="/posts/504d00cf/Hash_Tree.svg" alt="Hash_Tree.svg"></p><p>注意这里的虚线,最后的叶子节点是真正挂数据的节点。</p><h2 id="Merkle-Patricia-Tree"><a href="#Merkle-Patricia-Tree" class="headerlink" title="Merkle Patricia Tree"></a>Merkle Patricia Tree</h2><p>TODO</p><h2 id="以太坊-Merkle-Patricia-Tree-应用"><a href="#以太坊-Merkle-Patricia-Tree-应用" class="headerlink" title="以太坊 Merkle Patricia Tree 应用"></a>以太坊 Merkle Patricia Tree 应用</h2><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="https://en.wikipedia.org/wiki/Merkle_tree">https://en.wikipedia.org/wiki/Merkle_tree</a></p>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>如果是接触区块链开发相关的话题,Merkle Tree 是一个必需要了解的话题。<br>BTC和ETH都使用这项技术,但是数据结构不同。<b
</summary>
<category term="blockchain" scheme="https://liukai.net/categories/blockchain/"/>
<category term="ethereum" scheme="https://liukai.net/categories/ethereum/"/>
<category term="merkle" scheme="https://liukai.net/categories/ethereum/merkle/"/>
<category term="ethereum" scheme="https://liukai.net/categories/blockchain/ethereum/"/>
<category term="blockchain" scheme="https://liukai.net/tags/blockchain/"/>
<category term="merkle" scheme="https://liukai.net/tags/merkle/"/>
<category term="树" scheme="https://liukai.net/tags/%E6%A0%91/"/>
<category term="原理" scheme="https://liukai.net/tags/%E5%8E%9F%E7%90%86/"/>
<category term="trie" scheme="https://liukai.net/tags/trie/"/>
<category term="区块链" scheme="https://liukai.net/tags/%E5%8C%BA%E5%9D%97%E9%93%BE/"/>
<category term="算法" scheme="https://liukai.net/tags/%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>ethereum-geth常用操作</title>
<link href="https://liukai.net/posts/687e1894.html"/>
<id>https://liukai.net/posts/687e1894.html</id>
<published>2022-12-08T10:54:03.000Z</published>
<updated>2023-03-04T06:43:49.562Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>eth已经2.0了,但是1.0除了挖矿之外大部分功能都还是一样的。</p><h2 id="geth-能做什么"><a href="#geth-能做什么" class="headerlink" title="geth 能做什么"></a>geth 能做什么</h2><ul><li>与eth链交互:console</li><li>查看区块链状态</li><li>管理账号: personal</li><li>发送交易: </li><li>挖矿 miner</li></ul><h2 id="交互操作-console"><a href="#交互操作-console" class="headerlink" title="交互操作: console"></a>交互操作: console</h2><p>通过console启动,可以进行一系统的操作。</p><h3 id="1-连接eth主网"><a href="#1-连接eth主网" class="headerlink" title="1.连接eth主网"></a>1.连接eth主网</h3><p>默认连接最新的主网。</p><p><code>--datadir</code>: 数据存放目录,不指定默认:<code>/home/$user/.ethereum</code></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">geth --datadir /data/geth --goerli console</span><br></pre></td></tr></table></figure><h3 id="2-连接eth测试网"><a href="#2-连接eth测试网" class="headerlink" title="2.连接eth测试网"></a>2.连接eth测试网</h3><p><code>--goerli</code>: 加入 goerli测试网<br><code>--rpcapi</code>: 开启rpc服务,开启后才可以进行操作</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">geth --datadir "/data/geth" --rpc --rpcport 8545 --rpcapi "personal,eth,net,web3,admin" --rpccorsdomain "*" --goerli console </span><br></pre></td></tr></table></figure><hr><h2 id="节点管理-admin"><a href="#节点管理-admin" class="headerlink" title="节点管理: admin"></a>节点管理: admin</h2><p>自己搭建节点,第一步是要能使用,如果不是私链,那就需要连接上以太坊的主网或者测试网进行操作。</p><h3 id="1-添加节点-admin-addPeer"><a href="#1-添加节点-admin-addPeer" class="headerlink" title="1.添加节点 admin.addPeer"></a>1.添加节点 admin.addPeer</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">admin.addPeer("enode://19d3655aba7ef72065412365d95a66a10fcf0518f21594d0746b0177467c4d650b726a3e9612792e6dcb9716814498dc6826e3b47ab6e6270d85113d4bc7d6a1@135.181.82.60:30303")</span><br></pre></td></tr></table></figure><h3 id="2-查看当前连接节点-admin-peers"><a href="#2-查看当前连接节点-admin-peers" class="headerlink" title="2.查看当前连接节点 admin.peers"></a>2.查看当前连接节点 admin.peers</h3><p>下面这个是我连接的节点,是芬兰的一个节点。</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">[{</span><br><span class="line"> caps: ["eth/63", "eth/64", "eth/65"],</span><br><span class="line"> enode: "enode://19d3655aba7ef72065412365d95a66a10fcf0518f21594d0746b0177467c4d650b726a3e9612792e6dcb9716814498dc6826e3b47ab6e6270d85113d4bc7d6a1@135.181.82.60:30303",</span><br><span class="line"> enr: "enr:-Je4QAqQY0hSvgTJLu-FBPW6rnpHa-pm1dge3G3qV4ChlKlMJsZA8togglNFljRAFWhOU6bv7-UHAQxp-siymzU2a24Jg2V0aMfGhMJe-lyAgmlkgnY0gmlwhIe1UjyJc2VjcDI1NmsxoQMZ02Vaun73IGVBI2XZWmahD88FGPIVlNB0awF3RnxNZYN0Y3CCdl-DdWRwgnZf",</span><br><span class="line"> id: "2f927cec8a9408be8acfbf9ecc7b72a905d112c8842b9a1539a7cd40934b7357",</span><br><span class="line"> name: "Geth/v1.9.24-stable-cc05b050/linux-amd64/go1.15.5",</span><br><span class="line"> network: {</span><br><span class="line"> inbound: false,</span><br><span class="line"> localAddress: "192.168.31.128:53372",</span><br><span class="line"> remoteAddress: "135.181.82.60:30303",</span><br><span class="line"> static: false,</span><br><span class="line"> trusted: false</span><br><span class="line"> },</span><br><span class="line"> protocols: {</span><br><span class="line"> eth: {</span><br><span class="line"> difficulty: 6585792,</span><br><span class="line"> head: "0x8705d7d7a4aa189704385c325ff24ebc82496c87fff884e942bf4aba78467f0f",</span><br><span class="line"> version: 65</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}]</span><br></pre></td></tr></table></figure><h3 id="查看节点信息-admin-nodeInfo"><a href="#查看节点信息-admin-nodeInfo" class="headerlink" title="查看节点信息 admin.nodeInfo"></a>查看节点信息 admin.nodeInfo</h3><p>查询节点自身信息。</p><p><code>enode</code>: 自身的节点地址<br><code>enr</code>:<br><code>discovery</code>: 节点发现服务端口<br><code>listener</code>: 连接监听端口<br><code>protocols</code>: 协议信息</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> enode: "enode://514cf44d46abc26df3fbb084acef308483a6b1bc0712f9aead5fbbca0f1e5671f86467a2f0ec10628b48b771cde8501294715aa5d4c4b520b1a457daae9a0b3e@111.201.21.10:30303?discport=26172",</span><br><span class="line"> enr: "enr:-KK4QAzy9muCCHDtd8kwjgLS9MrRKa8YKutziw51hBXyjTrJEegdA2eFsh6BR-6BcAHFF9SEu3HPUGu0-yMYTo2xcKQHg2V0aMrJhKP1qwiDF9QzgmlkgnY0gmlwhG_JFcmJc2VjcDI1NmsxoQJRTPRNRqvCbfP7sISs7zCEg6axvAcS-a6tX7vKDx5WcYN0Y3CCdl-DdWRwgmY8hHVkcDaCdl8",</span><br><span class="line"> id: "45fe4324552ac00907ffea5bfbd48f678f3dad5adafe2041b585270a09034410",</span><br><span class="line"> ip: "111.201.21.10",</span><br><span class="line"> listenAddr: "[::]:30303",</span><br><span class="line"> name: "Geth/v1.9.25-stable-e7872729/linux-amd64/go1.16.15",</span><br><span class="line"> ports: {</span><br><span class="line"> discovery: 26172,</span><br><span class="line"> listener: 30303</span><br><span class="line"> },</span><br><span class="line"> protocols: {</span><br><span class="line"> eth: {</span><br><span class="line"> config: {</span><br><span class="line"> byzantiumBlock: 0,</span><br><span class="line"> chainId: 5,</span><br><span class="line"> clique: {...},</span><br><span class="line"> constantinopleBlock: 0,</span><br><span class="line"> daoForkSupport: true,</span><br><span class="line"> eip150Block: 0,</span><br><span class="line"> eip150Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br><span class="line"> eip155Block: 0,</span><br><span class="line"> eip158Block: 0,</span><br><span class="line"> homesteadBlock: 0,</span><br><span class="line"> istanbulBlock: 1561651,</span><br><span class="line"> petersburgBlock: 0</span><br><span class="line"> },</span><br><span class="line"> difficulty: 1,</span><br><span class="line"> genesis: "0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a",</span><br><span class="line"> head: "0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a",</span><br><span class="line"> network: 5</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><hr><h2 id="账号管理-personal"><a href="#账号管理-personal" class="headerlink" title="账号管理 personal"></a>账号管理 personal</h2><h3 id="1-创建账号-personal-newAccount"><a href="#1-创建账号-personal-newAccount" class="headerlink" title="1.创建账号 personal.newAccount()"></a>1.创建账号 personal.newAccount()</h3><p>创建账号可以创建多个账号。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">personal.newAccount("password")</span><br></pre></td></tr></table></figure><p>结果:</p><blockquote><p>INFO [12-09|23:28:39.162] Your new key was generated address=0x6C5d3DafE18B5108a0C02B5663f6963EBf9f4CfA<br>WARN [12-09|23:28:39.191] Please backup your key file! path=/data/geth/keystore/UTC--2022-12-09T15-28-34.293134840Z--6c5d3dafe18b5108a0c02b5663f6963ebf9f4cfa<br>WARN [12-09|23:28:39.191] Please remember your password!<br>"0x6c5d3dafe18b5108a0c02b5663f6963ebf9f4cfa"</p></blockquote><p>生成一个<code>keystore</code>文件,路径是启动时候我设定的路径: <code>/data/geth/keystore</code>。<br><code>keystore</code>文件是相关于密钥,签署交易的以太坊私钥的加密文件。如果你丢失了这个文件,你就丢失了私钥。<br>简单的说<code>keystore</code>就是你<strong>加密过后</strong>的私钥,要有私钥和你的密码,才能使用你的账号,这样就是双重保险。<br>几乎每条链都有<code>keystore</code>文件这种形式。</p><p>查看一下<code>keystore</code>文件内容:</p><p><strong>cipher</strong>: 对称加密,用对称加密是因为使用到密码,需要解密。<br><strong>cipherparams</strong>: 是 cipher 算法需要的参数。<br><strong>iv</strong>: 是加密算法需要的初始化向量。<br><strong>kdf</strong>: <code>scrypt</code> 密钥生成函数,用于让你用密码加密 keystore 文件。<br><strong>kdfparams</strong>: <code>kdf</code> 算法需要的参数(scrypt函数需要的参数)。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"address"</span>: <span class="string">"6c5d3dafe18b5108a0c02b5663f6963ebf9f4cfa"</span>, </span><br><span class="line"> <span class="attr">"crypto"</span>: {</span><br><span class="line"> <span class="attr">"cipher"</span>: <span class="string">"aes-128-ctr"</span>, </span><br><span class="line"> <span class="attr">"ciphertext"</span>: <span class="string">"a2816bbca5bf7805e75d4961375579eeb80ede2cb9364f9a8dd8be0be4694a7d"</span>, </span><br><span class="line"> <span class="attr">"cipherparams"</span>: {}, </span><br><span class="line"> <span class="attr">"kdf"</span>: <span class="string">"scrypt"</span>, </span><br><span class="line"> <span class="attr">"kdfparams"</span>: {</span><br><span class="line"> <span class="attr">"dklen"</span>: <span class="number">32</span>, </span><br><span class="line"> <span class="attr">"n"</span>: <span class="number">262144</span>, </span><br><span class="line"> <span class="attr">"p"</span>: <span class="number">1</span>, </span><br><span class="line"> <span class="attr">"r"</span>: <span class="number">8</span>, </span><br><span class="line"> <span class="attr">"salt"</span>: <span class="string">"6e7f880f2e53e744c2acb422b01ddad319fbd4ee6dfe38da3e921efbdb4604ff"</span></span><br><span class="line"> }, </span><br><span class="line"> <span class="attr">"mac"</span>: <span class="string">"24c823caf933a0563b1da19982b8259fcaafb423a69cb6fb85108303cd2ebd4e"</span></span><br><span class="line"> }, </span><br><span class="line"> <span class="attr">"id"</span>: <span class="string">"ef6cdbe1-dbe3-43b8-bcea-e7b3e0e121f7"</span>, </span><br><span class="line"> <span class="attr">"version"</span>: <span class="number">3</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-交互模式-personal-newAccount"><a href="#2-交互模式-personal-newAccount" class="headerlink" title="2.交互模式 personal.newAccount"></a>2.交互模式 personal.newAccount</h3><p>执行命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">personal.newAccount()</span><br></pre></td></tr></table></figure><p>结果:</p><blockquote><p>Passphrase: #输入密码<br>Repeat passphrase: #确认密码<br>INFO [12-09|23:41:31.682] Your new key was generated address=0x1d774CdA456C0f7cC84484b0316A4E959c206E14<br>WARN [12-09|23:41:31.682] Please backup your key file! path=/data/geth/keystore/UTC--2022-12-09T15-41-30.670272653Z--1d774cda456c0f7cc84484b0316a4e959c206e14<br>WARN [12-09|23:41:31.682] Please remember your password!<br>"0x1d774cda456c0f7cc84484b0316a4e959c206e14"</p></blockquote><hr><h2 id="链治理:eth"><a href="#链治理:eth" class="headerlink" title="链治理:eth"></a>链治理:eth</h2><h3 id="1-查询所有账号-eth-accounts"><a href="#1-查询所有账号-eth-accounts" class="headerlink" title="1.查询所有账号 eth.accounts"></a>1.查询所有账号 eth.accounts</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eth.accounts</span><br></pre></td></tr></table></figure><blockquote><p>["0x6c5d3dafe18b5108a0c02b5663f6963ebf9f4cfa", "0x1d774cda456c0f7cc84484b0316a4e959c206e14"]</p></blockquote><p>这是我刚生成的两个账号</p><p>选择其中一个:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">eth.accounts[0]</span><br></pre></td></tr></table></figure><blockquote><p>"0x6c5d3dafe18b5108a0c02b5663f6963ebf9f4cfa"</p></blockquote><h3 id="2-查看余额-eth-getBalance"><a href="#2-查看余额-eth-getBalance" class="headerlink" title="2.查看余额 eth.getBalance"></a>2.查看余额 eth.getBalance</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">eth.getBalance(eth.accounts[1])</span><br><span class="line"></span><br><span class="line">eth.getBalance("0x6c5d3dafe18b5108a0c02b5663f6963ebf9f4cfa")</span><br></pre></td></tr></table></figure><h2 id="挖矿-miner"><a href="#挖矿-miner" class="headerlink" title="挖矿 miner"></a>挖矿 miner</h2><h3 id="1-开启挖矿"><a href="#1-开启挖矿" class="headerlink" title="1.开启挖矿"></a>1.开启挖矿</h3><p>需要区块同步完成,否则无法挖矿</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">miner.start(10)</span><br></pre></td></tr></table></figure><p>10表示挖矿线程数。</p><p>如果没有同步完成就开启挖矿会报错:</p><blockquote><p>Block sealing failed err="unauthorized signer"<br>Block synchronisation started<br>Mining aborted due to sync</p></blockquote><h3 id="2-停止挖矿-miner-stop"><a href="#2-停止挖矿-miner-stop" class="headerlink" title="2.停止挖矿 miner.stop"></a>2.停止挖矿 miner.stop</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">miner.stop()</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>eth已经2.0了,但是1.0除了挖矿之外大部分功能都还是一样的。</p>
<h2 id="geth-能做什么"><a href="#get
</summary>
<category term="blockchain" scheme="https://liukai.net/categories/blockchain/"/>
<category term="ethereum" scheme="https://liukai.net/categories/ethereum/"/>
<category term="ethereum" scheme="https://liukai.net/categories/blockchain/ethereum/"/>
<category term="geth" scheme="https://liukai.net/categories/ethereum/geth/"/>
<category term="blockchain" scheme="https://liukai.net/tags/blockchain/"/>
<category term="ethereum" scheme="https://liukai.net/tags/ethereum/"/>
<category term="eth" scheme="https://liukai.net/tags/eth/"/>
<category term="ethereum原理" scheme="https://liukai.net/tags/ethereum%E5%8E%9F%E7%90%86/"/>
<category term="节点" scheme="https://liukai.net/tags/%E8%8A%82%E7%82%B9/"/>
<category term="geth" scheme="https://liukai.net/tags/geth/"/>
</entry>
</feed>