<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>블로그</title>
    <link>https://yuoa.tistory.com/</link>
    <description>지곡산 공대생 당도 최고</description>
    <language>ko</language>
    <pubDate>Sat, 16 May 2026 07:14:42 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>실토</managingEditor>
    <image>
      <title>블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/3020358/attach/db87774d11c0408db38991af93cfb91a</url>
      <link>https://yuoa.tistory.com</link>
    </image>
    <item>
      <title>인공지능과 무선 통신, CSI를 중심으로</title>
      <link>https://yuoa.tistory.com/entry/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5%EA%B3%BC-%EB%AC%B4%EC%84%A0-%ED%86%B5%EC%8B%A0-CSI%EB%A5%BC-%EC%A4%91%EC%8B%AC%EC%9C%BC%EB%A1%9C</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;고도로 발달한 무선 통신은 시각 처리와 구별할 수 없다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 2021년 5월 진행된 POSTECH TechReview 세미나에서 이어져 7월에 투고한 원고의 줄이기 전 원본입니다. 이 분야를 완전히 모르는 사람을 대상으로 풀어쓰려고 노력하다 보니 학술적 비약도 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;현대 네트워크 기술의 데이터 처리 속도는 굉장히 빠릅니다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경에 따라 성능 차이가 큰 무선 네트워크도 이제는 유선과 동등한 수준의 속도를 추구하고 있습니다. 하지만 AI 기술은 아직 네트워크만큼 빠르게 동작하지 않기 때문에 네트워킹 과정에 AI를 더하여 성능 향상을 꾀하는 것은 현실적으로 아직 먼 이야기입니다. 더군다나 모바일 네트워킹에서는 제한된 배터리로 동작하는 모바일 디바이스와의 상호작용이 주가 되기에 고전력&amp;middot;고성능 연산이 필요한 현대 AI 기술과의 결합은 아직 요원합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 무선 통신 과정에서 AI로 해결할 수 있는 것이 무엇인지는 명확히 알 수 있었고, 학자들은 그 문제에 대해 연구하기 시작했습니다. 그리고 그 결실로 오늘날에는 기존 무선 통신 기술과 비슷하거나 더 높은 성능을 보인 기계 학습 기반 논문이 상당수 나오고 있습니다. 물론 아직 상용화까지는 많이 남았지만요. 또, AI를 위해 데이터를 모으다 보면 고성능 무선 통신을 위해 개발했지만 새로운 방향으로의 기술 활용을 발견하게 되는 경우도 생깁니다. 이번 테크리뷰 세미나에서는 이와 관련해 어떤 일들이 벌어지고 있는지 살펴보았는데, 이 글에서는 그 중 CSI와 그 활용을 중심으로 일부를 싣고자 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고 : 요즘 시대 무선 통신 기술의 지향점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;다소 동떨어진 내용이라 접어놓습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;무선 통신 기술은 크게 두 가지 분야의 기술의 결합인데, 각각 물리(PHY) 계층과 MAC 계층이라고 합니다. 물리 계층은 실제 1010101... 데이터를 어떻게 전기 신호로 변환하고 송&amp;middot;수신할지에 관한 기술, MAC 계층은 신호 전달의 매질을 여러 장치가 공유할 때 어떻게 서로 순서를 정해서 겹치지 않게 통신할지에 관한 기술입니다. 물리 계층 기술이 발달하면 더 많은 데이터를 빠르게 주고받을 수 있게 되고, 그에 맞추어 MAC 계층 기술이 효율적인 프로토콜을 제시하게 되는 것이죠. 이러한 발전의 현황과 지향점은 ITU-R&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_1&quot; id=&quot;footnote_link_55_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;에서 공표하는 IMT&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_2&quot; id=&quot;footnote_link_55_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt; 시나리오를 보면 알 수 있습니다. 가장 최근에 발표된 것은 IMT-2020인데, 여기서는 '이 정도는 되어야 5G 기술이라 부를 수 있다'는 최소 요구 시나리오 세가지를 &lt;/span&gt;&lt;span&gt;명세하고 있습니다. 먼저 eMBB&lt;span&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_3&quot; id=&quot;footnote_link_55_3&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 3)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 3)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;3&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt; 시나리오에서는 안정적인 상황에서 20Gb/s의 통신 속도를 요구하고, URLLC&lt;span&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_4&quot; id=&quot;footnote_link_55_4&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 4)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 4)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;4&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt; 시나리오에서는 일반적인 상황에서 통신 지연 1ms 이하와 기지국 전환으로 인한 지연 0ms 이하를 요구합니다. 또 mMTC&lt;span&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_5&quot; id=&quot;footnote_link_55_5&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 5)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 5)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;5&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt; 시나리오에서는 제곱킬로미터당 백만 개의 디바이스가 있는 초고밀도 환경에 대응하기를 요구하고 있습니다. 이 세가지 시나리오를 모두 성공적으로 완수할 수 있어야 기술적으로 진정한 '5G'가 되는 것이죠.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;1435&quot; data-filename=&quot;그림3.png&quot; width=&quot;157&quot; height=&quot;174&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RIGXL/btraoBphYm1/FpohEVKVn1uF86RSSDrpB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RIGXL/btraoBphYm1/FpohEVKVn1uF86RSSDrpB1/img.png&quot; data-alt=&quot;ITU 로고&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RIGXL/btraoBphYm1/FpohEVKVn1uF86RSSDrpB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRIGXL%2FbtraoBphYm1%2FFpohEVKVn1uF86RSSDrpB1%2Fimg.png&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;1435&quot; data-filename=&quot;그림3.png&quot; width=&quot;157&quot; height=&quot;174&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ITU 로고&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;신호 전송의 원리와 채널&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신호의 전달은 미리 정해둔 주파수 대역에서 이루어집니다. 이 주파수 대역은 반송파(Carrier Frequency)라고 하는데, 현재는 그 대역을 서로 간섭이 없는 간격으로 더 잘게 쪼갠 부반송파(Subcarrier Frequency)에서 각기 다른 정보를 전달하는 방식으로 더 많은 정보를 전달하는 OFDM 기법을 이용합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2596&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;1217&quot; data-filename=&quot;그림6.png&quot; width=&quot;764&quot; height=&quot;358&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/569aH/btraoChqNal/X3xm8wZhgOukwOlZe0yRCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/569aH/btraoChqNal/X3xm8wZhgOukwOlZe0yRCK/img.png&quot; data-alt=&quot;OFDM(Orthogonal Frequency Division Multiplexing) 개념도. 각 부반송파에서 하나의 QAM 신호를 충분히 해석할 수 있는 시간동안 전송하는 높은 주파수 효율의 기법이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/569aH/btraoChqNal/X3xm8wZhgOukwOlZe0yRCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F569aH%2FbtraoChqNal%2FX3xm8wZhgOukwOlZe0yRCK%2Fimg.png&quot; data-origin-width=&quot;2596&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;1217&quot; data-filename=&quot;그림6.png&quot; width=&quot;764&quot; height=&quot;358&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;OFDM(Orthogonal Frequency Division Multiplexing) 개념도. 각 부반송파에서 하나의 QAM 신호를 충분히 해석할 수 있는 시간동안 전송하는 높은 주파수 효율의 기법이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, OFDM에서는 각 부반송파마다 다른 비트열(1010101...)을 적당히 신호로 나타내서 동시에 전송하는 것이죠. 여기서 '적당히 신호로 나타내는' 방법은 QAM을 주로 사용합니다. 신호 좌표 상에 점을 찍고, 미리 각 점이 의미하는 데이터를 00, 01, 10, 11과 같이 정해두는 방식입니다. 점을 더 잘게 찍을수록 더 많은 비트를 한번에 전송해서 더욱 전송 속도를 높일 수 있습니다. 하지만 여기서 우리는 '채널'을 고려해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;3474&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;670&quot; data-filename=&quot;그림4.png&quot; width=&quot;844&quot; height=&quot;163&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnMTwH/btraoaFl3EB/dIveK13sc9GHFa1Uf0hRs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnMTwH/btraoaFl3EB/dIveK13sc9GHFa1Uf0hRs0/img.png&quot; data-alt=&quot;QAM(Quadrature Amplitude Modulation) 신호 종류. 위 신호는 모두 같은 시간동안 전송되므로, 오른쪽으로 갈수록 식별은 어렵지만 더 많은 양을 전송할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnMTwH/btraoaFl3EB/dIveK13sc9GHFa1Uf0hRs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnMTwH%2FbtraoaFl3EB%2FdIveK13sc9GHFa1Uf0hRs0%2Fimg.png&quot; data-origin-width=&quot;3474&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;670&quot; data-filename=&quot;그림4.png&quot; width=&quot;844&quot; height=&quot;163&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;QAM(Quadrature Amplitude Modulation) 신호 종류. 위 신호는 모두 같은 시간동안 전송되므로, 오른쪽으로 갈수록 식별은 어렵지만 더 많은 양을 전송할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유선과 다르게 무선 신호는 선을 따라 전송되는 것이 아닙니다. 현재 대부분의 안테나는 '무지향성'이라 해서, 특정 방향을 목적으로 하는 것이 아닌 방사형으로 신호를 전파합니다. 그러다보니 신호를 받는 쪽에서 그걸 들을 때는 이리저리 반사되고 각종 벽이나 기물을 투과하며 중첩되고 왜곡된 신호가 들리게 됩니다. 이러한 신호 전달 환경을 우리는 &quot;채널(Channel)&quot;이라 부릅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2974&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;825&quot; data-filename=&quot;그림7.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKKmb5/btraiF1a0ou/8FvuIfk49u7Bgk7GLD202k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKKmb5/btraiF1a0ou/8FvuIfk49u7Bgk7GLD202k/img.png&quot; data-alt=&quot;채널(Channel) 개념도. 신호가 걸어가는 사람이라면, 채널은 인도라고 볼 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKKmb5/btraiF1a0ou/8FvuIfk49u7Bgk7GLD202k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKKmb5%2FbtraiF1a0ou%2F8FvuIfk49u7Bgk7GLD202k%2Fimg.png&quot; data-origin-width=&quot;2974&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;825&quot; data-filename=&quot;그림7.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;채널(Channel) 개념도. 신호가 걸어가는 사람이라면, 채널은 인도라고 볼 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 채널의 상태를 숫자로 나타낸 것을 '채널 상태 정보(Channel State Information)', CSI라고 합니다. CSI가 포함하는 정보는 두 가지 &amp;lt;진폭 감쇠&amp;gt; 정도와 &amp;lt;위상 이동&amp;gt; 정도입니다. 아까 신호 좌표 상에 점을 찍어서 정보를 나타낸다고 했는데, 여기서 보낸 신호와 받은 신호 간의 차이를 아래 그림처럼 극좌표계로 해석했을 때 각도의 변화가 위상 이동 정도, 반경의 변화가 진폭 감쇠 정도이고, 보통 복소수를 사용하여 수치화합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2926&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;697&quot; data-filename=&quot;그림11.png&quot; width=&quot;743&quot; height=&quot;177&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ym91D/btramg0FlU7/RFcFWtYYPwIypyhCcPhEI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ym91D/btramg0FlU7/RFcFWtYYPwIypyhCcPhEI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ym91D/btramg0FlU7/RFcFWtYYPwIypyhCcPhEI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYm91D%2Fbtramg0FlU7%2FRFcFWtYYPwIypyhCcPhEI0%2Fimg.png&quot; data-origin-width=&quot;2926&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;697&quot; data-filename=&quot;그림11.png&quot; width=&quot;743&quot; height=&quot;177&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채널은 주파수마다 달라지므로, CSI도 주파수마다 달라지게 됩니다. 만약 채널을 정확하게 안다면 어떻게 원본 신호가 변형되어 여기까지 왔는지 아는 것과 마찬가지이므로, 왜곡된 신호를 원본 신호로 복원할 수 있습니다. 채널 측정 방법은 일반적으로 미리 약속한 신호를 송신하고 수신 측에서 원래 찍혀야 할 점 위치에서 얼마나 벗어나는지를 측정하는 방식으로 이루어집니다. 여러분이 잘 알고 있는 Wi-Fi, 5G도 이러한 방식으로 채널을 추정하고 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;신호를 해석하는 AI : 심층 신경망을 활용한 채널 추정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 주파수 안에서 우리는 데이터도 보내야 하고, 정확한 데이터 왜곡 복구를 위해 채널 측정도 해야 합니다. 항상 채널 측정만 할 수 없고, 항상 데이터 교환만 할 수도 없습니다. 그러다보니 일정 기간동안 채널을 측정하지 않을 때가 생기는데, 이 때 알고 있는 채널 상태와 실제 채널 상태가 달라 정확한 원본 신호 복구가 이루어지지 않습니다. 여기서는 AI 기술 중 하나인 초해상화(Super-Resolution)를 사용해볼 수 있습니다. 초해상화를 간단히 말하자면 CNN 학습을 통해 저해상도 이미지를 고해상도 이미지로 변환하는 기법입니다. 기존 CSI의 측정은 띄엄띄엄 이루어지므로 저해상도라 할 수 있는데, 이를 CNN 변환을 통해 고해상도로 측정된 CSI로 변환하여 더 정확한 채널 추정을 해볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;468&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;226&quot; width=&quot;588&quot; height=&quot;284&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mHhEJ/btrao7nYib2/LU1DTvejSXPpxkZTR6kQW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mHhEJ/btrao7nYib2/LU1DTvejSXPpxkZTR6kQW0/img.png&quot; data-alt=&quot;The Pipeline for DL-based Channel Estimation&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mHhEJ/btrao7nYib2/LU1DTvejSXPpxkZTR6kQW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmHhEJ%2Fbtrao7nYib2%2FLU1DTvejSXPpxkZTR6kQW0%2Fimg.png&quot; data-origin-width=&quot;468&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;226&quot; width=&quot;588&quot; height=&quot;284&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;The Pipeline for DL-based Channel Estimation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 비전 처리 계열 기술을 통해 고해상도로 복원한 CSI를 기반으로 더욱 정확하게 원본 신호를 복구하고, 그것을 바탕으로 데이터를 해석하면 정보 전달 오류 또한 줄어들게 됩니다. 레퍼런스 논문&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_6&quot; id=&quot;footnote_link_55_6&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 6)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 6)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;6&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;의 시뮬레이션에서는 48개 주파수에서 알고 있는 신호를 쏘고, 72개의 주파수에 대해 채널 추정 오류를 측정했는데, 그 결과는 아래와 같았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-origin-width=&quot;527&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;361&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxCLv0/btrakSMEUFk/LF4HSDJMKA2yGyPYUTlQDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxCLv0/btrakSMEUFk/LF4HSDJMKA2yGyPYUTlQDK/img.png&quot; data-alt=&quot;Channel Estimation MSE at SUI5 Channel Model&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxCLv0/btrakSMEUFk/LF4HSDJMKA2yGyPYUTlQDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxCLv0%2FbtrakSMEUFk%2FLF4HSDJMKA2yGyPYUTlQDK%2Fimg.png&quot; data-origin-width=&quot;527&quot; style=&quot;margin: 20px 0;&quot; data-origin-height=&quot;361&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Channel Estimation MSE at SUI5 Channel Model&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #00ff00;&quot;&gt;&lt;b&gt;Ideal MMSE&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;모든 주파수의 채널 상태를 알 때&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Estimated MMSE&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;일반적인 채널 추정 기법 사용&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ideal ALMMSE&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;모든 주파수의 채널 상태를 알 때, 연산량이 적은 또 다른 채널 추정 기법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Deep Low-SNR&lt;/b&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;안 좋은 채널을 복구하도록 학습한 SRCNN&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Deep High-SNR&lt;/b&gt;나쁘지 않은 채널을 복구하도록 학습한 SRCNN&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 컴퓨팅 파워를 조금 더 들여 인공 지능 연산을 수행하면 더욱 많은 정보를 빠르고 안정적으로 보낼 수 있게 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;신호를 눈처럼 사용하는 AI : CSI 기반의 동작 인식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 CSI의 조금 재미있는 활용에 대해 알아보겠습니다. 동작 인식이라고 하면 웨어러블 디바이스나 카메라를 이용한 것이 먼저 떠오르는데, CSI를 활용한 동작 인식이라니. 기존의 방식과 다르게 CSI 기반의 동작 인식은 개인 정보 문제, 보이는 곳이어야 한다거나 착용해야만 한다는 전제 조건, 따로 디바이스를 구매해야한다는 단점이 없습니다. CSI는 여러분 집에 있을 무선 공유기에서 이미 계산하고 있는 정보이기 때문이죠. CSI에는 신호의 전파 과정에서 일어나는 여러 왜곡이 나타나는데, 이 중에는 사람의 동작에 따른 왜곡도 포함되어 있습니다. 즉, 이를 심층 신경망을 통해 학습한다면 사람의 동작을 분류할 수 있는 것이죠. 연구 단계에서 이 기술을 사용한 사례는 아래와 같이 다양합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CSI 기반 화재 감지&lt;/b&gt; : Zhong, S., Huang, Y., Ruby, R., Wang, L., Qiu, Y. X., &amp;amp; Wu, K. (2017, May). Wi-fire: Device-free fire detection using WiFi networks. In 2017 IEEE International Conference on Communications (ICC) (pp. 1-6). IEEE.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CSI 기반 실내 측위&lt;/b&gt; : Wang, X., Gao, L., Mao, S., &amp;amp; Pandey, S. (2016). CSI-based fingerprinting for indoor localization: A deep learning approach. IEEE Transactions on Vehicular Technology, 66(1), 763-776.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CSI 기반 호흡 감지&lt;/b&gt; : Wang, X., Yang, C., &amp;amp; Mao, S. (2020). On CSI-based vital sign monitoring using commodity WiFi. ACM Transactions on Computing for Healthcare, 1(3), 1-27.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CSI 기반 수화 인식&lt;/b&gt; : Ma, Y., Zhou, G., Wang, S., Zhao, H., &amp;amp; Jung, W. (2018). Signfi: Sign language recognition using wifi. Proceedings of the ACM on Interactive, Mobile, Wearable and Ubiquitous Technologies, 2(1), 1-21.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 상용 솔루션을 완성하기 위해 많은 사람들이 연구 중에 있는데, 앞으로 CSI 기반의 동작 인식 기술이 나아갈 방향을 소개하자면 이렇습니다. 신호가 송신 안테나에서 방사형으로 퍼지면 수신 안테나에서는 여러 경로를 통해 도달한 신호가 겹쳐져서 수신되는데, 이를 경로마다 각각 분리할 수 있다면 각 경로에 있는 사람들의 동작을 각각 인식할 수 있겠죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;3521&quot; data-origin-height=&quot;701&quot; style=&quot;margin: 20px 0;&quot; data-filename=&quot;그림12.png&quot; width=&quot;769&quot; height=&quot;153&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BNOCH/btraoaFnfvb/SPtJEyoRPOtNmRPuYH2wT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BNOCH/btraoaFnfvb/SPtJEyoRPOtNmRPuYH2wT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BNOCH/btraoaFnfvb/SPtJEyoRPOtNmRPuYH2wT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBNOCH%2FbtraoaFnfvb%2FSPtJEyoRPOtNmRPuYH2wT0%2Fimg.png&quot; data-origin-width=&quot;3521&quot; data-origin-height=&quot;701&quot; style=&quot;margin: 20px 0;&quot; data-filename=&quot;그림12.png&quot; width=&quot;769&quot; height=&quot;153&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, 현재 개발 중인 전이중(Full-Duplex) 통신 기술을 활용해 볼 수 있습니다. 현재는 반이중(Half-Duplex) 통신을 사용해 LTE, 5G, Wi-Fi, Blue-tooth 등 통신이 이루어집니다. 반이중 통신은 한 채널에서 양방향(Duplex) 통신을 하지만 한번에 보내거나 받는 것 둘 중 하나만 할 수 있는 것을 의미하는데&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_7&quot; id=&quot;footnote_link_55_7&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 7)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 7)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;7&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;, 이 때문에 현재 CSI를 측정하기 위해서는 신호를 보내는 측과 받는 측이 별개로 필요합니다. 전이중 통신을 위해서는 자신의 송신 안테나에서 보내지고 있는 신호가 바로 수신 안테나로 흘러들어오는 것을 방지하는 노이즈 캔슬링과 같은 기술(SIC&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_55_8&quot; id=&quot;footnote_link_55_8&quot; onmouseover=&quot;tistoryFootnote.show(this, 55, 8)&quot; onmouseout=&quot;tistoryFootnote.hide(55, 8)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;8&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;)이 필요한데, 이는 아직 활발히 개발되고 있으며 아직 상용 제품에 적용되지 않았습니다. 만일 전이중 통신을 기술이 사용 가능해지면 공유기 하나만 설치하여 자신의 신호가 반사되어 돌아오는 것을 측정하고, 그것에서 CSI를 계산함으로써 혼자서도 동작 인식을 할 수 있게 되겠죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 CSI 기반의 활용을 통해 통신 뿐 아니라 마치 카메라처럼 작동하는 동작 인식 분야로까지의 확장이 가능하다는 것을 알아보았습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 무선 통신 분야의 일부분인 CSI와 그 연관 기술에 대해 알아보았습니다. CSI 기반 기술은 무선 네트워크 자체의 성능을 높일 뿐 아니라 독거 노인의 낙상 여부 감지, 움직임 감지를 기반으로 한 방범 기능 등 다양한 분야로의 적용이 가능하다는 점에서 굉장히 흥미로운 기술입니다. CSI 기술과 그 발전상을 바라보면 마치 비전 기술을 따라가고 있는 것처럼, 마치 저해상도 CCTV를 효율적으로 이용하는 기술을 개발하는 것처럼 느껴집니다. 여러분도 느껴지시나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무선 통신 분야는 사전 지식이 많이 필요한 분야입니다. 유선 컴퓨터 네트워크 지식을 모두 알고있다는 전제 하에 많은 이론이 전개되기에 컴퓨터 네트워킹도 충분히 알고있어야 하며, 정보 전달에 있어서 '무선'이라는 불안정 요소가 크기 때문에 전자기학적 지식도 알아야 합니다. 분야가 깊다는 것은 다른 의미로는 '쉽게 따라잡히지 않는다'고도 할 수 있습니다. 만일 여러분이 무선 네트워크의 세계에 빠져 연구를 한다거나 기술 창업을 하게 된다면 분명 그 누구도 쉽게 카피할 수 없을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;End of Document&lt;/i&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_55_1&quot;&gt;ITU-R : International Telecommunication Union Radiocommunication Sector &lt;a href=&quot;#footnote_link_55_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_55_2&quot;&gt;IMT : International Mobile Telecom&lt;span&gt; &lt;a href=&quot;#footnote_link_55_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_55_3&quot;&gt;eMBB : enhanced Mobile Broadband&lt;/span&gt;&lt;span&gt; &lt;a href=&quot;#footnote_link_55_3&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_55_4&quot;&gt;URLLC : Ultra-Reliable &amp;amp; Low-Latency Communications&lt;/span&gt;&lt;span&gt; &lt;a href=&quot;#footnote_link_55_4&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_55_5&quot;&gt;mMTC : massive Machine Type Communications&lt;/span&gt;&lt;span&gt; &lt;a href=&quot;#footnote_link_55_5&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_55_6&quot;&gt;M. Soltani, V. Pourahmadi, A. Mirzaei and H. Sheikhzadeh, &quot;Deep Learning-Based Channel Estimation,&quot; in IEEE Communications Letters, vol. 23, no. 4, pp. 652-655, April 2019, doi: 10.1109/LCOMM.2019.2898944. &lt;a href=&quot;#footnote_link_55_6&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_55_7&quot;&gt;휴대폰 상단바 아이콘에서는 업로드/다운로드 화살표가 동시에 뜨는 표현이 있는데, 셀룰러 통신의 경우 이론적으로 업로드/다운로드가 다른 채널을 사용하기 때문에 반이중 통신이더라도 동시에 업로드/다운로드가 이루어질 수 있습니다. &lt;a href=&quot;#footnote_link_55_7&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_55_8&quot;&gt;Self-Interference Cancellation &lt;a href=&quot;#footnote_link_55_8&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>무선 네트워크/Channel State Information</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/55</guid>
      <comments>https://yuoa.tistory.com/entry/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5%EA%B3%BC-%EB%AC%B4%EC%84%A0-%ED%86%B5%EC%8B%A0-CSI%EB%A5%BC-%EC%A4%91%EC%8B%AC%EC%9C%BC%EB%A1%9C#entry55comment</comments>
      <pubDate>Fri, 23 Jul 2021 18:39:23 +0900</pubDate>
    </item>
    <item>
      <title>md-Track</title>
      <link>https://yuoa.tistory.com/entry/md-Track</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Leveraging Multi-Dimensionality in Passive Indoor Wi-Fi Tracking&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;2020년 9월 쯤에 랩 선배 추천으로 읽은 논문인데, 일정에 쫓겨 정리를 하다 말았음에도 그냥 지우자니 아까워서 부분이나마 블로그에 올려 본다.&lt;/i&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원문 : Xie, Yaxiong, Jie, Xiong, Mo, Li, and Kyle, Jamieson. &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3300061.3300133&quot;&gt;&quot;MD-Track: Leveraging Multi-Dimensionality for Passive Indoor Wi-Fi Tracking.&quot;&lt;/a&gt; In &lt;i&gt;The 25th Annual International Conference on Mobile Computing and Networking&lt;/i&gt;. Association for Computing Machinery, 2019.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이 논문에서는 뭘 하는가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광대역폭이나 대형 안테나 배열이 없어도 다차원 시그널을 잘 분해하는 시스템 &quot;mD-Track&quot;을 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dl.acm.org/doi/10.1145/2829988.2787487&quot;&gt;SpotFi&lt;/a&gt;와 비교했을 때 약 3.5배의 성능 차이를 보였다고 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무선 채널 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 건 신호 전파에서 각 Multipath 성분의 파라미터를 얼마나 &lt;i&gt;정확히&lt;/i&gt; 얻어내느냐가 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;경로 성분의 파라미터&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터의 종류는 크게 4가지가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ToF ($\mathbf{\tau}$)&lt;/b&gt;. 이것과 Tx-Rx 사이의 길이를 알면 해당 신호의 전파 경로의 범위를 타원형으로 한정지을 수 있다. &lt;a href=&quot;https://blog.wldh.org/entry/Precise-Power-Delay-Profiling-with-Commodity-Wi-Fi&quot;&gt;이 논문&lt;/a&gt;에 따르면 ToF의 해상도는 채널 대역폭에 비례한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AoA ($\mathbf{\phi}$), AoD ($\mathbf{\varphi}$)&lt;/b&gt;. 얘네들은 Tx/Rx의 안테나가 많을 수록 해상도가 높아진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Doppler Shift ($\mathbf{\gamma}$)&lt;/b&gt;. Tx, Rx 혹은 전파가 반사된 물체 그 어느 하나라도 상대적으로 움직임이 있다면 도플러 효과에 의한 주파수 변화가 발생한다. 이 파라미터는 관찰 간격이 클수록 더욱 정밀한 값을 얻을 수 있다고 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Complex attenuation ($\mathbf{\alpha}$)&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;경로 전파 모델&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tx 안테나 $N$개, Rx 안테나 $M$개가 각자 $d$의 간격으로 배치되어 있다고 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안테나 별 발신 신호 : $U(t)=[u_1(t), u_2(t), \cdots, u_N(t)]^T$ [^0]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[^0]: 논문에서 Transpose는 되어있지 않지만 아래 식과 아귀가 맞기 위해서 $U$는 Column Vector여야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수신단에 도달하는 신호 : $s(t;v)=\alpha e^{j2\pi\gamma t}c(\phi)g(\varphi)^TU(t-\tau),\quad v=[\phi, \varphi, \tau, \gamma, \alpha]^T$
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$g(\varphi)$ : $N$-element transmit array steering vector. $N$개의 안테나에서 나오는 신호 사이의 Phase 관계.&lt;/li&gt;
&lt;li&gt;$c(\phi)$ : $M$-element receive array steering vector. $M$개의 안테나에서 수신한 신호 사이의 Phase 관계.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;2222&quot; data-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k3ju4/btq8UdcvQk4/gqgRTIjkIoQRfYgIR2JWy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k3ju4/btq8UdcvQk4/gqgRTIjkIoQRfYgIR2JWy0/img.png&quot; data-alt=&quot;Example: steering vector of receive antenna array&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k3ju4/btq8UdcvQk4/gqgRTIjkIoQRfYgIR2JWy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk3ju4%2Fbtq8UdcvQk4%2FgqgRTIjkIoQRfYgIR2JWy0%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;2222&quot; data-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Example: steering vector of receive antenna array&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안테나 별 수신 신호 : $y(t)=s(t)_{M\times 1}+W(t)_{M\times 1}$
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$W(t)=[w_1(t), w_2(t), \cdots, w_M(t)]^T$ : $M$차원 가우시안 노이즈&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;파라미터 추정하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;경로 하나의 파라미터 추출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tx-Rx 사이에 Singlepath만이 존재하고, Phase Offset이 없는 완벽한 트랜시버가 구비되어 있다고 하자. Multipath와 Phase Offset은 뒤에서 고려할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터를 구하기 위해서는 가장 먼저 Channel State를 구해야 한다. Tx 안테나 2개와 Rx 안테나 2개가 있을 때 서브캐리어 $k$의 채널은 다음과 같이 나타낼 수 있다[^a] [^b].&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[^a]: 논문에서는 이 부분에서 서브캐리어 수를 $N$이라고 하는데, Tx 안테나 수와 헷갈릴 수 있으므로 이 글에서는 논문 Figure 7에 나온 대로 $F$라고 서술한다.&lt;br /&gt;[^b]: 또한 논문에서 $H$와 $h$에 대해 Notation 자체가 틀린 부분도 있고 헷갈리게 되어 있는데, 이 글에서는 $H$를 아래 식과 같이, 그리고 $h$에 대해서는 $h_{ij,k}$로 통일하여 바로잡아 서술한다. $i$는 Tx 안테나 인덱스, $j$는 Rx 안테나 인덱스, $k$는 서브캐리어 인덱스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$H_k=\left[\begin{matrix}h_{11,k} &amp;amp; h_{12,k} \ h_{21,k} &amp;amp; h_{22,k}\end{matrix}\right],\quad k=[1,2,\cdots,F]$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금부터 이 $h$들을 LTF의 특성과 수신한 LTF 구간의 신호 $\textbf{x}$를 이용해서 구할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;802.11n에서 MIMO를 사용하면 각 안테나를 구분하기 위한 목적으로 LTF를 나열할 때 Mapping Matrix $P_{HT-LTF}$를 곱하게 되는데[^1] [^2], 여기서는 Tx 안테나가 두 개이고 LTF가 2번 오므로, 아래처럼 좌상단 $2\times 2$를 잘라서 사용하게 된다[^3].&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[^1]: 논문에서는 갑작스런 신호 레벨 증가를 막기 위해서라고 하는데, 딱히 이 말은 그다지 이해가 가지 않는다. Tx 안테나를 구분하여 이용하기 위한 목적이라고 보는게 훨씬 맞다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[^2]: 논문에서는 $P_{HTLTF}$라고 되어 있고, 실제 옛날 표준에서 도 그렇게 칭했으나, 최신 표준에서는 $P_{HT-LTF}$로 표기가 변경되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[^3]: $N_{TX}$, 그리고 2개의 LTF 필드가 존재하는 이유와 관련해서는 802.11-2016 19.3.13.1에 자세히 설명되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$P_{HT-LTF}=\left[\begin{matrix}1 &amp;amp; -1 &amp;amp; 1 &amp;amp; 1 \ 1 &amp;amp; 1 &amp;amp; -1 &amp;amp; 1 \ 1 &amp;amp; 1 &amp;amp; 1 &amp;amp; -1 \ -1 &amp;amp; 1 &amp;amp; 1 &amp;amp; 1\end{matrix}\right]\Rightarrow\left[\begin{matrix}1 &amp;amp; -1 \ 1 &amp;amp; 1\end{matrix}\right]$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 안테나 별 Tx 안테나에서 전송되는 LTF와 $P_{HT-LTF}$의 곱 $P_{HT-LTF}\times \text{LTF}$의 IFFT를 시간축 그림으로 나타내면 아래와 같다. $P\times \text{LTF}$는 주파수 영역임을 기억하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;500&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;191&quot; height=&quot;102&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LkeDP/btq8R1cPMpo/oG90LCWPxcfsGY0nKlQwA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LkeDP/btq8R1cPMpo/oG90LCWPxcfsGY0nKlQwA1/img.png&quot; data-alt=&quot;802.11n Preamble&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LkeDP/btq8R1cPMpo/oG90LCWPxcfsGY0nKlQwA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLkeDP%2Fbtq8R1cPMpo%2FoG90LCWPxcfsGY0nKlQwA1%2Fimg.png&quot; width=&quot;500&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;191&quot; height=&quot;102&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;802.11n Preamble&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림대로 두 신호를 두 안테나가 동시에 발신했을 때, 수신 측에서 받는 신호(FFT 이후)는 $P_{HT-LTF}\times \textbf{LTF}(k)$에 채널 상태를 곱해서 아래처럼 나타낼 수 있다. 아래 중간 식에서의 $h$의 배열은 $H_k^T$와 같다. $k$는 서브캐리어 인덱스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\begin{matrix}\left[\begin{matrix}&amp;nbsp;\textbf{x}_{1,k,t_1}&amp;nbsp;&amp;amp;&amp;nbsp;\textbf{x}_{1,k,t_2}&amp;nbsp;\\&amp;nbsp;\textbf{x}_{2,k,t_1}&amp;nbsp;&amp;amp;&amp;nbsp;\textbf{x}_{2,k,t_2}&amp;nbsp;\end{matrix}\right]&amp;amp;=&amp;amp;\left[\begin{matrix}&amp;nbsp;h_{11,k}&amp;nbsp;&amp;amp;&amp;nbsp;h_{21,k}&amp;nbsp;\\&amp;nbsp;h_{12,k}&amp;nbsp;&amp;amp;&amp;nbsp;h_{22,k}&amp;nbsp;\end{matrix}\right]\cdot\left[\begin{matrix}&amp;nbsp;1&amp;nbsp;&amp;amp;&amp;nbsp;-1&amp;nbsp;\\&amp;nbsp;1&amp;nbsp;&amp;amp;&amp;nbsp;1&amp;nbsp;\end{matrix}\right]\cdot\left[\begin{matrix}\text{LTF}(k)&amp;amp;\text{LTF}(k)\\\text{LTF}(k)&amp;amp;\text{LTF}(k)\end{matrix}\right]\\&amp;amp;=&amp;amp;\left[\begin{matrix}&amp;nbsp;h_{11,k}&amp;nbsp;+h_{21,k}&amp;nbsp;&amp;amp;&amp;nbsp;-h_{11,k}+h_{21,k}&amp;nbsp;\\&amp;nbsp;h_{12,k}+h_{22,k}&amp;nbsp;&amp;amp;&amp;nbsp;-h_{12,k}+h_{22,k}&amp;nbsp;\end{matrix}\right]\cdot\textbf{LTF}(k)\end{matrix}$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 위처럼 $H_k$와 $P_{HT-LTF}$를 곱하기 전에 양변에 $P^T_{HT-LTF}$를 곱해서 LTF와 $H_k^T$만을 남길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\left[\begin{matrix}&amp;nbsp;\textbf{x}_{1,k,t_1}&amp;nbsp;&amp;amp;&amp;nbsp;\textbf{x}_{1,k,t_2}&amp;nbsp;\\&amp;nbsp;\textbf{x}_{2,k,t_1}&amp;nbsp;&amp;amp;&amp;nbsp;\textbf{x}_{2,k,t_2}&amp;nbsp;\end{matrix}\right]\cdot\left[\begin{matrix}&amp;nbsp;1&amp;nbsp;&amp;amp;&amp;nbsp;1&amp;nbsp;\\&amp;nbsp;-1&amp;nbsp;&amp;amp;&amp;nbsp;1&amp;nbsp;\end{matrix}\right]=2\cdot\left[\begin{matrix}&amp;nbsp;h_{11,k}&amp;nbsp;&amp;amp;&amp;nbsp;h_{21,k}&amp;nbsp;\\&amp;nbsp;h_{12,k}&amp;nbsp;&amp;amp;&amp;nbsp;h_{22,k}&amp;nbsp;\end{matrix}\right]\cdot\textbf{LTF}(k)$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 받아서 FFT한 신호에 $P^T_{HT-LTF}$와 $2\textbf{LTF}(k)$의 역행렬을 곱해서 서브캐리어 $k$에서의 채널 상태 ${h_{11}, h_{12}, h_{21}, h_{22}}$를 추정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 $H$는 행이 Rx 안테나 인덱스 열이 Tx 안테나 인덱스이고, $\textbf{X}$는 행이 Rx 안테나 인덱스고 열이 시간이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 추정한 채널 상태는 이제 본격적으로 파라미터 추정에 이용하게 된다. 앞으로 설명할 이 논문의 파라미터 추정 과정은 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2482&quot; data-origin-height=&quot;418&quot; data-filename=&quot;fig3.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCJl5U/btq8VFzJqJ8/mZe582WsIAov18392MRWek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCJl5U/btq8VFzJqJ8/mZe582WsIAov18392MRWek/img.png&quot; data-alt=&quot;mD-Track&amp;amp;#39;s&amp;amp;amp;nbsp;four-dimensional&amp;amp;amp;nbsp;estimator&amp;amp;amp;nbsp;that&amp;amp;amp;nbsp;estimates&amp;amp;amp;nbsp;parameters&amp;amp;amp;nbsp;AoA,&amp;amp;amp;nbsp;AoD,&amp;amp;amp;nbsp;Doppler,&amp;amp;amp;nbsp;and&amp;amp;amp;nbsp;ToF&amp;amp;amp;nbsp;of&amp;amp;amp;nbsp;a&amp;amp;amp;nbsp;wireless&amp;amp;amp;nbsp;signal&amp;amp;amp;nbsp;as&amp;amp;amp;nbsp;it&amp;amp;amp;nbsp;propagates&amp;amp;amp;nbsp;along&amp;amp;amp;nbsp;a&amp;amp;amp;nbsp;single&amp;amp;amp;nbsp;path&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCJl5U/btq8VFzJqJ8/mZe582WsIAov18392MRWek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCJl5U%2Fbtq8VFzJqJ8%2FmZe582WsIAov18392MRWek%2Fimg.png&quot; data-origin-width=&quot;2482&quot; data-origin-height=&quot;418&quot; data-filename=&quot;fig3.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;mD-Track's&amp;nbsp;four-dimensional&amp;nbsp;estimator&amp;nbsp;that&amp;nbsp;estimates&amp;nbsp;parameters&amp;nbsp;AoA,&amp;nbsp;AoD,&amp;nbsp;Doppler,&amp;nbsp;and&amp;nbsp;ToF&amp;nbsp;of&amp;nbsp;a&amp;nbsp;wireless&amp;nbsp;signal&amp;nbsp;as&amp;nbsp;it&amp;nbsp;propagates&amp;nbsp;along&amp;nbsp;a&amp;nbsp;single&amp;nbsp;path&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AoA와 AoD를 주파수 영역에서 구하고, 도플러 효과, ToF와 Amplitude Attenuation은 시간 영역에서 구하게 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AoA &amp;amp; AoD 구하기&lt;/h4&gt;
&lt;h5&gt;Angle of Arrival&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 Tx 안테나에서 발신된 Singlepath 신호가 여러 개의 Rx 안테나에 도달할 때, Rx 안테나가 규칙적으로 배열되어 있다면 그에 따라 전파 거리가 일정하게 달라질 것이다. 그리고 이는 각 Rx 안테나에서 얻은 채널 상태에 반영되어, 전파 거리 차이에 따른 규칙적인 Phase Offset이 나타날 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 하나 들어보자. 아래 그림은 Rx 안테나 3개에서 얻은 특정 서브캐리어에서의 채널 상태 복소수를 복소좌표계에 표시한 것인데, 옥색 R1과 회색 R2/R3가 바로 규칙적인 Phase Offset이 나타난 채널 상태다. Amplitude 값은 그냥 저렇다고 가정하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;1506&quot; data-filename=&quot;ownfig2.png&quot; width=&quot;400&quot; height=&quot;394&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7mTS7/btq8TPbSPFr/aE4BPLKVVAiI19KTYhMtv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7mTS7/btq8TPbSPFr/aE4BPLKVVAiI19KTYhMtv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7mTS7/btq8TPbSPFr/aE4BPLKVVAiI19KTYhMtv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7mTS7%2Fbtq8TPbSPFr%2FaE4BPLKVVAiI19KTYhMtv1%2Fimg.png&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;1506&quot; data-filename=&quot;ownfig2.png&quot; width=&quot;400&quot; height=&quot;394&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Steering Vector의 정의에 의해 이 규칙적인 Phase Offset은 각 Rx 안테나에서 얻은 채널 상태에 적당한 Steering Vector를 곱해서 없앨 수 있고, Phase Offset이 사라진 채널 상태는 모두 Phase값이 같아져 그들의 합의 Power는 최대가 될 것이다. 이 경우가 바로 위 그림에서 옥색 점 세개이다. 이를 수식으로 나타내면 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\text{Appropriate steering vector}=\underset{\text{steering vector}}{\operatorname{arg max}}\left\Vert \left[\begin{matrix}h_{R1} &amp;amp; h_{R2} &amp;amp; h_{R3}\end{matrix}\right] \cdot \text{steering vector}\right\Vert^2$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Steering Vector는 $\phi$의 함수이므로, 위 식의 결과값을 만들어내는 $\phi$가 바로 AoA 추정값 $\phi^*$가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;돌아와서 이 논문에서 제시한 Tx/Rx 안테나가 각각 2개씩인 구조에 적용해보자. 채널 상태와 Rx steering vector $c(\phi)$를 곱한 값을 $h'$라 하면, $\phi^*$는 아래와 같이 적을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\left[\begin{matrix}h'_{1,k}(\phi)\\h'_{2,k}(\phi)\end{matrix}\right]=\left[\begin{matrix}h_{11,k}&amp;nbsp;&amp;amp;&amp;nbsp;h_{12,k}&amp;nbsp;\\&amp;nbsp;h_{21,k}&amp;nbsp;&amp;amp;&amp;nbsp;h_{22,k}\end{matrix}\right]c(\phi)$$ &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\phi^*=\underset{\phi}{\operatorname{arg max}}\sum^2_{i=1}\sum^F_{k=1}\left\Vert h'_{i,k}(\phi)\right\Vert^2$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Tx-Rx 안테나 쌍에서 $\phi$는 거의 같으므로, 모든 안테나에 대해 Steering Vector를 곱하고 합친 Power가 가장 큰 $\phi$을 찾아내는 것으로 $\phi^*$를 얻은 것이다. $i$는 Tx 안테나 인덱스, $k$는 서브캐리어 인덱스이다.&lt;/p&gt;
&lt;h5&gt;Angle of Departure&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AoA에서 했던 것과 같은 원리로, Tx 안테나에 대해 가장 적당한 Steering Vector를 구하여 AoD 추정치 $\varphi^*$를 얻을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\varphi^*=\underset{\varphi}{\operatorname{arg&amp;nbsp;max}}\sum^F_{k=1}\left\Vert&amp;nbsp;h''_{k}(\varphi;\phi^*)\right\Vert^2,\quad&amp;nbsp;h''_k=g_(\varphi)^H\left[\begin{matrix}h'_{1,k}(\phi^*)&amp;nbsp;\\h'_{2,k}(\phi^*)\end{matrix}\right]$$ &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$g(\varphi)$를 Transpose가 아닌 Hermitian으로 적은 건 단순히 $g$를 어떻게 정의하느냐에 따라 달린 것으로, 뭐가 되든 결국 특정한 AoD 값을 추정할 수 있을 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Doppler Shift &amp;amp; ToF 구하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 AoA와 AoD를 구했으니 AoA, AoD에 의한 Phase Shift 효과가 제거된 시간 영역 수신 시그널을 재건할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$y''(t;\phi^*,\varphi^*)=\mathcal{F}^{-1}\{H''(\varphi^*,\phi^*)\odot&amp;nbsp;\text{LTF}\},\quad&amp;nbsp;H''=[\begin{matrix}h''_1&amp;amp;h''_2&amp;amp;\cdots&amp;amp;h''_F\end{matrix}]$$ &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$\odot$은&amp;nbsp;element-wise&amp;nbsp;multiplication이고,&amp;nbsp;여기서&amp;nbsp;$\text{LTF}$는&amp;nbsp;주파수&amp;nbsp;영역에&amp;nbsp;있다.&amp;nbsp;이를&amp;nbsp;활용하여&amp;nbsp;앞에서&amp;nbsp;나왔던&amp;nbsp;수신단&amp;nbsp;신호&amp;nbsp;$s(t)_{M\times&amp;nbsp;1}$에서&amp;nbsp;AoA,&amp;nbsp;AoD&amp;nbsp;효과를&amp;nbsp;제거한&amp;nbsp;신호&amp;nbsp;$s'(t)_{1\times&amp;nbsp;1}$를&amp;nbsp;적어보면&amp;nbsp;아래와&amp;nbsp;같다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$s'(t)_{1\times&amp;nbsp;1}=\alpha&amp;nbsp;e^{j2\pi\gamma&amp;nbsp;t}y''(t;\phi^*,\varphi^*)$$ &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 위에서 했던 방법과 비슷하게 Correlation Peak를 찾을 것이다. 먼저 ToF $\tau$부터 찾아보자[^4].&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[^4]: 이 글에서는 $\tau$와 $\gamma$를 순차적으로 찾지만 논문에서는 Doppler Shift와 ToF를 동시에 찾고, 뒤에서 또 $z$라는 Unified Estimator를 소개한다. 왜 내가 이악물고 $z$를 무시하면서 Doppler Shift와 ToF 추정이 분리된 논문 정리를 했는지는 &amp;lt;알고리즘 최적화&amp;gt; 섹션에서 다뤘다.&lt;/p&gt;
&lt;h5&gt;Time of Flight&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서&amp;nbsp;Tx&amp;nbsp;안테나&amp;nbsp;별&amp;nbsp;송신&amp;nbsp;신호를&amp;nbsp;$U(t)_{N\times&amp;nbsp;1}$라고&amp;nbsp;표시했다.&amp;nbsp;이번에는&amp;nbsp;각&amp;nbsp;안테나로&amp;nbsp;분배되기&amp;nbsp;이전&amp;nbsp;송신&amp;nbsp;신호를&amp;nbsp;$\underset{\leftarrow}{U}(t)_{1\times&amp;nbsp;1}$라고&amp;nbsp;하자.&amp;nbsp;이를&amp;nbsp;활용해서&amp;nbsp;아래와&amp;nbsp;같이&amp;nbsp;ToF를&amp;nbsp;찾을&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\tau^*=\underset{\tau}{\operatorname{arg&amp;nbsp;max}}\int_Ty''(t;\phi^*,\varphi^*)\underset{\leftarrow}{U}(t-\tau)dt$$ &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 $T$는 $y''$의 신호 길이, $\tau^*$는 $\tau$의 추정치이다.&lt;/p&gt;
&lt;h5&gt;Doppler Shift&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 한 번 Correlation을 이용하여 Doppler Shift 파라미터를 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\gamma^*=\underset{\gamma}{\operatorname{arg&amp;nbsp;max}}\int_Te^{-j2\pi\gamma&amp;nbsp;t}y''(t;\phi^*,\varphi^*)\underset{\leftarrow}{U}(t-\tau^*)dt$$ &lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Attenuation 구하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 구한 네 가지 파라미터를 가지고 아래와 같이 Amplitude Attenuation 정도를 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\alpha^*=\frac{1}{M\cdot&amp;nbsp;T\cdot&amp;nbsp;P}\int_Te^{-j2\pi\gamma^*&amp;nbsp;t}y''(t;\phi^*,\varphi^*)\underset{\leftarrow}{U}(t-\tau^*)dt$$ &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$M$은 Rx 안테나 수, $T$는 $y''$ 신호의 길이, $P$는 송신 전력이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;여러 경로의 파라미터 추출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때까지 Singlepath에 대한 이야기를 했다. 여러 경로를 다루는 건 &lt;a href=&quot;https://en.wikipedia.org/wiki/Self-interference_cancellation&quot;&gt;Self Interference Cancellation&lt;/a&gt;을 하듯이 중첩되어 있는 $s(t)$를 여러 $s(t)$로 분리하고, 각각의 $s(t)$에 대해 파라미터 벡터 $v=[\phi, \varphi, \tau, \gamma, \alpha]^T$를 뽑아내는 방식으로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 하나의 수신 신호에 들어있는 수많은 Multipath 중 $L$개의 Multipath를 뽑아낸다고 가정하자. SIC 방식을 그대로 따르면서 백색 소음 레벨까지 내려가게 되면 더이상 Multipath를 뽑을 수 없게 될 것인데, $L$은 그때까지 뽑을 수 있는 Multipath의 수로 한정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$Y(t)=\sum^L_{l=1}s_l(t;v_l)+\hat{\mathbf{W}}(t)$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$Y(t)$는 수신 신호, $\hat{\mathbf{W}}(t)$는 큼직한 덩어리를 다 뽑아내고 남은 백색 소음 + 뽑아낼 수 없었던 소음이 되어버린 시그널이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기까지만 하면 여전히 $s_l(t)$가 서로 겹쳐 있어서 상당히 부정확하게 $s_l(t)$이 뽑힌다고 한다. 그래서 나온 것이 한번 더 신호를 뽑아내는 것이다. 즉, 모든 $s_l(t)$에 대해 아래의 계산을 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$y'_l(t)=s_l(t;v_l)+\hat{\mathbf{W}}(t)\quad\Rightarrow\quad s'_l(t;v_l')$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의할 점은 $\hat{\mathbf{W}}$를 계속 업데이트하면서 진행하는 것이다. 예를 들어, $y'_1(t)$에서 $s'_1(t)$을 뽑아 내고, 나머지 신호를 $\hat{\mathbf{W}}$에 합산한다. 이후 그렇게 업데이트한 $\hat{\mathbf{W}}$를 사용해서 $y'_2(t)$를 구성하고, 거기서 또 $s'_2(t)$를 뽑아 낸다. 이 과정은 추출된 $l$번 신호에 대해, 큰 변화가 없을 때까지 계속 반복한다. 즉, $s_l\rightarrow s'_l \rightarrow s''_l \rightarrow \cdots$ 이다. 여기서 '큰 변화'를 판단하는 기준은 유동적으로 조절할 수 있는데 저자들은 이를 각 파라미터 찾기의 간격인 $0.02\text{rad}$, $0.5ns$, $0.1\text{Hz}$로 설정했다고 한다^[Section 6.3에 나와 있다.]. 또한, 논문에 따르면 이 반복 알고리즘으로 파라미터 벡터를 찾으면 거의 항상 수렴하는 값이 나온다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정은 아래 그림에 잘 나타나 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2934&quot; data-origin-height=&quot;396&quot; data-filename=&quot;fig6.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k3zmb/btq8MG1xYGO/tit3cKq1WGjmfJveXxqBU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k3zmb/btq8MG1xYGO/tit3cKq1WGjmfJveXxqBU1/img.png&quot; data-alt=&quot;The&amp;amp;amp;nbsp;framework&amp;amp;amp;nbsp;of&amp;amp;amp;nbsp;the&amp;amp;amp;nbsp;iterative&amp;amp;amp;nbsp;path&amp;amp;amp;nbsp;parameter&amp;amp;amp;nbsp;estimation&amp;amp;amp;nbsp;algorithm&amp;amp;amp;nbsp;($L=2$)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k3zmb/btq8MG1xYGO/tit3cKq1WGjmfJveXxqBU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk3zmb%2Fbtq8MG1xYGO%2Ftit3cKq1WGjmfJveXxqBU1%2Fimg.png&quot; data-origin-width=&quot;2934&quot; data-origin-height=&quot;396&quot; data-filename=&quot;fig6.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;The&amp;nbsp;framework&amp;nbsp;of&amp;nbsp;the&amp;nbsp;iterative&amp;nbsp;path&amp;nbsp;parameter&amp;nbsp;estimation&amp;nbsp;algorithm&amp;nbsp;($L=2$)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;알고리즘 최적화?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문에서는 위에서 내가 적은 것과 다르게 아래의 Unified Estimator $z$를 제시하여 한번에 AoA, AoD, Doppler Shift, ToF를 추정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$z(\phi, \varphi,\tau,\gamma)=\int_Te^{-j2\pi\gamma^* t}\mathcal{F}^{-1}{g^H(\varphi)Hc(\phi)\odot \text{LTF}}\underset{\leftarrow}{U}(t-\tau)dt$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$(\phi, \varphi, \tau, \gamma)_{est}=\underset{v}{\operatorname{arg max}}|z(\phi,\varphi,\tau,\gamma)|$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Channel Attenuation $\alpha$는 아래의 식으로 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\alpha_{est}=\frac{1}{M\cdot T\cdot P}z((\phi,\varphi,\tau,\gamma)_{est})$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 파라미터 $\phi$, $\varphi$, $\tau$, $\gamma$의 경우의 수를 각각 $p_\phi$, $p_\varphi$, $p_\tau$, $p_\gamma$라고 하면 이렇게 합쳐진 Estimator $z$는 총 $p_\phi\cdot p_\varphi\cdot p_\tau\cdot p_\gamma$의 Input 공간에서 최적값을 찾게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들도 이게 오버헤드가 있다는 걸 알고 있으며, 네 개를 동시에 찾는 것보다는 찾지 못한 파라미터를 고정시키고 순차적으로 찾는 아래의 방법을 뒤에서 &quot;Reducing computational complexity&quot;라며 제시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\phi^*=\underset{\phi}{\operatorname{arg&amp;nbsp;max}}|z(\phi,\varphi_\text{fixed},\tau_\text{fixed},\gamma_\text{fixed})|$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\varphi^*=\underset{\varphi}{\operatorname{arg max}}|z(\phi^*,\varphi,\tau_\text{fixed},\gamma_\text{fixed})|$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\tau^*=\underset{\tau}{\operatorname{arg max}}|z(\phi^*,\varphi^*,\tau,\gamma_\text{fixed})|$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\gamma^*=\underset{\gamma}{\operatorname{arg&amp;nbsp;max}}|z(\phi^*,\varphi^*,\tau^*,\gamma)|$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Input 공간을 $p_\phi\cdot p_\varphi\cdot p_\tau\cdot p_\gamma$ 에서 $p_\phi+ p_\varphi+ p_\tau+ p_\gamma$로 줄이는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고정하는 파라미터 값은 이전 Iteration에서 찾은 값을 활용한다고 한다. 제일 첫 번째 Iteration에서는 무슨 값으로 고정하는지 나와있지 않으며^[그저 가장 빠르게 수렴하는 지점을 &lt;i&gt;조심스레&lt;/i&gt; 선택했다고 한다.], 논문 중간의 &quot;이 알고리즘은 글로벌 맥시멈을 보장하지 않는다&quot;는 설명이 이와 관련이 있어보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 내가 든 생각이 &lt;b&gt;&quot;그럴거면 그냥 처음부터 $\mathbf{z}$를 제시하지 않고 순차적으로 계산하면 되는 것 아닌가?&quot;&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 내가 서술한대로, 그리고 논문 초반 AoA, AoD Estimator 설명에서 했던대로만 계산하면 굳이 $z$를 끝까지 계산할 필요 없이 $\phi$, $\varphi$값을 찾을 수 있어 한 번 추정하는 것에 대한 계산 양 자체도 줄어들 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 논문 저자들이 왜 굳이 $z$의 개념을 제시했는지 잘 모르겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;채널 측정 오차 바로잡기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와이파이 하드웨어에는 어쩔 수 없이 오차가 생기기 마련이다. 그리고 그 오차는 파라미터 및 Multipath 추정에 영향을 미친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문에서는 각 파라미터에 오차를 주는 주된 원인을 아래 다섯 가지로 지정하고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Tx 체인의 Phase Offset &amp;rarr; AoD 오차의 원인.&lt;/b&gt; 기계적 문제로 Tx의 모든 포트에서 동일한 Phase의 신호가 나오지는 않는데, 그 Offset을 말한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rx 체인의 Phase Offset &amp;rarr; AoA 오차의 원인.&lt;/b&gt; 기계적 문제로 Rx의 각 포트마다 같은 신호를 약간씩 다른 Phase로 받아들이는데, 그 Offset을 말한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Sampling Frequency Offset &amp;rarr; ToF 오차의 원인.&lt;/b&gt; Sampling Timing이 계속해서 일정하게 밀리는 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Symbol Timing Offset &amp;rarr; ToF 오차의 원인.&lt;/b&gt; 일정하게 증가하는 Frequency Offset 외에도 상수값으로 존재하는 Sampling Timing의 차이이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Carrier Frequency Offset &amp;rarr; Doppler Shift 오차의 원인.&lt;/b&gt; Up/Down converting에서의 주파수 차이이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 아래의 방법대로, Channel Estimation 이전에 Channel Information Correction을 진행한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tx/Rx Phase Offsets 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tx/Rx 포트의 Offset은 Antenna-specific, Chip-specific한 수치이다. 따라서 이 논문에서는 자신들이 실험하는 기기에서 Tx-Rx 안테나 포트를 유선으로 연결하여 Chip에서 발생하는 Phase Error를 측정, 제거했다. 안테나 간의 차이에 의한 Phase Offset은 제거하지 않은 듯하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SFO, STO 제거&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;3495&quot; data-origin-height=&quot;1000&quot; data-filename=&quot;fig9.png&quot; width=&quot;700&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mUvHj/btq8MGAuF3Y/iKTfpKilQZs5lmHOaTb86k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mUvHj/btq8MGAuF3Y/iKTfpKilQZs5lmHOaTb86k/img.png&quot; data-alt=&quot;A&amp;amp;amp;nbsp;microbenchmark&amp;amp;amp;nbsp;study&amp;amp;amp;nbsp;of&amp;amp;amp;nbsp;two&amp;amp;amp;nbsp;paths&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mUvHj/btq8MGAuF3Y/iKTfpKilQZs5lmHOaTb86k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmUvHj%2Fbtq8MGAuF3Y%2FiKTfpKilQZs5lmHOaTb86k%2Fimg.png&quot; data-origin-width=&quot;3495&quot; data-origin-height=&quot;1000&quot; data-filename=&quot;fig9.png&quot; width=&quot;700&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;A&amp;nbsp;microbenchmark&amp;nbsp;study&amp;nbsp;of&amp;nbsp;two&amp;nbsp;paths&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 했다고 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CFO 제거&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;564&quot; data-filename=&quot;ownfig3.png&quot; width=&quot;500&quot; height=&quot;237&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnk7Kv/btq8TrWDgNx/eprO0CIGbyLcfeemwsWLak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnk7Kv/btq8TrWDgNx/eprO0CIGbyLcfeemwsWLak/img.png&quot; data-alt=&quot;Channel sampling model&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnk7Kv/btq8TrWDgNx/eprO0CIGbyLcfeemwsWLak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnk7Kv%2Fbtq8TrWDgNx%2FeprO0CIGbyLcfeemwsWLak%2Fimg.png&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;564&quot; data-filename=&quot;ownfig3.png&quot; width=&quot;500&quot; height=&quot;237&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Channel sampling model&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 했다고 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구현 및 결과&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;572&quot; data-filename=&quot;fig10.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnrVSu/btq8RsIP5k9/3XkK2VMkMZYf240Gkaa1eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnrVSu/btq8RsIP5k9/3XkK2VMkMZYf240Gkaa1eK/img.png&quot; data-alt=&quot;Experimental&amp;amp;amp;nbsp;setup&amp;amp;amp;nbsp;in&amp;amp;amp;nbsp;a&amp;amp;amp;nbsp;indoor&amp;amp;amp;nbsp;meeting&amp;amp;amp;nbsp;room&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnrVSu/btq8RsIP5k9/3XkK2VMkMZYf240Gkaa1eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnrVSu%2Fbtq8RsIP5k9%2F3XkK2VMkMZYf240Gkaa1eK%2Fimg.png&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;572&quot; data-filename=&quot;fig10.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Experimental&amp;nbsp;setup&amp;nbsp;in&amp;nbsp;a&amp;nbsp;indoor&amp;nbsp;meeting&amp;nbsp;room&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://warpproject.org/trac&quot;&gt;WARP v3&lt;/a&gt; 플랫폼과 일반 와이파이 라우터를 사용해서 채널 샘플링 장치를 구성했고, 워크스테이션 서버를 이용해서 컴퓨팅을 했다고 한다. 위 사진은 여러 테스트 환경 중 실내 회의실 환경의 구성이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성능&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용은 논문을 직접 확인하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;해상력.&lt;/b&gt; 기존 기술 MUSIC, SpotFi와 비교했을 때 훨씬 정확했으며, 여기다가 AoD, ToF, Doppler를 추가한 경우 더욱 높은 해상력을 보여주었다고 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;처리 시간.&lt;/b&gt; $t_s$는 25ms로 설정했으며, 약 130ms의 컴퓨팅 시간을 보여주었다고 한다. 느려보이지만 SpotFi와 비교해서는 최소 14배 빠른 시간이라고 한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>무선 네트워크/Channel State Information</category>
      <category>AoA</category>
      <category>CFO</category>
      <category>csi</category>
      <category>SFO</category>
      <category>STO</category>
      <category>ToF</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/54</guid>
      <comments>https://yuoa.tistory.com/entry/md-Track#entry54comment</comments>
      <pubDate>Mon, 5 Jul 2021 21:37:27 +0900</pubDate>
    </item>
    <item>
      <title>Frequency Offset Estimation and Correction</title>
      <link>https://yuoa.tistory.com/entry/Frequency-Offset-Estimation-and-Correction</link>
      <description>&lt;p&gt;&lt;i&gt;in the IEEE 802.11a WLAN&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;원문 : E. Sourour, H. El-Ghoroury and D. McNeill, &lt;a href=&quot;https://ieeexplore.ieee.org/document/1405033&quot;&gt;&quot;Frequency offset estimation and correction in the IEEE 802.11a WLAN,&quot;&lt;/a&gt; &lt;i&gt;IEEE 60th Vehicular Technology Conference,&lt;/i&gt; 2004. VTC2004-Fall. 2004, Los Angeles, CA, 2004, pp. 4923-4927 Vol. 7, doi: 10.1109/VETECF.2004.1405033.&lt;/p&gt;
