-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
2182 lines (770 loc) · 81.6 KB
/
index.html
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
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html class="theme-next pisces use-motion" lang="">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2"/>
<meta name="theme-color" content="#222">
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=6.4.1" rel="stylesheet" type="text/css" />
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=6.4.1">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=6.4.1">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=6.4.1">
<link rel="mask-icon" href="/images/logo.svg?v=6.4.1" color="#222">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Pisces',
version: '6.4.1',
sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
fancybox: false,
fastclick: false,
lazyload: false,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:locale" content="default">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Hexo">
<link rel="canonical" href="http://yoursite.com/"/>
<script type="text/javascript" id="page.configurations">
CONFIG.page = {
sidebar: "",
};
</script>
<title>Hexo</title>
<noscript>
<style type="text/css">
.use-motion .motion-element,
.use-motion .brand,
.use-motion .menu-item,
.sidebar-inner,
.use-motion .post-block,
.use-motion .pagination,
.use-motion .comments,
.use-motion .post-header,
.use-motion .post-body,
.use-motion .collection-title { opacity: initial; }
.use-motion .logo,
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion {
.logo-line-before i { left: initial; }
.logo-line-after i { right: initial; }
}
</style>
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="default">
<div class="container sidebar-position-left
page-home">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-wrapper">
<div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">Hexo</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
</div>
<div class="site-nav-toggle">
<button aria-label="Toggle navigation bar">
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home menu-item-active">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />Home</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />Archives</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/11/08/常用git命令/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="John Doe">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2019/11/08/常用git命令/" itemprop="url">
常用git命令
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2019-11-08 16:10:40 / Modified: 16:34:31" itemprop="dateCreated datePublished" datetime="2019-11-08T16:10:40+08:00">2019-11-08</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="常用"><a href="#常用" class="headerlink" title="常用"></a>常用</h1><p>克隆远程项目到本地 默认在当前test目录<br><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">git clone xxx.com/test.git</span><br></pre></td></tr></table></figure></p>
<p>列出本地分支<br><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">git branch</span><br><span class="line">``` </span><br><span class="line"></span><br><span class="line">列出远程分枝</span><br></pre></td></tr></table></figure></p>
<p>git branch -r //列出远程和本地分枝<br><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">列出本地和远程分支</span><br></pre></td></tr></table></figure></p>
<p>git branche -a<br><figure class="highlight plain"><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"></span><br><span class="line">拉取远程develop分支到本地</span><br></pre></td></tr></table></figure></p>
<p>git fetch origin develop<br><figure class="highlight plain"><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"></span><br><span class="line">从当前分支创建feature分支并切换到feature</span><br></pre></td></tr></table></figure></p>
<p>git checkout -b feature<br><figure class="highlight plain"><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"></span><br><span class="line">查看变动的文件</span><br></pre></td></tr></table></figure></p>
<p>git status<br><figure class="highlight plain"><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"></span><br><span class="line">查看改动的内容</span><br></pre></td></tr></table></figure></p>
<p>git diff<br><figure class="highlight plain"><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"></span><br><span class="line">提交修改</span><br></pre></td></tr></table></figure></p>
<p>git add filename 提交某个文件<br>git add . 提交全部修改<br><figure class="highlight plain"><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"></span><br><span class="line">撤销修改</span><br></pre></td></tr></table></figure></p>
<p>git checkout filename 丢弃某个文件的改动<br>git checkout . //丢弃全部修改<br><figure class="highlight plain"><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"></span><br><span class="line">本地提交</span><br></pre></td></tr></table></figure></p>
<p>git commit -m “comment info”<br><figure class="highlight plain"><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"></span><br><span class="line">提交到远程</span><br></pre></td></tr></table></figure></p>
<p>git push<br><figure class="highlight plain"><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"></span><br><span class="line">拉取更新</span><br></pre></td></tr></table></figure></p>
<p>git pull<br><figure class="highlight plain"><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"></span><br><span class="line">合并别的分支到当前分支(可能有冲突)</span><br></pre></td></tr></table></figure></p>
<p>git merge branchname<br><code>`</code></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/08/07/以太坊truffle开发实战/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="John Doe">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2019/08/07/以太坊truffle开发实战/" itemprop="url">
以太坊truffle开发实战
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2019-08-07 12:11:49 / Modified: 15:36:19" itemprop="dateCreated datePublished" datetime="2019-08-07T12:11:49+08:00">2019-08-07</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="以太坊dapp开发入门指引"><a href="#以太坊dapp开发入门指引" class="headerlink" title="以太坊dapp开发入门指引"></a>以太坊dapp开发入门指引</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>适合想了解以太坊dapp开发,了解要做哪些事情,这篇教程以一个简单的部署在区块链上的投票合约为例详细讲述以太坊开发全流程体验。有过程序开基础的人可直接入手,代码很简单预计花费1小时。包含的技术点:</p>
<ul>
<li>使用以太坊开发的truffle框架</li>
<li>使用ganache图形界面版做测试环境</li>
<li>使用solidity 编写投票合约</li>
<li>将合约部署到ganache</li>
<li>使用web3.js调用合约里的方法进行投票和获取票数</li>
</ul>
<h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><p>安装node,npm, truffle, ganache(界面版),web3,lite-server</p>
<h2 id="流程"><a href="#流程" class="headerlink" title="流程"></a>流程</h2><h3 id="1-创建项目目录"><a href="#1-创建项目目录" class="headerlink" title="1,创建项目目录"></a>1,创建项目目录</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir Voting && <span class="built_in">cd</span> Voting</span><br></pre></td></tr></table></figure>
<h3 id="2,初始化truffle项目"><a href="#2,初始化truffle项目" class="headerlink" title="2,初始化truffle项目"></a>2,初始化truffle项目</h3><figure class="highlight sh"><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"><span class="comment"># 用truffle 初始化项目,会生成一些目录和文件</span></span><br><span class="line">truffle init</span><br></pre></td></tr></table></figure>
<h3 id="3-创建合约"><a href="#3-创建合约" class="headerlink" title="3,创建合约"></a>3,创建合约</h3><figure class="highlight sh"><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"><span class="comment"># 创建一个合约,文件生成在contracts/Voting.sol</span></span><br><span class="line">truffle create contract Voting</span><br></pre></td></tr></table></figure>
<h3 id="4-用solidity编写合约代码"><a href="#4-用solidity编写合约代码" class="headerlink" title="4,用solidity编写合约代码"></a>4,用solidity编写合约代码</h3><figure class="highlight sh"><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"><span class="comment"># 编写合约代码</span></span><br><span class="line">见contracts/Voting.sol</span><br></pre></td></tr></table></figure>
<h3 id="5-编译合约"><a href="#5-编译合约" class="headerlink" title="5,编译合约"></a>5,编译合约</h3><figure class="highlight sh"><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"><span class="comment"># 编译合约,检查是否报错</span></span><br><span class="line"><span class="built_in">cd</span> Voting && truffle compile</span><br></pre></td></tr></table></figure>
<h3 id="6-部署前的配置"><a href="#6-部署前的配置" class="headerlink" title="6,部署前的配置"></a>6,部署前的配置</h3><ul>
<li>打开ganache软件界面版<br>如图:软件自动生成了10个账户和对应的rpc地址和端口</li>
</ul>
<p><img src="/images/pasted-50.png" alt="upload successful"></p>
<ul>
<li>在Voting/truffle.config.js(truffle自动生成的)里面修改监听的url和端口,这个是ganache中给的</li>
</ul>
<p><img src="/images/pasted-52.png" alt="upload successful"></p>
<ul>
<li>在Voting/migrations/里复制一个migration.js 少动修改作为部署配置<br>如Voting/migrations/2_migtation_vote.js</li>
</ul>
<p><img src="/images/pasted-54.png" alt="upload successful"><br><figure class="highlight sh"><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="comment"># 部署合约</span></span><br><span class="line">$ <span class="built_in">cd</span> Voting </span><br><span class="line">$ truffle migrate --reset</span><br></pre></td></tr></table></figure></p>
<p>部署成功后合约就永久在区块链上了</p>
<h3 id="7,调用合约方法"><a href="#7,调用合约方法" class="headerlink" title="7,调用合约方法"></a>7,调用合约方法</h3><p>调用合约使用web3.js, 本案例直接用html引入js展示调用<br>具体看 Voting/src下的html,js 代码很简单,里面注释充分,不多讲。</p>
<h3 id="8,预览"><a href="#8,预览" class="headerlink" title="8,预览"></a>8,预览</h3><p><img src="/images/pasted-56.png" alt="upload successful"><br>package.json中红框内写lite-server,如果没有安装就<br><figure class="highlight plain"><figcaption><span>install lite-server``` 安装。</span></figcaption><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">创建Voting/bs-config.js 这个是用作node.js 服务器用的:</span><br><span class="line"></span><br><span class="line">![upload successful](/images/pasted-58.png)</span><br><span class="line">然后浏览器访问:</span><br><span class="line">```sh</span><br><span class="line">$ cd Voting</span><br><span class="line">$ npm run dev</span><br></pre></td></tr></table></figure></p>
<p><img src="/images/pasted-60.png" alt="upload successful"><br>此时浏览器会自动打开<a href="http://localhost:3000/" target="_blank" rel="noopener">http://localhost:3000/</a></p>
<p><img src="/images/pasted-62.png" alt="upload successful"><br>打开浏览器开发者模式的console,观察web3.js调用结果。</p>
<p>如有疑问多看代码,代码很少,注释很多,本篇只梳理开发流程。<br>至此一个简单的以太坊dapp在测试环境开发完成。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/07/09/比特币中的交易详解/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="John Doe">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2019/07/09/比特币中的交易详解/" itemprop="url">
比特币中的交易详解
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2019-07-09 22:30:29 / Modified: 22:33:27" itemprop="dateCreated datePublished" datetime="2019-07-09T22:30:29+08:00">2019-07-09</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="比特币中的交易详解"><a href="#比特币中的交易详解" class="headerlink" title="比特币中的交易详解"></a>比特币中的交易详解</h1><p>UTXO 是 Unspent Transaction Output 的缩写,意指“为花费的交易输出”,是中本聪最早在比特币中采用的一种技术方案。因为比特币中没有账户的概念,也就没有保存用户余额数值的机制。因为区块链中的历史交易都是被保存且不可修改的,而每一个交易(如前所述的Transaction)中又保存了“谁转移了多少给谁”的信息,所以要计算用户账户余额,只需要遍历所有交易进行累计即可。</p>
<p>账户的余额其实是之前其他人转给该账户的钱处于锁定状态,要使用这笔钱就要解锁并且把发送人改为别人即可。 一笔交易是一系列的输入输出的集合,输入是寻找用户可花费的输出(utxo), 输出是用户这笔交易要把金额给谁,包含输出给别人(转账), 输出给自己(找零),直接要代码定义的结构更直观。</p>
<h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><h3 id="1,-输入"><a href="#1,-输入" class="headerlink" title="1, 输入"></a>1, 输入</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> TXInput <span class="keyword">struct</span> {</span><br><span class="line"> Txid []<span class="keyword">byte</span> </span><br><span class="line"> Vout <span class="keyword">int</span> <span class="comment">// 是utxo 的某个下标 </span></span><br><span class="line"> Signature []<span class="keyword">byte</span></span><br><span class="line"> PubKey []<span class="keyword">byte</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<blockquote>
<blockquote>
</blockquote>
<p>输入TXInput:</p>
<ul>
<li>Txid : 交易ID(这个输入使用的是哪个交易的输出)</li>
<li>Vout : 该输入单元指向本次交易输出数组的下标,通俗讲就是,这个输入使用的是Txid中的第几个输出。</li>
<li>Signature : 输入发起方(转账出去方)的私钥签名本Transaction,表示自己认证了这个输入TXInput。</li>
<li>PubKey : 输入发起方的公钥</li>
</ul>
</blockquote>
<h3 id="2,-输出"><a href="#2,-输出" class="headerlink" title="2, 输出"></a>2, 输出</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> TXOutput <span class="keyword">struct</span> {</span><br><span class="line"> Value <span class="keyword">int</span> <span class="comment">//金额</span></span><br><span class="line"> PubKeyHash []<span class="keyword">byte</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<blockquote>
<blockquote>
</blockquote>
<p>输出TXOutput:</p>
<ul>
<li>Value : 表示这个输出中的代币数量</li>
<li>PubKeyHash : 存放了一个用户的公钥的hash值,表示这个输出里面的Value是属于哪个用户的</li>
</ul>
</blockquote>
<h3 id="3,-一个交易(多个输入输出的集合)"><a href="#3,-一个交易(多个输入输出的集合)" class="headerlink" title="3, 一个交易(多个输入输出的集合)"></a>3, 一个交易(多个输入输出的集合)</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Transaction <span class="keyword">struct</span> {</span><br><span class="line"> ID []<span class="keyword">byte</span> <span class="comment">//交易唯一ID</span></span><br><span class="line"> Vin []TXInput <span class="comment">//交易输入序列</span></span><br><span class="line"> Vout []TXOutput <span class="comment">//交易输出序列</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="交易范例"><a href="#交易范例" class="headerlink" title="交易范例"></a>交易范例</h1><p>Alice 去咖啡店买一杯咖啡,她需要支付给老板Bob的咖啡金额是5 个比特币。接下来看代码如何实现:</p>
<h2 id="1,在区块链中查询Alice的未花费的输出"><a href="#1,在区块链中查询Alice的未花费的输出" class="headerlink" title="1,在区块链中查询Alice的未花费的输出"></a>1,在区块链中查询Alice的未花费的输出</h2><p>如果一个账户需要进行一次交易,把自己的代币转给别人,由于没有一个账号系统可以直接查询余额和变更,而在utxo模型里面一个用户账户余额就是这个用户的所有utxo(未花费的输出)记录的合集,因此需要查询用户的转账额度是否足够,以及本次转账需要消耗哪些output(将“未花费”的output变成”已花费“的output),通过遍历区块链中每个区块中的每个交易中的output来得到结果。<br>下面看看怎么查找一个特定用户的utxo,utxo_set.go相关代码如下:<br><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// 找到用户可花费的输出,满足花费的金额即可,返回的可花费的金额 和 对应的交易输出的下标</span></span><br><span class="line"><span class="comment">// 注意返回的可花费的金额accumulated 是 大于等于 要花费的金额的,因为可花费金额是该用户的多笔不同金额的utxo累加的</span></span><br><span class="line"><span class="comment">// 如果返回的utxo金额累计大于要花费的金额,则多出的部分就是找零,相当于多个utxo是面额不同的金额累加成一个大额</span></span><br><span class="line"><span class="comment">//注意: 返回的第二个参数是某笔交易的某个下标 如 trans[txid_1111]=1 就是txid_1111这个交易的下标为1的输出被选用了</span></span><br><span class="line"><span class="comment">// FindSpendableOutputs finds and returns unspent outputs to reference in inputs</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(u UTXOSet)</span> <span class="title">FindSpendableOutputs</span><span class="params">(pubkeyHash []<span class="keyword">byte</span>, amount <span class="keyword">int</span>)</span> <span class="params">(<span class="keyword">int</span>, <span class="keyword">map</span>[<span class="keyword">string</span>][]<span class="keyword">int</span>)</span></span> {</span><br><span class="line"> unspentOutputs := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="keyword">string</span>][]<span class="keyword">int</span>)</span><br><span class="line"> accumulated := <span class="number">0</span></span><br><span class="line"> db := u.Blockchain.db</span><br><span class="line"></span><br><span class="line"> err := db.View(<span class="function"><span class="keyword">func</span><span class="params">(tx *bolt.Tx)</span> <span class="title">error</span></span> {</span><br><span class="line"> b := tx.Bucket([]<span class="keyword">byte</span>(utxoBucket))</span><br><span class="line"> c := b.Cursor()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> k, v := c.First(); k != <span class="literal">nil</span>; k, v = c.Next() {</span><br><span class="line"> txID := hex.EncodeToString(k)</span><br><span class="line"> outs := DeserializeOutputs(v)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> outIdx, out := <span class="keyword">range</span> outs.Outputs {</span><br><span class="line"> <span class="keyword">if</span> out.IsLockedWithKey(pubkeyHash) && accumulated < amount {</span><br><span class="line"> accumulated += out.Value</span><br><span class="line"> unspentOutputs[txID] = <span class="built_in">append</span>(unspentOutputs[txID], outIdx)</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="keyword">return</span> <span class="literal">nil</span></span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> log.Panic(err)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> accumulated, unspentOutputs</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>FindSpendableOutputs查找区块链上pubkeyHash账户的utxo集合,直到这些集合的累计未花费金额达到需求的amount为止。</p>
<p>blockchain_go中使用嵌入式key-value数据库boltdb存储区块链和未花费输出等信息,其中utxoBucket是所有用户未花费输出的bucket,其中的key表示交易ID,value是这个交易中未被引用的所有output的集合。所以通过遍历查询本次交易需要花费的output,得到Transaction的txID和这个output在Transaction中的输出数组中的下标组合unspentOutputs。</p>
<p>另外一个重点是utxobucket中保存的未花费输出结合是关于所有账户的,要查询特定账户需要对账户进行判断,因为TXOutput中有pubkeyhash字段,用来表示该输出属于哪个用户,此处采用out.IsLockedWithKey(pubkeyHash)判断特定output是否是属于给定用户。</p>
<h2 id="2-构建一个交易"><a href="#2-构建一个交易" class="headerlink" title="2, 构建一个交易"></a>2, 构建一个交易</h2><p>需要发起一笔交易的时候,需要新建一个Transaction,通过交易发起人的钱包得到足够的未花费输出,构建出交易的输入和输出,完成签名即可,blockchain_go中的实现如下</p>
<p>函数参数:</p>
<ul>
<li>wallet : 用户钱包参数,存储用户的公私钥,用于交易的签名和验证。</li>
<li>to : 交易转账的目的地址(转账给谁)。</li>
<li>amount : 需要交易的代币额度。</li>
<li>UTXOSet : uxto集合,查询用户的未花费输出。<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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewUTXOTransaction</span><span class="params">(wallet *Wallet, to <span class="keyword">string</span>, amount <span class="keyword">int</span>, UTXOSet *UTXOSet)</span> *<span class="title">Transaction</span></span> {</span><br><span class="line"> <span class="keyword">var</span> inputs []TXInput</span><br><span class="line"> <span class="keyword">var</span> outputs []TXOutput</span><br><span class="line"></span><br><span class="line"> pubKeyHash := HashPubKey(wallet.PublicKey)</span><br><span class="line"> <span class="comment">// 查询用户可花费金额 和 对应的可花费交易的下标</span></span><br><span class="line"> acc, validOutputs := UTXOSet.FindSpendableOutputs(pubKeyHash, amount)</span><br><span class="line"> <span class="comment">//可花费金额小于 要输出的金额 则报错</span></span><br><span class="line"> <span class="keyword">if</span> acc < amount {</span><br><span class="line"> log.Panic(<span class="string">"ERROR: Not enough funds"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Build a list of inputs</span></span><br><span class="line"> <span class="keyword">for</span> txid, outs := <span class="keyword">range</span> validOutputs {</span><br><span class="line"> txID, err := hex.DecodeString(txid)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> log.Panic(err)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> _, out := <span class="keyword">range</span> outs {</span><br><span class="line"> input := TXInput{txID, out, <span class="literal">nil</span>, wallet.PublicKey}</span><br><span class="line"> inputs = <span class="built_in">append</span>(inputs, input)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Build a list of outputs</span></span><br><span class="line"> from := fmt.Sprintf(<span class="string">"%s"</span>, wallet.GetAddress())</span><br><span class="line"> outputs = <span class="built_in">append</span>(outputs, *NewTXOutput(amount, to))</span><br><span class="line"> <span class="comment">// 如果返回的utxo金额累计大于要花费的金额,则多出的部分就是找零,相当于多个utxo是面额不同的金额累加成一个大额</span></span><br><span class="line"> <span class="keyword">if</span> acc > amount {</span><br><span class="line"> outputs = <span class="built_in">append</span>(outputs, *NewTXOutput(acc-amount, from)) <span class="comment">// a change 零钱</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> tx := Transaction{<span class="literal">nil</span>, inputs, outputs}</span><br><span class="line"> tx.ID = tx.Hash()</span><br><span class="line"> UTXOSet.Blockchain.SignTransaction(&tx, wallet.PrivateKey)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> &tx</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>因为用户的总金额是通过若干未花费输出累计起来的,而每个output所携带金额不一而足,所以每次转账可能需要消耗多个不同的output,而且还可能涉及找零问题。以上查询返回了一批未花费输出列表validOutputs和他们总共的金额acc. 找出来的未花费输出列表就是本次交易的输入,并将输出结果构造output指向目的用户,并检查是否有找零,将找零返还。</p>
<p>如果交易顺利完成,转账发起人的“未花费输出”被消耗掉变成了花费状态,而转账接收人to得到了一笔新的“未花费输出”,之后他自己需要转账时,查询自己的未花费输出,即可使用这笔钱。</p>
<p>最后需要对交易进行签名,表示交易确实是由发起人本人发起(私钥签名),而不是被第三人冒充。</p>
<h1 id="交易的签名和验证"><a href="#交易的签名和验证" class="headerlink" title="交易的签名和验证"></a>交易的签名和验证</h1><h4 id="签名"><a href="#签名" class="headerlink" title="签名"></a>签名</h4><p>交易的有效性需要首先建立在发起人签名的基础上,防止他人冒充转账或者发起人抵赖,blockchain_go中交易签名实现如下:<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// SignTransaction signs inputs of a Transaction</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(bc *Blockchain)</span> <span class="title">SignTransaction</span><span class="params">(tx *Transaction, privKey ecdsa.PrivateKey)</span></span> {</span><br><span class="line"> prevTXs := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="keyword">string</span>]Transaction)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> _, vin := <span class="keyword">range</span> tx.Vin {</span><br><span class="line"> prevTX, err := bc.FindTransaction(vin.Txid)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> log.Panic(err)</span><br><span class="line"> }</span><br><span class="line"> prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> tx.Sign(privKey, prevTXs)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Sign signs each input of a Transaction</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(tx *Transaction)</span> <span class="title">Sign</span><span class="params">(privKey ecdsa.PrivateKey, prevTXs <span class="keyword">map</span>[<span class="keyword">string</span>]Transaction)</span></span> {</span><br><span class="line"> <span class="keyword">if</span> tx.IsCoinbase() {</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">for</span> _, vin := <span class="keyword">range</span> tx.Vin {</span><br><span class="line"> <span class="keyword">if</span> prevTXs[hex.EncodeToString(vin.Txid)].ID == <span class="literal">nil</span> {</span><br><span class="line"> log.Panic(<span class="string">"ERROR: Previous transaction is not correct"</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> txCopy := tx.TrimmedCopy()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> inID, vin := <span class="keyword">range</span> txCopy.Vin {</span><br><span class="line"> prevTx := prevTXs[hex.EncodeToString(vin.Txid)]</span><br><span class="line"> txCopy.Vin[inID].Signature = <span class="literal">nil</span></span><br><span class="line"> <span class="comment">// 注意vin.Vout 是该账户之前存在的某比交易的某个可花费输出的下标</span></span><br><span class="line"> txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash</span><br><span class="line"></span><br><span class="line"> dataToSign := fmt.Sprintf(<span class="string">"%x\n"</span>, txCopy)</span><br><span class="line"></span><br><span class="line"> r, s, err := ecdsa.Sign(rand.Reader, &privKey, []<span class="keyword">byte</span>(dataToSign))</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> log.Panic(err)</span><br><span class="line"> }</span><br><span class="line"> signature := <span class="built_in">append</span>(r.Bytes(), s.Bytes()...)</span><br><span class="line"></span><br><span class="line"> tx.Vin[inID].Signature = signature</span><br><span class="line"> txCopy.Vin[inID].PubKey = <span class="literal">nil</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>交易输入的签名信息是放在TXInput中的signature字段,其中需要包括用户的pubkey,用于之后的验证。需要对每一个输入做签名。</p>
<h4 id="验证"><a href="#验证" class="headerlink" title="验证"></a>验证</h4><p>交易签名是发生在交易产生时,交易完成后,Transaction会把交易广播给邻居。节点在进行挖矿时,会整理一段时间的所有交易信息,将这些信息打包进入新的区块,成功加入区块链以后,这个交易就得到了最终的确认。但是在挖矿节点打包交易前,需要对交易的有效性做验证,以防虚假数据,验证实现如下:</p>
<p>// MineBlock mines a new block with the provided transactions<br>func (bc <em>Blockchain) MineBlock(transactions []</em>Transaction) *Block {<br> var lastHash []byte<br> var lastHeight int</p>
<pre><code>for _, tx := range transactions {
// TODO: ignore transaction if it's not valid
if bc.VerifyTransaction(tx) != true {
log.Panic("ERROR: Invalid transaction")
}
}
...
...
...
return block
</code></pre><p>}<br>// VerifyTransaction verifies transaction input signatures<br>func (bc <em>Blockchain) VerifyTransaction(tx </em>Transaction) bool {<br> if tx.IsCoinbase() {<br> return true<br> }</p>
<pre><code>prevTXs := make(map[string]Transaction)
for _, vin := range tx.Vin {
prevTX, err := bc.FindTransaction(vin.Txid)
if err != nil {
log.Panic(err)
}
prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX
}
return tx.Verify(prevTXs)
</code></pre><p>}<br>// Verify verifies signatures of Transaction inputs<br>func (tx *Transaction) Verify(prevTXs map[string]Transaction) bool {<br> if tx.IsCoinbase() {<br> return true<br> }</p>
<pre><code>for _, vin := range tx.Vin {
if prevTXs[hex.EncodeToString(vin.Txid)].ID == nil {
log.Panic("ERROR: Previous transaction is not correct")
}
}
txCopy := tx.TrimmedCopy()
curve := elliptic.P256()
for inID, vin := range tx.Vin {
prevTx := prevTXs[hex.EncodeToString(vin.Txid)]
txCopy.Vin[inID].Signature = nil
txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash
r := big.Int{}
s := big.Int{}
sigLen := len(vin.Signature)
r.SetBytes(vin.Signature[:(sigLen / 2)])
s.SetBytes(vin.Signature[(sigLen / 2):])
x := big.Int{}
y := big.Int{}
keyLen := len(vin.PubKey)
x.SetBytes(vin.PubKey[:(keyLen / 2)])
y.SetBytes(vin.PubKey[(keyLen / 2):])
dataToVerify := fmt.Sprintf("%x\n", txCopy)
rawPubKey := ecdsa.PublicKey{Curve: curve, X: &x, Y: &y}
if ecdsa.Verify(&rawPubKey, []byte(dataToVerify), &r, &s) == false {
return false
}
txCopy.Vin[inID].PubKey = nil
}
return true
</code></pre><p>}<br>可以看到验证的时候也是每个交易的每个TXInput都单独进行验证,和签名过程很相似,需要构造相同的交易数据txCopy,验证时会用到签名设置的TxInput.PubKeyHash生成一个原始的PublicKey,将前面的signature分拆后通过ecdsa.Verify进行验证。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上简单分析和整理了blockchain_go中的交易和UTXO机制的实现过程,加深了区块链中的挖矿,交易和转账的基础技术原理的理解。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/05/28/Pycharm设置翻译器(解决pip安装的包跟踪问题)/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="John Doe">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2019/05/28/Pycharm设置翻译器(解决pip安装的包跟踪问题)/" itemprop="url">
Pycharm设置翻译器(解决pip安装的包跟踪问题)
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2019-05-28 16:31:14" itemprop="dateCreated datePublished" datetime="2019-05-28T16:31:14+08:00">2019-05-28</time>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-calendar-check-o"></i>
</span>
<span class="post-meta-item-text">Edited on</span>
<time title="Modified: 2019-05-30 16:38:00" itemprop="dateModified" datetime="2019-05-30T16:38:00+08:00">2019-05-30</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>问题:</p>
<p>默认打开pycharm 会提示你:</p>
<p><img src="/images/pasted-34.png" alt="upload successful"></p>
<p>并且安装的包也无法跟踪</p>
<p>解决方法:</p>
<p>创建项目这样配置<br><img src="/images/pasted-48.png" alt="upload successful"></p>
<p>其他的项目创建或打开,点击那个上面的提示,将project interpreter 设置成上图即可</p>
<hr>
<h2 id="以下设置可能没卵用,废弃"><a href="#以下设置可能没卵用,废弃" class="headerlink" title="以下设置可能没卵用,废弃"></a>以下设置可能没卵用,废弃</h2><p>1, 点击这个提示或者(setting->preference 里搜索 interpreter)到这个页面:</p>
<p><img src="/images/pasted-38.png" alt="upload successful"></p>
<p>2,点击show all</p>
<p><img src="/images/pasted-40.png" alt="upload successful"></p>
<p>3,点击+ 后, 这一步是重点:</p>
<p><img src="/images/pasted-42.png" alt="upload successful"></p>
<p>4,点击Ok保存, 如此之后, 页面的提示会消失,后续其他项目也可以选这个配置。比如这个这个项目没有配置interpreter了, 且也无法跟踪代码就如下操作:</p>
<p><img src="/images/pasted-44.png" alt="upload successful"></p>
<p>5,设置完成,问题解决</p>
<p>新建项目就这么选</p>
<p><img src="/images/pasted-46.png" alt="upload successful"></p>
<p>已经建好的项目就修改interpreter就行了</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>