-
Notifications
You must be signed in to change notification settings - Fork 3
/
turbo_geth_release.html
370 lines (353 loc) · 62.5 KB
/
turbo_geth_release.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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="mobile-web-app-capable" content="yes">
<title>
Towards the first release of Turbo-geth - HackMD
</title>
<link rel="icon" type="image/png" href="https://hackmd.io/favicon.png">
<link rel="apple-touch-icon" href="https://hackmd.io/apple-touch-icon.png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/[email protected]/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
<style>
@charset "UTF-8";@import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);.hljs{display:block;background:#fff;padding:.5em;color:#333;overflow-x:auto}.hljs-comment,.hljs-meta{color:#969896}.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-number,.hljs-symbol{color:#0086b3}.hljs-built_in,.hljs-builtin-name{color:#005cc5}.hljs-name,.hljs-section{color:#63a35c}.hljs-tag{color:#333}.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3}.hljs-addition{color:#55a532;background-color:#eaffea}.hljs-deletion{color:#bd2c00;background-color:#ffecec}.hljs-link{text-decoration:underline}.markdown-body{font-size:16px;line-height:1.5;word-wrap:break-word}.markdown-body:after,.markdown-body:before{display:table;content:""}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;padding-right:4px;margin-left:-20px;line-height:1}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:16px}.markdown-body hr{height:.25em;padding:0;margin:24px 0;background-color:#e7e7e7;border:0}.markdown-body blockquote{font-size:16px;padding:0 1em;color:#777;border-left:.25em solid #ddd}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:1px solid #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:24px;margin-bottom:16px;font-weight:600;line-height:1.25}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{padding-bottom:.3em;border-bottom:1px solid #eee}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{font-size:.85em;color:#777}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{padding:0;list-style-type:none}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body table{display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{max-width:100%;box-sizing:content-box;background-color:#fff}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{max-width:none;vertical-align:text-top;background-color:transparent}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown-body span.align-center{display:block;overflow:hidden;clear:both}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{display:block;overflow:hidden;clear:both}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:transparent;border:0}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown-body pre code,.markdown-body pre tt{display:inline;max-width:auto;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.news .alert .markdown-body blockquote{padding:0 0 0 40px;border:0 none}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle;cursor:default!important}.markdown-body{padding-top:40px;padding-bottom:40px;max-width:758px;overflow:visible!important;position:relative}.markdown-body .emoji{vertical-align:top}.markdown-body pre{border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{text-align:right;position:relative;display:inline-block;cursor:default;z-index:4;padding:0 8px 0 0;min-width:20px;box-sizing:content-box;color:#afafaf!important;border-right:3px solid #6ce26c!important}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-left:none;border-top:none;border-bottom:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-spacing:0;border-collapse:inherit!important}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{overflow:unset;margin-bottom:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert>p{margin-bottom:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{text-align:center;background-color:inherit;border-radius:0;white-space:inherit;overflow:visible}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{max-width:100%;height:100%}.markdown-body pre>code.wrap{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.markdown-body .alert>p,.markdown-body .alert>ul{margin-bottom:0}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}.vimeo,.youtube{cursor:pointer;display:table;text-align:center;background-position:50%;background-repeat:no-repeat;background-size:contain;background-color:#000;overflow:hidden}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{width:100%;object-fit:contain;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{width:100%;height:100%;position:absolute;top:0;left:0}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{position:absolute;height:auto;width:auto;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;opacity:.3;transition:opacity .2s;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{position:relative;z-index:2;max-width:760px;margin:25px auto -25px;color:#777}.toc .invisable-node{list-style-type:none}.ui-toc{position:fixed;bottom:20px;z-index:998}.ui-toc.both-mode{margin-left:8px}.ui-toc.both-mode .ui-toc-label{height:40px;padding:10px 4px;border-top-left-radius:0;border-bottom-left-radius:0}.ui-toc-label{background-color:#e6e6e6;border:none;color:#868686;transition:opacity .2s}.ui-toc .open .ui-toc-label{opacity:1;color:#fff;transition:opacity .2s}.ui-toc-label:focus{opacity:.3;background-color:#ccc;color:#000}.ui-toc-label:hover{opacity:1;background-color:#ccc;transition:opacity .2s}.ui-toc-dropdown{margin-top:20px;margin-bottom:20px;padding-left:10px;padding-right:10px;max-width:45vw;width:25vw;max-height:70vh;overflow:auto;text-align:inherit}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{padding-right:0;letter-spacing:.0029em}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}.ui-toc-dropdown .nav>li:first-child:last-child > ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{padding-left:19px;color:#000;text-decoration:none;background-color:transparent;border-left:1px solid #000}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{padding-right:19px;border-left:none;border-right:1px solid #000}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{padding-left:18px;font-weight:700;color:#000;background-color:transparent;border-left:2px solid #000}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{padding-right:18px;border-left:none;border-right:2px solid #000}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{padding-top:1px;padding-bottom:1px;padding-left:40px;font-size:12px;font-weight:400}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{padding-left:28px;font-weight:500}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{padding-left:38px;font-weight:500}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif}html[lang^=ja] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS\ ゴシック,sans-serif}html[lang=zh-tw] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}html .markdown-body[lang^=ja]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS\ ゴシック,sans-serif}html .markdown-body[lang=zh-tw]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html .markdown-body[lang=zh-cn]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}html[lang^=ja] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS\ Pゴシック,sans-serif}html[lang=zh-tw] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html[lang=zh-cn] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}html .ui-toc-dropdown[lang^=ja]{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS\ Pゴシック,sans-serif}html .ui-toc-dropdown[lang=zh-tw]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html .ui-toc-dropdown[lang=zh-cn]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}.ui-affix-toc{position:fixed;top:0;max-width:15vw;max-height:70vh;overflow:auto}.back-to-top,.expand-toggle,.go-to-bottom{display:block;padding:4px 10px;margin-top:10px;margin-left:10px;font-size:12px;font-weight:500;color:#999}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{width:20px;height:20px;display:block;border-radius:3px;margin-top:2px;margin-bottom:2px;margin-right:5px;background-position:50%;background-repeat:no-repeat;background-size:cover}.ui-user-icon.small{width:18px;height:18px;display:inline-block;vertical-align:middle;margin:0 0 .2em}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-published-note{color:#337ab7}.ui-published-note .fa{font-size:20px;vertical-align:top}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{position:relative;z-index:1;color:#222}.markdown-body.slides:before{content:"";display:block;position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1;background-color:currentColor;box-shadow:0 0 0 50vw}.markdown-body.slides section[data-markdown]{position:relative;margin-bottom:1.5em;background-color:#fff;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{position:absolute;top:50%;left:1em;right:1em;transform:translateY(-50%);max-height:100%;overflow:hidden}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{content:"";position:absolute;top:-1.5em;right:1em;height:1.5em;border:3px solid #777}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS\ ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;text-shadow:0 0 1em transparent,1px 1px 1.2px rgba(0,0,0,.004);-webkit-overflow-scrolling:touch;letter-spacing:.025em;font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS\ ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}
</style>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
<![endif]-->
</head>
<body>
<div id="doc" class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true"><h1 id="Towards-the-first-release-of-Turbo-geth" data-id="Towards-the-first-release-of-Turbo-geth"><a class="anchor hidden-xs" href="#Towards-the-first-release-of-Turbo-geth" title="Towards-the-first-release-of-Turbo-geth"><span class="octicon octicon-link"></span></a><span>Towards the first release of Turbo-geth</span></h1><p><span>It has been more than two years since turbo-geth project started. Now we are almost there. This post will explain the criteria we will use for determining when the release is ready, and what to expect from turbo-geth in its first release. First, we will describe the current limitations (compared to other Ethereum implementations), and then go over things that are the reason for turbo-geth to exist - performance and architecture.</span></p><h2 id="When-is-it-going-to-be-ready" data-id="When-is-it-going-to-be-ready"><a class="anchor hidden-xs" href="#When-is-it-going-to-be-ready" title="When-is-it-going-to-be-ready"><span class="octicon octicon-link"></span></a><span>When is it going to be ready?</span></h2><p><span>It is now ready for public alpha stage. We encourage people to try it out, and talk to us about results, and report issues. Though the sync (and with it, the creation of the initial database) with the Ethereum main net has been massively improved due to the new architecture, it still takes non-trivial amount of time (several days).</span><br>
<span>We call this new architecture “staged sync”, and it will be explained in more detals further down.</span></p><h2 id="When-are-we-going-from-“alpha”-to-“beta”" data-id="When-are-we-going-from-“alpha”-to-“beta”"><a class="anchor hidden-xs" href="#When-are-we-going-from-“alpha”-to-“beta”" title="When-are-we-going-from-“alpha”-to-“beta”"><span class="octicon octicon-link"></span></a><span>When are we going from “alpha” to “beta”?</span></h2><p><span>Currently, the main criterion for us to go from alpha to beta is the (somewhat subjective) understanding of how “in control” of code our team is. At this moment the feeling is that we are mostly in control (meaning that we can identify and debug issues without too much digging into some unknown code), except for certain parts that pertain to devp2p, downloading of headers and blocks, and reactions on the new blocks. The code we are currently using has not been designed for staged sync architecture, and assumes that all “stages” are happening concurrently. Therefore, this code does much more than we need, and is unnecessarily complex for what we actually need. We also often experience stalling sometimes.</span><br>
<span>In order to address this, we have started a redesign of block header downloading, which should result in a more suitable, better understood code Here is current Work-In-Progress documentation (which is also accompanied by a Proof Of Concept implementation and tests): </span><a href="https://github.com/ledgerwatch/turbo-geth/blob/headers-poc/docs/programmers_guide/header_download.md" target="_blank" rel="noopener"><span>https://github.com/ledgerwatch/turbo-geth/blob/headers-poc/docs/programmers_guide/header_download.md</span></a></p><h2 id="Distribution" data-id="Distribution"><a class="anchor hidden-xs" href="#Distribution" title="Distribution"><span class="octicon octicon-link"></span></a><span>Distribution</span></h2><p><span>We would like to keep concentrating on developing and optimising the code, therefore we will not be publishing any binaries. Our first users would need to build from source. This may change in the future, if we find it being crucial.</span></p><h2 id="No-fast-sync-warp-sync-or-any-other-snapshot-sync" data-id="No-fast-sync-warp-sync-or-any-other-snapshot-sync"><a class="anchor hidden-xs" href="#No-fast-sync-warp-sync-or-any-other-snapshot-sync" title="No-fast-sync-warp-sync-or-any-other-snapshot-sync"><span class="octicon octicon-link"></span></a><span>No fast sync, warp sync or any other snapshot sync</span></h2><p><span>In the first release, the only way to synchronise with the Ethereum network will be to download block headers, download block bodies, and execute all the blocks from genesis to the current head of the chain. Although this may sound like a non-starter, we have managed to make this process very efficient. As our next steps, we would like to develop a version of snapshot sync, which is as simple as possible (as simple as downloading a file from a torrent), initial description and discussion can be found here: </span><a href="https://ethresear.ch/t/simpler-ethereum-sync-major-minor-state-snapshots-blockchain-files-receipt-files/7672" target="_blank" rel="noopener"><span>https://ethresear.ch/t/simpler-ethereum-sync-major-minor-state-snapshots-blockchain-files-receipt-files/7672</span></a></p><p><span>Work is underway on the initial code that will utilise BitTorrent for downloading headers and blocks.</span></p><h2 id="GPL-license" data-id="GPL-license"><a class="anchor hidden-xs" href="#GPL-license" title="GPL-license"><span class="octicon octicon-link"></span></a><span>GPL license</span></h2><p><span>Since turbo-geth is a derivative of go-ethereum, it inherits General Public License 3.0. We will not be able to relicense the code at any point, but we may, in the future, shift some or all parts of the functionality into external libraries that would be released under more permissive licenses than GPL3.</span></p><h2 id="Licence-and-language-migration-plan-out-of-scope-for-the-release" data-id="Licence-and-language-migration-plan-out-of-scope-for-the-release"><a class="anchor hidden-xs" href="#Licence-and-language-migration-plan-out-of-scope-for-the-release" title="Licence-and-language-migration-plan-out-of-scope-for-the-release"><span class="octicon octicon-link"></span></a><span>Licence and language migration plan (out of scope for the release)</span></h2><p><span>This would be an experiment which goes beyond technical, but it is rather trying to find out whether it is possible to build a financially sustainable operation around a product like Ethereum implementation. So far very few had tried and we do not see a lot of success. Lots of people believe that this lack of success has to do with the limitations of the GPL licence:</span></p><ul>
<li><span>It limits the engagement of big tech companies</span></li>
<li><span>Makes it difficult for small specialists to monetalise customisation work, therefore depriving the product ecosystem of motivated participants</span></li>
</ul><p><span>We would like to try to get to Apache 2.0 licence. But that means basically re-writing the product. And we do not see a good way of re-writing turbo-geth in Go without a lot of “rewriting for rewriting sake”, which is likely to be counterproductive. Also, going “into a cave” again and re-writing it from scratch is not something we would like to do. I would prefer gradual migration of the product that always works - in my experience this approach has much fewer risks. C++ seems to be a good first target for migration, for a few reasons:</span></p><ul>
<li><span>The original eth C++ client is de-facto dead, so we might get some help from people who used to work on it</span></li>
<li><span>Interfacing between Go and C/C++ is probably easier than to any other languages</span></li>
<li><span>We already found some great components to start with - evm1, lmdb</span></li>
<li><span>If we want to migrate to other languages, like Rust, in the future, it will be easier to do that from C++, again because of the language interfacing. Migration </span><code>Go => (Go;Rust) => Rust</code><span> is likely to be more troublesome than the migration </span><code>Go => (Go;C++) => C++ => (C++;Rust) => Rust</code><span>, though this is not currently a goal.</span></li>
</ul><p><span>Work is underway to convert certain stages of the sync process to C++.</span></p><h2 id="Separation-of-JSON-RPC-and-future-of-architecture-during-migration" data-id="Separation-of-JSON-RPC-and-future-of-architecture-during-migration"><a class="anchor hidden-xs" href="#Separation-of-JSON-RPC-and-future-of-architecture-during-migration" title="Separation-of-JSON-RPC-and-future-of-architecture-during-migration"><span class="octicon octicon-link"></span></a><span>Separation of JSON RPC and future of architecture during migration</span></h2><p><span>Presently, turbo-geth, like go-ethereum runs most of its its functionality in a single, monolithic process. We have started some experiments on separating the JSON RPC functionality out into a separate process (RPC daemon), to support more flexible scaling of “JSON RPC farms”. We are planning to experiment with separating out another networking component, which is currently handling peer discovery and devp2p, into a separate process, called Sentry. The resulting architecture would look like this:</span><br>
<img src="https://ledgerwatch.github.io/future_architecture.png" alt=""></p><p><span>When we migrate, we will first migrate the backend, and leave RPC daemon and the Sentry using Go, and decide on their migration plans at later point.</span></p><h2 id="JSON-RPC-API" data-id="JSON-RPC-API"><a class="anchor hidden-xs" href="#JSON-RPC-API" title="JSON-RPC-API"><span class="octicon octicon-link"></span></a><span>JSON RPC API</span></h2><p><span>It is mostly derived from go-ethereum, with some changes. Some methods will not be supported in the first release, for example, </span><code>eth_getProof</code><span>. It is possible to implement </span><code>eth_getProof</code><span>, and we have the implementation that works correctly, but very slowly. We do not currently consider it a big enough feature to delay the first release for. In the method </span><code>debug_accountRange</code><span>, turbo-geth will also be slower for the historical blocks that are very far away in the past. In methods </span><code>debug_accountRange</code><span> and </span><code>debug_storageRangeAt</code><span>, the order in which turbo-geth returns items is different from the order in which go-ethereum returns the same items.</span></p><p><span>Since these tests were done, the state and the history database format have changed again, therefore the RPC methods will need to be modified/fixed and re-tested again. The following section will be used to track the fixes and retests for these API methods.</span></p><h2 id="Testnet-support" data-id="Testnet-support"><a class="anchor hidden-xs" href="#Testnet-support" title="Testnet-support"><span class="octicon octicon-link"></span></a><span>Testnet support</span></h2><p><span>We did not routinely test on Ropsten, Görli, or Rinkeby, but we did some spot checks and they appear to be working with turbo-geth</span></p><h2 id="Disk-space" data-id="Disk-space"><a class="anchor hidden-xs" href="#Disk-space" title="Disk-space"><span class="octicon octicon-link"></span></a><span>Disk space</span></h2><p><span>Chart below shows approximate allocation of disk space between various buckets (you can think of them as tables in the database).</span></p><p><img src="https://ledgerwatch.github.io/space_chart.png" alt=""></p><p><span>The picture above shows the total size of the database as 629 Gb, although the sum of all buckets is actually 576 Gb. We are still not sure why, most probably we forgot to include a 53 Gb bucket in the picture.</span></p><h3 id="Two-state-buckets-and-no-preimages" data-id="Two-state-buckets-and-no-preimages"><a class="anchor hidden-xs" href="#Two-state-buckets-and-no-preimages" title="Two-state-buckets-and-no-preimages"><span class="octicon octicon-link"></span></a><span>Two state buckets and no preimages</span></h3><p><span>You may see that there are two buckets containing the state, one with original keys (account addresses and contract storage locations), another - with “hashed” keys. Although it might seem like a waste of space, you may also notice that there is no “Preimage” bucket that we had before. The size of preimage bucket would be roughly the same as the size of the state bucket. Why there is no preimage bucket? Because now all queries (JSON RPC, or Rest API) about accounts and contract storage can be answered from the un-hashed state bucket, without any need of preimages. Not only it is more efficient, but also allows some functionality not easily available with the “hashed” stage + preimage combination. One example is autocompletion search for addresses that you might have seen on etherscan:</span></p><p><img src="https://ledgerwatch.github.io/auto-completion.png" alt=""></p><p><span>You might imagine that etherscan has to maintain the list of currently active addresses to suport this, and in turbo-geth it will be built-in.</span></p><p><span>There is another way in which the un-hashed state will prove to be useful. When the snapshot sync is implemented, it is most likely be transmitting the state keys in an unhashed form, so that the receiving node can have the same advantages as the sending node, without having preimages (snapshot sync protocols do not transmit preimages).</span></p><h2 id="Staged-sync" data-id="Staged-sync"><a class="anchor hidden-xs" href="#Staged-sync" title="Staged-sync"><span class="octicon octicon-link"></span></a><span>Staged sync</span></h2><p><span>So-called full-sync, or its variant archive-sync is performed by downloading all historical block bodies and replaying all transactions contained in them. Traditionally, in go-ethereum, downloading the bodies and replaying transactions happens concurrently with other activities, like verification of Proof-Of-Work in the block headers, recovery of transaction senders from their signatures etc. In turbo-geth, we have recently taken a different approach. We tried to maximally decompose the sync process into stages, and perform them sequentially. From the first sight, it might sound like a bad idea - why not use concurrency? However, we noticed that running many things concurrently obscured our ability to profile and optimise code - there is simply too much going on. Decomposition allowed us to optimise each stage in separation, which is much more tractable. We also noticed the benefit of improved code structure.</span><br>
<span>Another interesting insight became apparent when we engineered the decomposed staged sync. We could decouple the execution of transactions from computing and verifying state root hashes. Before staged sync, the computation of state root hash and its verification would happen for every single block, and this is where we saw the biggest performance drag. At the same time, we knew that nodes that fast-sync or wrap-sync, only perform such verification on the state snapshot they are downloading, and subsequent blocks after that. We took similar approach in our staged sync - in one stage, we replayed all historical transactions, advancing the current state, and only verifying receipt hashes for each block. When the state is advanced to the head of the chain, we compute state trie, verify its root hash, and take it from there. This approach allowed for the drastic reduction of the sync time.</span></p><h2 id="Currently-envisaged-stages" data-id="Currently-envisaged-stages"><a class="anchor hidden-xs" href="#Currently-envisaged-stages" title="Currently-envisaged-stages"><span class="octicon octicon-link"></span></a><span>Currently envisaged stages</span></h2><p><span>At the moment we envisage about 14 stages in the “staged sync”, but more stages are likely to be added as a way of plugging more functionality. The first stage completes before the second one is started. After the last stage is complete, the control comes back to the first stage, and so on.</span></p><ol>
<li><span>Download block headers. The parent-child relationship between block headers, as well as their Proof Of Work is verified before they are written into the database. This stage is also a source of potential reorgs, when a heavier chain is detected compared to the one which is currently deemed canonical. In such situations, unwinding happens in the reverse order of the stages, from the 10th to the 1st.</span></li>
<li><span>Index of block numbers by block hashes. Since block hashes look like pseudo-random numbers, inserting them into the database in the order of their appearance causes unnecessary delays on the disks with high latency of access (HDD). This stage exists to alleviate it, and it pre-sorts the index by block hashes before inserting them into the database in “one go”.</span></li>
<li><span>Download block bodies. Block bodies contain list of transactions and list of ommers (uncles). The correspondence between transactions and the </span><code>TxHash</code><span> in the header, as well as the correspondence between ommers and the </span><code>UncleHash</code><span> in the header, is verified at this stage.</span></li>
<li><span>Recover transaction senders. Sender of each transaction is not explicitely contained inside the transaction’s data, but rather it is contained inside the ECDSA digital signature that comes with every transaction. The sender’s public key needs to be recovered from the signature, and then the address of the sender derived from the public key. This is what happens at this stage, and the bodies of the blocks are updated in the database to include the sender’s information, so that the recovery need not be repeated later.</span></li>
<li><span>Replay transactions contained in the blocks. As the transactions are getting replayed, three types of data are getting produced. Firstly, the current state, which is the mapping of account addresses (not the hashes of addresses) to the account records, the mapping of contract storage locations (not the hashes of the locations) to the contract storage values, and the mapping of contracts to their bytecode. Secondly, the reverse diffs of the state changes - for every processed block it is a mapping of all modified state objects to the values those objects had prior to modifications. And thirdly, transaction receipts are computed, and their merkle hash is compared with the </span><code>ReceiptHash</code><span> field in the corresponding header.</span></li>
<li><span>Transform the “plain state” to the “hashed state”. In Ethereum, in order to maintain the state trie balanced, the keys of all entries in the state trie are pre-scrambled using </span><code>Keccak256</code><span> function. At this stage, this transformation is performed en masse, for the entire state if this is the first sync cycle, or for the state increment otherwise.</span></li>
<li><span>Create or update intermediate state hashes. In order to improve performance of state root hash calculation and of generation of merkle proof, there is additional mapping of partial state key to the root hashes of the corresponding merkle sub-trees. The overhead is this structure is not very large, on the order of 15-20% of the state size. At the end of this stage, the state root hash becomes known, and it is verified against the </span><code>StateRoot</code><span> field of the corresponding header.</span></li>
<li><span>Generate account history index. Using the reverse diffs produced at the stage 4 (transaction replay), which are indexed by the block number, this stage creates and additional index, by the account’s address, which allows quick access to the list of block numbers in which a specific account was modified. The history index is essentially a mapping from account addresses to the sequence of block numbers.</span></li>
<li><span>Generate contract storage history index. This is simular to the previous stage. The reason it is in a separate stage is that the contract storage is a bit more complex than accounts: there is one-to-many relation between contracts and their storage items, storage items can disappear in large quantities during </span><code>SELFDESTRUCT</code><span> invocations.</span></li>
<li><span>Generate transaction lookup index. This is the mapping from transaction Id (transaction hash currently) to the location of that transaction (currently just the block number). This can be viewed as a reindexing of the block bodies.</span></li>
<li><span>Generate transaction receipts. Although transaction receipts are generated during the stage 4 (transaction replay), they are currently not persisted there, because this is an optional setting. Turbo-geth is able to serve receipts even if they are not explicitely persisted, by re-computing them on the fly from the history. This method saves space, but has a peformance penalty. The users who need quicker access to receipts in exchange for extra disk space, can enable this stage. This will effectively replay all transactions again, but, unlike in the stage 4 (transaction replay), there is no generation of current state and the reverse diffs, therefore the process is faster.</span></li>
<li><span>Activate transaction pool. Before the state is synced and is accessible, there is no use of running the transaction pool logic, because for the security of the network, transactions should not be relayed unless the node can verify that there are no nonce gaps created by those transactions, and that the sender can afford to pay for gas. Activation of the transaction pool means downloading the currently active transactions from peers and initiating verification and relay.</span></li>
<li><span>Activate mining. This stage will only be activated when needed.</span></li>
<li><span>History pruning (likely to be split into multiple stages too)</span></li>
</ol><p><span>There might be more stages added in the future.</span></p><h2 id="Readiness-of-the-stages-and-an-alternative-plan" data-id="Readiness-of-the-stages-and-an-alternative-plan"><a class="anchor hidden-xs" href="#Readiness-of-the-stages-and-an-alternative-plan" title="Readiness-of-the-stages-and-an-alternative-plan"><span class="octicon octicon-link"></span></a><span>Readiness of the stages, and an alternative plan</span></h2><table>
<thead>
<tr>
<th><span>Stage</span></th>
<th><span>Readiness</span></th>
<th><span>Further work</span></th>
<th><span>Duration on Intel NUC8i7HNK up to block 10’677’851 on mainnet</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>1. Download block headers</span></td>
<td><span>WORKS</span></td>
<td></td>
<td><span>1h 40m</span></td>
</tr>
<tr>
<td><span>2. Index of block hashes to block numbers</span></td>
<td><span>WORKS</span></td>
<td></td>
<td><span>1m</span></td>
</tr>
<tr>
<td><span>3. Download block bodies</span></td>
<td><span>WORKS</span></td>
<td></td>
<td><span>5h 30m</span></td>
</tr>
<tr>
<td><span>4. Recover transaction senders</span></td>
<td><span>WORKS</span></td>
<td></td>
<td><span>4h 10m</span></td>
</tr>
<tr>
<td><span>5. Replay transactions</span></td>
<td><span>WORKS</span></td>
<td><span>Optimisations on high-latency devices</span></td>
<td><span>32h30m (with generating receipts), ? (without generating receipts)</span></td>
</tr>
<tr>
<td><span>6. Transform plain state to hashed state</span></td>
<td><span>WORKS</span></td>
<td><span>More efficient support for larger increments</span></td>
<td><span>1h 17m</span></td>
</tr>
<tr>
<td><span>7. Create or update intermediate state hashes</span></td>
<td><span>WORKS</span></td>
<td><span>More efficient support for larger increments</span></td>
<td><span>27m</span></td>
</tr>
<tr>
<td><span>8. Generate account history index</span></td>
<td><span>WORKS</span></td>
<td><span>Bitmap-based indices</span></td>
<td><span>55m</span></td>
</tr>
<tr>
<td><span>9. Generate contract storage history index</span></td>
<td><span>WORKS</span></td>
<td><span>Bitmap-based indices</span></td>
<td><span>1h 30m</span></td>
</tr>
<tr>
<td><span>10. Generate transaction lookup index</span></td>
<td><span>WORKS</span></td>
<td></td>
<td><span>2h30m</span></td>
</tr>
<tr>
<td><span>11. Activate transaction pool</span></td>
<td><span>More tests for transaction invalidation</span></td>
<td></td>
<td></td>
</tr>
<tr>
<td><span>12. Activate mining</span></td>
<td><span>NOT IN SCOPE for Release 1</span></td>
<td></td>
<td></td>
</tr>
<tr>
<td><span>13. Prune history (likely multiple stages)</span></td>
<td><span>NOT IN SCOPE for Release 1</span></td>
<td></td>
<td></td>
</tr>
</tbody>
</table><h2 id="Integration-with-evmone-via-EVMC" data-id="Integration-with-evmone-via-EVMC"><a class="anchor hidden-xs" href="#Integration-with-evmone-via-EVMC" title="Integration-with-evmone-via-EVMC"><span class="octicon octicon-link"></span></a><span>Integration with evmone via EVMC</span></h2><p><span>When experimenting with the staged sync (as described in the previous section), and decomposing the transaction execution into a separate stage, we finally saw something really “promising” in the CPU profile - EVM execution became the main bottleneck, followed by the golang garbage collector. In order to quickly reduce the allocations happening inside the built-in go-EVM, we decided to integrate evmone (</span><a href="https://github.com/ethereum/evmone" target="_blank" rel="noopener"><span>https://github.com/ethereum/evmone</span></a><span>), C++ implementation of EVM, and re-profile. This allowed us to see more clearly the allocation spots outside of EVM, and also get some experience with EVMC (C-interface to EMVs, </span><a href="https://github.com/ethereum/evmc" target="_blank" rel="noopener"><span>https://github.com/ethereum/evmc</span></a><span>) and evmone. At the moment, support for EVMC is experimental, because it still have serious performance limitation.</span></p><h2 id="LMDB-is-default-database-backend" data-id="LMDB-is-default-database-backend"><a class="anchor hidden-xs" href="#LMDB-is-default-database-backend" title="LMDB-is-default-database-backend"><span class="octicon octicon-link"></span></a><span>LMDB is default database backend</span></h2><p><span>For most of the history of turbo-geth, we used a modified version of boltDb as the primary database backend.</span><br>
<span>Then we have also started experimenting with LMDB. We managed to find a configuration in which our integration with LMDB performs on par with boltDb (our version). Long iterations perform better than with BoltDB. Turbo-geth now uses LMDB by default, which bolt available as an option. We had a preference for LMDB, because it is actively maintained unlike BoltDB, and it might be a good starting point for gradually migrating functionality from Go to C++. It is likely that we abandon boltDb in the near future.</span><br>
<span>More recently, we started to think that it might be possible to achieve reasonable performance on high-latency devices even with B+tree databases.</span></p><h2 id="Python-bindings-remote-DB-access-and-REST-API-daemon" data-id="Python-bindings-remote-DB-access-and-REST-API-daemon"><a class="anchor hidden-xs" href="#Python-bindings-remote-DB-access-and-REST-API-daemon" title="Python-bindings-remote-DB-access-and-REST-API-daemon"><span class="octicon octicon-link"></span></a><span>Python bindings, remote DB access, and REST API daemon</span></h2><p><span>Although JSON RPC API seems to be the prevalent way of accessing data stored in Ethereum nodes, often more flexibility is required.</span><br>
<span>Turbo-geth offers three other alternatives:</span></p><ol>
<li><span>LMDB python bindings. If you want to access the turbo-geth data from the same computer where turbo-geth process is running, you can use LDMB to open turbo-geth’s database in a read-only mode. Perhaps the easiest way to do that is via Python bindings: </span><a href="https://lmdb.readthedocs.io/en/release/" target="_blank" rel="noopener"><span>https://lmdb.readthedocs.io/en/release/</span></a><span>. This, of course, requires the knowledge of turbo-geth’s data model.</span></li>
<li><span>Remote interface to the database. For those who run turbo-geth on one computer, but some analytics software or other things that need turbo-geth’s data, there is remote DB access. It uses gRPC as transport, and its use requires the knowledge of the turbo-geth’s data model.</span></li>
<li><span>REST API daemon. Such daemon can be run on the same or a different computer from the turbo-geth node. REST API daemon accesses the live database of turbo-geth locally or remotely, via read-only interface. There can also be multiple daemons connected to the same turbo-geth node, which can help creating more cost effective infrastructure for some users. The REST API has only couple of functions at the moment, and it is not standardised in any way, but it is a useful platforms for users who want to get their hands dirty and create bespoke interfaces for their or their clients’ needs.</span></li>
</ol></div>
<div class="ui-toc dropup unselectable hidden-print" style="display:none;">
<div class="pull-right dropdown">
<a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
<i class="fa fa-bars"></i>
</a>
<ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
<div class="toc"><ul class="nav">
<li class=""><a href="#Towards-the-first-release-of-Turbo-geth" title="Towards the first release of Turbo-geth">Towards the first release of Turbo-geth</a><ul class="nav">
<li><a href="#When-is-it-going-to-be-ready" title="When is it going to be ready?">When is it going to be ready?</a></li>
<li><a href="#When-are-we-going-from-“alpha”-to-“beta”" title="When are we going from “alpha” to “beta”?">When are we going from “alpha” to “beta”?</a></li>
<li><a href="#Distribution" title="Distribution">Distribution</a></li>
<li><a href="#No-fast-sync-warp-sync-or-any-other-snapshot-sync" title="No fast sync, warp sync or any other snapshot sync">No fast sync, warp sync or any other snapshot sync</a></li>
<li><a href="#GPL-license" title="GPL license">GPL license</a></li>
<li><a href="#Licence-and-language-migration-plan-out-of-scope-for-the-release" title="Licence and language migration plan (out of scope for the release)">Licence and language migration plan (out of scope for the release)</a></li>
<li><a href="#Separation-of-JSON-RPC-and-future-of-architecture-during-migration" title="Separation of JSON RPC and future of architecture during migration">Separation of JSON RPC and future of architecture during migration</a></li>
<li><a href="#JSON-RPC-API" title="JSON RPC API">JSON RPC API</a></li>
<li><a href="#Testnet-support" title="Testnet support">Testnet support</a></li>
<li><a href="#Disk-space" title="Disk space">Disk space</a><ul class="nav">
<li><a href="#Two-state-buckets-and-no-preimages" title="Two state buckets and no preimages">Two state buckets and no preimages</a></li>
</ul>
</li>
<li><a href="#Staged-sync" title="Staged sync">Staged sync</a></li>
<li><a href="#Currently-envisaged-stages" title="Currently envisaged stages">Currently envisaged stages</a></li>
<li><a href="#Readiness-of-the-stages-and-an-alternative-plan" title="Readiness of the stages, and an alternative plan">Readiness of the stages, and an alternative plan</a></li>
<li><a href="#Integration-with-evmone-via-EVMC" title="Integration with evmone via EVMC">Integration with evmone via EVMC</a></li>
<li><a href="#LMDB-is-default-database-backend" title="LMDB is default database backend">LMDB is default database backend</a></li>
<li><a href="#Python-bindings-remote-DB-access-and-REST-API-daemon" title="Python bindings, remote DB access, and REST API daemon">Python bindings, remote DB access, and REST API daemon</a></li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
</ul>
</div>
</div>
<div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" null null>
<div class="toc"><ul class="nav">
<li class=""><a href="#Towards-the-first-release-of-Turbo-geth" title="Towards the first release of Turbo-geth">Towards the first release of Turbo-geth</a><ul class="nav">
<li><a href="#When-is-it-going-to-be-ready" title="When is it going to be ready?">When is it going to be ready?</a></li>
<li><a href="#When-are-we-going-from-“alpha”-to-“beta”" title="When are we going from “alpha” to “beta”?">When are we going from “alpha” to “beta”?</a></li>
<li><a href="#Distribution" title="Distribution">Distribution</a></li>
<li><a href="#No-fast-sync-warp-sync-or-any-other-snapshot-sync" title="No fast sync, warp sync or any other snapshot sync">No fast sync, warp sync or any other snapshot sync</a></li>
<li><a href="#GPL-license" title="GPL license">GPL license</a></li>
<li><a href="#Licence-and-language-migration-plan-out-of-scope-for-the-release" title="Licence and language migration plan (out of scope for the release)">Licence and language migration plan (out of scope for the release)</a></li>
<li><a href="#Separation-of-JSON-RPC-and-future-of-architecture-during-migration" title="Separation of JSON RPC and future of architecture during migration">Separation of JSON RPC and future of architecture during migration</a></li>
<li><a href="#JSON-RPC-API" title="JSON RPC API">JSON RPC API</a></li>
<li><a href="#Testnet-support" title="Testnet support">Testnet support</a></li>
<li><a href="#Disk-space" title="Disk space">Disk space</a><ul class="nav">
<li><a href="#Two-state-buckets-and-no-preimages" title="Two state buckets and no preimages">Two state buckets and no preimages</a></li>
</ul>
</li>
<li><a href="#Staged-sync" title="Staged sync">Staged sync</a></li>
<li><a href="#Currently-envisaged-stages" title="Currently envisaged stages">Currently envisaged stages</a></li>
<li><a href="#Readiness-of-the-stages-and-an-alternative-plan" title="Readiness of the stages, and an alternative plan">Readiness of the stages, and an alternative plan</a></li>
<li><a href="#Integration-with-evmone-via-EVMC" title="Integration with evmone via EVMC">Integration with evmone via EVMC</a></li>
<li><a href="#LMDB-is-default-database-backend" title="LMDB is default database backend">LMDB is default database backend</a></li>
<li><a href="#Python-bindings-remote-DB-access-and-REST-API-daemon" title="Python bindings, remote DB access, and REST API daemon">Python bindings, remote DB access, and REST API daemon</a></li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
<script>
var markdown = $(".markdown-body");
//smooth all hash trigger scrolling
function smoothHashScroll() {
var hashElements = $("a[href^='#']").toArray();
for (var i = 0; i < hashElements.length; i++) {
var element = hashElements[i];
var $element = $(element);
var hash = element.hash;
if (hash) {
$element.on('click', function (e) {
// store hash
var hash = this.hash;
if ($(hash).length <= 0) return;
// prevent default anchor click behavior
e.preventDefault();
// animate
$('body, html').stop(true, true).animate({
scrollTop: $(hash).offset().top
}, 100, "linear", function () {
// when done, add hash to url
// (default click behaviour)
window.location.hash = hash;
});
});
}
}
}
smoothHashScroll();
var toc = $('.ui-toc');
var tocAffix = $('.ui-affix-toc');
var tocDropdown = $('.ui-toc-dropdown');
//toc
tocDropdown.click(function (e) {
e.stopPropagation();
});
var enoughForAffixToc = true;
function generateScrollspy() {
$(document.body).scrollspy({
target: ''
});
$(document.body).scrollspy('refresh');
if (enoughForAffixToc) {
toc.hide();
tocAffix.show();
} else {
tocAffix.hide();
toc.show();
}
$(document.body).scroll();
}
function windowResize() {
//toc right
var paddingRight = parseFloat(markdown.css('padding-right'));
var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
toc.css('right', right + 'px');
//affix toc left
var newbool;
var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
//for ipad or wider device
if (rightMargin >= 133) {
newbool = true;
var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
tocAffix.css('left', left + 'px');
} else {
newbool = false;
}
if (newbool != enoughForAffixToc) {
enoughForAffixToc = newbool;
generateScrollspy();
}
}
$(window).resize(function () {
windowResize();
});
$(document).ready(function () {
windowResize();
generateScrollspy();
});
//remove hash
function removeHash() {
window.location.hash = '';
}
var backtotop = $('.back-to-top');
var gotobottom = $('.go-to-bottom');
backtotop.click(function (e) {
e.preventDefault();
e.stopPropagation();
if (scrollToTop)
scrollToTop();
removeHash();
});
gotobottom.click(function (e) {
e.preventDefault();
e.stopPropagation();
if (scrollToBottom)
scrollToBottom();
removeHash();
});
var toggle = $('.expand-toggle');
var tocExpand = false;
checkExpandToggle();
toggle.click(function (e) {
e.preventDefault();
e.stopPropagation();
tocExpand = !tocExpand;
checkExpandToggle();
})
function checkExpandToggle () {
var toc = $('.ui-toc-dropdown .toc');
var toggle = $('.expand-toggle');
if (!tocExpand) {
toc.removeClass('expand');
toggle.text('Expand all');
} else {
toc.addClass('expand');
toggle.text('Collapse all');
}
}
function scrollToTop() {
$('body, html').stop(true, true).animate({
scrollTop: 0
}, 100, "linear");
}
function scrollToBottom() {
$('body, html').stop(true, true).animate({
scrollTop: $(document.body)[0].scrollHeight
}, 100, "linear");
}
</script>
</body>
</html>