&lt;p&gt;이 글은 단순히 읽은 논문을 정리한 것이다.&lt;/p&gt;
&lt;hr /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;이 논문에서는 뭘 하는가?&lt;/h2&gt;
&lt;p&gt;파일럿 신호인 STF와 LTF를 이용한 Coarse &amp;amp; Fine Frequency Offset Tracking을 진행한다. 검증은 AWGN까지 구현된 완전한 802.11a WLAN 시뮬레이터로 진행한다.&lt;/p&gt;
&lt;h2&gt;IEEE 802.11a PHY 레이어&lt;/h2&gt;
&lt;p&gt;아래 내용을 읽으면서 OFDM을 다시 떠올리는 데는 Keysight의 &lt;a href=&quot;http://rfmw.em.keysight.com/wireless/helpfiles/89600B/WebHelp/Subsystems/wlan-ofdm/content/ofdm_basicprinciplesoverview.htm&quot;&gt;Concepts of Orthogonal Frequency Division Multiplexing (OFDM) and 802.11 WLAN&lt;/a&gt; 문서와 WLANpedia의 &lt;a href=&quot;https://www.wlanpedia.org/ko/tech/phy/ofdm-in-wlan/&quot;&gt;OFDM in WLAN&lt;/a&gt; 문서를 참고했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;111&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KbH0W/btqHelXc7IK/oAvOVLtUbtNjzXbPdv4d91/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KbH0W/btqHelXc7IK/oAvOVLtUbtNjzXbPdv4d91/img.gif&quot; data-alt=&quot;IEEE&amp;amp;amp;nbsp;802.11a&amp;amp;amp;nbsp;Frame&amp;amp;amp;nbsp;Structure&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KbH0W/btqHelXc7IK/oAvOVLtUbtNjzXbPdv4d91/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/KbH0W/btqHelXc7IK/oAvOVLtUbtNjzXbPdv4d91/img.gif&quot; width=&quot;100%&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;111&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;IEEE&amp;nbsp;802.11a&amp;nbsp;Frame&amp;nbsp;Structure&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;$8\mu s$의 STF와 LTF, $4 \mu s$의 OFDM Symbol이 있다.&lt;/p&gt;
&lt;h4&gt;Short Training Sequence&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;총 10번의 동일한 파트($t_0 ~ t_9$, 각 $0.8\mu s$)로 나뉘며, 각 파트마다 16번 샘플링하도록 구성되어 있다.&lt;/li&gt;
&lt;li&gt;시간 동기화, AGC 설정, 안테나 선택, Coarse FO Estimation에 쓰인다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;(가정)&lt;/b&gt; 위 쓰임 중 나머지는 모두 성공했고, 마지막 Coarse FO Estimation에는 $t_5 - t_9$만을 사용한다고 하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Long Training Sequence&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;하나의 Guard Interval과 두 개의 동일한 Training 파트($T_0, T_1$)로 나뉘며, 각 파트마다 64번 샘플링하도록 되어 있다.&lt;/li&gt;
&lt;li&gt;Guard Interval은 $1.6 \mu s$, 두 Training Field는 $3.2\mu s$이다.&lt;/li&gt;
&lt;li&gt;Guard Interval은 $T_1$의 마지막 32 샘플을 이용한 Cyclic Prefix이다.&lt;/li&gt;
&lt;li&gt;Channel 추정과 Fine FO Estimation에 쓰인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;OFDM Symbols&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;$0.8\mu s$의 Guard Interval과 $3.2\mu s$의 Data Symbol로 구성되어 있다.&lt;/li&gt;
&lt;li&gt;첫 OFDM Symbol은 &lt;code&gt;SIGNAL&lt;/code&gt; 필드, 이후는 &lt;code&gt;DATA&lt;/code&gt; 필드이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;시뮬레이션 모델&lt;/h2&gt;
&lt;p&gt;시뮬레이터로 모든 검증을 진행했다고 하는데, 어떻게 환경과 오류를 모델링했는가?&lt;/p&gt;
&lt;h3&gt;채널 모델&lt;/h3&gt;
&lt;p&gt;논문 오류로 채널 모델이 정확히 표기되어 있지 않으나, 여기서 중요한 것은 채널 모델이 아니라 FO 부분이므로 대충 아래와 같이 정리하고 넘어간다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;레일리 실내 모델이고, 한 프레임을 받는 동안 채널 상태는 일정하다고 가정하자.&lt;/li&gt;
&lt;li&gt;전파 지연($D_{rms}$)은 $20 - 200 ns$ 이며 최대 다중 경로 수($L$)는 Sampling Period($T_s$)에 대해 $1+ \left\lfloor {10D_{rms}/T_s} \right\rfloor$ 이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Frequency Offset 모델&lt;/h3&gt;
&lt;p&gt;한 Rx에서 FO는 하나의 Oscillator에 의해 결정되므로, Carrier Frequency와 Baseband에서 FO는 같다고 가정한다.&lt;/p&gt;
&lt;h4&gt;Carrier Frequency Offset (CFO) 모델&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;265&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kpifd/btqHgvMj1nS/qsLU2I6dASyZri5UyLCKnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kpifd/btqHgvMj1nS/qsLU2I6dASyZri5UyLCKnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kpifd/btqHgvMj1nS/qsLU2I6dASyZri5UyLCKnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKpifd%2FbtqHgvMj1nS%2FqsLU2I6dASyZri5UyLCKnk%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;265&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;어긋난 Carrier Frequency에 의한 CFO Phase Shift Degree $\alpha$는 아래와 같이 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;$$\alpha=2\pi\epsilon f_c T_s$$&lt;/p&gt;
&lt;p&gt;$\epsilon$이 양수이면 샘플 당 Phase Shift $\alpha$ 역시 양수(반시계 방향)일 것이다.&lt;/p&gt;
&lt;p&gt;이는 한 프레임의 $n$번째 샘플 신호에 대해 $e^{jn\alpha}$를 곱하면 CFO를 모델링할 수 있다.&lt;/p&gt;
&lt;h4&gt;Sampling Frequency Offset (SFO) 모델&lt;/h4&gt;
&lt;p&gt;어긋난 Sampling duration은 아래와 같이 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;$$T_s'=(1-\epsilon)T_s$$&lt;/p&gt;
&lt;p&gt;$\epsilon$이 양수이면 샘플링 기간은 짧아지고, 기존 샘플링 시각보다 이른 $\tau_n=n\epsilon T_s$에 샘플링이 이루어지게 된다.&lt;/p&gt;
&lt;p&gt;이는 아래 그림과 같이 표현할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;501&quot; data-origin-height=&quot;372&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tvq3o/btqHlWvh0iu/tBSGTjIo5oDtSA2Hr2eS2K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tvq3o/btqHlWvh0iu/tBSGTjIo5oDtSA2Hr2eS2K/img.gif&quot; data-alt=&quot;Calculating&amp;amp;amp;nbsp;Offset&amp;amp;amp;nbsp;Samples&amp;amp;amp;nbsp;From&amp;amp;amp;nbsp;The&amp;amp;amp;nbsp;Ideal&amp;amp;amp;nbsp;Samples&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tvq3o/btqHlWvh0iu/tBSGTjIo5oDtSA2Hr2eS2K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Tvq3o/btqHlWvh0iu/tBSGTjIo5oDtSA2Hr2eS2K/img.gif&quot; width=&quot;100%&quot; data-origin-width=&quot;501&quot; data-origin-height=&quot;372&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Calculating&amp;nbsp;Offset&amp;nbsp;Samples&amp;nbsp;From&amp;nbsp;The&amp;nbsp;Ideal&amp;nbsp;Samples&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위쪽 그래프에서 실선으로 표시된 $S'$가 이상적인 샘플링 간격이며, 점선으료 표시된 $S$는 어긋난 샘플링 간격이다.&lt;/p&gt;
&lt;p&gt;이 샘플링 오류 SFO를 모델링하기 위해서 이 논문에서는 Sinc LPF에 딜레이를 주었으며, 식으로 표현하면 아래와 같다.&lt;/p&gt;
&lt;p&gt;$$C_m = Sinc(\pi(t+\tau_n)/T_s)|_{t=mT_s}=Sinc(\pi(m+n\epsilon)),\quad -\infty&amp;lt;m&amp;lt;\infty$$&lt;/p&gt;
&lt;p&gt;이는 위 그림의 아래쪽 그래프에도 그려져 있다.&lt;/p&gt;
&lt;p&gt;결국, CFO와 SFO를 모두 고려한 샘플은 $S_n=\sum^\infty_{m=-\infty}{C_mS'_{n+m}}$ 으로 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;이 논문에서는 시뮬레이션을 돌리므로, $m$을 $-50&amp;lt;m&amp;lt;50$으로 유한히 한정한다.&lt;/p&gt;
&lt;h2&gt;Frequency Offset 추정 및 교정&lt;/h2&gt;
&lt;p&gt;아까 STF를 가지고 Coarse FO Estimation, LTF로 Fine FO Estimation을 한다고 했다.&lt;/p&gt;
&lt;p&gt;위에서 $\alpha$를 실제 CFO로 거론했는데, 이 CFO 추정치 $\hat{\alpha}$를 구하고 그를 통해 CFO와 SFO를 교정할 것이다.&lt;/p&gt;
&lt;h3&gt;STF, LTF를 이용한 CFO 추정 및 교정&lt;/h3&gt;
&lt;h4&gt;Step 1. STF를 이용한 Coarse CFO Estimation&lt;/h4&gt;
&lt;p&gt;아까 10개의 STF 중 $t_5-t_9$ 를 이용한다고 했다. 이들은 총 80개의 샘플로 이루어졌으며, 각 샘플을 $S_m$이라고 하자 ($m=0,1,\cdots,79$).&lt;/p&gt;
&lt;p&gt;&lt;span&gt;그러면&amp;nbsp;$\hat{\alpha}=\frac{1}{16}\angle&amp;nbsp;\left(\sum^{63}_{m=0}S_m^*S_{m+16}\right)$&amp;nbsp;으로&amp;nbsp;$\hat{\alpha}$를&amp;nbsp;나타낼&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;여기서&amp;nbsp;$\angle$은&amp;nbsp;$\pm&amp;nbsp;\pi$&amp;nbsp;사이의&amp;nbsp;Phase&amp;nbsp;값을&amp;nbsp;말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이렇게 이 단계에서 대략 유추한 $\hat{\alpha}$ 를 $\hat{\alpha}_{ST}$ 라 하고, 다음 Fine Estimation으로 넘어가자.&lt;/p&gt;
&lt;h4&gt;Step 2. LTF를 이용한 Fine CFO Estimation&lt;/h4&gt;
&lt;p&gt;여기서는 두 개의 LTF를 모두 이용하며, 각 샘플을 $S_m;(m=0,1,\cdots,127)$ 이라고 하면 아래의 세 단계를 거쳐서 처리할 수 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Coarse Correction.&lt;/b&gt; 각 샘플을 위의 $\hat{\alpha}{ST}$를 이용하여 보상한다. &amp;rarr; $S_m=S_me^{-jm\hat{\alpha}_{ST}}$&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fine Estimation.&lt;/b&gt; 위와 동일한 방법으로, 하지만 조금 더 많은 샘플을 가지고 더 정확하게 FO Estimation을 수행한다. &amp;rarr; $\hat{\alpha}_{LT}=\frac{1}{64}\angle\left(\sum^{63}_{m=0}S_m^*S_{m+64}\right)$&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fine Correction.&lt;/b&gt; 1번과 동일한 방법으로 각 샘플을 보상한다. &amp;rarr; $S_m=S_me^{-jm\hat{\alpha}_{LT}}$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;STF, LTF 이후부터는 $\hat{\alpha}=\hat{\alpha}_{ST}+\hat{\alpha}_{LT}$를 이용하여 CFO를 교정할 수 있다.&lt;/p&gt;
&lt;p&gt;또한 위에서 언급한 $\alpha=2\pi\epsilon f_cT_s$ 관계를 이용하여 첫 번째 FO 값 $\hat\epsilon_0$을 구할 수도 있다.&lt;/p&gt;
&lt;h3&gt;Pilot Subcarrier를 이용한 FO 추정 및 교정&lt;/h3&gt;
&lt;p&gt;STF와 LTF를 이용하여 CFO를 교정하고 나서도 부정확성에 의해 Residual CFO가 나타나고, SFO도 아직 남아있다. 이로 인해 FFT 결과값에서 위상 오차가 나타나는데, 이는 Pilot Subcarrier로부터 얻은 정보를 통해 교정해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ieeexplore.ieee.org/abstract/document/803501&quot;&gt;이 논문&lt;/a&gt;에 따르면 OFDM 심볼과 서브캐리어에 따른 (이 단계에 진입했을 때) 남아 있는 위상 차이 $\phi_{l,k}$는 아래와 같다.&lt;/p&gt;
&lt;p&gt;$$\phi_{l,k}=2\pi l\left(\epsilon_rT_uf_c-\frac{N+N_g}{N}\epsilon k\right)$$&lt;/p&gt;
&lt;p&gt;여기서 $l$은 OFDM 심볼 인덱스, $k$는 서브캐리어 번호 (-26 ~ 26), $N$은 FFT Size (64), $N_g$는 GI의 샘플 수 (16), $T_u$는 OFDM Symbol 길이 ($4 \mu s$), $\epsilon_r$은 $\epsilon - \hat{\epsilon}_0$, 즉 Fine CFO Correction 이후 남아있는 CFO이다.&lt;/p&gt;
&lt;p&gt;위 식을 살펴보면 $\epsilon_rT_uf_c$ 부분은 서브캐리어 인덱스와 관계 없이 공통적으로 적용되는 Residual CFO이고, $\frac{N+N_g}{N}\epsilon k$ 부분은 SFO임을 알 수 있다.&lt;/p&gt;
&lt;p&gt;이 논문에서는 이 두 FO를 교정하기 위해 총 세 단계를 도입했다. 이 세 단계에서 사용하는 기호 표기는 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;[$\mathbf{H}$]&lt;/b&gt; 서브캐리어 $k$의 채널 이득을 $H_k$라 하자. $k$가 -26부터 26까지 존재하므로, $H_{-26},\cdots,H_{26}$이 존재할 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;[$\mathbf{Q}$]&lt;/b&gt; 802.11a 기준으로 Pilot Subcarrier는 -21, -7, 7, 21이므로 이를 $Q$를 이용하여 $Q_{-2}=H_{-21}$, $Q_{-1}=H_{-7}$, $Q_{1}=H_{7}$, $Q_{2}=H_{21}$ 과 같이 나타낼 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;[$\mathbf{X}$]&lt;/b&gt; 수신 측에서는 받은 신호에서 &lt;b&gt;[GI Dropping &amp;gt; 64-FFT]&lt;/b&gt; 를 수행하고, 그 중 48개의 Payload와 4개의 Pilot Symbol을 건져 낼 것이다. 각 Subcarrier의 Symbol을 $X_k$라 하자. 여기서부터는 Frequency Domain이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;[$\mathbf{P}$]&lt;/b&gt; Pilot Symbol은 Pseudo-random 값을 제거하고 채널 추정 및 시간 동기화에 쓸 수 있는데, 이를 $P$로 나타내면 $P_{l,-2}=X_{l,-21}$, $P_{l,-1}=X_{l,-7}$, $P_{l,1}=X_{l,7}$, $P_{l,2}=X_{l,21}$ 이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Step 1. SFO 교정&lt;/h4&gt;
&lt;p&gt;직전 Symbol에서 계산한 Sampling Frequency Offset 추정 값 $\hat{\epsilon}_{l-1}$과 위에서 나온 식 $\text{SFO}=2\pi l \frac{N+N_g}{N}\epsilon k$ 을 사용해서 간단히 보상해줄 수 있다. 자세한 내용은 &lt;a href=&quot;https://ieeexplore.ieee.org/abstract/document/803501&quot;&gt;위에서 언급한 논문&lt;/a&gt;을 보면 나온다.&lt;/p&gt;
&lt;p&gt;$\hat\epsilon_{0}$은 $\hat{\alpha}=\hat{\alpha}_{ST}+\hat{\alpha}_{LT}$ 와 $\alpha=2\pi\epsilon f_c T_s$ 을 이용해서 구한 $\hat\epsilon_0$ 이다.&lt;/p&gt;
&lt;p&gt;$$X_{l,k}=X_{l,k}\exp\left(2\pi l \frac{N+N_g}{N}\hat{\epsilon}_{l-1}k\right),\quad k=-26,\cdots,26$$&lt;/p&gt;
&lt;p&gt;$X$에 대해서 해주는 것이므로, 당연히 Pilot Symbol $P$에 대해서도 교정을 해 주는 것이다.&lt;/p&gt;
&lt;h4&gt;Step 2. Pilot Subcarrier를 이용한 Residual CFO 교정&lt;/h4&gt;
&lt;p&gt;위에서 말한 Residual CFO 부분($2\pi\epsilon_rT_uf_c$)은 모든 서브캐리어에 대해 공통으로 적용되며 OFDM Symbol 인덱스에 따라 일정하게 증가한다. 이는 $P$와 $Q$를 활용하여 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;$$\hat{\beta}_l=\angle\left({\sum_{i=-2,-1,1,2}P_{l,i}Q_i^*}\right)$$&lt;/p&gt;
&lt;p&gt;이를 이용하여 다시 한 번 보상해주면 아래와 같다.&lt;/p&gt;
&lt;p&gt;$$X_{l,k}=X_{l,k}e^{-\hat{\beta}_l},\quad k\neq -21,-7,7,21$$&lt;/p&gt;
&lt;p&gt;여기서 Pilot Symbol을 고려하지 않는 이유는 그 다음번 $\hat\epsilon_l$을 구해야 하기 때문이다. SFO Correction만 적용한 Pilot Symbol을 FO 추정에 사용하는 것과 관련해서는 &lt;a href=&quot;https://ieeexplore.ieee.org/abstract/document/803501&quot;&gt;위에서 언급한 논문&lt;/a&gt;을 보면 나온다.&lt;/p&gt;
&lt;h4&gt;Step 3. Pilot Subcarrier를 이용한 정밀한 FO 추정&lt;/h4&gt;
&lt;p&gt;이제 다음 OFDM Symbol의 SFO 교정(위 Step 1)에 쓸 $\hat{\epsilon}_{l}$ 값을 추정해야 한다.&lt;/p&gt;
&lt;p&gt;이 논문의 저자는 관찰을 바탕으로 실제 Frequency Offset $\epsilon$이 LTF 기반 교정 이후 구했던 초기 추정값 $\hat\epsilon_0$과 Residual CFO $\epsilon_r$의 합이라는 것을 알아냈다.&lt;/p&gt;
&lt;p&gt;한 OFDM Symbol 이후 Residual CFO로 인해 증가하는 위상 회전 값 $2\pi \epsilon_r T_u f_c$은 아래와 같이 현/전 심볼의 Pilot Symbol을 이용해 추정할 수 있다.&lt;/p&gt;
&lt;p&gt;$$\angle(W_l)=\angle\left(\sum_{i=-2,-1,1,2}P_{l,i}P_{l-1,i}^*\right)$$&lt;/p&gt;
&lt;p&gt;Training Sequence 뒤 처음으로 오는 &lt;code&gt;SIGNAL&lt;/code&gt; OFDM 심볼의 인덱스가 1임을 기억하자. 해당 심볼에서 위 값을 구할 때는 $P_{0,i}=Q_i$로 놓을 수 있다. 즉, $\angle(W_1)=\angle\left(\sum_{i=-2,-1,1,2}P_{1,i}Q_{,i}^*\right)$이 된다.&lt;/p&gt;
&lt;p&gt;연속적인 덧셈 연산은 Fixed-point 하드웨어에서 부정확한 계산의 원인이 될 수 있으므로 4개의 연속된 $W$를 Exponential 필터를 적용하여 아래와 같이 더해준다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Addition : $V_l=\sum^l_{m=l-3}W_m$&lt;/li&gt;
&lt;li&gt;Filter : $U_l=\rho V_l + (1-\rho)U_{l-4}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$l=4k$ 단위로 연산을 수행하므로 결국 $U_{4k}=\rho(W_{4k-3} + W_{4k-2} + W_{4k-1} + W_{4k}) + (1-\rho)U_{4(k-1)}$ 이 된다. 아주 부드럽게 변화하는 값이 나올 것 같다.&lt;/p&gt;
&lt;p&gt;이 논문에서 저자들은 파라미터 $\rho$ 를 경험적으로 $1/32$로 얻은 것 같다. 이제 이를 바탕으로 $\hat{\epsilon}_l$을 추정할 수 있다. $l=4$ 이전에는 $l=0$의 값($\hat\epsilon_0$)를 사용하는 듯하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$\hat\epsilon_r=\angle(U_l)/(2\pi T_uf_c),\quad l=4,8,12,16,\cdots$&lt;/li&gt;
&lt;li&gt;$\hat\epsilon_{l}=\hat\epsilon_{l+1}=\hat\epsilon_{l+2}=\hat\epsilon_{l+3}=\hat\epsilon_{0}+\hat\epsilon_{r},\quad l=4,8,12,16,\cdots$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위에서 다룬 각 과정의 결과는 &lt;a href=&quot;https://openofdm.readthedocs.io/en/latest/freq_offset.html&quot;&gt;OpenOFDM의 이 문서&lt;/a&gt;에서 Constellation Map으로 볼 수 있다.&lt;/p&gt;
&lt;h2&gt;안테나 다양성을 활용한 FO 추정 향상&lt;/h2&gt;
&lt;p&gt;안테나가 여러 개 있어도 하나의 Oscillator로 작동하므로 CFO, SFO 보상에 활용할 수 있는 데이터의 수가 늘어나 더욱 정교하게 CFO, SFO를 교정해줄 수 있다는 내용이다. 주요 관심 대상이 아니라 자세히는 읽지 않았다.&lt;/p&gt;
&lt;h2&gt;시뮬레이션 결과&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;481&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XJI0Y/btqG7Ro3Hfi/rvDpDrLFBt2gaDnfPYWUnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XJI0Y/btqG7Ro3Hfi/rvDpDrLFBt2gaDnfPYWUnk/img.png&quot; data-alt=&quot;Left:&amp;amp;amp;nbsp;RMS&amp;amp;amp;nbsp;error&amp;amp;amp;nbsp;after&amp;amp;amp;nbsp;ST&amp;amp;amp;nbsp;and&amp;amp;amp;nbsp;LT&amp;amp;amp;nbsp;processing,&amp;amp;amp;nbsp;Right:&amp;amp;amp;nbsp;RMS&amp;amp;amp;nbsp;error&amp;amp;amp;nbsp;after&amp;amp;amp;nbsp;Pilot&amp;amp;amp;nbsp;Symbol&amp;amp;amp;nbsp;processing&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XJI0Y/btqG7Ro3Hfi/rvDpDrLFBt2gaDnfPYWUnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXJI0Y%2FbtqG7Ro3Hfi%2FrvDpDrLFBt2gaDnfPYWUnk%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;481&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Left:&amp;nbsp;RMS&amp;nbsp;error&amp;nbsp;after&amp;nbsp;ST&amp;nbsp;and&amp;nbsp;LT&amp;nbsp;processing,&amp;nbsp;Right:&amp;nbsp;RMS&amp;nbsp;error&amp;nbsp;after&amp;nbsp;Pilot&amp;nbsp;Symbol&amp;nbsp;processing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;왼쪽은 STF와 LTF를 이용한 Coarse/Fine CFO Correction 이후인데, 점선이 Coarse Correction, 실선이 Fine Correction 이후이다. 오른쪽은 Pilot Subcarrier를 이용한 교정 이후이다. 가면 갈수록 RMS가 더 낮아지는 좋은 결과를 얻었다고 한다.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;다시 한 번 정리&lt;/h2&gt;
&lt;h3&gt;CFO, SFO 교정 방법&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;STF에서 대충 CFO를 유추하여 $\hat{\alpha}_{ST}$ 라 하고, 그를 이용하여 교정한다.&lt;/li&gt;
&lt;li&gt;남은 CFO를 LTF로 좀 정밀하게 유추하여 $\hat{\alpha}_{LT}$ 라 하고, 그를 이용하여 교정한다.&lt;/li&gt;
&lt;li&gt;이 단계에서 SFO와 또 남은 자잘한 CFO가 존재하게 된다.&lt;/li&gt;
&lt;li&gt;SFO와 Residual CFO를 Pilot Symbol과 Channel Gain을 이용하여 추정하고, 교정한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;QnA&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;$\alpha=2\pi \epsilon f_c T_s$인 이유는 무엇인가? &lt;br /&gt;Frequency Offset이 $\epsilon$이고, 각주파수(초당 라디안)의 식이 $w=2\pi f$이므로, 매번 샘플링을 할 때마다 $T_sw=2\pi\epsilon f_c T_s$만큼이 느려지게 된다. 따라서 매번 샘플링을 할 때마다 위상 회전은 $\alpha=2\pi \epsilon f_c T_s$ 만큼 발생한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;왜 $\hat{\alpha}_{ST}=\frac{1}{16}\angle \left(\sum^{63}_{m=0}S_m^*S_{m+16}\right)$ 인가? &lt;br /&gt;여기서 논문의 오류로 보이는 것이 있는데, $\hat{\alpha}_{ST}$는 사실 $\frac{1}{16\times 64}\angle \left(\sum^{63}_{m=0}S_m^*S_{m+16}\right)$가 되어야 한다고 본다. $\hat{\alpha}_{ST}$는 한 번 샘플링을 할 때마다 생기는 Frequency Offset의 정도인데, 위의 계산식은 16 hop의 샘플 차이가 나는 것을 총 64번 더했으므로 한 hop 차이가 나는 샘플 간의 Frequency Offset은 $16\times 64$로 나눠야 그 대략적인 평균값을 알 수 있을 것이기 때문이다. 이는 $\hat{\alpha}_{LT}$와 $\angle(W_l)$도 마찬가지로, $\hat{\alpha}_{LT}=\frac{1}{64\times 64}\angle\left(\sum^{63}_{m=0}S_m^*S_{m+64}\right)$ 와 $\angle(W_l)=\frac{1}{4}\angle\left(\sum_{i=-2,-1,1,2}P_{l,i}P_{l-1,i}^*\right)$ 가 되어야 한다고 본다. 이는 내가 논문 이해를 잘못한 것일 수 있으므로, 확신하지는 않는다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LTF를 이용한 CFO Correction의 첫 번째 단계에서 왜 STF + Guard Interval만큼의 Phase Rotation은 보상해주지 않는가?&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;1713&quot; data-origin-height=&quot;632&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pAd4o/btqHerXJ8tB/vx2UJZ8Bc6f37GQvpeaZ10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pAd4o/btqHerXJ8tB/vx2UJZ8Bc6f37GQvpeaZ10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pAd4o/btqHerXJ8tB/vx2UJZ8Bc6f37GQvpeaZ10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpAd4o%2FbtqHerXJ8tB%2Fvx2UJZ8Bc6f37GQvpeaZ10%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;1713&quot; data-origin-height=&quot;632&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p&gt;위 그림에서 볼 수 있듯이, $\hat{\alpha}_{ST}$와 $\hat{\alpha}_{LT}$를 활용한 CFO 제거 과정에서 두 LTF의 시작 부분에서부터 Sample 인덱스를 시작하기 때문에 그 이전의 STF와 GI 시간에 증가해 온 Frequency 차이는 보상이 이루어지지 않는다. 하지만 이 값은 상수 값에 가깝기 때문에 (기울기가 위에서 설명한 FO 보상으로 제거됨), Waveform을 보면 단순한 평행 이동으로 나타나게 된다. 이는 따로 &quot;Timing Offset&quot;이라는 용어가 있으며, 별개의 보상 방법을 따른다. 이는 이 내가 보려는 &quot;Frequency Offset&quot; 주제를 벗어나기에 굳이 이 글에서 따로 다루지는 않는다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Residual CFO 보상을 할 때와 Pilot Symbol을 활용한 Fine FO Estimation을 할 때, $P_{0,i}=Q_i$와 같이 Pilot Symbol($P$)이 들어가야 할 것 같은 자리에 채널 이득($Q$)을 대입하는데, 이렇게 해서 위상 회전 값을 구할 수 있는 이유는 무엇인가? &lt;br /&gt;모르겠다. 논문에서는 아무런 설명도 나와있지 않다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;위에서 나온 아래 말의 의미는 무엇인가?&lt;/p&gt;
&lt;p&gt;연속적인 덧셈 연산은 Fixed-point 하드웨어에서 부정확한 계산의 원인이 될 수 있으므로 4개의 연속된 $W$를 Exponential 필터를 적용하여 아래와 같이 더해준다.&lt;/p&gt;
모르겠다. 논문에서도 저 말 이외에 설명 혹은 인용 없이 그렇다고 하는데, 잘 모르겠다.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>무선 네트워크/Channel State Information</category>
      <category>802.11</category>
      <category>CFO</category>
      <category>SFO</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/49</guid>
      <comments>https://yuoa.tistory.com/entry/Frequency-Offset-Estimation-and-Correction#entry49comment</comments>
      <pubDate>Wed, 26 Aug 2020 05:08:56 +0900</pubDate>
    </item>
    <item>
      <title>Precise Power Delay Profiling with Commodity Wi-Fi</title>
      <link>https://yuoa.tistory.com/entry/Precise-Power-Delay-Profiling-with-Commodity-Wi-Fi</link>
      <description>&lt;p&gt;CSI에서 제시하는 각 성분에 대해 더 자세히 이해하기 위해 읽게 된 논문이다. ACM MobiCom과 IEEE TMC에 등재되었는데, 더 많은 리뷰를 거친 듯한 TMC의 것을 읽었다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ieeexplore.ieee.org/document/8423070&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IEEE Explore (2018)&lt;/a&gt; / &lt;a href=&quot;https://dl.acm.org/doi/10.1145/2789168.2790124&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ACM Library (2015)&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;이 논문에서는 더 정확한 Power Delay Profile (PDP) 분석 및 활용을 위해 인접한 채널의 CSI를 이어 큰 Bandwidth에 대한 CSI 정보를 얻고자 했다.&lt;/p&gt;
&lt;p&gt;Power Delay Profile의 시간축 Resolution은 신호의 대역폭에 따라 결정되는데 &lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_43_1&quot; id=&quot;footnote_link_43_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 43, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(43, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_43_2&quot; id=&quot;footnote_link_43_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 43, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(43, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;, 20MHz로 샘플링을 할 경우 감지할 수 있는 Multipath의 거리 차이는 최소 약 15m ($c \times (\frac{1}{20e+6})=14.9896$)이다. 만일 대역폭을 늘려 80MHz가 된다면, 감지할 수 있는 거리 차이는 최소 약 4m ($c \times (\frac{1}{80e+6})=3.7474$)로 줄어든다. 더욱 정확한 프로파일 분석이 가능해지는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;하지만 인접한 채널의 CSI를 그대로 이어붙이는 건 불가능했다. 회로의 부정확함과 통신에 영향을 주지 않는 결함이 컸기 때문이다. 따라서, 이 논문에서는 그러한 여러 오류를 어떻게 보상할 수 있을지에 대해 연구하였고, 시변 채널에 대해 얼마의 주기로 보상 값 계산을 해야하는지 등의 시스템 설계를 진행하였다.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Phase 값 이어 붙이기&lt;/h2&gt;
&lt;p&gt;이어붙이기 전에 몇 가지 문제를 해결해야 한다.&lt;/p&gt;
&lt;h3&gt;값의 겉보기 형태적 문제 (Non-linear Error)&lt;/h3&gt;
&lt;p&gt;자연의 신호는 연속이고, Phase는 선형이지만 실제 신호를 합쳐보거나 신호를 보면 그렇지 아니했다.&lt;/p&gt;
&lt;h4&gt;그래프에서 Phase값이 직선이 아니다.&lt;/h4&gt;
&lt;p&gt;원래 Propagation 거리 ($d$)가 일정하다면 주파수에 따른 Phase 값($\phi_k$)은 일정히 증가해야 한다.&lt;/p&gt;
&lt;p&gt;$$\phi_k=2\pi( f_0+k\Delta f)\frac{d}{c}$$&lt;/p&gt;
&lt;p&gt;하지만 Tx-Rx를 안테나를 써봐도, 안테나 대신 유선으로 땡깡 이어보아도 그러지 못했다. 즉, 아래의 (a), (b), (c)에서 직선 형태가 관찰되지 않았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgUI5h/btqBAV9MwDO/fHeObhpphpCluBVYwGiZy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgUI5h/btqBAV9MwDO/fHeObhpphpCluBVYwGiZy0/img.png&quot; width=&quot;389&quot; height=&quot;276&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 52.6972%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgUI5h/btqBAV9MwDO/fHeObhpphpCluBVYwGiZy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgUI5h%2FbtqBAV9MwDO%2FfHeObhpphpCluBVYwGiZy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMVgKs/btqBzPJrlMQ/UC6dKeM5iV85ZO84tQEALK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMVgKs/btqBzPJrlMQ/UC6dKeM5iV85ZO84tQEALK/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 46.14%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMVgKs/btqBzPJrlMQ/UC6dKeM5iV85ZO84tQEALK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMVgKs%2FbtqBzPJrlMQ%2FUC6dKeM5iV85ZO84tQEALK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;(좌) 유선으로 Tx/Rx 칩을 이어 본 결과. 다른 색깔은 다른 칩이다. (우) 예상되는 결과.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;서브캐리어 중간 부분은 어느 정도 직선 형태를 띄었는데, 양쪽 가에서는 그러지 못했다. 다만 이 Phase 왜곡 값은 모든 채널에서 각 서브캐리어에 대해 동일하게 나타났으므로, 칩마다 그 상수값을 측정하여 보상하면 된다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p&gt;개인적으로 이 내용을 구현해볼 때는 다음과 같이 했다.&lt;/p&gt;
&lt;p&gt;40 MHz 채널에 대해서는 이 보정을 적용하기 이전에 아래의 Phase 튀는 문제의 보정을 먼저 적용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1581472231811&quot; class=&quot;matlab&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% original_phase = o_phase
% linearified phase = l_phase
phase_newavg = mean(l_phase);
if size(o_phase, 2) == 114
  phase_center = mean(phase_newavg(39:76));
  phase_grad = mean(gradient(phase_newavg(39:76)));
else
  phase_center = mean(phase_newavg(19:36));
  phase_grad = mean(gradient(phase_newavg(19:36)));
end

syms x;
phase_line = x * phase_grad + phase_center;

if size(o_phase, 2) == 114
  phase_lindiff = phase_newavg - double(subs(phase_line, [-58:-2 2:58]));
else
  phase_lindiff = phase_newavg - double(subs(phase_line, [-28:-1 1:28]));
end

for i = 1:size(o_phase, 1)
  l_phase(i, :) = l_phase(i, :) - phase_lindiff;
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 구현하면 아래와 같은 결과가 나온다.&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u2I7r/btqBVgs0sUF/9ua9D1uBKk0yRJoFxMreLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u2I7r/btqBVgs0sUF/9ua9D1uBKk0yRJoFxMreLk/img.png&quot; data-filename=&quot;untitled4.png&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;573&quot; style=&quot;width: 49.4318%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u2I7r/btqBVgs0sUF/9ua9D1uBKk0yRJoFxMreLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu2I7r%2FbtqBVgs0sUF%2F9ua9D1uBKk0yRJoFxMreLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;726&quot; height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QtrI0/btqBVfgtQJJ/AQSnDwyDvCvYFyu4VDrss1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QtrI0/btqBVfgtQJJ/AQSnDwyDvCvYFyu4VDrss1/img.png&quot; data-filename=&quot;untitled3.png&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;574&quot; style=&quot;width: 49.3457%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QtrI0/btqBVfgtQJJ/AQSnDwyDvCvYFyu4VDrss1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQtrI0%2FbtqBVfgtQJJ%2FAQSnDwyDvCvYFyu4VDrss1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;726&quot; height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4&gt;40MHz 채널 중간에서 Phase가 튄다.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;405&quot; height=&quot;217&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVgOuW/btqByF7Vfg4/voYrm3G9KZjzaR4yb16JTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVgOuW/btqByF7Vfg4/voYrm3G9KZjzaR4yb16JTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVgOuW/btqByF7Vfg4/voYrm3G9KZjzaR4yb16JTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVgOuW%2FbtqByF7Vfg4%2FvoYrm3G9KZjzaR4yb16JTk%2Fimg.png&quot; width=&quot;405&quot; height=&quot;217&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;튄다. 위 그래프에서 아래 50-60 사이를 보면 훅 올라가는 구간이 있다. 이는 이 사람들이 조사해 본 결과 항상 일정한 값 (이 사람들 기기에서는 약 1.7rad)을 유지하는 경향이 있는 것이 확인되어 그냥 상수로 조사하여 보상해주면 된다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p&gt;개인적으로 이 내용을 구현해볼 때는 다음과 같이 했다.&lt;/p&gt;
&lt;pre id=&quot;code_1581472534168&quot; class=&quot;matlab&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% original phase = o_phase
% linearified phase = l_phase
if size(o_phase, 2) == 114
  phase_avg = mean(o_phase);
  phase_diff = phase_avg(58) - phase_avg(57) + ( ...
      (phase_avg(56) - phase_avg(41) ...
      + phase_avg(74) - phase_avg(59)) / 30 ...
      ) * 4;
  for i = 1:size(o_phase, 1)
      l_phase(i, :) = [ ...
          o_phase(i, 1:57) (o_phase(i, 58:114)' - phase_diff) ...
      ];
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 구현하면 아래와 같은 결과가 나온다.&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnCoFJ/btqBUArZBaU/itKkdkjIfFA9urVkvH15gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnCoFJ/btqBUArZBaU/itKkdkjIfFA9urVkvH15gk/img.png&quot; data-filename=&quot;figure_0 (1).png&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1313&quot; style=&quot;width: 49.3888%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnCoFJ/btqBUArZBaU/itKkdkjIfFA9urVkvH15gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnCoFJ%2FbtqBUArZBaU%2FitKkdkjIfFA9urVkvH15gk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1750&quot; height=&quot;1313&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by9dT0/btqBUSTqnaX/C80LGRaU0G2txpJaMYstEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by9dT0/btqBUSTqnaX/C80LGRaU0G2txpJaMYstEK/img.png&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1313&quot; style=&quot;width: 49.3888%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by9dT0/btqBUSTqnaX/C80LGRaU0G2txpJaMYstEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby9dT0%2FbtqBUSTqnaX%2FC80LGRaU0G2txpJaMYstEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1750&quot; height=&quot;1313&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;위 두가지를 동작 인식에 사용할 수 있을까?&lt;/h4&gt;
&lt;p&gt;물론 사용할 수 있다. 하지만 결국 이상적으로 생각해보면 CSI의 Phase 데이터로부터 얻는 것은 하나의 일차방정식일 것이기 때문에, 위의 Nonlinear Error를 보상하는 것보다는 아래의 Linear Error를 보상하는 것이 훨씬 그 정확도를 높일 것이다. 컴퓨팅 리소스도 아낄 겸...! 뉴럴넷이 해결해줄거야...!&lt;/p&gt;
&lt;h3&gt;선형성에는 영향이 없는 오류들 (Linear Error)&lt;/h3&gt;
&lt;p&gt;이제부터는 겁나 어렵다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dELrIl/btqBzjjemDF/EPTT0lAHHNyf5r3YUSiqLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dELrIl/btqBzjjemDF/EPTT0lAHHNyf5r3YUSiqLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dELrIl/btqBzjjemDF/EPTT0lAHHNyf5r3YUSiqLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdELrIl%2FbtqBzjjemDF%2FEPTT0lAHHNyf5r3YUSiqLK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;안테나로부터 CSI를 얻는 과정은 위와 같은데, Phase값에 오류가 생기는 부분과 그 오류는 (그림에는 나와있지 않지만) Up/Downconverter에서 CFO, Packet Detector에서 Packet Detection Uncertainty (시간 오류), DAC/ADC에서 SFO이다.이다. CFO는 그림에 나와있듯이 CFO Corrector에서 어느정도 보상이 가능하다. 하지만 여전히 CFO 문제는 조금 남아있게 된다. AGC가 일으키는 문제는 추후 Amplitude 값 오류 해결 부분에서 다룬다.&lt;/p&gt;
&lt;h4&gt;Packet Boundary Detection Uncertainty 제거&lt;/h4&gt;
&lt;p&gt;들어오는 신호와 칩의 샘플링 주기가 정확하게 맞아 떨어지지 않는 이상, Packet Boundary Detection Error는 작은 범위 내에서 항상 일어나기 마련이다. 802.11n 칩은 &lt;a href=&quot;https://dsp.stackexchange.com/questions/17968/sampling-rate-in-wifi-802-11-20-mhz-enough-with-a-bw-of-20-mhz&quot;&gt;Packet Boundary를 20MHz로 체크&lt;/a&gt;하므로, 아마 많아야 0.00000005초 이내로 차이가 날 것이라고 나는 생각하고 있다. 아무튼 PBD 에러는 거의 무조건 발생하는데, 이로 인해 실제 패킷의 시작 부분과 차이가 나는 만큼 Time Delay($\tau_b$)가 생긴다.&lt;/p&gt;
&lt;p&gt;이 논문에서 인용한 [20]번째 문서&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_43_3&quot; id=&quot;footnote_link_43_3&quot; onmouseover=&quot;tistoryFootnote.show(this, 43, 3)&quot; onmouseout=&quot;tistoryFootnote.hide(43, 3)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;3&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;에 따르면 이 PBD 오류는 오류가 없는 점($\tau_b=0$)을 기준으로 가우시안 분포를 이룬다고 한다. 그리고 이 논문에서는 그를 직접 증명하는데, 실제로 가우시안 분포이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O955e/btqBuPi96LL/sH57L6jdaHqqtTkBQQaIfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O955e/btqBuPi96LL/sH57L6jdaHqqtTkBQQaIfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O955e/btqBuPi96LL/sH57L6jdaHqqtTkBQQaIfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO955e%2FbtqBuPi96LL%2FsH57L6jdaHqqtTkBQQaIfk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;가우시안 분포를 따르는 오류는 어떻게 해결하는가?! 평균내면 된다. 그럼 영에 수렴할 터이다.&lt;/p&gt;
&lt;p&gt;측정하려는 임의의 밴드 $b$에서 평균을 계산하기 위해 모을 패킷의 개수를 $n_b$라 하면...&lt;/p&gt;
&lt;p&gt;$$\bar{\phi}^b_k=\sum^{n_b}_{i=1}\phi^b_k(i)/n_b$$&lt;/p&gt;
&lt;p&gt;이다. 여기서 $i$는 측정한 Packet의 번호이고, $k$는 서브캐리어의 번호이다. 즉, 각 밴드 각 서브캐리어마다 몇개의 CSI를 모아 평균을 때린다는 것이다.&lt;/p&gt;
&lt;p&gt;이 보정을 동작 인식에 사용한다고 생각해보자. 분명... Phase 변화가 더 부드러워질 것이다. 하지만 우리의 뉴럴넷은 어느정도의 노이즈는 받아주므로 뉴럴넷에 넣을 데이터에 이 전처리는 안 해줘도 될 것이다.&lt;/p&gt;
&lt;h4&gt;Sampling Frequency Offset 제거&lt;/h4&gt;
&lt;p&gt;SFO는 DAC와 ADC 사이의 샘플링 Frequency 차이인데, Tx와 Rx의 샘플링 주파수를 각각 $f_t$, $f_r$이라고 하면 이들로 인해 일어날 수 있는 Offset의 최소 배수 (fractional difference)를 $\zeta=\frac{f_t}{f_r}-1$이라고 할 수 있다. SFO를 $\phi_k$에서 제거하려면 $\phi_k$에다 $e^{-j\cdot \zeta'\cdot k}$를 곱하면 될 것이다. $j$는 허수, $\zeta'$는 fractional difference의 배수이다.&lt;/p&gt;
&lt;p&gt;그렇다면 저 SFO($\zeta'$, 아래에서는 $\epsilon$)는 어떻게 구하는가? 이 논문의 저자들은 같은 환경 및 조건에서 여러 밴드에 대해 CSI를 측정할 경우 같은 Multi Path를 거치기 때문에, PBD로 인한 오류를 제거한 다음의 Phase값이 만일 SFO가 없다면 밴드 관계 없이 모두 동일해야 한다는 점을 이용했다. &lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_43_4&quot; id=&quot;footnote_link_43_4&quot; onmouseover=&quot;tistoryFootnote.show(this, 43, 4)&quot; onmouseout=&quot;tistoryFootnote.hide(43, 4)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;4&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;for each Wi-Fi Band Pair &quot;$c$&quot; do  
    Record the top-two local maximal similarity values and the  
    corresponding $\epsilon:&amp;lt;\epsilon^c_1,\rho^c_1&amp;gt;$ and $&amp;lt;\epsilon^c_2,\rho^c_2&amp;gt;$.  
Clustering on $\epsilon$ and find the cluster with the maximal similarity sum.  
Return the cluster center as the final $\epsilon$ value.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;알고리즘을 해석해보자면, 두 밴드의 페어를 $c$라 하고, 한쪽 밴드에 $\epsilon^c$만큼을 곱하여 &quot;rotate&quot; 시킨 뒤, 두 밴드의 Phase 유사도를 $\rho^c$라 하며, 그들을 저장하여 클러스터링하여 가장 유사도가 높은 곳의 $\epsilon$값을 SFO로 추정하겠다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uvIUx/btqBxz1clfO/La44LVlg4wdLewszdMEKrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uvIUx/btqBxz1clfO/La44LVlg4wdLewszdMEKrk/img.png&quot; data-alt=&quot;이런 결과가 나오며, 여기서는 $\epsilon=0.75$ 정도가 가장 유사도($\rho$)가 크게 나왔다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uvIUx/btqBxz1clfO/La44LVlg4wdLewszdMEKrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuvIUx%2FbtqBxz1clfO%2FLa44LVlg4wdLewszdMEKrk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이런 결과가 나오며, 여기서는 $\epsilon=0.75$ 정도가 가장 유사도($\rho$)가 크게 나왔다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;컴퓨팅 효율이 안좋을 것 같아 보이지만, 그에 대해서는 후술한다.&lt;/p&gt;
&lt;h4&gt;Central Frequency Offset 제거&lt;/h4&gt;
&lt;p&gt;Central Frequency Offset은 Tx와 Rx가 중앙 주파수를 서로 못 맞춰서 벌어지는 일이다. 이때까지의 오류 원인들은 모두 서브캐리어마다 다르게 작용하여 Normalize한 CSI 값에도 영향을 주었으나, Central Frequency Offset은 모든 서브캐리어에 동일하게 더해지기에 Normalize 결과에 영향을 주지 않는다. 따라서 하나의 밴드를 레퍼런스 삼아 다른 밴드를 캘리브레이션한다면 CFO는 고려하지 않아도 되게 될 것이다.&lt;/p&gt;
&lt;p&gt;어떻게 캘리브레이션하냐면... [업데이트 예정]&lt;/p&gt;
&lt;h4&gt;Unused Subcarriers 메꾸기&lt;/h4&gt;
&lt;p&gt;CSI에서 보고되는 서브캐리어에는 일부가 빠져 있다. Atheros CSI Tool의 경우 아래의 $Ng=1$, Intel CSI Tool의 경우 20MHz 대역폭에서는 $Ng=2$, 40MHz 대역폭에서는 $Ng=4$를 보고한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;548&quot; height=&quot;311&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckgEXo/btqBuQvNuTE/7sCvQjzMIz0aflgkLLkvr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckgEXo/btqBuQvNuTE/7sCvQjzMIz0aflgkLLkvr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckgEXo/btqBuQvNuTE/7sCvQjzMIz0aflgkLLkvr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckgEXo%2FbtqBuQvNuTE%2F7sCvQjzMIz0aflgkLLkvr0%2Fimg.png&quot; width=&quot;548&quot; height=&quot;311&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;어떤 툴을 써도 중앙의 DC(Central) 서브캐리어와 양쪽의 가드 밴드는 보고하지 않는다. 각각 DC Offset과 인접 채널의 영향을 막기 위해서이다. 이러면 사실상 측정하려는 밴드에 대해 연속적으로 샘플링을 하지 않는것이 되는데, 통신 이론에 따르면 특정 대역폭($B_c$) 안의 주파수 대역은 페이딩을 비슷하게 겪는다고 하며, 실내 환경에서 $B_c$는 10MHz를 넘는다고 한다. 즉, 보고되지 않은 아이들은 커브 피팅으로 보완해줄 수 있는 것이다.&lt;/p&gt;
&lt;p&gt;어떤 커브를 썼느냐면... [업데이트 예정]&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Phase 값 이어 붙이기 마무리&lt;/h3&gt;
&lt;p&gt;아직 더 오류가 남아있을 수 있지만 (Thermal Noise, AGC Error 등) 이렇게 각 신호/패킷 분석 과정에서 일어나는 오류는 보상하고 여러 밴드의 Phase값을 이어붙일 수 있다.&lt;/p&gt;
&lt;p&gt;이어붙인 다음에 한 번 더 SFO 보상을 해줄 수 있는데, 이어붙인 넓은 Bandwidth에서 일부 서브캐리어를 연속으로 선택하여 윈도우로 만들고, 그 윈도우들끼리 SFO 보상 알고리즘을 다시 한 번 실행하여 더욱 정확하게 SFO 값을 없앨 수 있다고 한다.&lt;/p&gt;
&lt;p&gt;윈도우의 크기가 클 수록 더 정확한 SFO를 얻을 수 있을 것으로 보이지만, 그게 아니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvMwrU/btqBAUQ1e0t/2EyIiZGk3bwI9gi5MWfGR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvMwrU/btqBAUQ1e0t/2EyIiZGk3bwI9gi5MWfGR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvMwrU/btqBAUQ1e0t/2EyIiZGk3bwI9gi5MWfGR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvMwrU%2FbtqBAUQ1e0t%2F2EyIiZGk3bwI9gi5MWfGR1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;따라서 전체 Bandwidth의 0.75를 사용하여 SFO 보상을 하면 가장 정확하며, 이렇게 이어붙이고 보상을 해줄 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Amplitude 값 이어 붙이기&lt;/h2&gt;
&lt;p&gt;AGC에서 발생하는 Power Control 오류 또한 가우시안 분포를 따른다고 한다. 허나 이는 밴드와 무관한 현상이므로, Phase에서 평균을 내는 방식과는 다르게 얻은 모든 CSI값을 평균내어 구할 수 있다.&lt;/p&gt;
&lt;p&gt;어떻게 했냐면... [업데이트 예정]&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;오류 보상 주기&lt;/h2&gt;
&lt;p&gt;올바른 이어붙이기를 위해서는 언제 CSI를 측정하여 시시각각 달라지는 오류를 보상해줄지 그 스케쥴링 또한 필요하다. 하지만 지금 내 목표는 이미 기록된, Windowed CSI에 대한 후처리이기 때문에, 여기 부분은 읽지 않았다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_43_1&quot;&gt;T. S. Rappaport, et al., Wireless Communications: Principles and Practice. Upper Saddle River, NJ, USA: Prentice Hall, 1996. &lt;a href=&quot;#footnote_link_43_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_43_2&quot;&gt;A. Goldsmith, Wireless Communications. Cambridge, U.K.: Cambridge Univ. Press, 2005. &lt;a href=&quot;#footnote_link_43_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_43_3&quot;&gt;M. Speth, S. Fechtel, G. Fock, and H. Meyr, &amp;ldquo;Optimum receiver design for wireless broad-band systems using OFDM. I,&amp;rdquo; IEEE Trans. Commun., vol. 47, no. 11, pp. 1668&amp;ndash;1677, Nov. 1999. &lt;a href=&quot;#footnote_link_43_3&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_43_4&quot;&gt;아래 말할 Central Frequency Offset으로 인한 오류는 여기에 영향을 주지 않는다! 왜 그런가에 대해서는 후술한다. &lt;a href=&quot;#footnote_link_43_4&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>무선 네트워크/Channel State Information</category>
      <category>802.11</category>
      <category>csi</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/43</guid>
      <comments>https://yuoa.tistory.com/entry/Precise-Power-Delay-Profiling-with-Commodity-Wi-Fi#entry43comment</comments>
      <pubDate>Tue, 11 Feb 2020 02:12:46 +0900</pubDate>
    </item>
    <item>
      <title>Where is the orthogonality in OFDM?</title>
      <link>https://yuoa.tistory.com/entry/Where-is-the-orthogonality-in-OFDM</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Mathematical&amp;nbsp;Concept&amp;nbsp;of&amp;nbsp;&quot;Orthogonality&quot;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;Generally &lt;/span&gt;&lt;i&gt;&lt;span&gt;orthogonality&lt;/span&gt;&lt;/i&gt;&lt;span&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;means&amp;nbsp;that&amp;nbsp;the&amp;nbsp;inner&amp;nbsp;product&amp;nbsp;of&amp;nbsp;two&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span&gt;vector&lt;/span&gt;&lt;/b&gt;&lt;span&gt; is zero.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;There's&amp;nbsp;not&amp;nbsp;only&amp;nbsp;a&amp;nbsp;concept&amp;nbsp;of&amp;nbsp;the&amp;nbsp;inner&amp;nbsp;product&amp;nbsp;of&amp;nbsp;vectors,&amp;nbsp;but&amp;nbsp;the&amp;nbsp;inner&amp;nbsp;product&amp;nbsp;of&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span&gt;functions&lt;/span&gt;&lt;/b&gt;&lt;span&gt;,&amp;nbsp;and&amp;nbsp;this&amp;nbsp;can&amp;nbsp;be&amp;nbsp;expressed&amp;nbsp;as&amp;nbsp;a&amp;nbsp;definite&amp;nbsp;integral.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;$$\left\lbrace \begin{array}{ccc}&amp;lt;f,g&amp;gt;=\int_a^b f(x)g(x)~dx &amp;amp;&amp;nbsp;&amp;nbsp;&amp;amp; \textrm{Inner}\;\textrm{Prod.}\;\textrm{of}\;\textrm{Real}\;\textrm{Fn.}\\&amp;lt;f,g&amp;gt;=\int_a^b f(x)\overline{g(x)} ~dx &amp;amp;&amp;nbsp;&amp;nbsp;&amp;amp; \textrm{Inner}\;\textrm{Prod.}\;\textrm{of}\;\textrm{Complex}\;\textrm{Fn.}\end{array}\right.$$&lt;/p&gt;
&lt;p&gt;Therefore,&amp;nbsp;we&amp;nbsp;can&amp;nbsp;say&amp;nbsp;that&amp;nbsp;two&amp;nbsp;functions&amp;nbsp;are&amp;nbsp;orthogonal&amp;nbsp;if&amp;nbsp;their&amp;nbsp;inner&amp;nbsp;product&amp;nbsp;value&amp;nbsp;is&amp;nbsp;zero&amp;nbsp;and&amp;nbsp;this&amp;nbsp;can&amp;nbsp;be&amp;nbsp;applied&amp;nbsp;to&amp;nbsp;complex&amp;nbsp;signals.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Orthogonality&amp;nbsp;of&amp;nbsp;OFDM&amp;nbsp;Subcarriers&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Mathematical&amp;nbsp;Expression&amp;nbsp;of&amp;nbsp;OFDM&amp;nbsp;Signal&lt;/h3&gt;
&lt;p&gt;The&amp;nbsp;OFDM&amp;nbsp;signal&amp;nbsp;can&amp;nbsp;be&amp;nbsp;expressed&amp;nbsp;as&amp;nbsp;below.&lt;/p&gt;
&lt;p&gt;$$\left\lbrace \begin{array}{ccc}S(t)=\frac{1}{N}\sum_{n=0}^{N-1} A_n (t)e^{j\left\lbrack \omega_n t+\phi_n (t)\right\rbrack }&amp;nbsp;&amp;nbsp;&amp;amp;&amp;nbsp;&amp;nbsp;&amp;amp; \textrm{OFDM}\;\textrm{Signal}\\S_n (t)=A_n (t)e^{j\left\lbrack \omega_n t+\phi_n (t)\right\rbrack }&amp;nbsp;&amp;nbsp;&amp;amp;&amp;nbsp;&amp;nbsp;&amp;amp; \textrm{Signal}\;\textrm{of}\;\textrm{Each}\;\textrm{Subcarrier}\end{array}\right.$$&lt;/p&gt;
&lt;p&gt;$N$&amp;nbsp;is&amp;nbsp;the&amp;nbsp;number&amp;nbsp;of&amp;nbsp;subcarriers,&amp;nbsp;$A_n$&amp;nbsp;is&amp;nbsp;amplitude&amp;nbsp;of&amp;nbsp;each&amp;nbsp;subcarrier,&amp;nbsp;and&amp;nbsp;$\phi_n$&amp;nbsp;is&amp;nbsp;phase&amp;nbsp;of&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;$A_n&amp;nbsp;(t)$&amp;nbsp;and&amp;nbsp;$\phi_n&amp;nbsp;(t)$&amp;nbsp;has&amp;nbsp;a&amp;nbsp;constant&amp;nbsp;value&amp;nbsp;during&amp;nbsp;a&amp;nbsp;symbol&amp;nbsp;duration&amp;nbsp;and&amp;nbsp;$\omega_n&amp;nbsp;=\omega_0&amp;nbsp;+n\Delta&amp;nbsp;\omega$.&lt;/p&gt;
&lt;p&gt;Suppose&amp;nbsp;that&amp;nbsp;the&amp;nbsp;sampling&amp;nbsp;rate&amp;nbsp;is&amp;nbsp;$1/T_s$,&amp;nbsp;then&amp;nbsp;a&amp;nbsp;period&amp;nbsp;of&amp;nbsp;one&amp;nbsp;OFDM&amp;nbsp;symbol&amp;nbsp;is&amp;nbsp;$T=NT_s$&amp;nbsp;because&amp;nbsp;we&amp;nbsp;should&amp;nbsp;sample&amp;nbsp;$N$&amp;nbsp;times&amp;nbsp;in&amp;nbsp;one&amp;nbsp;symbol.&amp;nbsp;Also&amp;nbsp;suppose&amp;nbsp;that&amp;nbsp;$\omega_0&amp;nbsp;=0$,&amp;nbsp;then&amp;nbsp;$\omega_n$&amp;nbsp;becomes&amp;nbsp;$n\Delta&amp;nbsp;\omega$.&lt;/p&gt;
&lt;p&gt;We&amp;nbsp;can&amp;nbsp;now&amp;nbsp;write&amp;nbsp;a&amp;nbsp;simple&amp;nbsp;sampled&amp;nbsp;signal&amp;nbsp;expression:&amp;nbsp;$S(tT_s&amp;nbsp;)=\frac{1}{N}\sum_{n=0}^{N-1}&amp;nbsp;\textrm{C}e^{jn\Delta&amp;nbsp;\omega&amp;nbsp;tT_s&amp;nbsp;}&amp;nbsp;~~(0\le&amp;nbsp;t&amp;lt;T)$&lt;/p&gt;
&lt;p&gt;$\textrm{C}$&amp;nbsp;is&amp;nbsp;a&amp;nbsp;const&amp;nbsp;from&amp;nbsp;amplitude&amp;nbsp;and&amp;nbsp;phase&amp;nbsp;values&amp;nbsp;at&amp;nbsp;a&amp;nbsp;specific&amp;nbsp;symbol.&lt;/p&gt;
&lt;p&gt;The&amp;nbsp;OFDM&amp;nbsp;signal&amp;nbsp;is&amp;nbsp;generated&amp;nbsp;from&amp;nbsp;IDFT&amp;nbsp;calculation,&amp;nbsp;so&amp;nbsp;let's&amp;nbsp;compare&amp;nbsp;above&amp;nbsp;with&amp;nbsp;general&amp;nbsp;IDFT&amp;nbsp;expression.&lt;/p&gt;
&lt;p&gt;$$\left\lbrace \begin{array}{ccc}S(tT_s )=\frac{1}{N}\sum_{n=0}^{N-1} \textrm{C}e^{jn\Delta \omega tT_s }&amp;nbsp;&amp;nbsp;&amp;amp;&amp;nbsp;&amp;nbsp;&amp;amp; \textrm{Simplified}\;\textrm{OFDM}\;\textrm{Signal}\\x(tT_s )=\frac{1}{N}\sum_{n=0}^{N-1} X(tT_s )e^{j2\pi tn/N}&amp;nbsp;&amp;nbsp;&amp;amp;&amp;nbsp;&amp;nbsp;&amp;amp; \textrm{General}\;\textrm{IDFT}\;\textrm{Expression}\end{array}\right.$$&lt;/p&gt;
&lt;p&gt;So, $\Delta \omega =\frac{2\pi }{T}$. This is a condition for the orthogonality. &lt;i&gt;Why?&lt;/i&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Dealing&amp;nbsp;with&amp;nbsp;Orthogonality&lt;/h3&gt;
&lt;p&gt;Let's&amp;nbsp;try&amp;nbsp;to&amp;nbsp;show&amp;nbsp;that&amp;nbsp;subcarrier&amp;nbsp;$\alpha$&amp;nbsp;and&amp;nbsp;$\beta$&amp;nbsp;is&amp;nbsp;orthogonal.&amp;nbsp;We&amp;nbsp;should&amp;nbsp;solve&amp;nbsp;definite&amp;nbsp;integral&amp;nbsp;of&amp;nbsp;two&amp;nbsp;signal&amp;nbsp;of&amp;nbsp;each&amp;nbsp;subcarrier.&lt;/p&gt;
&lt;p&gt;$$\int_0^T&amp;nbsp;S_{\alpha&amp;nbsp;}&amp;nbsp;(t)\overline{S_{\beta&amp;nbsp;}&amp;nbsp;(t)}&amp;nbsp;~dt$$&lt;/p&gt;
&lt;p&gt;For&amp;nbsp;convinience&amp;nbsp;of&amp;nbsp;thinking,&amp;nbsp;the&amp;nbsp;amplitude&amp;nbsp;part&amp;nbsp;and&amp;nbsp;phase&amp;nbsp;part&amp;nbsp;can&amp;nbsp;be&amp;nbsp;expressed&amp;nbsp;as&amp;nbsp;a&amp;nbsp;symbol&amp;nbsp;$C$&amp;nbsp;because&amp;nbsp;they&amp;nbsp;are&amp;nbsp;constant.&amp;nbsp;Also&amp;nbsp;suppose&amp;nbsp;that&amp;nbsp;the&amp;nbsp;lowest&amp;nbsp;frequency&amp;nbsp;is&amp;nbsp;0&amp;nbsp;($\omega_0&amp;nbsp;=0$).&lt;/p&gt;
&lt;p&gt;$$C\int_0^T&amp;nbsp;e^{j(\alpha&amp;nbsp;\Delta&amp;nbsp;\omega&amp;nbsp;)t}&amp;nbsp;e^{-j(\beta&amp;nbsp;\Delta&amp;nbsp;\omega&amp;nbsp;)t}&amp;nbsp;~dt=C\int_0^T&amp;nbsp;e^{jt\Delta&amp;nbsp;\omega&amp;nbsp;(\alpha&amp;nbsp;-\beta&amp;nbsp;)}&amp;nbsp;~dt$$&lt;/p&gt;
&lt;p&gt;Then&amp;nbsp;the&amp;nbsp;trigonometric&amp;nbsp;form&amp;nbsp;of&amp;nbsp;the&amp;nbsp;integration&amp;nbsp;is&amp;nbsp;$C\int_0^T&amp;nbsp;\cos&amp;nbsp;(t\Delta&amp;nbsp;\omega&amp;nbsp;k)+j\sin&amp;nbsp;(t\Delta&amp;nbsp;\omega&amp;nbsp;k)~dt$&amp;nbsp;if&amp;nbsp;$k=\alpha&amp;nbsp;-\beta$.&lt;/p&gt;
&lt;p&gt;This&amp;nbsp;equals&amp;nbsp;to&amp;nbsp;$C\int_0^T&amp;nbsp;\cos&amp;nbsp;(\frac{2\pi&amp;nbsp;tk}{T})+j\sin&amp;nbsp;(\frac{2\pi&amp;nbsp;tk}{T})~dt$&amp;nbsp;and&amp;nbsp;$k$&amp;nbsp;is&amp;nbsp;an&amp;nbsp;integer!&lt;/p&gt;
&lt;p&gt;When&amp;nbsp;we&amp;nbsp;solve&amp;nbsp;the&amp;nbsp;integral:&amp;nbsp;$C(0+0j)=0$&lt;/p&gt;
&lt;p&gt;&lt;b&gt;So, for any subcarrier&lt;/b&gt; $\mathbf{\alpha}$&lt;b&gt; and&lt;/b&gt; $\mathbf{\beta}$&lt;b&gt;, they are orthogonal!&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MATLAB Example&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/BSvBS/btqBIIwxyPc/9g0mp4PF4DQkLdf7vd1huK/csi_0006_OinOFDM.mlx?attach=1&amp;amp;knm=tfile.mlx&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;csi_0006_OinOFDM.mlx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.17MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1580815064316&quot; class=&quot;matlab&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% Select Two Subcarriers
sub_a = 11; % Subcarrier A [1 64]
sub_b = 48; % Subcarrier B [1 64]

% Environment Configuration
symbol_duration = 3.2e-6; % 3.2 microseconds
rx_sampling_time = 5e-8:5e-8:symbol_duration; % 20MHz
N = 64; % 64 subcarriers

% One Symbol Signal Generation
rng('shuffle');
syms t;
% oscillator_resolution = (symbol_duration / (N * 1e+2));
signal = sym(zeros(N));
for i = 1:N
    signal(i) = (rand(1) + rand(1) * 1i) * ...
        exp(1i * i * 2 * pi / symbol_duration * t);
end

% Plot Signals
figure(1); clf;
hold on;
plot(NaN, 'Color', [0 0 0], 'LineWidth', 2);
plot(NaN, 'Color', 'g', 'LineWidth', 2);
plot(NaN, 'Color', 'r');
for i = 1:N
    if i ~= sub_a &amp;amp;&amp;amp; i ~= sub_b
        fplot(real(signal(i)), [0 27e-8], 'Color', [0 0 0] + 0.8);
    end
end
fplot(real(signal(sub_a)), [0 27e-8], 'Color', [0 0 0], 'LineWidth', 2);
fplot(real(signal(sub_b)), [0 27e-8], 'Color', 'g', 'LineWidth', 2);
for i = 1:5
    plot([i * 5e-8 i * 5e-8], [-1.5 1.5], 'Color', 'r');
end
hold off;
ylim([-1.5 1.5]);
xlim([0 27e-8]);
xticks(0:5e-8:25e-8);
xticklabels({'0ns' '50ns' '100ns' '150ns' '200ns' '250ns'});
text(28e-8, 0, '. . .');
legend('Subcarrier A', 'Subcarrier B', 'Sampling Time', 'Location', 'southeast');
title('Real Value of Subcarriers');

% Inner Product
signal_a = signal(sub_a);
signal_b_conj = conj(signal(sub_b));
product = int(signal_a * signal_b_conj, t, 0, symbol_duration);

% Display Product Result
figure(2); clf;
scatter(real(double(product)), imag(double(product)), 1200, 'Marker', '*', ...
    'MarkerEdgeColor', [1 0.8 0.4] - 0.1, 'LineWidth', 2);
ylim([-1e-15 1e-15]);
yticks(-0.8e-15:0.2e-15:0.8e-15);
ylabel('Imag');
xlim([-1e-15 1e-15]);
xticks(-0.8e-15:0.2e-15:0.8e-15);
xlabel('Real');
pbaspect([1 1 1]);
ax = gca;
ax.XAxisLocation = 'origin';
ax.YAxisLocation = 'origin';
text(1.2e-16, 1.2e-16, '↙ Zero?');
title({'Product Result =', strtrim(evalc('disp(double(product))'))});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dctr5l/btqBHzfOHwg/2jRkaNEgwXjdDHCIoMGHwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dctr5l/btqBHzfOHwg/2jRkaNEgwXjdDHCIoMGHwk/img.png&quot; data-filename=&quot;figure_0.png&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1313&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dctr5l/btqBHzfOHwg/2jRkaNEgwXjdDHCIoMGHwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdctr5l%2FbtqBHzfOHwg%2F2jRkaNEgwXjdDHCIoMGHwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1750&quot; height=&quot;1313&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0feXL/btqBHVbPtsZ/hQvL48dz6SRlqqrZ5f4P20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0feXL/btqBHVbPtsZ/hQvL48dz6SRlqqrZ5f4P20/img.png&quot; data-filename=&quot;figure_1.png&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1313&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0feXL/btqBHVbPtsZ/hQvL48dz6SRlqqrZ5f4P20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0feXL%2FbtqBHVbPtsZ%2FhQvL48dz6SRlqqrZ5f4P20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1750&quot; height=&quot;1313&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;(Left) Figure 1 / (Right) Figure 2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;http://ocw.snu.ac.kr/sites/default/files/NOTE/10361.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://ocw.snu.ac.kr/sites/default/files/NOTE/10361.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://web.wpi.edu/Pubs/ETD/Available/etd-041806-174713/unrestricted/navalekar.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://web.wpi.edu/Pubs/ETD/Available/etd-041806-174713/unrestricted/navalekar.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fdocuments.us/document/tutorial-de-orthogonal-frequency-division-multiplexing.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://fdocuments.us/document/tutorial-de-orthogonal-frequency-division-multiplexing.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.wirelesscommunication.nl/reference/chaptr05/ofdm/ofdmmath.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.wirelesscommunication.nl/reference/chaptr05/ofdm/ofdmmath.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://math.stackexchange.com/questions/1358485/what-does-it-mean-when-two-functions-are-orthogonal-why-is-it-important&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://math.stackexchange.com/questions/1358485/what-does-it-mean-when-two-functions-are-orthogonal-why-is-it-important&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.wirelesscommunication.nl/reference/chaptr05/ofdm/ofdmqual.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.wirelesscommunication.nl/reference/chaptr05/ofdm/ofdmqual.htm&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>무선 네트워크/기본 개념</category>
      <category>802.11</category>
      <category>OFDM</category>
      <category>orthogonality</category>
      <category>영어는_그만</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/45</guid>
      <comments>https://yuoa.tistory.com/entry/Where-is-the-orthogonality-in-OFDM#entry45comment</comments>
      <pubDate>Tue, 4 Feb 2020 20:25:06 +0900</pubDate>
    </item>
    <item>
      <title>2019년 1월 블로그, 서버 개편</title>
      <link>https://yuoa.tistory.com/entry/2019%EB%85%84-1%EC%9B%94-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%84%9C%EB%B2%84-%EA%B0%9C%ED%8E%B8</link>
      <description>&lt;p&gt;겨울 방학을 맞아 서버와 블로그 관리를 조금 하고 있다.&lt;/p&gt;
&lt;p&gt;블로그는 아예 Hexo 기반에서 티스토리 기반으로 옮기면서 그 동안 생각해오던 블로그 기능을 거의 다 넣었다. 약 3일간을 쉬지 않고 작업한 것 같다. 아직 티스토리 에디터는 코드 삽입을 제대로 지원하지 않는데, 곧 바뀔 에디터처럼 보이는 &amp;#39;페이지 에디터&amp;#39;를 보니 정식으로 코드 삽입을 잘 지원할 것 같다. 일단은 HTML 편집 모드와 위지윅 편집 모드를 오가며 엄청난 노가다를 했다. 글이 얼마 없었어서 망정이지 큰일 날 뻔 했다.&lt;/p&gt;
&lt;p&gt;서버는 그대로 토스트 클라우드를 이용하는데, 정적 리소스 서버와 리디렉션 서버를 하나로 합치고 404 페이지를 안내하는 서버는 개인 프로젝트 페이지 리스트를 띄워 주는 서버와 합쳐 총 두 개의 서버를 돌리게 되었다.&lt;/p&gt;
&lt;p&gt;이전에 이용하던 오브젝트 스토리지는 정적 리소스 서버로 옮겼다. 체계화된 리소스 관리가 필요하지 않기 때문이다.&lt;/p&gt;
&lt;p&gt;춥다.&lt;/p&gt;</description>
      <category>기타/홈페이지 관리</category>
      <category>블로그</category>
      <category>서버</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/15</guid>
      <comments>https://yuoa.tistory.com/entry/2019%EB%85%84-1%EC%9B%94-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%84%9C%EB%B2%84-%EA%B0%9C%ED%8E%B8#entry15comment</comments>
      <pubDate>Thu, 10 Jan 2019 22:15:35 +0900</pubDate>
    </item>
    <item>
      <title>EOS, DPOS 핥아보기</title>
      <link>https://yuoa.tistory.com/entry/EOS-DPOS-%ED%95%A5%EC%95%84%EB%B3%B4%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;i&gt;이 글은 Hexo 기반의 블로그에서 옮겨온 글이며, 원본 글은 2018년 10월 7일에 작성되었다.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://eos.io&quot;&gt;EOS&lt;/a&gt;는 수많은 DPOS 기반의 블록체인을 만들어 온 댄 라리머(Dan Larimer)가 주도하여 만든 블록체인이다. 왜 굳이 &lt;b&gt;EOS&lt;/b&gt;인가에 대해, &lt;b&gt;댄&lt;/b&gt; 라리머가 한글을 배워 자신의 이름 &lt;b&gt;댄&lt;/b&gt;을 영어로 입력하여 &lt;b&gt;EOS&lt;/b&gt;라고 이름을 지은 것으로 나는 추측하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;EOS를 한글로 치면 댄이다&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;이름이야 뭐 어쨌든 이 글에서는 EOS 프로젝트의 목적과 특징을 알아보고, EOS 빌드, 테스트넷 가동, 간단한 스마트 컨트랙트 실행을 직접 해 본다.&lt;/p&gt;
&lt;p&gt;추가적으로 DPOS의 장단점과 공격 가능 포인트들도 짚어 보았다.&lt;/p&gt;
&lt;h1&gt;EOS가 무엇일까&lt;/h1&gt;
&lt;p&gt;먼저, EOS가 무엇인지, EOS 측에서 주장하는 EOS의 특징과 장점이 무엇인지 알아보자.&lt;/p&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; align=&quot;center&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;EOS, block.one 로고&quot; style=&quot;width: 305px; height: 164px;&quot; width=&quot;305&quot; height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/997F9D3F5C3737C60C?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/997F9D3F5C3737C60C?original&quot; data-alt=&quot;EOS, block.one 로고&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997F9D3F5C3737C60C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997F9D3F5C3737C60C&quot; alt=&quot;EOS, block.one 로고&quot; style=&quot;width: 305px; height: 164px;&quot; width=&quot;305&quot; height=&quot;164&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EOS, block.one 로고&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;td&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;EOS 트랜잭션 수&quot; style=&quot;width: 305px; height: 176px;&quot; width=&quot;305&quot; height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9977E2425C3737C620?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9977E2425C3737C620?original&quot; data-alt=&quot;EOS 트랜잭션 수&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9977E2425C3737C620&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9977E2425C3737C620&quot; alt=&quot;EOS 트랜잭션 수&quot; style=&quot;width: 305px; height: 176px;&quot; width=&quot;305&quot; height=&quot;176&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EOS 트랜잭션 수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;왼쪽이 EOS의 로고이고, 오른쪽이 EOS를 만든 &lt;a href=&quot;https://block.one/&quot;&gt;block.one&lt;/a&gt;의 로고이다. 이더리움의 ERC20 토큰을 기반으로 교환이 이루어지다 현재는 독자적인 메인넷을 런칭한 블록체인인 EOS는 &lt;a href=&quot;https://www.blocktivity.info/&quot;&gt;Blocktivity&lt;/a&gt;에 따르면 현재 가장 활동량이 많은 블록체인이 되었다&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_1&quot; id=&quot;footnote_link_14_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;. 오른쪽 &lt;a href=&quot;https://coinmetrics.io/&quot;&gt;CoinMetrics&lt;/a&gt;의 자료를 보면 EOS의 트랜잭션 수는 폭발적으로 증가했음을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;EOS는 일부로부터 &quot;3세대 블록체인&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_2&quot; id=&quot;footnote_link_14_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&quot;이라고 불리고 있는데, 이는 기존의 이더리움 체계에서 나타난 여러가지 문제들(대표적으로 Scalability)을 해결하면서 나타난 것이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;BTC&lt;/th&gt;
&lt;th&gt;ETH&lt;/th&gt;
&lt;th&gt;EOS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;채굴 (합의 알고리즘)&lt;/td&gt;
&lt;td&gt;PoW&lt;/td&gt;
&lt;td&gt;PoS&lt;/td&gt;
&lt;td&gt;DPOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스마트 컨트랙트 지원&lt;/td&gt;
&lt;td&gt;✕&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;통치(Governance) 형태&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_3&quot; id=&quot;footnote_link_14_3&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 3)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 3)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;3&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;Off-chain&lt;/td&gt;
&lt;td&gt;Off-chain&lt;/td&gt;
&lt;td&gt;On-chain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지연 (블록 포함 시간)&lt;/td&gt;
&lt;td&gt;5 ~ 40분&lt;/td&gt;
&lt;td&gt;5 ~ 40초&lt;/td&gt;
&lt;td&gt;1.5초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;트랜잭션 수&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_4&quot; id=&quot;footnote_link_14_4&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 4)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 4)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;4&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;0.22M&lt;/td&gt;
&lt;td&gt;0.77M&lt;/td&gt;
&lt;td&gt;7.71M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TPS&lt;/td&gt;
&lt;td&gt;7 내외&lt;/td&gt;
&lt;td&gt;20 내외&lt;/td&gt;
&lt;td&gt;수천 TPS&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_5&quot; id=&quot;footnote_link_14_5&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 5)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 5)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;5&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;트랜잭션 비용&lt;/td&gt;
&lt;td&gt;사용자 부담 (BTC)&lt;/td&gt;
&lt;td&gt;사용자 부담 (Gas)&lt;/td&gt;
&lt;td&gt;개발자 부담 (EOS)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;위는 다른 블록체인과의 차이를 비교해 둔 것이다. EOS가 채택한 DPOS 합의 알고리즘으로 인해 트랜잭션 수에서 다른 블록체인과 크게 차이가 난다. 특이한 점으로는 EOS에서의 지연 시간에는 범위 표시(~)가 없다는 것인데, 비트코인이나 이더리움은 트랜잭션 비용에 따라 블록 포함 속도가 달라지기 때문에 지연 시간에 차이가 날 수 있지만, EOS는 그런 건 없기에, 트랜잭션이 생성된 이후 가장 최근 블록이 생성될 때 같이 포함된다. 나머지 부분들에 대해서는 아래에서 자세히 설명한다.&lt;/p&gt;
&lt;h1&gt;EOS의 겉보기 특징&lt;/h1&gt;
&lt;p&gt;이전 세대 블록체인과는 다른, EOS의 특징을 간단히 알아보자.&lt;/p&gt;
&lt;h2&gt;1. Scalable&lt;/h2&gt;
&lt;p&gt;첫 번째는 확장가능하다는 것이다. EOS에서는 EOS.IO가 수많은 사용자들이 동시에 EOS 애플리케이션을 구동할 수 있는 OS라고 홍보하는데, 이를 위해서는 트래픽이 커져도 빠른 속도를 유지하며 작업을 처리하는 것이 중요하다. 이더리움의 스마트 컨트랙트는 이 문제를 해결하지 못해 자주 병목 현상이 발생하곤 한데, EOS에서는 DPOS라는 무지하게 빠른 합의 알고리즘으로 빠른 블록 생성 속도를 구현한다. 또한 DPOS의 빠른 블록 생성 속도를 뒷받침하기 위해 애플리케이션의 병렬 실행을 지원한다. 멀티 체인도 지원한다. 비교를 해보자면, 비자(VISA)가 초당 약 일만 개의 트랜잭션을 처리할 수 있을 때, EOS는 이론 상 &lt;b&gt;약 백만 개&lt;/b&gt;의 트랜잭션을 처리할 수 있다. 이를 보았을 때, 아마 EOS의 가장 큰 특징은 이러한 Scalability일 것이다.&lt;/p&gt;
&lt;h2&gt;2. Governance&lt;/h2&gt;
&lt;p&gt;두 번째는 통치 방식이다. EOS는 21개의 대표 노드(Block Producer; BP)가 전체 네트워크를 통솔하고 움직이는데, 이들은 투표를 통해 엄청 다양한 일들을 처리할 수 있다. 블록체인을 특정 블록으로 되돌릴 수 있고, 계정 동결, 프로토콜 및 약관의 개정 등 정말 다양한 일을 할 수 있다.&lt;/p&gt;
&lt;p&gt;EOS에는 &quot;EOS 헌법&quot;이라는 것이 존재하는데, 아직은 임시 헌법이지만 곧 BP들 사이의 투표를 통해 제대로 된 헌법으로 확정하고 EOS 전체 네트워크의 방향과 활동을 규정하게 된다.&lt;/p&gt;
&lt;h2&gt;3. Flexible&lt;/h2&gt;
&lt;p&gt;세 번째는 유연함이다. EOS는 위에서 말한 통치 방식으로, 하드포크하지 않고도 블록체인의 문제점을 손볼 수 있고, 문제되는 DApp이 있으면 해당 DApp만을 정지하고 손볼 수 있다.&lt;/p&gt;
&lt;p&gt;또한, Role-Based Access Control 방식을 채택하여, 유저가 불필요한 권한을 가지게 되는 상황을 방지하고 있다. 무슨 말이냐면, 사람에게 권한을 주는 기존의 방법이 아니라, 특정 &quot;역할&quot;에 권한을 미리 다 부여한 다음, 해당 사람의 역할만 바꾸어주어 필요한 권한만 부여될 수 있도록 권한을 관리한다.&lt;/p&gt;
&lt;p&gt;EOS는 다양한 VM을 유연하게 지원하여, 이더리움의 스마트 컨트랙트도, 웹 어셈블리로 만들어진 스마트 컨트랙트 등 다양한 컨트랙트 종류를 EOS 네트워크에서 실행시킬 수 있다.&lt;/p&gt;
&lt;h1&gt;EOS의 세부 특징&lt;/h1&gt;
&lt;p&gt;이제는 EOS의 특징에 대해 조금 더 자세히 살펴보자.&lt;/p&gt;
&lt;h2&gt;1. 트랜잭션 비용 없음 (수익 모델)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;EOS 수익 모델&quot; width=&quot;630&quot; height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/998708435C3737C61E?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/998708435C3737C61E?original&quot; data-alt=&quot;EOS 수익 모델&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998708435C3737C61E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998708435C3737C61E&quot; alt=&quot;EOS 수익 모델&quot; width=&quot;630&quot; height=&quot;282&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EOS 수익 모델&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;EOS에는 트랜잭션 비용이 없다. 이더리움은 DApp의 사용자들이 트랜잭션을 보낼 때마다 사용료로 일정량의 Gas를 지불한다. 예를 들어 사용자가 DApp에서 댓글을 작성하려 하거나, 메시지를 보내는 &lt;b&gt;비금융 활동&lt;/b&gt;을 하면 그것에 대해서도 사용료를 내야 한다. 하지만 이런 방식은 사용자들이 DApp을 쓰는 데 불편함을 주게 된다. EOS는 더 많은 사람들을 네트워크로 끌어들이고자 DApp 사용자가 아니라 개발자로부터 사용료를 청구한다. 정확히는, 개발자가 가지고 있는 EOS 양에 비례하여 개발자에게 네트워크 대역폭과 연산 처리 능력(CPU)을 할당한다 (개발자로부터 EOS를 가져가는 것이 아니다). 전체 구조적으로 생각해보자면, 사용자는 트랜잭션 비용을 지불하지 않으면서도 블록체인 네트워크 기반 서비스를 사용할 수 있고, 그러면 사용자가 많으면서 DApp의 개발 및 유지비용이 적게 드는&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_6&quot; id=&quot;footnote_link_14_6&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 6)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 6)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;6&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; EOS로 개발자들이 모이게 된다. 이렇게 모인 사용자와 개발자로 EOS는 점차 점유율을 높일 수 있고, EOS 화폐 자체의 가치도 높아지면서 EOS 네트워크와 EOS 화폐를 다량 소유한 BP들이 수익을 얻게 되는 것이다.&lt;/p&gt;
&lt;h2&gt;2. DPOS (Delegated Proof-Of-Stake)&lt;/h2&gt;
&lt;h3&gt;PoW와 PoS&lt;/h3&gt;
&lt;p&gt;DPOS를 이해하려면 먼저 PoW(Proof-of-Work)와 PoS(Proof-of-Stake)를 알고있는 것이 좋다. EOS를 공부하는 사람이라면 아마 PoW에 대해서는 알고있을 것이므로 PoW에 대해서는 설명하지 않겠다. PoW와 양대 산맥을 이루는 합의 알고리즘으로 PoS(지분 증명)가 있는데, 이는 암호화폐 지분을 많이 가진 사람에게 더 큰 힘을 주고자 하는 것이다. 즉, 동시에 많은 블록이 만들어진다면 지분을 많이 가진 사람의 블록을 채택하는 것이다.&lt;/p&gt;
&lt;h3&gt;DPOS&lt;/h3&gt;
&lt;p&gt;DPOS는 PoS와 원리는 같다. 이 둘의 차이는 &lt;b&gt;직접 민주주의&lt;/b&gt;와 &lt;b&gt;간접 민주주의&lt;/b&gt;로 이해하면 아주 쉬워진다. 둘 다 투표를 통해 무언가를 결정하지만, 직접 민주주의는 구성원 모두가 권리를 직접 행사하고, 간접 민주주의는 대리인을 내세워 그들로 하여금 권리를 행사하게 한다. PoS는 직접 민주주의로, 많은 사람들의 동의를 얻어 블록을 형성하기에 블록 형성에 시간이 오래 걸린다. 이를 해결하기 위해 등장한 DPOS는 지분을 가지고 있는 사람들이 뽑은 소수의 대표들만 투표를 진행하기 때문에 블록이 빠르게 형성될 수 있다. 이러한 DPOS 방식을 채택하는 블록체인에는 &lt;a href=&quot;https://steem.io/&quot;&gt;스팀&lt;/a&gt;, EOS 등이 있다.&lt;/p&gt;
&lt;h3&gt;EOS에서의 DPOS&lt;/h3&gt;
&lt;p&gt;그래서, EOS가 DPOS를 어떻게 적용했는지 알아보자. 앞서 말했듯이, DPOS 방식이 PoW와 PoS에 비해 월등히 빠르기에 EOS는 DPOS를 채택할 수 밖에 없었다. EOS는 매 &quot;&lt;i&gt;라운드&lt;/i&gt;&quot;마다 126개의 블록을 생성하는데, 이 라운드가 시작될 때 투표를 옽해 21명의 BP(Block Producers)를 선출한다. 이 BP들은 모든 노드를 대표하여 블록을 생산하는 노드가 된다. EOS를 보유한 사람은 1 EOS당 30개의 노드에 투표할 수 있으며, 선출된 대표들은 매 라운드마다 각자 6개의 블록을 만들게 된다. 즉, 21&amp;times;6=126 인 것이다. 새로운 블록은 21개의 BP 중 15개 이상이 동의하면 체인에 포함된다. 매 초마다 두 개의 블록이 체인에 포함되므로 결국 한 라운드에 1분, 즉 약 1분 동안 126개의 블록이 생성되는데, 이는 10분에 한 블록을 생성하는 비트코인과 비교하면 무척이나 빠른 속도라고 할 수 있다.&lt;/p&gt;
&lt;p&gt;이외에 DPOS 공격 가능성과 DPOS Tradeoffs 등 부가적인 내용은 아래에 적어놓았다.&lt;/p&gt;
&lt;h2&gt;3. TaPoS (Transaction as Proof of Stake)&lt;/h2&gt;
&lt;p&gt;EOS는 네트워크의 보안을 높이는 기술인 TaPoS를 채택하고 있다. 기존의 PoS/DPOS 방식에서는 일부 노드만이 PoS 계산에 참여했는데, TaPoS는 모든 트랜잭션이 가장 최근 생성된 블록 헤더의 해시값을 포함하도록 하여 트랜잭션을 만드는 모든 노드들이 전체 네트워크의 보안에 참여하도록 한다.&lt;/p&gt;
&lt;h2&gt;4. Smart Contract Development Using C++&lt;/h2&gt;
&lt;p&gt;EOS는 이더리움이 Solidity를 사용하듯이, 스마트 컨트랙트 언어로 C++를 사용하고 있다. C++로 작성된 스마트 컨트랙트는 추후 웹 어셈블리로 컴파일되어 WASM 위에서 돌아가게 된다.&lt;/p&gt;
&lt;h1&gt;EOS 프로그램, 네트워크 구조&lt;/h1&gt;
&lt;h2&gt;EOS 프로그램 구조&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;EOS 프로그램 구조&quot; width=&quot;630&quot; height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/998D1D4C5C3737C61E?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/998D1D4C5C3737C61E?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998D1D4C5C3737C61E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998D1D4C5C3737C61E&quot; alt=&quot;EOS 프로그램 구조&quot; width=&quot;630&quot; height=&quot;300&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;EOS는 &lt;code&gt;nodeos&lt;/code&gt;, &lt;code&gt;keosd&lt;/code&gt;, &lt;code&gt;cleos&lt;/code&gt;의 세 가지 프로그램으로 구성되어있다. &lt;code&gt;nodeos&lt;/code&gt;는 node와 eos가 결합한 말로, EOS의 블록을 생성하는 가장 주요한 기능을 담당한다. 사용자가 보낸 트랜잭션이 유효한지, 블록이 유효한지 등을 결정하는 하나의 노드 프로그램이다. &lt;code&gt;keosd&lt;/code&gt;는 key와 eos가 결합한 말로, 지갑 단위로 키를 관리하는 구성요소이다. 마지막으로 &lt;code&gt;cleos&lt;/code&gt;는 CLI와 eos가 결합한 말로, 사용자가 다른 EOS 구성요소에 접근할 수 있는 인터페이스를 제공한다. 즉, 사용자는 이를 이용하여, &lt;code&gt;keosd&lt;/code&gt; 및 &lt;code&gt;nodeos&lt;/code&gt;에 접근할 수 있다.&lt;/p&gt;
&lt;p&gt;간단한 예시를 들어보자면, 사용자는 트랜잭션을 만들기 위해 일단 자신의 지갑에 접근해야 하는데, 이 때 &lt;code&gt;keosd&lt;/code&gt;를 거쳐 올바른 키를 사용하여 지갑을 잠금 해제하게 된다. 그 다음 트랜잭션을 만들고, &lt;code&gt;nodeos&lt;/code&gt;에 접근하여 트랜잭션 검증을 받은 후, &lt;code&gt;nodeos&lt;/code&gt;가 블록체인 네트워크로 해당 트랜잭션을 브로드캐스트하여 블록체인에 트랜잭션이 포함되게 된다.&lt;/p&gt;
&lt;h2&gt;EOS 네트워크 구조&lt;/h2&gt;
&lt;p&gt;EOS의 메인넷에는 21개의 Block Producer 노드와 79개의 Backup Producer 노드가 있다. 만일 DDoS 공격 등으로 인해 어떤 Block Producer에게 문제가 생기면, Backup Producer가 그 일을 대신하게 된다. 각각의 노드는 자신이 소유한 EOS 만큼의 투표권을 활용하여 최대 30개의 노드에게 자신의 권한을 위임할 수 있다. 결과적으로, 이를 통해 매 라운드마다 21개의 Block Producer 노드가 투표에 의해 선출된다. 선출된 Block Producer는 각각 블록을 만들어 다른 Block Producer에게 검증을 받고, 블록체인을 잇는다.&lt;/p&gt;
&lt;p&gt;각 노드가 EOS를 얼마나 가지고 있는지는 EOS 네트워크에서 DApp을 구현하는 데 영향을 미친다. DApp 개발자는 자신이 가지고 있는 EOS의 양에 비례하여 투표권 뿐 아니라 CPU 할당, 네트워크 대역폭을 보장받을 수 있다.&lt;/p&gt;
&lt;h1&gt;EOS 설치&lt;/h1&gt;
&lt;p&gt;이제 본격적으로 EOS를 만나보자. &lt;a href=&quot;https://developers.eos.io/eosio-nodeos/docs/autobuild-script&quot;&gt;EOS는 자동 빌드 스크립트는 현재 아래와 같은 환경을 지원한다.&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Amazon 2017.09 이상&lt;/li&gt;
&lt;li&gt;CentOS 7&lt;/li&gt;
&lt;li&gt;Fedora 25 이상 (27 추천)&lt;/li&gt;
&lt;li&gt;Mint 18&lt;/li&gt;
&lt;li&gt;Ubuntu 16.04 이상 (16.10 추천)&lt;/li&gt;
&lt;li&gt;MacOS Darwin 10.12 이상 (10.13.x 추천)&lt;/li&gt;
&lt;li&gt;Docker 17.05 이상&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;공식적으로 언급하지는 않았지만, 아래의 OS도 추가로 지원하도록 짜여져 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;elementary OS&lt;/li&gt;
&lt;li&gt;Debian&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이는 데비안이나 엘리멘트리 OS나 둘 다 우분투와 같은 설치 로직을 쓸 수 있기에 같이 지원하는 듯하다. 위 목록에 없는 리눅스 배포판을 사용한다면, &lt;a href=&quot;https://developers.eos.io/eosio-nodeos/docs/manually-build&quot;&gt;이 링크&lt;/a&gt;를 참고하여 직접 빌드해야 한다.&lt;/p&gt;
&lt;p&gt;여기서는 도커 환경을 제외한 나머지 리눅스 환경을 기준으로 설명하겠다. 도커 환경에서의 설치 방법은 &lt;a href=&quot;https://developers.eos.io/eosio-nodeos/docs/docker&quot;&gt;이 링크&lt;/a&gt;를 참조하면 된다. 참고로 위 리눅스 배포판 목록에 있는 리눅스라면, WSL 환경에서라도 잘 돌아간다.&lt;/p&gt;
&lt;p&gt;아래의 코드에서, 작업 디렉토리는 홈 디렉토리(&lt;code&gt;~&lt;/code&gt;)이다.&lt;/p&gt;
&lt;h2&gt;1. EOS 소스 코드 다운로드하고 빌드하기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;소스 코드 다운로드 및 빌드&quot; width=&quot;630&quot; height=&quot;253&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99DE95405C3737C604?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99DE95405C3737C604?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DE95405C3737C604&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DE95405C3737C604&quot; alt=&quot;소스 코드 다운로드 및 빌드&quot; width=&quot;630&quot; height=&quot;253&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;git clone https://github.com/EOSIO/eos --recursive
cd eos; ./eosio_build.sh -s EOS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 작업은 오래 걸린다. 환경에 따라 다르겠지만, 내 개인 서버 기준으로 약 한 시간이 걸렸다.&lt;/p&gt;
&lt;h2&gt;2. 빌드 테스트하고 바이너리 설치하기&lt;/h2&gt;
&lt;h3&gt;빌드 테스트&lt;/h3&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;export PATH=${HOME}/opt/mongodb/bin:$PATH
~/opt/mongodb/bin/mongod -f ~/opt/mongodb/mongod.conf &amp;amp;
cd ~/eos/build; make test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;몇 개의 테스트는 실패하기도 하지만, 실제 이후 EOS의 동작에는 아무런 문제가 없었다.&lt;br /&gt;이 과정도 아주 오래 걸렸는데, 약 한 시간 반이 소모되었다. 시간이 없는 사람은 그냥 넘어가도 좋을 듯하다.&lt;/p&gt;
&lt;h3&gt;바이너리 설치&lt;/h3&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;cd build
sudo make install
export PATH=$PATH:/usr/local/eosio/bin
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 테스트넷 구동&lt;/h2&gt;
&lt;p&gt;아래 명령어로 테스트넷을 구동해보자.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;nodeos -e -p eosio --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 각 파라미터를 설명하면 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; : 체인이 정상 체인이 아니더라도 블록을 생성하게 한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p eosio&lt;/code&gt; : 이 노드가 통제하는 프로듀서의 ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--plugin&lt;/code&gt; : 활성화 할 플러그인을 지정할 수 있으며, 여러 개를 지정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;블록 생성중인 EOS&quot; width=&quot;630&quot; height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/991080465C3737C60E?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/991080465C3737C60E?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991080465C3737C60E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991080465C3737C60E&quot; alt=&quot;블록 생성중인 EOS&quot; width=&quot;630&quot; height=&quot;327&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;만일 EOS 노드를 성공적으로 구동했으면 계속해서 블록을 만드는 로그가 콘솔에 뜰 것이다. 약 0.5초에 한 블록이 생성될 것이다.&lt;/p&gt;
&lt;h2&gt;4. CLI 실행해보기&lt;/h2&gt;
&lt;p&gt;이전의 &lt;code&gt;nodeos&lt;/code&gt;를 닫지 말고, 다른 터미널에서 아래의 명령어를 입력하여 &lt;code&gt;cleos&lt;/code&gt;를 이용해보자.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;export PATH=$PATH:/usr/local/eosio/bin
cleos get info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;블록체인 정보&quot; width=&quot;630&quot; height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9998A74A5C3737C627?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9998A74A5C3737C627?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9998A74A5C3737C627&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9998A74A5C3737C627&quot; alt=&quot;블록체인 정보&quot; width=&quot;630&quot; height=&quot;174&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이 커맨드는 현재 블록체인의 상태, 정보를 &lt;code&gt;nodeos&lt;/code&gt;로부터 받아와 위와 같이 출력해준다. 위와 같이 출력된다면, 정상적으로 EOS가 설치된 것이다.&lt;/p&gt;
&lt;h1&gt;EOS Hello-World App 빌드해보기&lt;/h1&gt;
&lt;p&gt;테스트넷 위에 Hello World 애플리케이션을 설치해보자.&lt;/p&gt;
&lt;h2&gt;1. 애플리케이션 빌드&lt;/h2&gt;
&lt;p&gt;EOS 애플리케이션을 빌드하기 위해서는 EOSIO Contract Development Toolkit이 필요하다. &lt;a href=&quot;https://github.com/EOSIO/eosio.cdt#binary-releases&quot;&gt;이 링크&lt;/a&gt;의 설명을 따라 먼저 툴킷을 설치하자.&lt;br /&gt;이후 미리 작성된 컨트랙트 코드를 &lt;code&gt;git&lt;/code&gt;으로 받아 &lt;code&gt;make&lt;/code&gt;하여 간단하게 Hello World 컨트랙트를 빌드할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;$ git clone https://github.com/yuoa/eos-hello-world
$ cd eos-hello-world; make
Compiling hello.cpp to web assembly files... Finished.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이후 &lt;code&gt;ls&lt;/code&gt; 명령어로 결과를 확인해보면 &lt;code&gt;hello.abi&lt;/code&gt;, &lt;code&gt;hello.wasm&lt;/code&gt; 파일이 생겼을 것이다.&lt;/p&gt;
&lt;p&gt;아래는 수동으로 방금 만든 컨트랙트 코드를 테스트하는 방법을 적어놓았는데, 시간이 없으면서도 내 EOS가 작동하는지 확인하고 싶은 사람들은 &lt;code&gt;make test&lt;/code&gt; 명령어로 자동 테스트를 해볼 수 있다.&lt;/p&gt;
&lt;h2&gt;2. 지갑과 개인 키 만들기&lt;/h2&gt;
&lt;p&gt;방금 만든 애플리케이션을 런칭할 계정이 필요하므로, 만들어주자. 아까 실행시켜둔 &lt;code&gt;nodeos&lt;/code&gt;는 계속 켜 두고, 다른 터미널에서 계속 진행한다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ cleos wallet create --to-console
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
&quot;PW5JXSUH1uTaQarXgSDZgdWzGeWupPFmwd2RtFkzrivudMtu2Xxs2&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 명령줄의 마지막이 지갑의 비밀번호이므로, 따로 메모해두자.&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;$ cleos create-key --to-console
Private key: 5KeHEF9xm5E32DMth2K8tFwvcwT9DJohNmycLegwAnCCe3WBejT
Public key: EOS7zgbYJFXRMhcW8MtRyCKv4LS94xVQh7DHGif5ruVmHHYrmqu7d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 명령줄로 개인/공개 키 쌍을 만들 수 있다. 이제 이 개인 키를 지갑에 추가하자.&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;$ cleos wallet import -n default --private-key 5KeHEF9xm5E32DMth2K8tFwvcwT9DJohNmycLegwAnCCe3WBejT
imported private key for: EOS7zgbYJFXRMhcW8MtRyCKv4LS94xVQh7DHGif5ruVmHHYrmqu7d
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. BIOS 컨트랙트 구동&lt;/h2&gt;
&lt;p&gt;이제 EOS 테스트넷에 BIOS 컨트랙트를 구동시킬 차례이다. BIOS 컨트랙트는 개발의 목적으로, 다른 계정의 리소스 할당이나 권한이 필요한 내부 API 호출 등을 직접적으로 가능하게 해 주는 컨트랙트이다. 아래의 명령으로 바이오스 컨트랙트를 로드할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ cleos wallet unlock --password PW5JXSUH1uTaQarXgSDZgdWzGeWupPFmwd2RtFkzrivudMtu2Xxs2
Unlocked: default
$ cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
imported private key for: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
$ cleos set contract eosio ~/eos/build/contracts/eosio.bios -p eosio
Reading WASM from ~/eos/build/contracts/eosio.bios/eosio.bios.wasm...
Publishing contract...
(the rest omitted)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 난데없이 &lt;code&gt;5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3&lt;/code&gt;이라는 개인 키를 추가하는데, 이는 EOS 테스트넷을 만들 때 내부적으로 쓰인 키로, 바이오스 컨트랙트를 로드 및 구동하는 데 필수적이다.&lt;/p&gt;
&lt;p&gt;참고로, EOS 메인넷에서 바이오스 컨트랙트는 EOS 보유량에 따른 CPU 및 네트워크 대역폭 할당을 담당하고 있다.&lt;/p&gt;
&lt;h2&gt;4. 테스트용 계정 만들기&lt;/h2&gt;
&lt;p&gt;아까 빌드한 스마트 컨트랙트를 테스트하기 위해 계정 두 개(&lt;code&gt;user&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;)를 만들어주자.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;cleos create account eosio user EOS7zgbYJFXRMhcW8MtRyCKv4LS94xVQh7DHGif5ruVmHHYrmqu7d EOS7zgbYJFXRMhcW8MtRyCKv4LS94xVQh7DHGif5ruVmHHYrmqu7d
cleos create account eosio test EOS7zgbYJFXRMhcW8MtRyCKv4LS94xVQh7DHGif5ruVmHHYrmqu7d EOS7zgbYJFXRMhcW8MtRyCKv4LS94xVQh7DHGif5ruVmHHYrmqu7d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;아까 생성한 개인 키/공개 키 쌍을 사용해 두 개의 계정을 만들고 나면, 아래와 같이 두 개의 계정이 성공적으로 등록되었음을 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;$ cleos get accounts EOS7zgbYJFXRMhcW8MtRyCKv4LS94xVQh7DHGif5ruVmHHYrmqu7d
{
  &quot;account_names&quot;: [
    &quot;test&quot;,
    &quot;user&quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. &lt;code&gt;nodeos&lt;/code&gt; 설정 바꾸기&lt;/h2&gt;
&lt;p&gt;마지막으로, Hello World 메시지가 콘솔에 직접 표시되도록 &lt;code&gt;nodeos&lt;/code&gt;의 설정을 바꿔 주어야 한다. 최신 EOS에서는 기본적으로 표준 출력이 표시되지 않게 설정되어 있어, &lt;code&gt;config.ini&lt;/code&gt; 파일에서 &lt;code&gt;contracts-console&lt;/code&gt; 항목을 바꿔 준다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;cd ~/.local/share/eosio/nodeos/config/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 디렉토리에서 &lt;code&gt;config.ini&lt;/code&gt;를 열고, 중간의 &lt;code&gt;contracts-console = false&lt;/code&gt;를 &lt;code&gt;contracts-console = true&lt;/code&gt;로 바꾸어 준다. 이후 &lt;code&gt;nodeos&lt;/code&gt;를 재시작하자.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;nodeos -e -p eosio --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 스마트 컨트랙트 구동하기&lt;/h2&gt;
&lt;p&gt;드디어 스마트 컨트랙트를 구동할 차례이다! 아까 전, 스마트 컨트랙트를 빌드했던 디렉토리로 돌아가서 아래 작업을 진행하자.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ cleos set contract test . hello.wasm hello.abi -p test
$ cleos push action test greet '[&quot;Belli Dura Despicio&quot;]' -p user
executed transaction: 54ad914ea76831ac248fd1930461aff03089cf01e6cfa87e08fc44cec6831969  104 bytes  725 us
#    test &amp;lt;= test::greet               {&quot;user&quot;:&quot;user&quot;}
&amp;gt;&amp;gt; Hello world, hello Belli Dura Despicio!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이는 &lt;code&gt;nodeos&lt;/code&gt;이 실행되고 있는 터미널에서도 확인할 수 있다. 아래의 로그를 보면 트랜잭션 하나가 블록에 포함되었음을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;subunit&quot;&gt;&lt;code&gt;&amp;hellip;
2018-09-06T20:53:41.069 thread-0   apply_context.cpp:28          print_debug          ]
[(test,greet)-&amp;gt;test]: CONSOLE OUTPUT BEGIN =====================
Hello world, hello Belli Dura Despicio!
[(test,greet)-&amp;gt;test]: CONSOLE OUTPUT END   =====================
2018-09-06T20:53:41.500 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 000147bc376605d3... #83900 @ 2018-09-06T20:53:41.500 signed by eosio [trxs: 1, lib: 83899, confirmed: 0]
&amp;hellip;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;DPOS: Tradeoffs and Attacks&lt;/h1&gt;
&lt;p&gt;이 부분은 부록같은 느낌으로 작성하였다. 여기서는 DPOS의 장단점과 공격 가능한 요소들을 살펴본다.&lt;/p&gt;
&lt;h2&gt;DPOS Tradeoffs&lt;/h2&gt;
&lt;h3&gt;A. 블록 프로듀서와 탈중앙화&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;Delegated Proof of Stake is too centralized: True 50%, False 50%&quot; width=&quot;529&quot; height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/992711445C3737C620?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/992711445C3737C620?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992711445C3737C620&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992711445C3737C620&quot; alt=&quot;Delegated Proof of Stake is too centralized: True 50%, False 50%&quot; width=&quot;529&quot; height=&quot;311&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;DPOS는 지분을 가진 사람이 일부 사람에게 자신의 결정권을 위임하기에, '&lt;b&gt;Controlled Semi-Centralization&lt;/b&gt;'이라고 할 수 있다. 여기서 우리는 기존의 PoW나 PoS에서 항상 문제가 되어 온 '의사 결정의 효율성과 속도'라는, 중앙화의 장점을 잡을 수 있게 되고, 또 지분을 가진 사람으로부터의 선출이라는 점에서 탈중앙화의 장점 또한 잡게 된다. 하지만 그래도 기존의 방식과 비교해보았을 때, &quot;중앙화 된다&quot;는 점에서 일부 사람들은 DPOS를 지지하지 않는다. 또한 '중앙화의 정도'가 결정되는 중요한 요소인 &quot;몇 명의 후보를 블록 생산자로 선출해야 적당히 효율과 탈중앙화를 모두 잡을 수 있는가&quot; 또한 중요한 문제가 된다.&lt;/p&gt;
&lt;h3&gt;B. 체인 내부 통치 (On-Chain Governance)&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_7&quot; id=&quot;footnote_link_14_7&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 7)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 7)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;7&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;체인 내부 통치&quot; width=&quot;630&quot; height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/993152355C3737C60C?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/993152355C3737C60C?original&quot; data-alt=&quot;두 통치 방식.&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993152355C3737C60C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993152355C3737C60C&quot; alt=&quot;체인 내부 통치&quot; width=&quot;630&quot; height=&quot;308&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;두 통치 방식.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;On-Chain Governance는 &lt;b&gt;블록체인의 정책을 결정하는 권위체가 블록체인 내부에 있다&lt;/b&gt;는 것을 의미한다. EOS에서는 선출된 21명의 BP가 EOS의 정책과 방향성에 대해 토의하고 결정한다. 이는 비트코인 개발자들이 비트코인 블록체인 외부에서 활동하며 메일링 리스트를 두고 비트코인 체계를 관리하는 Off-Chain Governance와는 다른 방식이다. DPOS는 모든 블록체인 네트워크가 정치적이고, 정치 과정을 공식화하려고 한다는 것을 인정하는 방식이다. On-Chain Governance는 일부 사람들이 문제를 제기하기도 하지만, 이는 DPOS의 핵심 특징이다. DPOS는 공개적이고 분산된 구조이며, 결과적으로 중앙화된 권력이 아닌, 커뮤니티의 소유이다.&lt;/p&gt;
&lt;p&gt;결론적으로, On-Chain Governance가 다른 블록체인 운영 방식과 비교했을 때 더 나은지, 더 나쁜지는 아직 분명하지 않으며, 앞으로 계속해서 테스트되어야 한다.&lt;/p&gt;
&lt;h2&gt;Possibility of Attacks&lt;/h2&gt;
&lt;p&gt;이제 DPOS 네트워크가 어떻게 공격받을 수 있을지 생각해보고, DPOS가 그 공격 방법으로부터 안전한지도 생각해보자.&lt;/p&gt;
&lt;h3&gt;A. Nothing at Stake&lt;/h3&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; align=&quot;center&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;Nothing at Stake&quot; style=&quot;width: 305px; height: 135px;&quot; width=&quot;305&quot; height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9959344A5C3737C608?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9959344A5C3737C608?original&quot; data-alt=&quot;Nothing at Stake 문제&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9959344A5C3737C608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9959344A5C3737C608&quot; alt=&quot;Nothing at Stake&quot; style=&quot;width: 305px; height: 135px;&quot; width=&quot;305&quot; height=&quot;135&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Nothing at Stake 문제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;td&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;Nas in DPOS&quot; style=&quot;width: 305px; height: 146px;&quot; width=&quot;305&quot; height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/993A504E5C3737C615?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/993A504E5C3737C615?original&quot; data-alt=&quot;DPOS에서의 NaS 문제&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993A504E5C3737C615&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993A504E5C3737C615&quot; alt=&quot;Nas in DPOS&quot; style=&quot;width: 305px; height: 146px;&quot; width=&quot;305&quot; height=&quot;146&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DPOS에서의 NaS 문제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;여기서 'At stake'라는 말은 &quot;위험에 처하다&quot; 라는 뜻이다. 즉, &quot;Nothing at Stake&quot;는 &quot;아무것도 위험하지 않다&quot;는 뜻이다. 이는 노드의 입장에서 말한 것인데, 어떠한 악의적인 개입으로, 유효해 보이는 블록체인이 두 개 이상 존재하게 되었을 때, 그 두 개 블록체인에 모두 블록을 생성해도 손해가 없으므로, 보상 확률을 높이기 위해 두 블록체인에 모두 블록을 생성하는 행위를 하게 된다는 것이다. 이는 본디 PoS 방식의 문제이기도 하다.&lt;/p&gt;
&lt;p&gt;하지만 DPOS는 이런 공격에 취약하지 않다. 일정 수의 대표가 매 라운드마다 선출되어, 순서대로 블록을 생성하기 때문에 가장 긴 블록을 형성함으로써 체인에 공격을 가하기는 힘들다. 또한 다수의 대표들이 악의적으로 몰래 체인을 형성하고 있더라도, 정직한 소수의 대표들이 있다면 체인의 길이에 의한 공격은 실패가 된다.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;물론 모든 노드가 악의적이라면...&lt;/del&gt;&lt;/p&gt;
&lt;h3&gt;B. Exploit Low Voter Turnout&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;PoS&lt;/b&gt;에서는 자신의 가진 지분에 비례하여 투표에서의 힘을 가진다. 매우 적은 지분을 가진 사람들은 투표를 하는 방법에 대해 찾아보는 그 노력에 비해 상응하는 보상을 받기는 어렵게 된다. 이런 현상으로, 10%의 지분의 블록이 투표에 참여했다고 한다면 5%의 지분을 가진 &quot;고래&quot;가 이를 악용하여 자신이 원하는 대로 정책을 결정할 수 있는 문제가 생긴다.&lt;/p&gt;
&lt;p&gt;하지만 &lt;b&gt;DPOS&lt;/b&gt;에서는 자신의 지분에서 나오는 투표권을 위임할 수 있으므로, 간접적으로 전체 투표율에 기여하게 된다. 이로써, 단순히 5%의 소유로 블록 형성에 관여할 수 있었던 '중앙화'의 위험에서 벗어나게 된다.&lt;/p&gt;
&lt;h3&gt;C. Bribing Attacks&lt;/h3&gt;
&lt;p&gt;DPOS에서는 블록 생성 권한을 토큰 소유자로부터 위임받기 때문에, 많은 사용자로부터 권한을 위임받을수록 자신이 블록 생성 노드가 될 확률이 높아지고, 더불어 채굴로 인한 보상을 받을 가능성도 커진다. 이를 이용해, 일부 노드가 &quot;나에게 투표하면 내 채굴 보상의 일부를 나눠주겠다&quot;며 접근했고, 일곽에서는 가장 많은 보상을 주는 노드를 알려주는 사이트까지 등장했다. 하지만 이는 DPOS 네트워크의 발전을 저해하며, 보안상 큰 문제를 야기할 수 있다. 악의적인 의도로 사용자로부터 권한을 위임받아 블록을 생성할 수 있는 것이다. 이는 실제로 스팀잇이나 리스트 등의 DPOS 기반 블록체인에서 일어났던 일이다.&lt;/p&gt;
&lt;p&gt;하지만 우리의 EOS는 이 문제로부터 안전하다. EOS 블록체인에 참가하는 모두가 동의해야 하는 &lt;b&gt;EOS 헌법&lt;/b&gt;에는 &quot;투표권을 사서는 안된다&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_8&quot; id=&quot;footnote_link_14_8&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 8)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 8)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;8&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&quot;라는 내용이 명시가 되어 있어, Bribing Attack을 시도하는 노드는 바로 네트워크에서 퇴출될 것이다. 또한 각 BP는 유일한 수입원인 블록 채굴 보상만으로 BP의 공약 중 하나인 &quot;안정적인 네트워크와 유효한 블록체인을 유지한다&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_14_9&quot; id=&quot;footnote_link_14_9&quot; onmouseover=&quot;tistoryFootnote.show(this, 14, 9)&quot; onmouseout=&quot;tistoryFootnote.hide(14, 9)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;9&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&quot;를 이행해야 하므로, 퇴출당하지 않으려면 꽤 많은 양의 돈을 인프라 유지에 사용해야 할 것이다. 이로써 Bribing Attack은 조금 더 힘들어진다.&lt;/p&gt;
&lt;h3&gt;D. Attacks at Scale&lt;/h3&gt;
&lt;p&gt;기본적으로 블록 생산자들은 DPOS 네트워크에 자신의 CPU나 네트워크 등의 리소스를 제공한다. 여기서 문제가 발생할 수 있는 부분은 &quot;거대한 리소스를 제공하는 BP가 블록 생산에서의 실수에 의해 쫓겨났을 때&quot; 이다. 거대한 리소스가 한 번에 사라지면 네트워크의 능력은 현저히 떨어진다. 블록 생산 수, 제공되는 리소스 자원이 큰 폭으로 줄어들고, 전체 DPOS 네트워크는 운영에 힘이 부치게 된다. 쫓겨난 BP 대신 새로 선출된 BP가 기존의 BP와 같은 리소스 능력을 가지고 있으리라는 보장도 없다. 아직 실제 사례는 없지만, 전체 네트워크를 손상시킬 수 있는 한 가지 방법은 이와 같이 &lt;b&gt;거대한 리소스를 가진 BP를 퇴출시키는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;h3&gt;E. Block Producers Collude&lt;/h3&gt;
&lt;p&gt;DPOS에서는 블록을 형성하는 대표자의 수가 적기 때문에 단합이 가능하다. 단합으로 저지를 수 있는 수많은 가능성 중 하나는 &lt;b&gt;Censorship&lt;/b&gt;이다. 이들은 단합하여 마음에 들지 않지만 유효한 트랜잭션을 거부할 수 있다. 또 다른 가능성 중 하나는 &lt;b&gt;프로토콜 변경&lt;/b&gt;이다. 악의적인 블록 제작자는 프로토콜을 변경하여 블록 생성 보상 변경, 특정 지분 소유자 추방 등 여러 일을 벌일 수 있다. EOS에서는 이를 막기 위해 21명 중 17명 이상의 동의가 있어야 프로토콜을 개정할 수 있도록 하고 있다. 또 다른 가능성 중 하나는 &lt;b&gt;이중 지불 공격&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;여러 노드들이 협의한다면 정말 못 할 일이 없게 되는 것이 DPOS의 단점이다. 소수의 블록 프로듀서가 자신의 차례에 이런 일을 벌인다면 블록은 거절 당할 것이고, 단순히 다음 블록이 몇 초 늦게 만들어지는 정도의 타격이 될 것이다. 그 소수 블록 프로듀서는 물론 자신의 명성과 미래의 수입 등 많은 부분에서 큰 타격을 입게 될 것이다. 하지만, 대다수의 BP들이 악의를 가지고 협동한다면 못할 일은 전혀 없을 것이다.&lt;/p&gt;
&lt;h3&gt;F. Distributed Denial-of-Seretvice Attack (DDoS)&lt;/h3&gt;
&lt;p&gt;DPOS의 경우, 블록을 형성하는 대표들은 IP 주소와 각 라운드마다 무작위로 결정된 블록 생성 순서가 공개되어 있기 때문에 충분히 DDoS 공격의 대상이 될 수 있다. 하지만 DPOS에는 예비 블록 프로듀서(백업 프로듀서)가 항상 대기하고 있기 때문에, DDoS 공격은 효율성이 떨어진다. 매 라운드마다 계속 BP가 바뀌므로, DDoS를 대다수의 블록 프로듀서에게 공격한다고 해도 일시적인 타격에 불과할 것이다. 참고로, EOS에서는 21명의 BP 중 한 BP가 제 기능을 못하게 되면 그 다음으로 투표를 많이 한 22번쨰 백업 프로듀서가 진짜배기 BP가 된다.&lt;/p&gt;
&lt;h1&gt;참고한 문서&lt;/h1&gt;
&lt;p&gt;EOS를 공부하면서 정말 수많은 문서를 보았다. 대부분 나보다 글을 잘 썼고, 내 글의 일부 부분은 그들 문서의 단순한 번역이 되기도 한다. 좋은 문서를 만들어 주신 모든 분들께 진심으로 감사의 말을 전하고 싶다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://biccur.com/blog/2016/12/16/three-generations-of-blockchain/&quot;&gt;http://biccur.com/blog/2016/12/16/three-generations-of-blockchain/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.blockmedia.co.kr/%EA%B6%81%EA%B8%88%ED%95%B4%EC%9A%94-%EC%95%94%ED%98%B8%ED%99%94%ED%8F%90-1%EC%84%B8%EB%8C%80%C2%B72%EC%84%B8%EB%8C%80%C2%B73%EC%84%B8%EB%8C%80-%EC%BD%94%EC%9D%B8%EC%9D%B4%EB%9E%80/&quot;&gt;https://www.blockmedia.co.kr/궁금해요-암호화폐-1세대&amp;middot;2세대&amp;middot;3세대-코인이란/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/coinmonks/a-deep-dive-into-eos-governance-49e892eeb4a2&quot;&gt;https://medium.com/coinmonks/a-deep-dive-into-eos-governance-49e892eeb4a2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/EOSIO/Documentation/blob/master/ko-KR/TechnicalWhitePaper.md&quot;&gt;https://github.com/EOSIO/Documentation/blob/master/ko-KR/TechnicalWhitePaper.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coinpan.com/eos/25153897&quot;&gt;https://coinpan.com/eos/25153897&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/eos/comments/7kntfd/why_eos_today_is_worth_more_than_ethereum/&quot;&gt;https://www.reddit.com/r/eos/comments/7kntfd/why_eos_today_is_worth_more_than_ethereum/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://terms.naver.com/entry.nhn?docId=3432104&amp;amp;cid=58437&amp;amp;categoryId=58437&quot;&gt;https://terms.naver.com/entry.nhn?docId=3432104&amp;amp;cid=58437&amp;amp;categoryId=58437&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/appetizermonster/4c0cee9d6778b0996f6d2b6a587b7188&quot;&gt;https://gist.github.com/appetizermonster/4c0cee9d6778b0996f6d2b6a587b7188&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bitoxycoin.com/blog/proof-work-vs-proof-stake/&quot;&gt;https://bitoxycoin.com/blog/proof-work-vs-proof-stake/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/tooza/@hingomaster/dpos&quot;&gt;https://steemit.com/tooza/@hingomaster/dpos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coinone.co.kr/eos/&quot;&gt;https://coinone.co.kr/eos/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cobak.co.kr/community/4/post/11746&quot;&gt;https://cobak.co.kr/community/4/post/11746&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/eos/@smarteasy/eos-eosio-dapp-4-consensus-algorithm-bft-dpos&quot;&gt;https://steemit.com/eos/@smarteasy/eos-eosio-dapp-4-consensus-algorithm-bft-dpos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bravenewcoin.com/assets/Uploads/TransactionsAsProofOfStake10.pdf&quot;&gt;https://bravenewcoin.com/assets/Uploads/TransactionsAsProofOfStake10.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.blockinpress.com/archives/5968&quot;&gt;https://www.blockinpress.com/archives/5968&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/coinkorea/@seungjae1012/dpos&quot;&gt;https://steemit.com/coinkorea/@seungjae1012/dpos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://multicoin.capital/2018/03/02/delegated-proof-stake-features-tradeoffs/&quot;&gt;https://multicoin.capital/2018/03/02/delegated-proof-stake-features-tradeoffs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/acroeos/eos%ED%86%A0%ED%81%B0%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%B8%94%EB%A1%9D%ED%94%84%EB%A1%9C%EB%93%80%EC%84%9C-%ED%88%AC%ED%91%9C-%EB%B0%A9%EB%B2%95-c6dabd17620d&quot;&gt;https://medium.com/acroeos/eos토큰을-통한-블록프로듀서-투표-방법-c6dabd17620d&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/kr/@quick94sm/eos-staking&quot;&gt;https://steemit.com/kr/@quick94sm/eos-staking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://koreos.io/News/106162&quot;&gt;http://koreos.io/News/106162&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/hexlant/eos-dawn-v4-0-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%8B%A4%ED%96%89-2-4-8ac29ad0f2ec&quot;&gt;https://medium.com/hexlant/eos-dawn-v4-0-설치-및-실행-2-4-8ac29ad0f2ec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/EOSIO/eos&quot;&gt;https://github.com/EOSIO/eos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.eos.io/eosio-nodeos/docs/overview-1&quot;&gt;https://developers.eos.io/eosio-nodeos/docs/overview-1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.hashedpost.com/2017/08/hashed-report-vs-eos.html&quot;&gt;http://www.hashedpost.com/2017/08/hashed-report-vs-eos.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/eoseoul/docs/blob/master/ko/translations/Local-Environment.md&quot;&gt;https://github.com/eoseoul/docs/blob/master/ko/translations/Local-Environment.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://freestartupkits.com/articles/technology/cryptocurrency-news-and-tips/how-to-build-an-eos-application-eosio-1/&quot;&gt;https://freestartupkits.com/articles/technology/cryptocurrency-news-and-tips/how-to-build-an-eos-application-eosio-1/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.eos.io/eosio-cpp/docs/introduction-to-smart-contracts&quot;&gt;https://developers.eos.io/eosio-cpp/docs/introduction-to-smart-contracts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/itam/eos-%ED%86%A0%ED%81%B0-%EB%B0%9C%ED%96%89-%EB%B0%8F-%EC%86%A1%EA%B8%88%ED%95%98%EA%B8%B0-centos-ver-9eeb28146eeb&quot;&gt;https://medium.com/itam/eos-토큰-발행-및-송금하기-centos-ver-9eeb28146eeb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/eos/comments/7z7h4r/why_21/&quot;&gt;https://www.reddit.com/r/eos/comments/7z7h4r/why_21/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.investopedia.com/terms/o/onchain-governance.asp&quot;&gt;https://www.investopedia.com/terms/o/onchain-governance.asp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coinjournal.net/on-chain-vs-off-chain-governance-the-ins-and-outs/&quot;&gt;https://coinjournal.net/on-chain-vs-off-chain-governance-the-ins-and-outs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://verticalplatform.kr/archives/9984&quot;&gt;https://verticalplatform.kr/archives/9984&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ddengle.com/traders_free/8298725&quot;&gt;https://www.ddengle.com/traders_free/8298725&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.forbes.com/sites/ksamani/2018/09/18/the-definitive-voting-guide-for-eos-block-producers/#62a556414d4f&quot;&gt;https://www.forbes.com/sites/ksamani/2018/09/18/the-definitive-voting-guide-for-eos-block-producers/#62a556414d4f&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/eosys/eos-%EA%B1%B0%EB%B2%84%EB%84%8C%EC%8A%A4-%EB%8C%84-%EB%9D%BC%EB%A6%AC%EB%A8%B8%EC%9D%98-%EB%8F%84%EC%A0%84%EA%B3%BC-%EA%B8%B0%ED%9A%8C-6af16b7587a2&quot;&gt;https://medium.com/eosys/eos-거버넌스-댄-라리머의-도전과-기회-6af16b7587a2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/kr/@holcoin/eos-reward-and-inflation&quot;&gt;https://steemit.com/kr/@holcoin/eos-reward-and-inflation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/loom-network-korean/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EA%B8%B0%EB%B3%B8-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%A0%9C3%EB%B6%80-%EC%9C%84%EC%9E%84-%EC%A7%80%EB%B6%84-%EC%A6%9D%EB%AA%85-dpos-4fc585e42b9f&quot;&gt;https://medium.com/loom-network-korean/블록체인-기본-원리-이해-제3부-위임-지분-증명-dpos-4fc585e42b9f&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vitalik.ca/general/2018/03/28/plutocracy.html&quot;&gt;https://vitalik.ca/general/2018/03/28/plutocracy.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;이미지 출처&lt;/h1&gt;
&lt;p&gt;아래 적힌 출처 이외의 이미지는 내가 만든 이미지이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EOS, 블록원 로고 ー &lt;a href=&quot;https://eos.io/&quot;&gt;eos.io&lt;/a&gt;, &lt;a href=&quot;https://block.one/&quot;&gt;block.one&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;EOS 프로그램 구조도 ー &lt;a href=&quot;https://developers.eos.io/eosio-nodeos/v1.1.0/docs/overview-1&quot;&gt;developers.eos.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On-Chain-Governance (왼쪽 EOS DApp 도표) ー &lt;a href=&quot;https://steemit.com/cryptocurrency/@abdulqadir01/list-and-details-of-dapps-that-will-be-airdropped-to-eos-holders&quot;&gt;abdulqadir01@steemit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Off-Chain-Governance (오른쪽 꼭두각시 조종 손 일러스트) ー &lt;a href=&quot;https://www.linkedin.com/pulse/how-do-you-manage-controlling-behaviour-part-1-john-edward-hind-llb&quot;&gt;John Edward Hind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Off-Chain-Governance (오른쪽 비트코인 네트워크 도표) ー &lt;a href=&quot;https://altcointoday.com/bitcoin-network-death/&quot;&gt;altcointoday.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nothing at Stake 설명 도표 (공격) ー &lt;a href=&quot;https://www.franceos.fr/2-avantages-et-inconvenients-de-la-preuve-denjeu/&quot;&gt;franceos.fr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nothing at Stake 설명 도표 (방어) ー &lt;a href=&quot;https://multicoin.capital/2018/03/02/delegated-proof-stake-features-tradeoffs/&quot;&gt;multicoin.capital&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이렇게 EOS와 DPOS에 대해서 간단히 수박겉핥기식으로 알아보았다. 다음에는 무엇을 공부해볼까...&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_14_1&quot;&gt;2018년 10월 기준으로, &lt;a href=&quot;https://bitshares.org/&quot;&gt;BitShares&lt;/a&gt;가 1위를 가져갔다. &lt;a href=&quot;#footnote_link_14_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_2&quot;&gt;1세대는 &quot;화폐&quot;로서의 블록체인으로, 비트코인 등이 해당하고, 2세대는 &quot;스마트 컨트랙트&quot;를 등장시킨 것으로, 이더리움이 대표적이다. &lt;a href=&quot;#footnote_link_14_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_3&quot;&gt;후술하겠지만 Off-chain이란 블록체인의 정책과 방향을 결정하는 권위체가 블록체인 외부에 있음(블록체인에 참가하지 않음)을 뜻하고, On-chain은 그 반대의 개념이다. &lt;a href=&quot;#footnote_link_14_3&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_4&quot;&gt;출처: 2018년 8월 15일 기준이며, &lt;del&gt;EOS 설명 글이니 EOS를 띄워 주기 위해 좋을 때를 찍은 것이다&lt;/del&gt; &lt;a href=&quot;coinmetrics.io&quot;&gt;coinmetrics.io&lt;/a&gt; &lt;a href=&quot;#footnote_link_14_4&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_5&quot;&gt;2018년 10월 기준으로, 메인넷이 겪은 최대 TPS는 약 4000 TPS이다. &lt;a href=&quot;#footnote_link_14_5&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_6&quot;&gt;실제로 들어가는 돈이 이더리움보다 훨씬 적다고 한다. &lt;a href=&quot;#footnote_link_14_6&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_7&quot;&gt;On-Chain Governance는 무조건적인 DPOS의 특징은 아니지만, DPOS를 따르는 블록체인들은 DPOS를 채택하는 이유인 성능상의 문제를 살리고 DPOS의 권한 위임이라는 특징을 살리기 위해 대부분 On-Chain Governance를 채택하는 것으로 보인다. &lt;a href=&quot;#footnote_link_14_7&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_8&quot;&gt;&lt;a href=&quot;https://github.com/EOS-Mainnet/eos/blob/mainnet-1.1.4/contracts/eosio.system/eosio.system-clause-constitution-rc.md&quot;&gt;이 페이지&lt;/a&gt;에서 EOS 헌법을 볼 수 있다. &lt;a href=&quot;#footnote_link_14_8&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_14_9&quot;&gt;&lt;a href=&quot;https://github.com/EOS-Mainnet/eos/blob/mainnet-1.1.4/contracts/eosio.system/eosio.system-regproducer-rc.md&quot;&gt;이 페이지&lt;/a&gt;에서 EOS 메인넷의 BP가 되기 위한 BP의 약속문을 볼 수 있다. &lt;a href=&quot;#footnote_link_14_9&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>다른 분야 공부/블록체인</category>
      <category>DPOS</category>
      <category>EOS</category>
      <category>공부</category>
      <category>블록체인</category>
      <category>암호화폐</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/14</guid>
      <comments>https://yuoa.tistory.com/entry/EOS-DPOS-%ED%95%A5%EC%95%84%EB%B3%B4%EA%B8%B0#entry14comment</comments>
      <pubDate>Thu, 10 Jan 2019 21:36:42 +0900</pubDate>
    </item>
    <item>
      <title>Hyperledger 사용해보기</title>
      <link>https://yuoa.tistory.com/entry/Hyperledger-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;i&gt;이 글은 Hexo 기반의 블로그에서 옮겨온 글이며, 원본 글은 2018년 8월 10일에 작성되었다.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;지난 번 &lt;a href=&quot;/entry/이더리움-개인-네트워크-써보기&quot;&gt;이더리움 개인 네트워크 써보기&lt;/a&gt;에 이어서, &lt;a href=&quot;https://www.hyperledger.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hyperledger&lt;/a&gt;를 써보았다. 이는 여름 방학 블록체인 공부의 일환이다.&lt;/p&gt;
&lt;p&gt;이 글의 내용으로는 Hyperledger Fabric 설치, 네트워크 실행 및 구축해보기, Hyperledger Fabric 애플리케이션 만들기를 담고 있다.&lt;/p&gt;
&lt;p&gt;아래의 모든 코드블럭에서 사용자 계정에서 실행된 줄은 &lt;code&gt;$&lt;/code&gt;, 루트 계정에서 실행된 줄은 &lt;code&gt;&amp;gt;&lt;/code&gt;로 표기하였다.&lt;/p&gt;
&lt;h1&gt;Hyperledger&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.hyperledger.org/wp-content/uploads/2018/08/HL_Whitepaper_IntroductiontoHyperledger.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hyperledger&lt;/a&gt;는 오픈소스 블록체인 기반의 &lt;a href=&quot;http://dic.daum.net/word/view.do?wordid=kkw000195736&amp;amp;supid=kku000247746&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;원장(ledger)&lt;/a&gt; 및 관련 툴을 다루는 &lt;a href=&quot;https://projects.coin-or.org/CoinTLC/wiki/UmbrellaProjects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;엄브렐라(우산) 구조&lt;/a&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_13_1&quot; id=&quot;footnote_link_13_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 13, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(13, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;의 프로젝트이다. Hyperledger 프로젝트에 대한 보다 본격적인 설명은 &lt;a href=&quot;https://medium.com/@yjw113080/%ED%95%98%EC%9D%B4%ED%8D%BC%EB%A0%88%EC%A0%80-hyperledger-%EA%B0%9C%EC%9A%94-c8baafc33fc5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 Medium 글&lt;/a&gt;에 잘 적혀 있다. Medium 계정이 있는 사람이라면 들어가서 박수쳐주자.&lt;/p&gt;
&lt;p&gt;여기서는 Hyperledger의 구현체 중 하나인 &lt;a href=&quot;https://www.hyperledger.org/projects/fabric&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hyperledger Fabric&lt;/a&gt;에서 제공하는 기본적인 기능과 예제를 사용하였다. Hyperledger Fabric에 관한 보다 본격적인 설명은 &lt;a href=&quot;http://cyberx.tistory.com/187&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 블로그 글&lt;/a&gt;의 작성자분께서 아주 잘 설명해주셨다.&lt;/p&gt;
&lt;h1&gt;Hyperledger Fabric 준비하기&lt;/h1&gt;
&lt;h2&gt;요구 사항&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hyperledger Fabric 사전 요구사항&lt;/a&gt;에 나와 있는 프로그램들이다. 괄호 안의 버전은 이 글을 작성할 때 사용한 Archlinux에 설치된 버전이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.docker.com/get-started&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Docker&lt;/a&gt; 엔진 17.06.2 이상&lt;/strong&gt; (&lt;em&gt;18.05.0-ce&lt;/em&gt;)&lt;br /&gt;
이 글에서 도커를 많이 활용하게 되는데, 도커에 대한 간략한 개념은 &lt;a href=&quot;https://seunguklee.github.io/2018/02/13/what-is-docker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 블로그 글&lt;/a&gt;에 잘 설명되어 있다.&lt;br /&gt;
WSL 환경에서 Docker는 제대로 작동하지 않을 수 있으니, WSL 말고 다른 환경에서 진행하길 권장한다.&lt;br /&gt;
다음 단계로 넘어가기 이전에 도커 데몬 실행은 필수이다. &lt;code&gt;sudo systemctl start docker&lt;/code&gt; 명령어로 도커 데몬을 시작할 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.docker.com/compose/install/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Docker Compose&lt;/a&gt; 1.14.0 이상&lt;/strong&gt; (&lt;em&gt;1.22.0&lt;/em&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://nodejs.org/ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;node&lt;/a&gt; 8.9 이상&lt;/strong&gt; (&lt;em&gt;v10.8.0 (by arch repo), v9.11.2 (by nvm)&lt;/em&gt;)&lt;br /&gt;
현재 노드 10 이상은 지원되지 않는 것으로 보인다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://docs.npmjs.com/getting-started/installing-node#install-npm--manage-npm-versions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;npm&lt;/a&gt;&lt;/strong&gt; (&lt;em&gt;6.3.0 (by arch repo), v5.6.0 (by nvm)&lt;/em&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://golang.org/doc/install#download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Go&lt;/a&gt; 1.10.x&lt;/strong&gt; (&lt;em&gt;go1.10.3&lt;/em&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;cURL 가장 최신 버전&lt;/strong&gt; (&lt;em&gt;7.61.0&lt;/em&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;python 2.7&lt;/strong&gt; (&lt;em&gt;2.7.15&lt;/em&gt;)&lt;br /&gt;
만일 커맨드라인에 &lt;code&gt;python --version&lt;/code&gt;이라고 입력했을때 python 3 이상이 먼저 실행되어도 python 2가 설치되어 있으면 상관이 없었다. 이 글을 작성하는 도중 &lt;code&gt;*.py&lt;/code&gt; 파일을 한 번도 본 적이 없지만, 그래도 요구사항이라고 하니 설치해주자.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이외에, &lt;strong&gt;Windows&lt;/strong&gt; 사용자는 &lt;a href=&quot;https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html#windows-extras&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 링크&lt;/a&gt;에서 추가 안내가 있다.&lt;/p&gt;
&lt;h2&gt;Hyperledger Fabric 다운로드&lt;/h2&gt;
&lt;p&gt;먼저 Hyperledger Fabric 공식 예제를 다운로드하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ git &lt;span class=&quot;built_in&quot;&gt;clone&lt;/span&gt; https://github.com/hyperledger/fabric-samples&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ &lt;span class=&quot;built_in&quot;&gt;cd&lt;/span&gt; fabric-samples&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;그런 다음, Hyperledger Fabric을 설치하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ &lt;span class=&quot;built_in&quot;&gt;cd&lt;/span&gt; scripts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ sudo ./bootstrap.sh&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;위 명령어를 입력하면, 수 분 안에 도커 이미지 몇 개가 받아질 것이다. 저 &lt;code&gt;bootstrap.sh&lt;/code&gt;, 친절하게 마지막에 설치된 Hyperledger Fabric 이미지 리스트를 출력해준다.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-ca          1.2.0               66cc132bd09c        5 weeks ago         252MB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-ca          latest              66cc132bd09c        5 weeks ago         252MB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-tools       1.2.0               379602873003        5 weeks ago         1.51GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-tools       latest              379602873003        5 weeks ago         1.51GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-ccenv       1.2.0               6acf31e2d9a4        5 weeks ago         1.43GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-ccenv       latest              6acf31e2d9a4        5 weeks ago         1.43GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-orderer     1.2.0               4baf7789a8ec        5 weeks ago         152MB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-orderer     latest              4baf7789a8ec        5 weeks ago         152MB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-peer        1.2.0               82c262e65984        5 weeks ago         159MB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-peer        latest              82c262e65984        5 weeks ago         159MB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-zookeeper   0.4.10              2b51158f3898        5 weeks ago         1.44GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-zookeeper   latest              2b51158f3898        5 weeks ago         1.44GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-kafka       0.4.10              936aef6db0e6        5 weeks ago         1.45GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-kafka       latest              936aef6db0e6        5 weeks ago         1.45GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-couchdb     0.4.10              3092eca241fc        5 weeks ago         1.61GB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;hyperledger/fabric-couchdb     latest              3092eca241fc        5 weeks ago         1.61GB&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;방금 받았으니 각 &lt;code&gt;latest&lt;/code&gt; 이미지는 각 버전에서 태그만 다른 이미지일 것이다. 대략 8GB정도의 저장 공간이 소모되었다.&lt;/p&gt;
&lt;h1&gt;Hyperledger Fabric 구동하기&lt;/h1&gt;
&lt;h2&gt;BYFN(Building Your First Network) 시나리오 예제 실행해보기&lt;/h2&gt;
&lt;p&gt;드디어, 첫 Hyperledger 네트워크를 구축해 볼 때이다. 아무것도 몰라도 좋다. &lt;code&gt;fabric-samples/first-network&lt;/code&gt; 디렉토리 안의 &lt;code&gt;byfn.sh&lt;/code&gt;를 실행해서 간단한 네트워크를 구성해보자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ sudo ./byfn.sh up&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;약 1~2분간 무언가가 실행되고, 마지막에 이 메시지가 뜨면 정상이다.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;========= All GOOD, BYFN execution completed ===========&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt; _____   _   _   ____&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;| ____| | \ | | |  _ \&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;|  _|   |  \| | | | | |&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;| |___  | |\  | | |_| |&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;|_____| |_| \_| |____/&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제, &lt;code&gt;byfn.sh&lt;/code&gt;가 도대체 무슨 행동을 한 건지 살펴보자. 먼저, &lt;code&gt;byfn.sh&lt;/code&gt;를 뜯어보면, 방금 실행시킨 코드는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;&lt;span class=&quot;title&quot;&gt;networkUp&lt;/span&gt;&lt;/span&gt;() {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 도커 이미지 버전 확인&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    checkPrereqs&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# fabric-samples/first-network/crypto-config 폴더가 없으면 아티팩트를 생성한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 여기서 아티팩트란 &quot;설정 기록 파일&quot;, 즉 &quot;설정 파일&quot;이라고 보면 된다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; [ ! -d &lt;span class=&quot;string&quot;&gt;&quot;crypto-config&quot;&lt;/span&gt; ]; &lt;span class=&quot;keyword&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        generateCerts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        replacePrivateKey&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        generateChannelArtifacts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# CouchDB 사용 옵션 여부에 따라 다르게 도커 이미지를 제작한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 우리는 그런 옵션을 주지 않았으므로, 아래쪽 else 명령어로 도커 이미지가 제작되었을 것이다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; [ &lt;span class=&quot;string&quot;&gt;&quot;&lt;span class=&quot;variable&quot;&gt;${IF_COUCHDB}&lt;/span&gt;&quot;&lt;/span&gt; == &lt;span class=&quot;string&quot;&gt;&quot;couchdb&quot;&lt;/span&gt; ]; &lt;span class=&quot;keyword&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        IMAGE_TAG=&lt;span class=&quot;variable&quot;&gt;$IMAGETAG&lt;/span&gt; docker-compose -f &lt;span class=&quot;variable&quot;&gt;$COMPOSE_FILE&lt;/span&gt; -f &lt;span class=&quot;variable&quot;&gt;$COMPOSE_FILE_COUCH&lt;/span&gt; up -d 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;# 별다른 옵션을 주지 않았으므로, 아래 $COMPOSE_FILE 변수는 스크립트 초반에 자동으로&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;# 설정된 'docker-compose-cli.yaml' 일 것이다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;# 이 파일은 fabric-samples/first-network 디렉토리에 존재한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;# docker-compose 명령어를 알기 쉽게 분석하면 아래와 같다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;#   'docker-compose'   : docker-compose 프로그램에게 아래의 동작을 시킨다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;#   '-f $COMPOSE_FILE' : docker-compose-cli.yaml 파일을 주고 도커 이미지를&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;#                        만든다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;#   'up -d'            : 만들어진 도커 이미지를 컨테이너로 백그라운드에서&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;#                        실행시킨다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;comment&quot;&gt;# 참고로, 2&amp;gt;&amp;amp;1은 (간단히 말해서) 에러 메시지도 가감없이 다 보여주라는 뜻이다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        IMAGE_TAG=&lt;span class=&quot;variable&quot;&gt;$IMAGETAG&lt;/span&gt; docker-compose -f &lt;span class=&quot;variable&quot;&gt;$COMPOSE_FILE&lt;/span&gt; up -d 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# docker-compose가 정상 (0)으로 끝나지 않았으면 오류 메시지를 출력한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; [ $? -ne 0 ]; &lt;span class=&quot;keyword&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;ERROR !!!! Unable to start network&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;built_in&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 이제 위의 docker-compose에서 실행시켰던 도커 컨테이너들 중 'cli' 이미지에 접속해서&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# fabric-samples/first-network/scripts/script.sh를 실행하게 된다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    docker &lt;span class=&quot;built_in&quot;&gt;exec&lt;/span&gt; cli scripts/script.sh &lt;span class=&quot;variable&quot;&gt;$CHANNEL_NAME&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;$CLI_DELAY&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;$LANGUAGE&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;$CLI_TIMEOUT&lt;/span&gt; &lt;span class=&quot;variable&quot;&gt;$VERBOSE&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 도커가 정상 (0)으로 끝나지 않았으면 오류 메시지를 출력한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; [ $? -ne 0 ]; &lt;span class=&quot;keyword&quot;&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;ERROR !!!! Test failed&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;built_in&quot;&gt;exit&lt;/span&gt; 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;살펴보니 위의 코드는 사전 준비 작업일 뿐, 실제 몸통은 &lt;code&gt;fabric-samples/first-network/scripts/script.sh&lt;/code&gt;에 있어보인다. 위에서 &lt;code&gt;docker-compose&lt;/code&gt; 명령어로 만들었던 도커 컨테이너들은 &lt;code&gt;sudo docker ps -a&lt;/code&gt; 명령으로 확인할 수 있었고, 9개의 컨테이너가 실행중이었다. 이번엔 &lt;code&gt;script.sh&lt;/code&gt;를 살펴보자. 이를 참고해서 이제 직접 Hyperledger 네트워크를 만들어 볼 것이다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# (전략)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# 아래에서 사용되는 함수들은 script.sh 혹은 같은 폴더에서 확인할 수 있는 utils.sh에 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 채널 만들기.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 채널이라 함은 'Hyperledger Fabric 네트워크'라고 해도 되고, 둘 이상의 네트워크 구성원이 있는&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 논리적인 개념을 &quot;채널&quot;이라 한다. 채널에는 구성원('조직'), 그리고 그 '조직' 당 하나 이상의 중계&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 피어(anchor peer), 채널 정책, 분산 공유 원장, 원장을 관리하는 체인코드 애플리케이션, 주문&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 서비스 노드 등을 포함한다. 많은 개념들이 나왔지만 여기서 모든걸 다 알 필요는 없다. 일단은 그냥&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 그렇구나 하고 넘어가도 좋다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Creating channel...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;createChannel&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 아까 docker-compose로 만든 피어가 이 채널에 들어오도록 한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Having all peers join the channel...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;joinChannel&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 등록한 피어를 각 조직의 중계 피어로 설정한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Updating anchor peers for org1...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;updateAnchorPeers 0 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Updating anchor peers for org2...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;updateAnchorPeers 0 2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## peer0.org1, peer0.org2 피어에 체인코드 애플리케이션을 설치한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Installing chaincode on peer0.org1...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;installChaincode 0 1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Install chaincode on peer0.org2...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;installChaincode 0 2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## peer0.org2의 체인코드를 채널에 인스턴스화한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 인스턴스화를 도커에 비유하자면, 도커 이미지로 도커 컨테이너를 만드는 것으로 보면 된다. 이 함수&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 소스 코드를 보면 &quot;a&quot;에 &quot;100&quot;, &quot;b&quot;에 200을 넣어 초기화하는 구문이 포함되어있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Instantiating chaincode on peer0.org2...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;instantiateChaincode 0 2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## peer0.org1의 체인코드를 채널에서 조회한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## chaincodeQuery 함수에서는 &quot;a&quot; 값을 찾아 주어진 예상값과 비교하는 절차가 함수 막바지에&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 포함되어 있다. 즉, 여기서 &quot;a&quot;와 100을 비교하는 것이다. 위의 체인코드가 인스턴스화에 성공했다면&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## &quot;a&quot;에는 100이 저장되어 있을 것이고, 이 절차는 잘 넘어갈것이다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Querying chaincode on peer0.org1...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;chaincodeQuery 0 1 100&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## peer0.org1과 peer0.org2의 체인코드를 호출한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## chaincodeInvoke 함수 소스 코드를 살펴보면 'mycc' 라는 체인코드를 호출하고 있는데, 이&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## mycc라는 체인코드는 인자 3개를 받아 첫번째 인자에서 세번째 인자 만큼을 빼고, 두번째 인자에&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 세번째 인자 만큼을 더하는 것이다. chaincodeInvoke 함수에서는 이 mycc에게&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## '{&quot;Args&quot;:[&quot;invoke&quot;,&quot;a&quot;,&quot;b&quot;,&quot;10&quot;]}'라는 인자를 넘겨주어, &quot;a&quot;에서 10을 빼어 &quot;b&quot;에게&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 더해주게된다. 진짜로 이렇게 되었는지, 아래쪽 chaincodeQuery 함수에서 확인해보게 될 것이다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 여기서 언급한 'mycc'의 체인코드의 소스 코드는 다음 링크에 있다: https://git.io/fN7hO&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Sending invoke transaction on peer0.org1 peer0.org2...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;chaincodeInvoke 0 1 0 2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## peer1.org2에 체인코드 애플리케이션을 설치한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Installing chaincode on peer1.org2...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;installChaincode 1 2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## peer1.org2의 체인코드를 채널에서 조회한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 위에서 'mycc' 체인코드를 호출했기에, &quot;a&quot;는 90, &quot;b&quot;는 100이 되어있을 것이다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;## 따라서, 여기선 &quot;a&quot;와 90을 비교하도록 chaincodeQuery 함수가 호출되었다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;Querying chaincode on peer1.org2...&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;chaincodeQuery 1 2 90&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;========= All GOOD, BYFN execution completed =========== &quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# (후략)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;script.sh&lt;/code&gt;는 간단히 채널과 피어를 만들고, 체인코드 조회와 호출이 정상 작동하는지 테스트해보는 것이었다. 이제 직접 네트워크를 만들어보기 위해, BYFN 네트워크를 종료하자. 아래 명령어를 입력하면 &lt;code&gt;byfn.sh&lt;/code&gt;에서 생성한 도커 컨테이너까지 말끔히 없애준다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ sudo ./byfn.sh down&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;h2&gt;직접 Hyperledger 네트워크 빌드하기&lt;/h2&gt;
&lt;p&gt;이제 위 &lt;code&gt;first-network&lt;/code&gt;의 &lt;code&gt;byfn.sh&lt;/code&gt;에서 자동으로 수행한 작업을 수동으로 수행해보면서 나의 Hyperledger 네트워크를 직접 만들어보자. 먼저 적당한 곳에 작업 디렉토리를 따로 하나 생성해주자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ mkdir my-network&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ &lt;span class=&quot;built_in&quot;&gt;cd&lt;/span&gt; my-network&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;그리고 &lt;code&gt;cryptogen&lt;/code&gt; 명령어를 이용해서 Hyperledger Fabric 인증서를 만들어주기 위해, &lt;code&gt;cryptogen&lt;/code&gt;의 설정파일인 &lt;code&gt;crypto-config.yaml&lt;/code&gt; 파일을 아래와 같이 작성하자. YAML 형식을 모른다면, &lt;a href=&quot;https://soulsearcher.github.io/blog/2017/09/22/yaml_syntax/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 글&lt;/a&gt;에 간단하게 잘 적혀있다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# 이 파일은 fabric-samples/first-network/crypto-config.yaml의 한글 번역본이며, 일부&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# 자체 조사하여 설명을 첨했다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# &quot;OrdererOrgs&quot; - 다른 원고 노드(orderer node)를 관리하는 조직의 정의&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;OrdererOrgs:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# Orderer&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;  - Name:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Orderer&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Domain:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;example.com&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# &quot;Specs&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# Specs는 조직의 특성을 정의하는 행렬이다. 각 특성 항목은 두개의 필드로 구성되어있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;#   - Hostname:   (필수) 도메인을 제외한 호스트 이름&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;#   - CommonName: (선택) 기본 설정 &quot;{{Hostname}}.{{Domain}}&quot;을 덮어쓰는 FQDN&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Specs:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;      - Hostname:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;orderer&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# &quot;PeerOrgs&quot; - 피어 노드를 관리하는 조직의 정의&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;PeerOrgs:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# Org1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;  - Name:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Org1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Domain:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;org1.example.com&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# &quot;EnableNodeOUs&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# Hyperledger Fabric MSP에서 해당 노드에 대해 신원 분류를 할지 말지를 결정하는 항목이다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 아래 문서가 이 변수의 정확한 사용에 대해 알 수 있는 유일한 문서인데, 보아도 정확히 어떤&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 작용을 하는지 아직 이해할 수 없었다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# https://hyperledger-fabric.readthedocs.io/en/release-1.1/msp.html&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    EnableNodeOUs:&lt;/span&gt; &lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# &quot;Specs&quot; - 위에서 설명한 Specs 항목을 이곳에도 지정할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# &quot;Template&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 템플릿으로부터 1개 이상의 호스트를 자동으로 만들 수 있게 하는 옵션이다. 호스트 이름은&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 기본적으로 peer%d 형식으로, 0 부터 지정개수 - 1 까지 지정된다. 아래와 같은 옵션을 지정할&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;#   - Count:    생성할 호스트의 수&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;#   - Start:    호스트 번호 세기가 시작하는 숫자&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;#   - Hostname: 지정하는 호스트 이름이다. (기본값: {{.Prefix}}{{.Index}})&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 참고: 위의 &quot;Specs&quot; 와 이 &quot;Template&quot;을 모두 활용한다면 같은 이름의 호스트가 생성될 수&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 있으므로 이름 충돌에 주의해야한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Template:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;      Count:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# &quot;Users&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# 옵션은 한 가지다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;#   - Count: 관리자(Admin) 이외의 유저 수&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Users:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;      Count:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# Org2: 위의 Org1과 같은 방법으로 옵션을 지정하였다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;comment&quot;&gt;# -------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;  - Name:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Org2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Domain:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;org2.example.com&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    EnableNodeOUs:&lt;/span&gt; &lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Template:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;      Count:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Users:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;      Count:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 이 파일을 &lt;code&gt;cryptogen&lt;/code&gt; 프로그램으로 넣어주자. 나는 &lt;code&gt;fabric-samples/my-network&lt;/code&gt; 디렉토리에서 진행했다. 자신이 만든 작업 디렉토리와 &lt;code&gt;fabric-samples/bin&lt;/code&gt; 디렉토리의 상대 위치를 잘 살펴가며 진행하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ ../bin/cryptogen generate --config=./crypto-config.yaml&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;org1.example.com&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;org2.example.com&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 &lt;code&gt;crypto-config&lt;/code&gt;라는 디렉토리가 작업 디렉토리 안에 생성되었을 것이다. 이제는 Hyperledger Fabric 네트워크(채널)의 첫 블록(제네시스 &lt;s&gt;태초마을&lt;/s&gt; 블록)을 만들자. &lt;code&gt;configtxgen&lt;/code&gt; 프로그램에 넣어줄 설정 파일을 먼저 만들어야 한다. &lt;code&gt;configtx.yaml&lt;/code&gt; 파일 안에 아래의 내용을 입력하자.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# 이 파일은 fabric-samples/first-network/configtx.yaml의 복사본이며, 자세한 주석은&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# 삭제하였다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;Organizations:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;    -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;OrdererOrg&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Name:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;OrdererOrg&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        ID:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;OrdererMSP&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        MSPDir:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;crypto-config/ordererOrganizations/example.com/msp&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;    -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;Org1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Name:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Org1MSP&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        ID:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Org1MSP&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        MSPDir:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;crypto-config/peerOrganizations/org1.example.com/msp&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        AnchorPeers:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;            - Host:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;peer0.org1.example.com&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;              Port:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;7051&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;    -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;Org2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Name:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Org2MSP&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        ID:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;Org2MSP&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        MSPDir:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;crypto-config/peerOrganizations/org2.example.com/msp&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        AnchorPeers:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;            - Host:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;peer0.org2.example.com&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;              Port:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;7051&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;Capabilities:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Global:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;ChannelCapabilities&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        V1_1:&lt;/span&gt; &lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Orderer:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;OrdererCapabilities&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        V1_1:&lt;/span&gt; &lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Application:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;ApplicationCapabilities&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        V1_2:&lt;/span&gt; &lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;Application:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;ApplicationDefaults&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Organizations:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;Orderer:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;&amp;amp;OrdererDefaults&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    OrdererType:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;solo&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Addresses:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;        -&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;orderer.example.com:7050&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    BatchTimeout:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    BatchSize:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        MaxMessageCount:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        AbsoluteMaxBytes:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;99&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;MB&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        PreferredMaxBytes:&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;KB&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Kafka:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Brokers:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;            -&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;.1&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;:9092&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    Organizations:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;Profiles:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    TwoOrgsOrdererGenesis:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Capabilities:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;            &lt;span class=&quot;string&quot;&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*ChannelCapabilities&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Orderer:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;            &lt;span class=&quot;string&quot;&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*OrdererDefaults&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;            Organizations:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;                -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*OrdererOrg&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;            Capabilities:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;                &lt;span class=&quot;string&quot;&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*OrdererCapabilities&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Consortiums:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;            SampleConsortium:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;                Organizations:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;                    -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*Org1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;                    -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*Org2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;    TwoOrgsChannel:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Consortium:&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;SampleConsortium&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;        Application:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;            &lt;span class=&quot;string&quot;&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*ApplicationDefaults&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;            Organizations:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;                -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*Org1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;bullet&quot;&gt;                -&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*Org2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;attr&quot;&gt;            Capabilities:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;                &lt;span class=&quot;string&quot;&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class=&quot;meta&quot;&gt;*ApplicationCapabilities&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 &lt;code&gt;configtxgen&lt;/code&gt;을 실행해서 태초마을 블록을 생성하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ mkdir channel-artifacts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ ../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block -channelID mychannel&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이후 차례로 채널 구성 트랜잭션을 보내 채널 구성을 완료하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 기본 도커 설정 파일을 작성하고 Hyperledger Fabric 네트워크를 실행하자. 도커 설정도 &lt;code&gt;first-network&lt;/code&gt;의 것을 그대로 가져왔으며, &lt;code&gt;docker-compose&lt;/code&gt;의 설정 파일을 다루는 것은 이 글의 범주에서 벗어나므로 크게 다루지는 않는다. 다만, 아래 명령을 수행함으로써 하나의 orderer 컨테이너(노드)와 네 개의 peer 컨테이너(노드)가 생성된다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ cp ../first-network/base . -r&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ cp ../first-network/docker-compose-cli.yaml .&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ sudo env IMAGE_TAG=latest CHANNEL_NAME=mychannel docker-compose -f docker-compose-cli.yaml up -d&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;WARNING: The COMPOSE_PROJECT_NAME variable is not &lt;span class=&quot;built_in&quot;&gt;set&lt;/span&gt;. Defaulting to a blank string.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating network &lt;span class=&quot;string&quot;&gt;&quot;my-network_byfn&quot;&lt;/span&gt; with the default driver&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating volume &lt;span class=&quot;string&quot;&gt;&quot;my-network_orderer.example.com&quot;&lt;/span&gt; with default driver&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating volume &lt;span class=&quot;string&quot;&gt;&quot;my-network_peer0.org1.example.com&quot;&lt;/span&gt; with default driver&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating volume &lt;span class=&quot;string&quot;&gt;&quot;my-network_peer1.org1.example.com&quot;&lt;/span&gt; with default driver&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating volume &lt;span class=&quot;string&quot;&gt;&quot;my-network_peer0.org2.example.com&quot;&lt;/span&gt; with default driver&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating volume &lt;span class=&quot;string&quot;&gt;&quot;my-network_peer1.org2.example.com&quot;&lt;/span&gt; with default driver&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating peer1.org2.example.com ... &lt;span class=&quot;keyword&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating peer0.org1.example.com ... &lt;span class=&quot;keyword&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating peer1.org1.example.com ... &lt;span class=&quot;keyword&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating peer0.org2.example.com ... &lt;span class=&quot;keyword&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating orderer.example.com    ... &lt;span class=&quot;keyword&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Creating cli                    ... &lt;span class=&quot;keyword&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 &lt;code&gt;docker ps -a&lt;/code&gt; 명령어로 확인하면 6개의 도커 이미지가 돌아가고 있음을 확인할 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;지금부터는 도커에 접속하여 위의 &lt;code&gt;first-network&lt;/code&gt;에서 했던 테스트를 직접 해보자. 먼저 도커에 접속해본다. 참고로, &lt;code&gt;cli&lt;/code&gt; 도커는 우분투 환경을 기반으로 구성되어있다. (다른 컨테이너는 확인해보지 않았다.)&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ sudo docker &lt;span class=&quot;built_in&quot;&gt;exec&lt;/span&gt; -it cli bash&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; (이 부분은 곧 업데이트할 예정이다.)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이렇게, 씹고 뜯고 맛보고 즐기고 볼 장 다 봤으면 아래의 명령어로 나의 네트워크를 종료하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ sudo docker-compose -f docker-compose-cli.yaml down --volumes --remove-orphans&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;h1&gt;Hyperledger Fabric 애플리케이션 실행해보기&lt;/h1&gt;
&lt;p&gt;마지막으로, Hyperledger Fabric 예제 애플리케이션 &lt;code&gt;fabcar&lt;/code&gt;를 구동해보자. 먼저 아래 코드를 &lt;code&gt;fabric-samples/fabcar&lt;/code&gt; 디렉토리에서 실행하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ sudo ./startFabric.sh&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;1분 가량의 작업이 끝나면 다음과 같은 메시지가 나타난다.&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;Start by installing required packages run 'npm install'&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Then run 'node enrollAdmin.js', then 'node registerUser'&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;The 'node invoke.js' will fail until it has been updated with valid arguments&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;The 'node query.js' may be run at anytime once the user has been registered&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;저들의 말에 순순히 따라주자. 먼저 &lt;code&gt;npm i&lt;/code&gt; 명령어를 입력하여 &lt;code&gt;package.json&lt;/code&gt;에 적힌 요구 &lt;code&gt;npm&lt;/code&gt; 패키지를 받아오자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ npm i&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;위 명령 실행 도중에 나타나는 &lt;code&gt;cc&lt;/code&gt;의 warning과 note는 신경쓰지 않아도 좋다. (&lt;code&gt;ERR&lt;/code&gt;가 발생하면 더이상 진행이 불가능하다. 아래 &lt;a href=&quot;#npm-i-%EC%8B%A4%ED%96%89-%EC%A4%91-%EB%AC%B8%EC%A0%9C-%EB%B0%9C%EC%83%9D&quot;&gt;문제 해결&lt;/a&gt;에 해결법이 적혀 있다.) 의존 패키지 설치가 완료되었으면 &lt;code&gt;Admin&lt;/code&gt;과 &lt;code&gt;user1&lt;/code&gt;을 영입할 차례이다. 아래 명령어로 관리자와 &lt;code&gt;user1&lt;/code&gt;을 만들어주자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ node enrollAdmin.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ node registerUser.js&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;그런 다음, 간단하게 쿼리(조회)를 해보자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ node query.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;(...)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Response is  [&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR0&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;blue&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Toyota&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Prius&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Tomoko&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR1&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;red&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Ford&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Mustang&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Brad&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR2&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;green&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Hyundai&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Tucson&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Jin Soo&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR3&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;yellow&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Volkswagen&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Passat&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Max&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR4&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;black&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Tesla&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;S&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Adriana&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR5&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;purple&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Peugeot&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;205&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Michel&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR6&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;white&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Chery&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;S22L&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Aarav&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR7&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;violet&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Fiat&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Punto&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Pari&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR8&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;indigo&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Tata&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Nano&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Valeria&quot;&lt;/span&gt;}},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    {&lt;span class=&quot;string&quot;&gt;&quot;Key&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;CAR9&quot;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;Record&quot;&lt;/span&gt;:{&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;brown&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Holden&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Barina&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Shotaro&quot;&lt;/span&gt;}}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 원장(ledger)을 업데이트해보자. &lt;code&gt;invoke.js&lt;/code&gt; 파일을 열어 &lt;code&gt;chaincodeId&lt;/code&gt;와 &lt;code&gt;fcn&lt;/code&gt; 등을 담고 있는 &lt;code&gt;var request&lt;/code&gt;를 아래와 같이 수정한다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// createCar chaincode function - requires 5 args, ex: args: ['CAR12', 'Honda', 'Accord', 'Black', 'Tom'],&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// changeCarOwner chaincode function - requires 2 args , ex: args: ['CAR10', 'Dave'],&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// must send the proposal to endorsing peers&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; request = {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    chaincodeId: &lt;span class=&quot;string&quot;&gt;'fabcar'&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    fcn: &lt;span class=&quot;string&quot;&gt;'createCar'&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    args: [&lt;span class=&quot;string&quot;&gt;'CAR10'&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;'Chevy'&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;'Volt'&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;'Red'&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;'Nick'&lt;/span&gt;],&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    chainId: &lt;span class=&quot;string&quot;&gt;'mychannel'&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    txId: tx_id&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 &lt;code&gt;invoke.js&lt;/code&gt;를 실행한 뒤(&lt;code&gt;node invoke.js&lt;/code&gt;), &lt;code&gt;query.js&lt;/code&gt; 파일을 열어 &lt;code&gt;const request&lt;/code&gt;를 아래와 같이 수정한다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;const&lt;/span&gt; request = {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    chaincodeId: &lt;span class=&quot;string&quot;&gt;'fabcar'&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    fcn: &lt;span class=&quot;string&quot;&gt;'queryCar'&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    args: [&lt;span class=&quot;string&quot;&gt;'CAR10'&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이제 &lt;code&gt;query.js&lt;/code&gt;를 실행시키면 아래와 같은 결과가 나온다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;$ node query.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;(...)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Response is  {&lt;span class=&quot;string&quot;&gt;&quot;colour&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Red&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;make&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Chevy&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Volt&quot;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&quot;owner&quot;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&quot;Nick&quot;&lt;/span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;아까 &lt;code&gt;invoke.js&lt;/code&gt;를 통해 추가한 &lt;code&gt;CAR10&lt;/code&gt;이 제대로 추가되었음을 확인할 수 있다. 이제 아래 명령어로 생성된 도커를 지우고 모든 것을 끝내자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# fabric-samples/basic-network 디렉토리로 이동&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ &lt;span class=&quot;built_in&quot;&gt;cd&lt;/span&gt; ../basic-network&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# fabcar에서 이용한 basic-network를 종료하고 삭제&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ sudo ./teardown.sh&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;h1&gt;문제 해결&lt;/h1&gt;
&lt;h2&gt;&lt;code&gt;bootstrap.sh&lt;/code&gt; 실행 중 문제 발생&lt;/h2&gt;
&lt;h3&gt;Cannot connect to the Docker daemon&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;Warning: failed to get default registry endpoint from daemon (Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?). Using system default: https://index.docker.io/v1/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;만일 위와 같은 메시지가 뜬다면 꼭 &lt;code&gt;sudo systemctl start docker&lt;/code&gt; 혹은 &lt;code&gt;sudo service docker start&lt;/code&gt;를 해주자. 도커 데몬이 실행중이지 않아서 발생하는 오류이다.&lt;/p&gt;
&lt;h3&gt;Got permission denied&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;Warning: failed to get default registry endpoint from daemon (Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.37/info: dial unix /var/run/docker.sock: connect: permission denied). Using system default: https://index.docker.io/v1/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.37/images/create?fromImage=hyperledger%2Ffabric-peer&amp;amp;tag=1.2.0: dial unix /var/run/docker.sock: connect: permission denied&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.37/images/hyperledger/fabric-peer:1.2.0/tag?repo=hyperledger%2Ffabric-peer&amp;amp;tag=latest: dial unix /var/run/docker.sock: connect: permission denied&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;도커 데몬 소켓을 가져올 권한이 없어서 발생하는 오류이다. &lt;code&gt;bootstrap.sh&lt;/code&gt;를 관리자 권한(&lt;code&gt;sudo&lt;/code&gt;)으로 실행해주자.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;byfn.sh&lt;/code&gt; 실행 중 문제 발생&lt;/h2&gt;
&lt;h3&gt;Couldn't connect to Docker daemon&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running?&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;ERROR !!!! Unable to start network&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;byfn.sh&lt;/code&gt;가 도커 데몬 소켓을 가져오지 못해 발생하는 오류이다. &lt;code&gt;byfn.sh&lt;/code&gt;를 관리자 권한(&lt;code&gt;sudo&lt;/code&gt;)으로 실행해주자.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;configtxgen&lt;/code&gt; 실행 중 문제 발생&lt;/h2&gt;
&lt;h3&gt;Could not find configtx.yaml.&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;2018-08-11 05:26:53.159 KST [common/tools/configtxgen/localconfig] Load -&amp;gt; CRIT 003 Error reading configuration:  Unsupported Config Type &quot;&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;2018-08-11 05:26:53.159 KST [common/tools/configtxgen] func1 -&amp;gt; ERRO 004 Could not find configtx.yaml. Please make sure that FABRIC_CFG_PATH or --configPath is set to a path which contains configtx.yaml&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;configtxgen&lt;/code&gt;에서 &lt;code&gt;configtx.yaml&lt;/code&gt; 파일을 찾지 못해 벌어진 일이다. &lt;code&gt;--configPath&lt;/code&gt; 옵션은 오류 메시지와 달리 현재 버전에서 &lt;code&gt;-configPath&lt;/code&gt;로 하이픈이 하나 줄어들었고, 또한 그 역할은 설정 파일의 위치를 지정하는 것이 아닌 &lt;code&gt;configtx.yaml&lt;/code&gt;이 들어있는 디렉터리를 지정하는 옵션이므로, 설정 파일 이름은 꼭 &lt;code&gt;configtx.yaml&lt;/code&gt;로 해주도록 하고, 되도록이면 해당 &lt;code&gt;configtx.yaml&lt;/code&gt; 파일이 들어있는 디렉토리에서 &lt;code&gt;configtxgen&lt;/code&gt; 명령을 실행하자.&lt;/p&gt;
&lt;h3&gt;Error writing genesis block&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;2018-08-11 05:42:53.723 KST [common/tools/configtxgen] main -&amp;gt; CRIT 00c Error on outputBlock: Error writing genesis block: open ./channel-artifacts/genesis.block: no such file or directory&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;파일을 만드려는 디렉토리가 존재하지 않아 발생하는 오류이다. &lt;code&gt;mkdir&lt;/code&gt; 명령어로 &lt;code&gt;channel-artifacts&lt;/code&gt; 디렉토리를 먼저 생성해주자.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;npm i&lt;/code&gt; 실행 중 문제 발생&lt;/h2&gt;
&lt;h3&gt;node-pre-gyp ERR!&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;node-pre-gyp ERR! Tried to download(403): https://storage.googleapis.com/grpc-precompiled-binaries/node/grpc/v1.10.1/node-v64-linux-x64-glibc.tar.gz&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;node-pre-gyp ERR! Pre-built binaries not found for grpc@1.10.1 and node@10.8.0 (node-v64 ABI, glibc) (falling back to source compile with node-gyp)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;node-pre-gyp ERR! Pre-built binaries not installable for grpc@1.10.1 and node@10.8.0 (node-v64 ABI, glibc) (falling back to source compile with node-gyp)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;node-pre-gyp ERR! Hit error Connection closed while downloading tarball file&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;grpc&lt;/code&gt;가 최신 node 버전에 대응하지 않아서 발생한 문제이다. node 9, npm 5에서 정상적으로 작동하니, node 10을 이용하고 있다면 아래와 같이 nvm을 이용하여 낮은 버전의 node를 사용하자.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# 아래 끝 부분에는 자신이 이용하는, bash 계열의 쉘을 적자. 딱히 없다면 그냥 bash로 두면 된다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ &lt;span class=&quot;built_in&quot;&gt;export&lt;/span&gt; NVM_DIR=&lt;span class=&quot;string&quot;&gt;&quot;&lt;span class=&quot;variable&quot;&gt;$HOME&lt;/span&gt;/.nvm&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ [ -s &lt;span class=&quot;string&quot;&gt;&quot;&lt;span class=&quot;variable&quot;&gt;$NVM_DIR&lt;/span&gt;/nvm.sh&quot;&lt;/span&gt; ] &amp;amp;&amp;amp; \. &lt;span class=&quot;string&quot;&gt;&quot;&lt;span class=&quot;variable&quot;&gt;$NVM_DIR&lt;/span&gt;/nvm.sh&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ [ -s &lt;span class=&quot;string&quot;&gt;&quot;&lt;span class=&quot;variable&quot;&gt;$NVM_DIR&lt;/span&gt;/bash_completion&quot;&lt;/span&gt; ] &amp;amp;&amp;amp; \. &lt;span class=&quot;string&quot;&gt;&quot;&lt;span class=&quot;variable&quot;&gt;$NVM_DIR&lt;/span&gt;/bash_completion&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ nvm install 9&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;$ nvm use 9&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# 이후 이 쉘에서 fabric-samples/fabcar 디렉토리로 가 node와 npm 작업을 수행한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;참고로, nvm의 사용은 &lt;code&gt;fish&lt;/code&gt; 에서 지원되지 않는다. 혹시 &lt;code&gt;fish&lt;/code&gt;를 사용중이라면 &lt;code&gt;zsh&lt;/code&gt;나 &lt;code&gt;bash&lt;/code&gt;에서 nvm을 설치 및 실행하자.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;node invoke.js&lt;/code&gt; 실행 중 문제 발생&lt;/h2&gt;
&lt;h3&gt;Promise is rejected&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;error: [client-utils.js]: sendPeersProposal - Promise is rejected: Error: Invalid Smart Contract function name.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;h1&gt;참고한 문서&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://hihellloitland.tistory.com/24?category=766220&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://hihellloitland.tistory.com/24?category=766220&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vitalflux.com/hyperledger-fabric-channels-private-blockchain-deep-dive/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://vitalflux.com/hyperledger-fabric-channels-private-blockchain-deep-dive/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hihellloitland.tistory.com/26&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://hihellloitland.tistory.com/26&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spri.kr/download/21810&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://spri.kr/download/21810&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hihellloitland.tistory.com/28&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://hihellloitland.tistory.com/28&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/49924937/meaning-of-enablenodeous-in-crypto-config-yaml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/49924937/meaning-of-enablenodeous-in-crypto-config-yaml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hyperledger-fabric.readthedocs.io/en/release-1.1/msp.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://hyperledger-fabric.readthedocs.io/en/release-1.1/msp.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hyperledger/fabric/blob/release-1.2/docs/source/glossary.rst&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/hyperledger/fabric/blob/release-1.2/docs/source/glossary.rst&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hyperledger/fabric/blob/release-1.2/docs/source/network/network.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/hyperledger/fabric/blob/release-1.2/docs/source/network/network.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hyperledger/fabric/blob/77c3aa6ce5b0cfba93bfda009095886dbcadff91/docs/source/chaincode4noah.rst&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/hyperledger/fabric/blob/77c3aa6ce5b0cfba93bfda009095886dbcadff91/docs/source/chaincode4noah.rst&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_13_1&quot;&gt;'표준안' 만을 정의하는 하나의 메인 프로젝트를 중심으로, 그 표준안을 구현한 여러 서브 프로젝트가 있는 프로젝트의 형태를 말한다. &lt;a href=&quot;#footnote_link_13_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>다른 분야 공부/블록체인</category>
      <category>Hyperledger</category>
      <category>공부</category>
      <category>블록체인</category>
      <category>암호화폐</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/13</guid>
      <comments>https://yuoa.tistory.com/entry/Hyperledger-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0#entry13comment</comments>
      <pubDate>Thu, 10 Jan 2019 21:14:39 +0900</pubDate>
    </item>
    <item>
      <title>이더리움 개인 네트워크 써보기</title>
      <link>https://yuoa.tistory.com/entry/%EC%9D%B4%EB%8D%94%EB%A6%AC%EC%9B%80-%EA%B0%9C%EC%9D%B8-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8D%A8%EB%B3%B4%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;i&gt;이 글은 Hexo 기반의 블로그에서 옮겨온 글이며, 원본 글은 2018년 7월 26일에 작성되었다.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;이 글은 &lt;a href=&quot;/entry/이더리움-Genesis-파일-만들고-개인-네트워크-구동하기&quot;&gt;지난 글&lt;/a&gt;에 이어서 개인 이더리움 네트워크를 활용해보면서 남기는 기록이다.&lt;/p&gt;
&lt;h1&gt;시작 상태&lt;/h1&gt;
&lt;p&gt;이더리움 개인 네트워크 설정 이후로, Javascript IPC에서 현재 상황을 알아보면 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; eth.accounts &lt;span class=&quot;comment&quot;&gt;//등록된 계좌들&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;[]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; eth.mining &lt;span class=&quot;comment&quot;&gt;//현재 내가 채굴중인지 여부&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;literal&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; net.peerCount &lt;span class=&quot;comment&quot;&gt;//이 네트워크에서 나와 연결된 다른 피어의 수&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;h1&gt;계좌 만들고 채굴하기&lt;/h1&gt;
&lt;h2&gt;계좌 만들기&lt;/h2&gt;
&lt;p&gt;먼저, 아래의 명령어로 계좌를 만들 수 있다. 적당한 계좌 비밀번호를 입력하면 된다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; personal.newAccount()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Passphrase:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Repeat passphrase:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;eth.accounts&lt;/code&gt; 명령어로 만든 계좌가 계좌 목록에 올라갔음을 확인할 수 있다.&lt;/p&gt;&lt;p&gt;참고로, &lt;code&gt;personal.newAccount&lt;/code&gt; 함수로 계좌를 만들면 &lt;code&gt;geth&lt;/code&gt;의 데이터 디렉토리의 &lt;code&gt;keystore&lt;/code&gt; 디렉토리 안에 개인 키 파일이 생성된다. 앞으로 사용할 개인 키는 이 곳에서 확인할 수 있다.&lt;/p&gt;
&lt;h2&gt;계좌 잔액 확인&lt;/h2&gt;
&lt;p&gt;혹시라도 시스템 오류가 생겨 처음 만든 내 계좌에 돈이 충전되어 있을 지 모르니 확인해보자.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; eth.getBalance(&lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;꿈 깨자.&lt;/strong&gt; 그럴 일 없다.&lt;/p&gt;
&lt;h2&gt;내 계좌로 채굴 시작하기&lt;/h2&gt;
&lt;p&gt;역시 돈을 벌려면 일을 해야 하는 법이다. 채굴을 시작하려면 먼저 &lt;code&gt;coinbase&lt;/code&gt; 주소를 설정해야 하는데, 아래와 같이 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; miner.setEtherbase(&lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;) &lt;span class=&quot;comment&quot;&gt;//coinbase 설정&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; eth.coinbase &lt;span class=&quot;comment&quot;&gt;//coinbase 확인&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;처음이라면 그저 &lt;code&gt;eth.coinbase&lt;/code&gt;라고 입력하는 것 만으로 자동으로 &lt;code&gt;coinbase&lt;/code&gt;를 설정할 수 있다.&lt;/p&gt;&lt;p&gt;이제 &lt;code&gt;miner.start()&lt;/code&gt; 명령어를 입력하여 채굴을 해 보자.&lt;/p&gt;&lt;p&gt;아래와 같은 로그가 뜨면 블록이 하나 만들어 진 것이다. (실제 로그 출력은 아마 &lt;code&gt;number&lt;/code&gt;가 뒤죽박죽 섞여 있을 것이다.)&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;INFO [07-26|16:21:13.424] Commit new mining work                   number=76 txs=0 uncles=0 elapsed=150.49µs&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;INFO [07-26|16:21:13.946] Successfully sealed new block            number=76 hash=320aac…7a0d4e&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;INFO [07-26|16:21:13.947]   mined potential block                  number=76 hash=320aac…7a0d4e&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;INFO [07-26|16:21:22.677]   block reached canonical chain          number=76 hash=320aac…7a0d4e&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;채굴을 끝내는 것은 &lt;code&gt;miner.stop()&lt;/code&gt; 명령어로 할 수 있다. 참고로, DAG를 만들고 있을 때 이 명령어를 입력한다면 DAG 생성 과정이 끝난 후에 완전히 채굴이 멈추게 된다. DAG의 개념에 관해서는 &lt;a href=&quot;https://steemkr.com/kr/@sjchoi/adk-3-0-dag-directed-acyclic-graph&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 잘 정리된 글&lt;/a&gt;을 추천한다.&lt;/p&gt;&lt;p&gt;채굴을 끝낸 다음에는 나의 잔액을 &lt;code&gt;eth.getBalance(&quot;0x2f2ae...&quot;)&lt;/code&gt; 명령어로 다시 확인해보자. 나는 &lt;code&gt;250000000000000000000&lt;/code&gt;이 들어와 있었다... 떼부자다...&lt;/p&gt;
&lt;h1&gt;거래(트랜잭션) 만들기&lt;/h1&gt;
&lt;h2&gt;계좌 잠금 해제&lt;/h2&gt;
&lt;p&gt;이 계좌로 경제 활동을 하려면 계좌를 잠금 해제해야 하는데, 쓰려고 의도하지 않은 계좌로 행동을 해버리는 사고를 막기 위해 계좌 잠금의 기능이 있다고 한다. 아래와 같이 잠금 해제할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; personal.unlockAccount(&lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Unlock account &lt;span class=&quot;number&quot;&gt;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;Passphrase:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;나중에 작업이 끝나면 꼭 &lt;code&gt;personal.lockAccount(&quot;0x2f2ae...&quot;)&lt;/code&gt; 같은 명령어로 계좌를 다시 잠구도록 하자.&lt;/p&gt;
&lt;h2&gt;코인 보내기&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;이 과정을 진행하기 전, 위의 &lt;a href=&quot;#%EA%B3%84%EC%A2%8C-%EB%A7%8C%EB%93%A4%EA%B8%B0&quot;&gt;계좌 만들기 부분&lt;/a&gt;과 같은 방법으로 계좌를 하나 더 생성했다. 이 계좌의 주소는 &lt;code&gt;0xb0f3506ad5cb776bccb521a3da9ef6026394cbf9&lt;/code&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이제 트랜잭션을 만들 차례이다. &lt;code&gt;eth.sendTransaction&lt;/code&gt; 함수를 이용해서 트랜잭션을 만들어 보내자. 아래는 20 ether를 보내는 트랜잭션을 생성하는 예시이다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; eth.sendTransaction(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;... {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;...... from : &lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;...... to   : &lt;span class=&quot;string&quot;&gt;&quot;0xb0f3506ad5cb776bccb521a3da9ef6026394cbf9&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;...... value: web3.toWei(&lt;span class=&quot;number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&quot;ether&quot;&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;...... }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;... );&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;INFO [&lt;span class=&quot;number&quot;&gt;07&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;-26&lt;/span&gt;|&lt;span class=&quot;number&quot;&gt;17&lt;/span&gt;:&lt;span class=&quot;number&quot;&gt;10&lt;/span&gt;:&lt;span class=&quot;number&quot;&gt;42.321&lt;/span&gt;] Submitted transaction                    fullhash=&lt;span class=&quot;number&quot;&gt;0x03ab851182a5c906aee4cb6c0d0f16fedadd94837260be54deee4567b16918b1&lt;/span&gt; recipient=&lt;span class=&quot;number&quot;&gt;0xb0F3506Ad5cb776BcCb521A3Da9EF6026394CbF9&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&quot;0x03ab851182a5c906aee4cb6c0d0f16fedadd94837260be54deee4567b16918b1&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;여기서, &lt;code&gt;value&lt;/code&gt; 파라미터는 &lt;a href=&quot;http://ethdocs.org/en/latest/ether.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wei 단위&lt;/a&gt;이기 때문에, &lt;code&gt;web3.toWei&lt;/code&gt; 함수를 활용하여 20 ether를 wei 단위로 변환하였다. 또한 필요한 &lt;code&gt;gas&lt;/code&gt;의 양은 자동 책정된다.&lt;/p&gt;&lt;p&gt;결과값으로는 트랜잭션 해시 값이 나온다.&lt;/p&gt;
&lt;h2&gt;승인되지 않은 거래 확인하기&lt;/h2&gt;
&lt;p&gt;아직 다음 블록이 나오지 않아, 위에서 만든 거래는 확인받지 못했을 것이다. 이 사실을 확인해보자.&lt;/p&gt;
&lt;pre class=&quot;js&gt;&lt;span class=&quot; line&quot;=&quot;&quot;&gt;&amp;gt; txpool.content.pending&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;number&quot;&gt;0x2F2ae2B466B08758A29f74f5ecAE6d7114b2D562&lt;/span&gt;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    ... &lt;span class=&quot;comment&quot;&gt;// 이 글에 언급하지 않은, 테스트용 거래가 세 개가 앞서 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;: {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      blockHash: &lt;span class=&quot;string&quot;&gt;&quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      blockNumber: &lt;span class=&quot;literal&quot;&gt;null&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      &lt;span class=&quot;keyword&quot;&gt;from&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      gas: &lt;span class=&quot;string&quot;&gt;&quot;0x15f90&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      gasPrice: &lt;span class=&quot;string&quot;&gt;&quot;0x430e23400&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      hash: &lt;span class=&quot;string&quot;&gt;&quot;0x03ab851182a5c906aee4cb6c0d0f16fedadd94837260be54deee4567b16918b1&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      input: &lt;span class=&quot;string&quot;&gt;&quot;0x&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      nonce: &lt;span class=&quot;string&quot;&gt;&quot;0x3&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      r: &lt;span class=&quot;string&quot;&gt;&quot;0xb62d5de13a99b4caaf941999d5aa96bef276ff29f96b61025237fd20bbac740c&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      s: &lt;span class=&quot;string&quot;&gt;&quot;0x383b6c2e3ec23c8aa24785d291f41d40c55b13470ea6a61ccfb5d4ce35790ef4&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      to: &lt;span class=&quot;string&quot;&gt;&quot;0xb0f3506ad5cb776bccb521a3da9ef6026394cbf9&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      transactionIndex: &lt;span class=&quot;string&quot;&gt;&quot;0x0&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      v: &lt;span class=&quot;string&quot;&gt;&quot;0xe483020ed9ed1&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;      value: &lt;span class=&quot;string&quot;&gt;&quot;0x1158e460913d00000&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;역시 pending 거래 목록에 있음을 확인할 수 있다.&lt;/p&gt;
&lt;h2&gt;블록을 만들고 거래 확인하기&lt;/h2&gt;
&lt;p&gt;다시 채굴 명령어 &lt;code&gt;miner.start()&lt;/code&gt;로 하나 이상의 블록을 만든 이후 다시 &lt;code&gt;txpool.content.pending&lt;/code&gt;을 살펴보면 미승인된 거래가 없음을 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; txpool.content.pending&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;{}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;``&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;`m[, ]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;`&lt;/span&gt;eth.getTransaction&lt;span class=&quot;string&quot;&gt;` 명령어로 아까 우리의 트랜잭션을 확인해보자.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;``&lt;/span&gt;js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; eth.getTransaction(&lt;span class=&quot;string&quot;&gt;&quot;0x03ab851182a5c906aee4cb6c0d0f16fedadd94837260be54deee4567b16918b1&quot;&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  blockHash: &lt;span class=&quot;string&quot;&gt;&quot;0x0147af80c0ec9db07debcdc1006ce37cdec765672fca49aca0325b9267eed166&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  blockNumber: &lt;span class=&quot;number&quot;&gt;84&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword&quot;&gt;from&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&quot;0x2f2ae2b466b08758a29f74f5ecae6d7114b2d562&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  gas: &lt;span class=&quot;number&quot;&gt;90000&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  gasPrice: &lt;span class=&quot;number&quot;&gt;18000000000&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  hash: &lt;span class=&quot;string&quot;&gt;&quot;0x03ab851182a5c906aee4cb6c0d0f16fedadd94837260be54deee4567b16918b1&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  input: &lt;span class=&quot;string&quot;&gt;&quot;0x&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  nonce: &lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  r: &lt;span class=&quot;string&quot;&gt;&quot;0xb62d5de13a99b4caaf941999d5aa96bef276ff29f96b61025237fd20bbac740c&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  s: &lt;span class=&quot;string&quot;&gt;&quot;0x383b6c2e3ec23c8aa24785d291f41d40c55b13470ea6a61ccfb5d4ce35790ef4&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  to: &lt;span class=&quot;string&quot;&gt;&quot;0xb0f3506ad5cb776bccb521a3da9ef6026394cbf9&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  transactionIndex: &lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  v: &lt;span class=&quot;string&quot;&gt;&quot;0xe483020ed9ed1&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;  value: &lt;span class=&quot;number&quot;&gt;20000000000000000000&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;아주 잘 승인된 듯하다.&lt;/p&gt;&lt;p&gt;&lt;code&gt;eth.getBalance&lt;/code&gt; 명령어로 돈을 받은 계좌의 잔액을 확인해보면 적절하게 변동하였음을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; eth.getBalance(&lt;span class=&quot;string&quot;&gt;&quot;0xb0f3506ad5cb776bccb521a3da9ef6026394cbf9&quot;&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;number&quot;&gt;23000000000000000000&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;//이 글에서 언급하지 않은 세 번의 거래로 3 ether가 더 들어 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 개인 이더리움 네트워크로 간단한 이더리움 거래를 해 보았다.&lt;/p&gt;
&lt;h1&gt;참고한 글&lt;/h1&gt;
&lt;p&gt;이번에도 많은 다른 글에서 도움을 받았다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ethereum/go-ethereum/blob/master/console/bridge.go&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/ethereum/go-ethereum/blob/master/console/bridge.go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://steemit.com/kr/@sangphilkim/geth&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://steemit.com/kr/@sangphilkim/geth&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;이 글에서 가장 큰 도움을 받았다.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://crosswave.net/?p=2785&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://crosswave.net/?p=2785&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethereum.stackexchange.com/questions/12181/how-do-you-configure-geth-to-use-coinbase&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ethereum.stackexchange.com/questions/12181/how-do-you-configure-geth-to-use-coinbase&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>다른 분야 공부/블록체인</category>
      <category>공부</category>
      <category>블록체인</category>
      <category>암호화폐</category>
      <category>이더리움</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/12</guid>
      <comments>https://yuoa.tistory.com/entry/%EC%9D%B4%EB%8D%94%EB%A6%AC%EC%9B%80-%EA%B0%9C%EC%9D%B8-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8D%A8%EB%B3%B4%EA%B8%B0#entry12comment</comments>
      <pubDate>Thu, 10 Jan 2019 20:58:47 +0900</pubDate>
    </item>
    <item>
      <title>이더리움 Genesis 파일 만들고 개인 네트워크 구동하기</title>
      <link>https://yuoa.tistory.com/entry/%EC%9D%B4%EB%8D%94%EB%A6%AC%EC%9B%80-Genesis-%ED%8C%8C%EC%9D%BC-%EB%A7%8C%EB%93%A4%EA%B3%A0-%EA%B0%9C%EC%9D%B8-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B5%AC%EB%8F%99%ED%95%98%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;i&gt;이 글은 Hexo 기반의 블로그에서 옮겨온 글이며, 원본 글은 2018년 7월 25일에 작성되었다.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;이번 학교의 DPNM 연구실에서 여름 방학에 블록체인 관련 공부를 하고 있는데, 간단한 이더리움 활용 과제가 나와 수행하던 도중 난데없이 사설 네트워크와 &quot;genesis&quot;라는 단어가 나와 그에 대해 간단히 정리해본다.&lt;/p&gt;
&lt;p&gt;아래의 글은 이미 서버에 이더리움이 설치되어 &lt;code&gt;geth&lt;/code&gt; 명령어를 실행할 수 있다고 가정하고 작성하였다. 작성 당시 &lt;code&gt;geth&lt;/code&gt; 버전은 &lt;code&gt;1.8.12-stable&lt;/code&gt;이다.&lt;/p&gt;&lt;h1&gt;이더리움 사설 네트워크와 Genesis 파일&lt;/h1&gt;&lt;p&gt;이더리움은 사설 이더리움 네트워크를 만들 수 있게 되어 있는데, genesis 파일이란 이 개인 네트워크의 초기 설정이라 할 수 있다. &quot;the genesis&quot;는 &lt;b&gt;발생, 창시&lt;/b&gt; 등의 뜻이 있다고 한다. 이더리움뿐 아니라, 다른 암호 화폐에서도 최초의 블록을 &quot;Genesis block&quot; 이라고 한다고 한다. 뭐... 그런 느낌이다. Genesis의 표기에 대해서는 첫 글자가 대문자이면 좀 더 멋져 보이므로, 내 맘대로 첫 글자를 대문자로 하기로 한다.&lt;/p&gt;&lt;h1&gt;Genesis 파일 구조&lt;/h1&gt;&lt;p&gt;Genesis 파일은 JSON 형식으로 네트워크 설정을 저장하고, 이 파일을 먼저 만들어야 나만의 이더리움 네트워크를 가동할 수 있다. 일단 그 태를 보면 아래와 같다.&lt;/p&gt;&lt;pre class=&quot;json&quot;&gt;{
    &quot;config&quot; : {
        &quot;chainId&quot;        : 0,
        &quot;homesteadBlock&quot; : 0,
        &quot;eip155Block&quot;    : 0,
        &quot;eip158Block&quot;    : 0
    },
    &quot;alloc&quot;      : {},
    &quot;coinbase&quot;   : &quot;0x0000000000000000000000000000000000000000&quot;,
    &quot;difficulty&quot; : &quot;0x10000&quot;,
    &quot;extraData&quot;  : &quot;&quot;,
    &quot;gasLimit&quot;   : &quot;0xffffff&quot;,
    &quot;nonce&quot;      : &quot;0x0000000000000000&quot;,
    &quot;mixhash&quot;    : &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
    &quot;parentHash&quot; : &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
    &quot;timestamp&quot;  : &quot;0x00000000&quot;
}&lt;/pre&gt;
&lt;p&gt;이제 위에서부터 하나하나 말해보자면...&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;code&gt;config&lt;/code&gt;&lt;br /&gt;새로 만들 개인 블록체인 네트워크의 설정을 담당하는 오브젝트이다. 이 오브젝트 이외의 설정값들은 대망의 &lt;b&gt;첫 블록&lt;/b&gt;에 관한 것이다.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;code&gt;chainId&lt;/code&gt; : 현재 블록체인의 ID이다. &lt;a href=&quot;https://en.wikipedia.org/wiki/Replay_attack&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;리플레이 공격&lt;/a&gt;을 막기 위해 사용된다. 그저 이더리움 네트워크를 공부할 때는 &lt;b&gt;&lt;a href=&quot;https://ethereum.stackexchange.com/questions/17051/how-to-select-a-network-id-or-is-there-a-list-of-network-ids/17101#17101&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;예약된 ID&lt;/a&gt;가 아닌 것으로 아무렇게나 적어도 괜찮다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;homesteadBlock&lt;/code&gt; : 이더리움은 네트워크의 발전 단계에 따라 &lt;a href=&quot;https://en.wikipedia.org/wiki/Ethereum#Milestones&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;버전을 미리 구상해 놓았다.&lt;/a&gt; 그 각 단계에 올림픽, 프론티어, 홈스테드 등 여러가지 코드 네임을 붙여놓았는데, 그 중 처음으로 &quot;안정&quot; 단계에 해당하는 단계가 바로 &lt;b&gt;홈스테드&lt;/b&gt; 이다. 그 홈스테드 단계가 시작되는 블록의 ID를 적으면 된다. 그저 이더리움 네트워크를 공부할 때는 처음부터 홈스테드 단계로 들어가서 살펴보게 되므로, &lt;b&gt;&lt;code&gt;0&lt;/code&gt;이라고 적으면 된다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;eip155Block&lt;/code&gt; : EIP는 &lt;i&gt;Ethereum Improvement Proposal&lt;/i&gt; 의 약자로, 이더리움 네트워크를 개선하는 여러 제안들을 말한다. 그 중 &lt;a href=&quot;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;리플레이 공격 방어에 관한 155번째 제안&lt;/a&gt;이 적용이 시작되는 블록 ID를 적으면 된다. 그저 이더리움 네트워크를 공부할 때는 처음부터 이 보안을 적용할 것이므로, &lt;b&gt;&lt;code&gt;0&lt;/code&gt;이라고 적으면 된다.&lt;/b&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;code&gt;alloc&lt;/code&gt; : 네트워크 초기에 특정한 계좌에 특정한 액수의 코인을 지급할 수 있다. 암호 화폐의 초기 부흥을 위해서 화폐를 사전 판매하는 경우가 있는데, 이 때 쓰일 수 있다. 예를 들면, 아래와 같다.&lt;br /&gt;&lt;pre class=&quot;json&quot;&gt;&quot;alloc&quot; : {
    &quot;19yadv8h2ebalnlrqszzlph54lci6d6pdvht5abi&quot; : { &quot;balance&quot; : 10000 },
    &quot;haq72tf9ldqzyavp3slocx55jb00hvldm4ai9iln&quot; : { &quot;balance&quot; : 10000 }
}&lt;/pre&gt;&lt;p&gt;이 경우 저 두 계좌로 각각 10,000 코인을 지급한 것이 된다. 그저 이더리움 네트워크를 공부할 때는 &lt;b&gt;&lt;code&gt;{}&lt;/code&gt;로 비워놔도 좋다.&lt;/b&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;coinbase&lt;/code&gt; : 지금 설정하고 있는 이 첫 블록의 채굴 보상이 돌아갈 계좌 주소이다. 이더리움에서 주소는 160비트로 이루어져 있다. 그저 이더리움 네트워크를 공부할 때는 &lt;b&gt;&lt;code&gt;0&lt;/code&gt;으로 해놔도 좋다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;difficulty&lt;/code&gt; : 첫 블록의 논스 값 범위의 난이도이다. 값이 낮을 수록 채굴이 쉬워진다. 첫 블록 이후에는 이전 블록의 &lt;code&gt;difficulty&lt;/code&gt;와 &lt;code&gt;timestamp&lt;/code&gt;를 참고하여 이더리움 소프트웨어가 자동으로 &lt;code&gt;difficulty&lt;/code&gt;를 계산할 것이다. 그저 이더리움 네트워크를 공부하는 사람은 거대한 채굴 능력이 없기 때문에, 난이도를 낮게 설정하여 쉽게 채굴하도록 하는 것이 좋으므로, &lt;b&gt;&lt;code&gt;0x10000&lt;/code&gt; 정도로 설정해놓는 것이 좋다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;extraData&lt;/code&gt; : 어떠한 데이터를 블록체인에 영구적으로 보존하기 위해 존재하는 32비트의 빈 공간이다. &lt;b&gt;보통 &lt;code&gt;&quot;&quot;&lt;/code&gt;로 비워둔다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;gasLimit&lt;/code&gt; : 이더리움 거래 수수료 단위를 &lt;i&gt;Gas&lt;/i&gt; 라 하는데, 이더리움 ETH 자체는 시장 가치의 변동폭이 매우 크므로, 그 대신 안정적으로 트랜잭션 비용을 지불하기 위해 만들어진 단위이다. 거래 별 거래 수수료는 해당 거래를 처리하기 위해 필요한 컴퓨터 연산의 정도로 책정된다. 따라서 한 블럭의 전체 거래 수수료 합이 매우 크다는 건 한 블럭을 처리하는데 엄청난 연산이 필요하다는 말이 된다. 그래서 한 블럭에 포함된 거래 수수료에 한도를 두어 한 블럭을 연산하는데 시간이 많이 걸리지 않도록 한다. 그저 이더리움 네트워크를 공부하는 사람은 굳이 여기에 제한을 둘 필요가 없으므로, &lt;b&gt;&lt;code&gt;0xffffff&lt;/code&gt;로 설정해놓을 수 있다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;nonce&lt;/code&gt; : 64비트의 상수으로, &lt;code&gt;mixhash&lt;/code&gt;와 합쳐져서 작업을 증명하는 데 사용된다. 블록 채굴자들은 이 &lt;code&gt;nonce&lt;/code&gt; 값을 증가시켜가며 정답 범위에 들어가는 &lt;code&gt;nonce&lt;/code&gt;값을 순차적으로 찾아나설 것이다. 그저 이더리움 네트워크를 공부할 때는 &lt;b&gt;&lt;code&gt;0&lt;/code&gt;으로 설정해놓아도 좋다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;mixhash&lt;/code&gt; : PoW의 핵심이 되는 값 중 하나로, 256비트의 해시값이며 &lt;code&gt;nonce&lt;/code&gt;와 결합하여 작업을 증명하게 된다. 그저 이더리움 네트워크를 공부할 때는 그냥 간편히 &lt;b&gt;&lt;code&gt;0&lt;/code&gt;으로 설정해놓으면 된다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;parentHash&lt;/code&gt; : 이전 블록의 해시값이다. 이전 블록의 &lt;code&gt;mixhash&lt;/code&gt;가 아니다. 이전 블록 전체에 관한 해시값이다. 첫 블록(Genesis block)은 이전 블록이란 게 없으므로, (parent...가 없으므로?) &lt;b&gt;&lt;code&gt;0&lt;/code&gt;으로 설정해놓으면 된다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt; : 블록이 받아들여진 시간을 &lt;a href=&quot;https://www.unixtimestamp.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;유닉스 시각&lt;/a&gt;으로 나타낸다. 이 값은 블록의 순서를 검증할 때도 사용된다. 그저 이더리움 네트워크를 공부하는 사람은 크게 신경쓸 것 없이 &lt;b&gt;&lt;code&gt;0&lt;/code&gt;으로 설정해놓으면 된다.&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;위의 예시에 적히지 않은 설정 파라미터도 있고 생략가능한 파라미터도 있지만, 그저 이더리움 네트워크를 공부하는 입장에서 적당하게 적어놓았다.&lt;/div&gt;&lt;h1&gt;Genesis 파일 만들고 개인 네트워크 시작하기&lt;br /&gt;&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;먼저, 작업 디렉토리를 만들었다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;~ $ mkdir tessup &lt;span class=&quot;comment&quot;&gt;#테스트 서버 (...)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;~ $ &lt;span class=&quot;built_in&quot;&gt;cd&lt;/span&gt; tessup&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;위의 내용을 참고하여 아래의 내용으로 &lt;code&gt;genesis.json&lt;/code&gt; 파일을 만들어 작업 디렉토리 안에 저장했다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;span class=&quot;line&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;config&quot;&lt;/span&gt; : {&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;attr&quot;&gt;&quot;chainId&quot;&lt;/span&gt;        : &lt;span class=&quot;number&quot;&gt;2010010611011415&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;attr&quot;&gt;&quot;homesteadBlock&quot;&lt;/span&gt; : &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;attr&quot;&gt;&quot;eip155Block&quot;&lt;/span&gt;    : &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;        &lt;span class=&quot;attr&quot;&gt;&quot;eip158Block&quot;&lt;/span&gt;    : &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    },&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;alloc&quot;&lt;/span&gt;      : {},&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;coinbase&quot;&lt;/span&gt;   : &lt;span class=&quot;string&quot;&gt;&quot;0x0000000000000000000000000000000000000000&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;difficulty&quot;&lt;/span&gt; : &lt;span class=&quot;string&quot;&gt;&quot;0x20000&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;extraData&quot;&lt;/span&gt;  : &lt;span class=&quot;string&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;gasLimit&quot;&lt;/span&gt;   : &lt;span class=&quot;string&quot;&gt;&quot;0x300000&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;nonce&quot;&lt;/span&gt;      : &lt;span class=&quot;string&quot;&gt;&quot;0x0000000000000000&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;mixhash&quot;&lt;/span&gt;    : &lt;span class=&quot;string&quot;&gt;&quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;parentHash&quot;&lt;/span&gt; : &lt;span class=&quot;string&quot;&gt;&quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;attr&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;  : &lt;span class=&quot;string&quot;&gt;&quot;0x00000000&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;작업 디렉토리 안에 블록이 저장될 디렉토리로 &lt;code&gt;data&lt;/code&gt; 디렉토리를 생성했다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;~/tessup $ mkdir data&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;bootnode&lt;/code&gt; 명령어를 사용하여 부트 노드를 시작했다. &lt;code&gt;bootnode&lt;/code&gt;는 부트스트랩 노드를 구현한 소프트웨어이다. 여기서 부트스트랩 노드는 일종의 시동 노드로, 다른 노드들의 목록을 저장하여 네트워크를 유지하는 노드를 말한다.&lt;/p&gt;
&lt;pre class=&quot;sh&gt;&lt;span class=&quot; line&quot;=&quot;&quot;&gt;~/tessup $ bootnode -genkey=tessup.key&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;~/tessup $ bootnode -nodekey=tessup.key&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;개인적으로는 위 마지막 명령을 백그라운드에서 관리하기 위해 아래와 같이 &lt;code&gt;pm2&lt;/code&gt;라는 패키지를 활용했다. &lt;code&gt;pm2&lt;/code&gt;는 &lt;a href=&quot;https://docs.npmjs.com/getting-started/installing-node#install-npm--manage-npm-versions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NPM&lt;/a&gt;이 설치되어 있는 상황에서 &lt;code&gt;sudo npm i pm2 -g&lt;/code&gt; 명령을 통해 설치할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;~/tessup $ pm2 start bootnode -- -nodekey=tessup.key&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;위 명령을 다 실행하면 내 부트스트랩 노드의 주소가 콘솔에 (&lt;code&gt;pm2&lt;/code&gt;의 경우, &lt;code&gt;pm2 log bootnode&lt;/code&gt; 명령어를 입력하면) 나타남을 볼 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;geth&lt;/code&gt; 명령어를 사용하여 네트워크에 시동을 건다.&lt;/p&gt;
&lt;pre class=&quot;sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;~/tessup $ geth --datadir=&lt;span class=&quot;string&quot;&gt;&quot;./data/&quot;&lt;/span&gt; init genesis.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;~/tessup $ geth --bootnodes=&lt;span class=&quot;string&quot;&gt;&quot;(enode://로 시작하는 노드 주소)&quot;&lt;/span&gt; --datadir=&lt;span class=&quot;string&quot;&gt;&quot;./data/&quot;&lt;/span&gt; --networkid=(genesis.json 파일에 적었던 chainId) console&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;이 과정이 성공적으로 완료되었다면 &lt;strong&gt;Geth Javascript Console&lt;/strong&gt;이 나타남을 볼 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;노드 정보를 확인해본다.&lt;br /&gt;
일이 다 끝나면 아래와 같이 자바스크립트 콘솔에 입력하여 내가 실행 중인 노드 정보를 알아볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;js&quot;&gt;&lt;span class=&quot;line&quot;&gt;&amp;gt; admin.nodeInfo&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;여기서 내가 설정한 Genesis 파일과 동일하게 돌아가는지, 나의 부트스트랩 노드와 연결했는지 확인해보자.&lt;/p&gt;
&lt;p&gt;확인을 끝냈다면, 이제부터 나만의 네트워크를 즐겨보자!&lt;/p&gt;
&lt;p&gt;나의 이더리움 네트워크에서 해볼 수 있는 예시 활동은 &lt;a href=&quot;http:///entry/이더리움-개인-네트워크-써보기&quot; target=&quot;_top&quot; class=&quot;tx-link&quot;&gt;이 글&lt;/a&gt;에 적어놓았다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;h1&gt;문제 해결&lt;/h1&gt;&lt;h2&gt;유효하지 않은 IP 주소 문제&lt;/h2&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;Fatal: Error starting protocol stack: bad bootstrap/fallback node &quot;enode://...@[::]:30301&quot; (invalid IP (multicast/unspecified))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;이 문제는 bootnode의 output을 그대로 가져다 붙여서 &lt;code&gt;geth&lt;/code&gt;를 실행했을 때 나타나는 문제인데, bootnode에서 제공하는 주소 끝의 IP (0.0.0.0 혹은 ::)는 받는 IP의 종류로, 외부에서 들어오는 접속을 IP 가리지 않고 받는다는 뜻이다. 여기서 의도하는 것은 &lt;strong&gt;어디로 접속해야 할 지&lt;/strong&gt;가 중요하므로, 0.0.0.0 혹은 :: 대신 아까 &lt;code&gt;bootnode&lt;/code&gt;를 실행한 서버의 IP, 혹여 같은 서버라면 &lt;code&gt;127.0.0.1&lt;/code&gt;을 적어주자. 30301 포트가 막혀 있다면 꼭 포트를 열어주자.&lt;/p&gt;&lt;div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;계속 뭔가가 나오는 문제&lt;/h2&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;INFO [07-26|12:57:49.005] Imported new state entries               count=1152 elapsed=4.020ms   processed=99887672 pending=21784 retry=2   duplicate=0 unexpected=192&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;line&quot;&gt;INFO [07-26|12:57:49.400] Imported new state entries               count=953  elapsed=7.046ms   processed=99888625 pending=21836 retry=0   duplicate=0 unexpected=192&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;아무것도 하지 않았는데 무언가 계속 통신이 이루어지는 듯한, 위와 같은 로그가 1초에 한 번 이상의 빈도로 반복적으로 나타난다면, 혹시 위의 &lt;code&gt;geth&lt;/code&gt; 실행 과정에서 지정한 &lt;code&gt;--datadir&lt;/code&gt; 옵션이 잘못되어있을 수 있다. 꼭 새로운 전용 작업 디렉토리와 새로운 데이터 디렉토리를 만들고, 그 디렉토리를 그대로 적어주자.&lt;/p&gt;&lt;h1&gt;참고한 글&lt;br /&gt;&lt;/h1&gt;&lt;p&gt;다들 필력이 대단하다. 나는 쨉도 안 된다.&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/0mkara/b953cc2585b18ee098cd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gist.github.com/0mkara/b953cc2585b18ee098cd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethereum.stackexchange.com/questions/15682/the-meaning-specification-of-config-in-genesis-json&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ethereum.stackexchange.com/questions/15682/the-meaning-specification-of-config-in-genesis-json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/HomoEfficio/warehouse/blob/master/etc/Ethereum-dApp-%EA%B0%9C%EB%B0%9C.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/HomoEfficio/warehouse/blob/master/etc/Ethereum-dApp-개발.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-158.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/ethereum/EIPs/blob/master/EIPS/eip-158.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ethereum/go-ethereum/issues/14831&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/ethereum/go-ethereum/issues/14831&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/kr/@cryptoboy516/blockchain-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://steemit.com/kr/@cryptoboy516/blockchain-1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/kr/@icoreport/icoreport-gas-ether-gas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://steemit.com/kr/@icoreport/icoreport-gas-ether-gas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/kr-newbie/@ico-altcoin/ico-gas-gwei-gas-limit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://steemit.com/kr-newbie/@ico-altcoin/ico-gas-gwei-gas-limit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethereum.stackexchange.com/questions/2376/what-does-each-genesis-json-parameter-mean&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ethereum.stackexchange.com/questions/2376/what-does-each-genesis-json-parameter-mean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://steemit.com/coinkorea/@etainclub/smart-contract-8-2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://steemit.com/coinkorea/@etainclub/smart-contract-8-2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ethereum/go-ethereum/wiki/Setting-up-private-network-or-local-cluster&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/ethereum/go-ethereum/wiki/Setting-up-private-network-or-local-cluster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>다른 분야 공부/블록체인</category>
      <category>공부</category>
      <category>블록체인</category>
      <category>암호화폐</category>
      <category>이더리움</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/11</guid>
      <comments>https://yuoa.tistory.com/entry/%EC%9D%B4%EB%8D%94%EB%A6%AC%EC%9B%80-Genesis-%ED%8C%8C%EC%9D%BC-%EB%A7%8C%EB%93%A4%EA%B3%A0-%EA%B0%9C%EC%9D%B8-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B5%AC%EB%8F%99%ED%95%98%EA%B8%B0#entry11comment</comments>
      <pubDate>Thu, 10 Jan 2019 20:20:43 +0900</pubDate>
    </item>
    <item>
      <title>30년간 미뤄온 블로그 개발 계획</title>
      <link>https://yuoa.tistory.com/entry/30%EB%85%84%EA%B0%84-%EB%AF%B8%EB%A4%84%EC%98%A8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EA%B0%9C%EB%B0%9C-%EA%B3%84%ED%9A%8D</link>
      <description>&lt;p&gt;&lt;em&gt;이 글은 구 블로그에서 옮겨온 글이며, 원본 글은 2018년 7월 25일에 작성하였다.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hexo를 이용해서 블로그를 만든 게 올해 초, 3월이었다. 지금은 그로부터 4개월의 시간이 지났고, 블로그는 초기화시켰으며, &lt;strong&gt;아무런 진전도 없다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;서버 관리나 블로그 개발 등 일련의 작업이 &lt;strong&gt;[dman 개발] &amp;gt; [Redirection 서버 구축] &amp;gt; [지난 학기 프로젝트를 공개용으로 변경 및 오류 수정] &amp;gt; [블로그 개발] &amp;gt; [기타 각종 페이지 제작]&lt;/strong&gt; 순으로 가야 하는데, dman 개발이 서버 이전이나 연구 참여 등으로 계속 지연되고 있는지라 이게 제대로 진행이 안되고 있던 것이다.&lt;/p&gt;
&lt;p&gt;그래도, 앞으로 개발해야 하는 블로그 기능 등을 상기시킬 겸 다시 한 번 계획을 적어보아야겠다는 생각이 들어서 글을 써 본다. 지금은 지워진, 3월 23일에 썼던 블로그 개발 계획 글에서 기반하였다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;모바일 레이아웃 고치기&lt;/li&gt;
&lt;li&gt;404 페이지 제대로 연결시키기&lt;/li&gt;
&lt;li&gt;포트폴리오 페이지 만들기 (&amp;quot;about&amp;quot;)&lt;/li&gt;
&lt;li&gt;태그(카테고리) 모아보기 페이지 만들기&lt;/li&gt;
&lt;li&gt;`meta[name=theme-color]` 부분 고치기 (sass와 pug의 통합적 관리)&lt;/li&gt;
&lt;li&gt;작은 화면에서의 레이아웃 고치기&lt;/li&gt;
&lt;li&gt;검색 기능 추가핟기&lt;/li&gt;
&lt;li&gt;구글 번역으로 번역 기능 추가하기&lt;/li&gt;
&lt;li&gt;포스트 페이지에서도 사이드바를 작게라도 표시해주기&lt;/li&gt;
&lt;li&gt;사이드바에 트위터 추가하기&lt;/li&gt;
&lt;li&gt;페이지 목차 (TOC) 기능 추가하기&lt;/li&gt;
&lt;li&gt;HTML 표준 및 웹접근성 확인하기&lt;/li&gt;
&lt;li&gt;단락 접기 기능 추가하기&lt;/li&gt;
&lt;li&gt;각 페이지에서 태그 목록 띄워주기&lt;/li&gt;
&lt;li&gt;긴 코드 X축 스크롤 시 코드 종류 텍스트가 고정되지 않는 문제 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;현재 내 블로그의 레이아웃/테마가 기반하는 테마인 &amp;quot;Prontera&amp;quot; 테마의 초기 개발자에게 개선사항 다 개선시켜서 커밋 7월까지 할 예정이라고 말을 해놨는데 아마 못지킬듯하다.&lt;/p&gt;
&lt;p&gt;부디 8월까지 모두 완성할 수 있길... &lt;/p&gt;
&lt;h3&gt;18년 8월 10일 기록&lt;/h3&gt;
&lt;p&gt;아직도 아무런 진전도 없다. 이게 다 학과 홈페이지 개발 프로젝트 때문이다.&lt;/p&gt;
&lt;h3&gt;18년 10월 7일 기록&lt;/h3&gt;
&lt;p&gt;전체적으로 살짝 리팩토링했다. 이제 남은 건 위에 기술한 할 일 목록들을 모두 처리하고, scss를 리팩토링하는 것이다.&lt;/p&gt;</description>
      <category>기타/홈페이지 관리</category>
      <category>블로그</category>
      <category>서버</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/10</guid>
      <comments>https://yuoa.tistory.com/entry/30%EB%85%84%EA%B0%84-%EB%AF%B8%EB%A4%84%EC%98%A8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EA%B0%9C%EB%B0%9C-%EA%B3%84%ED%9A%8D#entry10comment</comments>
      <pubDate>Thu, 10 Jan 2019 19:51:51 +0900</pubDate>
    </item>
    <item>
      <title>2018년 여름 서버 구획 정리</title>
      <link>https://yuoa.tistory.com/entry/2018%EB%85%84-%EC%97%AC%EB%A6%84-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%9A%8D-%EC%A0%95%EB%A6%AC</link>
      <description>&lt;p&gt;&lt;em&gt;이 글은 구 블로그에서 옮겨온 글이며, 원본 글은 2018년 7월 25일에 작성되었다.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2016년부터 서버 정리와 블로그 제작 등을 조금씩 아주 조금씩 진전시키고 있었는데, 이번 여름에 몰아서 일을 처리하기로 했다. (참 오래도 해왔다...) 그 김에 이때까지 해온 일들도 미래의 나를 위해 정리를 해보기로 했다. 나를 위한 정리이기에 이 글은 다른 사람이 가상 서버 서비스를 선택할 때 그다지 큰 도움은 안 되리라 생각한다.&lt;/p&gt;
&lt;p&gt;제일 먼저 했던 것은 서버 서비스 선정 및 구획 정리였다. 세상에는 정말 많은 가상 서버 서비스가 있었는데, 그 중 일부를 사용해보았고 최종적으로는 &lt;strong&gt;TOAST Cloud&lt;/strong&gt;에 정착하였다.&lt;/p&gt;
&lt;h2&gt;계획한 서버 구조 (처음)&lt;/h2&gt;
&lt;p&gt;아무래도 큰 하나의 거대 서버에 여러 서비스를 몰아 넣는 일은 좋아하지 않는지라 (이 습성은 나중에 AWS에서 환경을 구성할 때 매우 큰 도움이 되었다), 적당히 서버의 역할을 쪼개서 구상하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;서버 계획 구조도&quot; style=&quot;width: 530px; height: 397px;&quot; width=&quot;530&quot; height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99B50A335C371B8021?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99B50A335C371B8021?original&quot; data-alt=&quot;서버 계획 구조도&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B50A335C371B8021&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B50A335C371B8021&quot; alt=&quot;서버 계획 구조도&quot; style=&quot;width: 530px; height: 397px;&quot; width=&quot;530&quot; height=&quot;397&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서버 계획 구조도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;개발 서버&lt;/strong&gt;&lt;br&gt;나는 개인적으로 물리적으로 소장한, 서버로 사용하는 장치가 없었으므로 언제 어디서나 접속가능하고 상시 켜져있는 개발 서버가 필요했다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;웹 서버&lt;/strong&gt;&lt;br&gt;정적으로 파일을 서비스하는 서버가 필요했다. 이때까지만 해도 Github Pages를 이용할 생각을 못 하고 있었다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;앱 서버&lt;/strong&gt;&lt;br&gt;내가 제작한 서버사이드 애플리케이션과 API를 항상 프리뷰 형태로 제공할 계획인데, 이 백엔드 서비스를 돌리는 서버가 필요했다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;노드 밸런싱 서버&lt;/strong&gt;&lt;br&gt;노드 밸런싱에 관심을 가지고 있었고, 혹시나 모르는 DDoS 상황에 대비할 필요가 있었다. 아주 오래 전 코노하에서의 안 좋은 추억이 있기도 하고, 항상 모든 상황에 대한 준비를 하고싶었기에...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;세상에는 좋고 편한 서비스가 많지만 처음 서버 구조를 생각할 때까지만 해도 나는 그것들을 이용할 생각이 없었다. 그렇기에 이런 돈낭비가 심한 서버 구조를 구상하게 된 것이다. 여하튼, 이렇게 꾸밀 생각으로 난 각 가상 서버 제공업자들을 떠돌아다니기 시작했다.&lt;/p&gt;
&lt;h2&gt;가상 서버 서비스계의 떠돌이&lt;/h2&gt;
&lt;h3&gt;1. Linode&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;Linode 로고&quot; width=&quot;630&quot; height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9993A33A5C371B8030?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9993A33A5C371B8030?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9993A33A5C371B8030&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9993A33A5C371B8030&quot; alt=&quot;Linode 로고&quot; width=&quot;630&quot; height=&quot;297&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;가장 먼저 이용했던 곳은 Linode였다. 서버 대 개편을 시작하기 전 이용하고 있던 곳이 리노드였기에, 바로 리노드에서 시작하려 했으나...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ping이 너무 높았다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;내가 Linode를 이용할 때까지만 해도 도쿄 시설이 없었기 때문에, 런던 지역의 인스턴스를 이용했고, 반응 속도가 너무나도 느렸다. 그래서 빠르게 Vultr로 넘어가보게 되었다.&lt;/p&gt;
&lt;h3&gt;2. Vultr&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;Vultr 로고&quot; style=&quot;width: 530px; height: 186px;&quot; width=&quot;530&quot; height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/992B233F5C371B8022?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/992B233F5C371B8022?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992B233F5C371B8022&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992B233F5C371B8022&quot; alt=&quot;Vultr 로고&quot; style=&quot;width: 530px; height: 186px;&quot; width=&quot;530&quot; height=&quot;186&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;정말 좋았다. Vultr은 정말 쉽게 모든 것을 할 수 있게 해주는 최고의 서비스였다. 가격도 좋았으며, ping은 들쑥날쑥했지만 가장 좋지 않을 때도 나름 쓸만한 ping을 내 주었다. 서버 관리 패널도 최신식이었고, DNS 서비스까지 제공해주었다.&lt;/p&gt;
&lt;p&gt;내부 네트워크의 경우 수동 &lt;code&gt;systemd-networkd&lt;/code&gt;로 설정해주어야 한다는게 귀찮기는 했지만, 한 번 설정하면 정말 빠르고 탄탄한 백본망을 제공하기에 만족스러웠다.&lt;/p&gt;
&lt;p&gt;Vultr의 서비스를 이용하면서 리눅스 시스템에 대해서 많이 배울 수 있었는데, 서버 디스플레이를 VNC로 제공해주어 네트워크 설정이나 SSH 설정을 잘못해서 접속이 안되게 망쳐놨을 때도 VNC로 들어가서 복구를 스스로 할 수 있었기 때문이다.&lt;/p&gt;
&lt;p&gt;하지만 1년 정도 이후 Azure로 옮겨가게 되는데, 좀 더 체계적이고, 더욱 직접 관리를 하고 싶고, (Vultr도 매우 대형 서비스이지만) 더욱 대형 서비스를 체험해보고 싶었기 때문이었다.&lt;/p&gt;
&lt;h3&gt;3. Microsoft Azure&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;Azure 로고&quot; style=&quot;width: 582px; height: 133px;&quot; width=&quot;582&quot; height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99F010335C371B801E?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99F010335C371B801E?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F010335C371B801E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F010335C371B801E&quot; alt=&quot;Azure 로고&quot; style=&quot;width: 582px; height: 133px;&quot; width=&quot;582&quot; height=&quot;133&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;정말 복잡했다. 처음으로 써 본 대형 서비스라서가 아니었다. 마이크로소프트 특유의 번역과 특유의 느낌이 나는 서비스명 선정 등이 내가 이해하기에 너무 어려웠다. 물론 나중에 차츰 적응이 되긴 했지만, 와닿지는 않았다. 서비스 관리 패널에서의 원인을 알 수 없는 오류도 많이 났다.&lt;/p&gt;
&lt;p&gt;서비스 자체의 질은 나쁘지 않았고, Vultr보다 성능이 좋았다. &amp;#39;한국 Azure 사용자 모임&amp;#39;이라는 페이스북 그룹도 존재하여, 가끔 도움을 구할 수 있다.&lt;/p&gt;
&lt;p&gt;그래도, 상기한 단점들로 결국 GCP(Google Cloud Platform)로 자리를 옮겨가게 된다.&lt;/p&gt;
&lt;h3&gt;4. Google Cloud Platform&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;GCP 로고&quot; style=&quot;width: 500px; height: 283px;&quot; width=&quot;500&quot; height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/997B093A5C371B8031?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/997B093A5C371B8031?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997B093A5C371B8031&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997B093A5C371B8031&quot; alt=&quot;GCP 로고&quot; style=&quot;width: 500px; height: 283px;&quot; width=&quot;500&quot; height=&quot;283&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Azure와는 확실히 다르게 메뉴를 이해하기 쉬웠다. 이건 구글이 잘 했다기 보다는 Azure가 너무 나에게 어려웠기 때문이다.&lt;/p&gt;
&lt;p&gt;여하튼, 성능도 괜찮고 통합/연계 서비스 (G-Suite 등)도 매력적인 상품이었으나, 다소 비용이 비쌌다. 다른 곳보다 월등히 비싸지는 않지만, 내 개인적인 기준과 판단으로 비용이 많다고 생각되어 3개월 정도 후 AWS로 옮기게 되었다. 자세한 비용 비교는 기억나지 않으므로 생략한다. 내가 기억이 난다면 나중에 이 글을 업데이트 하길...&lt;/p&gt;
&lt;h3&gt;5. Amazon Web Services&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; alt=&quot;AWS 로고&quot; style=&quot;width: 500px; height: 182px;&quot; width=&quot;500&quot; height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99B0E5355C371B801A?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99B0E5355C371B801A?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B0E5355C371B801A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B0E5355C371B801A&quot; alt=&quot;AWS 로고&quot; style=&quot;width: 500px; height: 182px;&quot; width=&quot;500&quot; height=&quot;182&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;남들이 다 쓴다는 AWS이기에, AWS를 안 써 볼 수가 없었다. 써 본 결과는... 정말 컴퓨팅 서비스의 명가이구나를 느낄 수 있었다. 컴퓨팅 성능도 우수했고, 핑도 상당히 괜찮았다.&lt;/p&gt;
&lt;p&gt;하지만 AWS에서도 2달 이후 자리를 옮기게 되는데, AWS에서 제공하는 사양 중 메모리가 다른 저렴한 서비스와 비교해봤을 때 상당히 부족함을 느꼈기 때문이다. 타사에서 같은 가격으로 1GB의 메모리를 제공할 때 AWS EC2는 0.5GB를 제공했는데, Docker 위에서 nginx를 하나 돌리면 0.5GB 메모리가 가득 차서, 더이상 다른 도커 이미지를 올릴 수가 없었다.&lt;/p&gt;
&lt;p&gt;물론, 0.5GB 인스턴스에 도커를, 그도 이미지 두개를 올린다는 것 자체가 원래부터가 정말 말도 안되는 억지인 일이고, 좋은 서비스를 이용하려면 그에 상응하는 가격을 지불하는 건 당연한 일이지만... 그냥 적어도 학생 신분일 때 까지만은 세상 공짜로 살고싶은 (혹자가 보면 매우 짜증날 만 한) 소비자가 되어보기로 했다.&lt;/p&gt;
&lt;p&gt;AWS를 지나면서 나의 서버 계획도 바뀌었는데, 서버사이드 언어로 돌아가는 서비스를 제외하고는 모두 Github 페이지를 이용하고, 개발 서버는 내가 쓰던 예전 노트북을 DDNS와 결합하여 서버로 쓰기로 하고, 서버사이드 언어로 돌아가는 메일서버, 404 페이지 서비스, 기타 앱 서비스만을 가상 서버 서비스에 올리기로 했다.&lt;/p&gt;
&lt;h3&gt;6. TOAST Cloud&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; style=&quot;width: 500px; height: 57px;&quot; width=&quot;500&quot; height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99BB484D5C371B801B?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99BB484D5C371B801B?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BB484D5C371B801B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BB484D5C371B801B&quot; style=&quot;width: 500px; height: 57px;&quot; width=&quot;500&quot; height=&quot;57&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이제 고려할 만 한 다른 외국 서비스는 그다지 없었고, 핑이 중요한지라 국내 서비스를 찾아보았는데, ucloud는 개인 서비스를 종료했고, 대신 새로 떠오르는 TOAST 서비스가 있어서 이 기회에 이용해보게 되었다. 이렇게 말하니까 기승전광고글같지만 이건 그냥 개인 기록일 뿐이다.&lt;/p&gt;
&lt;p&gt;아직까지는 지원하는 리눅스 이미지 종류도 매우 적고 (CentOS/Ubuntu/Debian/RHEL/Windows), 콘솔 로그인 계정에 대해 보안도 매우 허술하다 (TOTP 미지원 및 이메일/비밀번호만 알면 로그인이 가능).&lt;/p&gt;
&lt;p&gt;하지만 꽤 경쟁력이 있다 (고 내가 생각하는) 가격 정책, 무엇보다도 국내 서비스라 국내 고객센터이고, 말이 잘 통하는 사람들이 답변을 달아준다. 문의를 하면 고객 센터 직원뿐 아니라 내부 운영 및 개발 직원이 직접 답변을 해주기도 한다. 이 점은 나머지 어떤 서비스에서도 찾아볼 수 없는 고객 관리라고 생각이 든다. 내가 현재 TOAST 서비스에서 떠나지 않는 이유도 이것이 주이다. 여하튼, 핑과 성능도 좋으므로, 현재 만족하며 사용중이다. 다만 TOAST Cloud에서 docker를 이용한다면 손이 많이 가게 될 것이다. docker-ready OS를 제공하지 않기 때문이다.&lt;/p&gt;
&lt;h2&gt;현재 서버 구조&lt;/h2&gt;
&lt;p&gt;현재는 상기한 TOAST Cloud 위에 아래와 같은 서비스를 굴리고 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;404 페이지 서버&lt;/li&gt;
&lt;li&gt;메일 서버&lt;/li&gt;
&lt;li&gt;채팅 앱 데모용 백엔드 서버&lt;/li&gt;
&lt;li&gt;공용 콘텐츠 저장용 오브젝트 스토리지 두 개&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;나머지는 모두 Github Pages로 이전했으며, 개발은 개인 노트북 서버에서 진행한다.&lt;/p&gt;
&lt;p&gt;두서 없이 글을 썼지만, 나중에 언젠가 나 자신에게 참고가 되겠지?&lt;/p&gt;</description>
      <category>기타/홈페이지 관리</category>
      <category>서버</category>
      <category>클라우드</category>
      <author>실토</author>
      <guid isPermaLink="true">https://yuoa.tistory.com/9</guid>
      <comments>https://yuoa.tistory.com/entry/2018%EB%85%84-%EC%97%AC%EB%A6%84-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%9A%8D-%EC%A0%95%EB%A6%AC#entry9comment</comments>
      <pubDate>Thu, 10 Jan 2019 19:44:14 +0900</pubDate>
    </item>
  </channel>
</rss>